function synchronize($task, $entitiesToSynchronize = null) { $this->maybeInit($entitiesToSynchronize); $options = $this->options; if (count($options) > 0) { $syncQuery = "INSERT INTO {$this->tableName} (option_name, option_value, autoload) VALUES "; foreach ($options as $optionName => $option) { $option = $this->urlReplacer->restore($option); $option = $this->maybeRestoreReference($option); if (!isset($option['autoload'])) { $option['autoload'] = 'yes'; } // default value if (!isset($option['option_value'])) { $option['option_value'] = ''; } $syncQuery .= "(\"{$optionName}\", \"" . $this->database->_real_escape($option['option_value']) . "\", \"{$option['autoload']}\"),"; } $syncQuery[strlen($syncQuery) - 1] = " "; // strip last comma $syncQuery .= " ON DUPLICATE KEY UPDATE option_value = VALUES(option_value), autoload = VALUES(autoload);"; $this->database->query($syncQuery); } $ignoredOptionNames = ArrayUtils::column($options, 'option_name'); $ignoredOptionNames = array_merge($ignoredOptionNames, OptionStorage::$optionsBlacklist); $deleteSql = "DELETE FROM {$this->tableName} WHERE option_name NOT IN (\"" . join('", "', $ignoredOptionNames) . "\") OR option_name NOT LIKE '_%'"; if ($entitiesToSynchronize) { $synchronizedOptions = ArrayUtils::column($entitiesToSynchronize, 'vp_id'); $deleteSql = "DELETE FROM {$this->tableName} WHERE option_name NOT IN (\"" . join('", "', $ignoredOptionNames) . "\") AND option_name IN (\"" . join('", "', $synchronizedOptions) . "\")"; } $this->database->query($deleteSql); return array(); }
/** * Chooses an appropriate storage and calls its {@see VersionPress\Storages\Storage::save() save()} method. * * @see Storage::save() * * @param string $entityName Entity type determines the storage used * @param array $data Data passed to the `VersionPress\Storages\Storage::save()` method */ public function save($entityName, $data) { $storage = $this->storageFactory->getStorage($entityName); if ($storage == null) { return; } $data = $this->urlReplacer->replace($data); $changeInfo = $storage->save($data); if ($changeInfo) { $this->changeList[] = $changeInfo; } }
/** * Loads entities from storage. For full synchronization it loads all entities. For selective synchronization it loads * only entities from $this->entitiesToSynchronize. * * @return array */ private function loadEntitiesFromStorage() { if ($this->isSelectiveSynchronization) { $entities = []; foreach ($this->entitiesToSynchronize as $entityToSynchronize) { if ($this->storage->exists($entityToSynchronize['vp_id'], $entityToSynchronize['parent'])) { $entities[] = $this->storage->loadEntity($entityToSynchronize['vp_id'], $entityToSynchronize['parent']); } } } else { $entities = $this->storage->loadAll(); } $entities = $this->maybeStripMetaEntities($entities); $entities = array_map(function ($entity) { return $this->urlReplacer->restore($entity); }, $entities); $entities = array_map(function ($entity) { return $this->vpidRepository->restoreForeignKeys($this->entityName, $entity); }, $entities); return $entities; }
/** * @test * @dataProvider entityDataProvider * * @param $entity * @param $entityWithReplacedUrls */ public function itRestoresUrl($entity, $entityWithReplacedUrls) { $result = $this->filter->restore($entityWithReplacedUrls); $this->assertEquals($entity, $result); }
/** * @param $entityName */ private static function assertEntitiesEqualDatabase($entityName) { $storage = self::$storageFactory->getStorage($entityName); $entityInfo = self::$schemaInfo->getEntityInfo($entityName); $allDbEntities = self::selectAll(self::$schemaInfo->getPrefixedTableName($entityName)); $idMap = self::getVpIdMap(); $allDbEntities = self::identifyEntities($entityName, $allDbEntities, $idMap); $allDbEntities = self::replaceForeignKeys($entityName, $allDbEntities, $idMap); $dbEntities = array_filter($allDbEntities, [$storage, 'shouldBeSaved']); $urlReplacer = new AbsoluteUrlReplacer(self::$testConfig->testSite->url); $storageEntities = array_map(function ($entity) use($urlReplacer) { return $urlReplacer->restore($entity); }, $storage->loadAll()); $countOfentitiesInDb = count($dbEntities); $countOfentitiesInStorage = count($storageEntities); if ($countOfentitiesInDb !== $countOfentitiesInStorage) { if ($countOfentitiesInStorage > $countOfentitiesInDb) { $problematicEntities = self::findMissingEntities($entityName, $storageEntities, $dbEntities); } else { $problematicEntities = self::findExceedingEntities($entityName, $storageEntities, $dbEntities); } throw new \PHPUnit_Framework_AssertionFailedError("Different count of synchronized entities ({$entityName}): DB = {$countOfentitiesInDb}, " . "storage = {$countOfentitiesInStorage}\nProblematic entities: " . join(", ", $problematicEntities)); } foreach ($dbEntities as $dbEntity) { $id = $dbEntity[$entityInfo->vpidColumnName]; $storageEntity = $storageEntities[$id]; $dbEntity = self::$shortcodesReplacer->replaceShortcodesInEntity($entityName, $dbEntity); foreach ($dbEntity as $column => $value) { if ($entityInfo->idColumnName === $column || isset($entityInfo->getIgnoredColumns()[$column])) { continue; } if (!isset($storageEntity[$column])) { throw new \PHPUnit_Framework_AssertionFailedError("{$entityName}[{$column}] with value = {$value}, ID = {$id} not found in storage"); } if (is_string($storageEntity[$column])) { $storageEntity[$column] = str_replace("\r\n", "\n", $storageEntity[$column]); } if (is_string($value)) { $value = str_replace("\r\n", "\n", $value); } if ($storageEntity[$column] != $value) { throw new \PHPUnit_Framework_AssertionFailedError("Different values ({$entityName}[{$column}]: {$id}): DB = {$value}, storage = {$storageEntity[$column]}"); } } } $missingReferences = []; $exceedingReferences = []; foreach ($entityInfo->mnReferences as $reference => $targetEntity) { if ($entityInfo->isVirtualReference($reference)) { continue; } $referenceDetails = ReferenceUtils::getMnReferenceDetails(self::$schemaInfo, $entityName, $reference); $sourceColumn = $referenceDetails['source-column']; $targetColumn = $referenceDetails['target-column']; $junctionTable = $referenceDetails['junction-table']; $prefixedJunctionTable = self::$schemaInfo->getPrefixedTableName($junctionTable); $prefixedVpIdTable = self::$schemaInfo->getPrefixedTableName('vp_id'); $sourceTable = self::$schemaInfo->getTableName($referenceDetails['source-entity']); $targetTable = self::$schemaInfo->getTableName($referenceDetails['target-entity']); $junctionTableContent = self::fetchAll("SELECT HEX(s_vp_id.vp_id), HEX(t_vp_id.vp_id) FROM {$prefixedJunctionTable} j\n JOIN {$prefixedVpIdTable} s_vp_id ON j.{$sourceColumn} = s_vp_id.id AND s_vp_id.`table`='{$sourceTable}'\n JOIN {$prefixedVpIdTable} t_vp_id ON j.{$targetColumn} = t_vp_id.id AND t_vp_id.`table` = '{$targetTable}'", MYSQLI_NUM); $checkedReferences = []; $missingReferences[$junctionTable] = []; foreach ($storageEntities as $storageEntity) { if (!isset($storageEntity["vp_{$targetEntity}"])) { continue; } foreach ($storageEntity["vp_{$targetEntity}"] as $referenceVpId) { if (!ArrayUtils::any($junctionTableContent, function ($junctionRow) use($storageEntity, $referenceVpId) { return $junctionRow[0] === $storageEntity['vp_id'] && $junctionRow[1] === $referenceVpId; })) { $missingReferences[$junctionTable][] = [$sourceColumn => $storageEntity['vp_id'], $targetColumn => $referenceVpId]; } $checkedReferences[] = [$storageEntity['vp_id'], $referenceVpId]; } } $exceedingReferences[$junctionTable] = array_map(function ($pair) use($sourceColumn, $targetColumn) { return [$sourceColumn => $pair[0], $targetColumn => $pair[1]]; }, array_filter($junctionTableContent, function ($pair) use($checkedReferences) { foreach ($checkedReferences as $reference) { if ($reference[0] === $pair[0] && $reference[1] === $pair[1]) { return false; } } return true; })); } self::reportResultOfMnReferenceCheck($missingReferences, "Missing"); self::reportResultOfMnReferenceCheck($exceedingReferences, "Exceeding"); }