/**
  * @param CommitMessage $commitMessage
  * @return ChangeInfoEnvelope
  */
 public function parse(CommitMessage $commitMessage)
 {
     $fullBody = $commitMessage->getBody();
     $splittedBodies = explode("\n\n", $fullBody);
     $lastBody = $splittedBodies[count($splittedBodies) - 1];
     $changeInfoList = [];
     $version = null;
     $environment = null;
     if (self::containsVersion($lastBody)) {
         $version = self::extractTag(ChangeInfoEnvelope::VP_VERSION_TAG, $lastBody);
         $environment = self::extractTag(ChangeInfoEnvelope::VP_ENVIRONMENT_TAG, $lastBody);
         array_pop($splittedBodies);
     }
     if (!self::isTrackedChangeInfo($fullBody)) {
         return new ChangeInfoEnvelope([new UntrackedChangeInfo($commitMessage)], $version, $environment);
     }
     foreach ($splittedBodies as $body) {
         $partialCommitMessage = new CommitMessage("", $body);
         $actionTag = $partialCommitMessage->getVersionPressTag(TrackedChangeInfo::ACTION_TAG);
         list($scope, $action, $id) = array_pad(explode('/', $actionTag, 3), 3, null);
         $tags = $partialCommitMessage->getVersionPressTags();
         unset($tags[TrackedChangeInfo::ACTION_TAG]);
         $actionsInfo = $this->actionsInfoProvider->getActionsInfo($scope);
         if ($this->dbSchema->isEntity($scope)) {
             $entityInfo = $this->dbSchema->getEntityInfo($scope);
             $changeInfoList[] = new EntityChangeInfo($entityInfo, $actionsInfo, $action, $id, $tags, []);
         } else {
             $changeInfoList[] = new TrackedChangeInfo($scope, $actionsInfo, $action, $id, $tags, []);
         }
     }
     return new ChangeInfoEnvelope($changeInfoList, $version, $environment);
 }
 public function createEntityChangeInfo($entity, $entityName, $action, $customTags = [], $customFiles = [])
 {
     $entityInfo = $this->dbSchema->getEntityInfo($entityName);
     $vpid = $entity[$entityInfo->vpidColumnName];
     $actionsInfo = $this->actionsInfoProvider->getActionsInfo($entityName);
     $automaticallySavedTags = $actionsInfo->getTags();
     $tags = ChangeInfoUtils::extractTags($automaticallySavedTags, $entity, $entity);
     $tags = array_merge($tags, $customTags);
     return new EntityChangeInfo($entityInfo, $actionsInfo, $action, $vpid, $tags, $customFiles);
 }
 /**
  * @test
  */
 public function dbSchemaInfoMergesReferencesFromMultipleSources()
 {
     $schema1 = ['some-entity' => ['id' => 'some_column', 'value-references' => ['some_column@another_column' => ['some_value' => 'another-entity']]]];
     $schema2 = ['some-entity' => ['value-references' => ['some_column@another_column' => ['another_value' => 'another-entity']]]];
     $schemaFile1 = $this->createSchemaFile($schema1);
     $schemaFile2 = $this->createSchemaFile($schema2);
     $schemaInfo = new DbSchemaInfo([$schemaFile1, $schemaFile2], 'prefix_', PHP_INT_MAX);
     $entityInfo = $schemaInfo->getEntityInfo('some-entity');
     $expectedValueReferences = ['some_column=some_value@another_column' => 'another-entity', 'some_column=another_value@another_column' => 'another-entity'];
     $this->assertSame($expectedValueReferences, $entityInfo->valueReferences);
 }
 /**
  * Returns name of column referencing synchronized entity in the junction table.
  * Example:
  * We are synchronizing posts with M:N reference to the taxonomies. The reference is defined
  * as term_relationships.term_taxonomy_id => term_taxonomy. Name of column referencing term_taxonomy is obvious,
  * it's term_taxonomy_id. However we need also name of column referencing the post. We can find this name
  * in the definition of M:N references of term_taxonomy, where it's defined as term_relationships.object_id => post.
  * So in the end we are looking for M:N reference to post with same junction table (term_relationships).
  *
  * @param DbSchemaInfo $dbSchema
  * @param $sourceEntity
  * @param $targetEntity
  * @param $junctionTable
  * @return string
  */
 private static function getSourceColumn(DbSchemaInfo $dbSchema, $sourceEntity, $targetEntity, $junctionTable)
 {
     $targetEntityMnReferences = $dbSchema->getEntityInfo($targetEntity)->mnReferences;
     foreach ($targetEntityMnReferences as $reference => $referencedEntity) {
         list($referencedTable, $referenceColumn) = explode(".", $reference);
         if ($referencedTable === $junctionTable && $referencedEntity === $sourceEntity) {
             return $referenceColumn;
         }
     }
     return null;
 }
Example #5
0
 private function fillId($entityName, $data, $id)
 {
     $idColumnName = $this->schemaInfo->getEntityInfo($entityName)->idColumnName;
     if (!isset($data[$idColumnName])) {
         $data[$idColumnName] = $id;
     }
     return $data;
 }
 /**
  * @param $entityName
  * @return mixed
  */
 private function getEntitiesFromDatabase($entityName)
 {
     if ($this->dbSchema->isChildEntity($entityName)) {
         $entityInfo = $this->dbSchema->getEntityInfo($entityName);
         $parentReference = $entityInfo->parentReference;
         return $this->database->get_results("SELECT * FROM {$this->dbSchema->getPrefixedTableName($entityName)} ORDER BY {$parentReference}", ARRAY_A);
     }
     return $this->database->get_results("SELECT * FROM {$this->dbSchema->getPrefixedTableName($entityName)}", ARRAY_A);
 }
 private function countEntities()
 {
     $entities = $this->schema->getAllEntityNames();
     $totalEntitiesCount = 0;
     foreach ($entities as $entity) {
         $table = $this->schema->getPrefixedTableName($entity);
         $totalEntitiesCount += $this->database->get_var("SELECT COUNT(*) FROM {$table}");
     }
     return $totalEntitiesCount;
 }
Example #8
0
 private function fillParentId($metaEntityName, $where, $id)
 {
     $entityInfo = $this->dbSchemaInfo->getEntityInfo($metaEntityName);
     $parentReference = $entityInfo->parentReference;
     $parent = $entityInfo->references[$parentReference];
     $vpIdTable = $this->dbSchemaInfo->getPrefixedTableName('vp_id');
     $entityTable = $this->dbSchemaInfo->getPrefixedTableName($metaEntityName);
     $parentTable = $this->dbSchemaInfo->getTableName($parent);
     $idColumnName = $this->dbSchemaInfo->getEntityInfo($metaEntityName)->idColumnName;
     $where["vp_{$parentReference}"] = $this->database->get_var("SELECT HEX(vp_id) FROM {$vpIdTable} WHERE `table` = '{$parentTable}' AND ID = (SELECT {$parentReference} FROM {$entityTable} WHERE {$idColumnName} = {$id})");
     return $where;
 }
Example #9
0
 /**
  * For standard entities just checks the storage.
  * For child entities (like postmeta) loads all entities and checks them.
  *
  * @param $referencedEntityName
  * @param $referencedEntityId
  * @param $maybeParentId
  * @return bool
  */
 private function entityExists($referencedEntityName, $referencedEntityId, $maybeParentId)
 {
     if (!$this->dbSchemaInfo->isChildEntity($referencedEntityName)) {
         return $this->storageFactory->getStorage($referencedEntityName)->exists($referencedEntityId, null);
     }
     // Optimalization for child entities saved within their parents
     if ($this->storageFactory->getStorage($referencedEntityName)->exists($referencedEntityId, $maybeParentId)) {
         return true;
     }
     $allEntities = $this->storageFactory->getStorage($referencedEntityName)->loadAll();
     return isset($allEntities[$referencedEntityId]);
 }
 /**
  * Determines sequence in which entities should be synchronized.
  * It's based on their dependencies on other entities.
  *
  * @return array
  */
 private function resolveSynchronizationSequence()
 {
     $unresolved = $this->dbSchema->getAllReferences();
     $sequence = [];
     $triedRemovingSelfReferences = false;
     while (count($unresolved) > 0) {
         $resolvedInThisStep = [];
         // 1st step - move all entities with resolved dependencies to $sequence
         foreach ($unresolved as $entity => $deps) {
             if (count($deps) === 0) {
                 unset($unresolved[$entity]);
                 $sequence[] = $entity;
                 $resolvedInThisStep[] = $entity;
             }
         }
         // 2nd step - update unresolved dependencies of remaining entities
         foreach ($resolvedInThisStep as $resolvedEntity) {
             foreach ($unresolved as $unresolvedEntity => $deps) {
                 $unresolved[$unresolvedEntity] = array_diff($deps, [$resolvedEntity]);
             }
         }
         // Nothing changed - circular dependency
         if (count($resolvedInThisStep) === 0) {
             if (!$triedRemovingSelfReferences) {
                 // At first try to remove all self-references as they have to run in 2-pass sync anyway
                 $triedRemovingSelfReferences = true;
                 foreach ($unresolved as $unresolvedEntity => $deps) {
                     $unresolved[$unresolvedEntity] = array_diff($deps, [$unresolvedEntity]);
                 }
             } else {
                 // Simply eliminate dependencies one by one until it is resolvable
                 reset($unresolved);
                 $firstEntity = key($unresolved);
                 array_pop($unresolved[$firstEntity]);
             }
         }
     }
     return $sequence;
 }
 private function maybeRestoreReference($option)
 {
     $entityInfo = $this->dbSchema->getEntityInfo('option');
     foreach ($entityInfo->valueReferences as $reference => $targetEntity) {
         $referenceDetails = ReferenceUtils::getValueReferenceDetails($reference);
         if ($option[$referenceDetails['source-column']] === $referenceDetails['source-value'] && isset($option[$referenceDetails['value-column']])) {
             $vpid = $option[$referenceDetails['value-column']];
             $vpidTable = $this->dbSchema->getPrefixedTableName('vp_id');
             $targetTable = $this->dbSchema->getTableName($targetEntity);
             $dbId = $this->database->get_var("SELECT id FROM {$vpidTable} WHERE `table`='{$targetTable}' AND vp_id=UNHEX('{$vpid}')");
             $option[$referenceDetails['value-column']] = $dbId;
         }
     }
     return $option;
 }
Example #12
0
 /**
  * @param $entities
  * @return array
  */
 private function getExistingMnReferences($entities)
 {
     $entityInfo = $this->dbSchema->getEntityInfo($this->entityName);
     $mnReferences = $entityInfo->mnReferences;
     $referencesToFix = array();
     foreach ($entities as $entity) {
         foreach ($mnReferences as $reference => $referencedEntity) {
             $vpReference = "vp_{$referencedEntity}";
             if (!isset($entity[$vpReference]) || count($entity[$vpReference]) == 0) {
                 continue;
             }
             foreach ($entity[$vpReference] as $referencedVpId) {
                 $referencesToFix[$reference][] = array('vp_id' => $entity['vp_id'], 'referenced_vp_id' => $referencedVpId);
             }
         }
     }
     return $referencesToFix;
 }
 /**
  * Saves all already existing meta and M:N references for an entity that wasn't tracked yet
  *
  * @param array $data
  * @param string $entityName
  */
 private function storeRelatedEntities($data, $entityName)
 {
     $id = $data[$this->dbSchemaInfo->getEntityInfo($entityName)->idColumnName];
     foreach ($this->dbSchemaInfo->getAllEntityNames() as $referencedEntityName) {
         $entityInfo = $this->dbSchemaInfo->getEntityInfo($referencedEntityName);
         if ($this->dbSchemaInfo->isChildEntity($referencedEntityName) && $entityInfo->references[$entityInfo->parentReference] === $entityName) {
             $childEntities = $this->database->get_results("SELECT * FROM {$this->dbSchemaInfo->getPrefixedTableName($referencedEntityName)} WHERE `{$entityInfo->parentReference}` = '{$id}'", ARRAY_A);
             foreach ($childEntities as $childEntity) {
                 $childEntity = $this->vpidRepository->replaceForeignKeysWithReferences($referencedEntityName, $childEntity);
                 if (!$this->mirror->shouldBeSaved($referencedEntityName, $childEntity)) {
                     continue;
                 }
                 $id = $childEntity[$entityInfo->idColumnName];
                 $vpid = $this->vpidRepository->getVpidForEntity($referencedEntityName, $id);
                 if ($vpid) {
                     $childEntity[$entityInfo->vpidColumnName] = $vpid;
                 } else {
                     $childEntity = $this->vpidRepository->identifyEntity($referencedEntityName, $childEntity, $childEntity[$entityInfo->idColumnName]);
                 }
                 $childEntity = $this->shortcodesReplacer->replaceShortcodesInEntity($referencedEntityName, $childEntity);
                 $this->mirror->save($referencedEntityName, $childEntity);
             }
         }
     }
     foreach ($this->dbSchemaInfo->getAllMnReferences() as $mnReferenceDetails) {
         if ($mnReferenceDetails['source-entity'] === $entityName) {
             $junctionTable = $mnReferenceDetails['junction-table'];
             $prefixedJunctionTable = $this->dbSchemaInfo->getPrefixedTableName($junctionTable);
             $sourceColumn = $mnReferenceDetails['source-column'];
             $references = $this->database->get_results("SELECT * FROM `{$prefixedJunctionTable}` WHERE `{$sourceColumn}` = '{$id}'", ARRAY_A);
             foreach ($references as $reference) {
                 $reference = $this->vpidRepository->replaceForeignKeysWithReferences($junctionTable, $reference);
                 $this->mirror->save($junctionTable, $reference);
             }
         }
     }
 }
 /**
  * Returns entity name for a table
  *
  * @param DbSchemaInfo $schema
  * @param string $table
  * @return mixed
  */
 private function resolveEntityName($schema, $table)
 {
     $entity = $schema->getEntityInfoByPrefixedTableName($table);
     return $entity == null ? $schema->trimPrefix($table) : $entity->entityName;
 }
function vp_update_table_ddl_scripts(DbSchemaInfo $dbSchemaInfo, TableSchemaStorage $tableSchemaStorage)
{
    $tableSchemaStorage->deleteAll();
    $entityNames = $dbSchemaInfo->getAllEntityNames();
    foreach ($entityNames as $entityName) {
        $table = $dbSchemaInfo->getPrefixedTableName($entityName);
        $tableSchemaStorage->saveSchema($table);
    }
    $referenceDetails = $dbSchemaInfo->getAllMnReferences();
    foreach ($referenceDetails as $referenceDetail) {
        $table = $dbSchemaInfo->getPrefixedTableName($referenceDetail['junction-table']);
        $tableSchemaStorage->saveSchema($table);
    }
}
 private function adjustSynchronizationSequenceToDbVersion()
 {
     $allSupportedEntities = $this->dbSchema->getAllEntityNames();
     $this->synchronizationSequence = array_intersect($this->synchronizationSequence, $allSupportedEntities);
 }
Example #17
0
 private static function isInIdMap($idMap, $targetEntity, $id)
 {
     return isset($idMap[self::$schemaInfo->getTableName($targetEntity)]) && isset($idMap[self::$schemaInfo->getTableName($targetEntity)][$id]);
 }