public function detectObsoleteConnections(Schema $schema, ObjectFetcher $objectFetcher) { // CHANGED objects can have persisted relationships that don't exist in the parsed dataset. // Such persisted relationships must be removed. This implies that either // a. nothing special needs to be done, or // b. persisted connected objects must be 'patched', i.e. their foreign key must be set to NULL, or // c. persisted connected objects must be deleted, or // d. a persisted link (mant-to-many relationship) must be deleted. // Option a. is the case when the CHANGED object holds the foreign key and if is NOT an owner of the // connected object, or when the connected object is present in the set of ParsedObjects. // Option b. applies to connected objects that are not in the set of ParsedObjects. Such connected objects // must be added as CHANGED ParsedObjects and filled with all existing property values, except for the // foreign key. // Option c. applies to situations where the CHANGED object is the owning entity. In this case the existing // connected object must be added to the set of ParsedObjects and marked as DELETED. // Option d. is similar to option c, but the connected object is a LinkEntity. LinkEntities cannot be referred // to by a single id and therefore cannot be dealt with via ParsedObjects. Creating or deleting LinkEntities is // done in ParsedObject::establishLinks(). // // Note that ParsedObjects marked as 'touched' are not modified themselves, but they may have modified // relationships. These ParsedObjects must be treadet the same as CHANGED objects here. // // So these are the steps to be taken: // 1. loop over the CHANGED and 'touched' ParsedObjects // 2. per object, loop over the relationships, ignoring many-to-many (link) relationships // 3. check if the entity of the object is NOT the foreign key entity in the relationship // and check if the object is owner of the connected object // 4. if either is the case, then see if the parsed data specifies a connection for this relationship // 5. if NOT, then add the connected object to the set of ParsedObjects // 6. if the connected object is NOT an owner, then fetch its id and mark the newly created ParsedObject // as DELETED // 7. if the connected object is the foreign key entity, then fetch and set its id and all its properties // (except for the foreign key) and mark the newly created ParsedObject as CHANGED foreach ($this->getChangedAndTouchedObjects() as $changedObject) { if ($changedObject->getScope()->includes(Scope::TAG_COMPONENTS) == Scope::INCLUDES_NONE) { continue; } $changedEntity = $changedObject->getEntity(); foreach ($changedEntity->getRelationships() as $relationship) { // Ignore LinkEntities, see ParsedObject::establishLinks(). if ($relationship->getFkEntity()->isObjectEntity()) { $connectedEntity = $relationship->getOppositeEntity($changedEntity); $isFkEntity = $changedEntity == $relationship->getFkEntity(); $isOwnerEntity = $changedEntity == $relationship->getOwnerEntity(); if ($isOwnerEntity or !$isFkEntity) { // Check if the parsed data specifies a (new) connection for this relationship. $parsedConnectedObject = NULL; foreach ($changedObject->getRelatedObjects() as $relatedObject) { if ($relatedObject->getEntity() == $connectedEntity) { $parsedConnectedObject = $relatedObject; break; } } // Also check the other direction. foreach ($this->parsedObjects as $parsedObject) { if ($parsedConnectedObject != NULL) { break; } if ($parsedObject->getEntity() == $connectedEntity) { foreach ($parsedObject->getRelatedObjects() as $relatedObject) { if ($relatedObject->getEntity() == $changedEntity) { $parsedConnectedObject = $parsedObject; break; } } } } // Only do something if there is no (new) connection for this relationship, so any existing // connection must be deleted. if ($parsedConnectedObject == NULL) { $persistedConnectionIds = NULL; if ($isFkEntity) { $persistedConnectionIds = array(); $fkColumnName = $relationship->getFkColumnName($connectedEntity); // Fetch the foreign key. $persistedConnectionId = $objectFetcher->getObjectProperty($changedEntity, $changedObject->getId(), $fkColumnName, array()); if ($persistedConnectionId != NULL) { $persistedConnectionIds[] = $persistedConnectionId; } } else { // The existing connected object must be patched or deleted. // Fetch the ids of the connected objects. $changedObjectRef = new ObjectRef($changedEntity, $changedObject->getId()); $persistedConnectionIds = $changedObjectRef->fetchRelatedObjectIdsOfEntity($schema->getMySQLi(), $connectedEntity); } foreach ($persistedConnectionIds as $persistedConnectionId) { // Check if the existing connected object is already specified in the current // transaction. $alreadyParsedObject = NULL; foreach ($this->parsedObjects as $parsedObject) { if ($parsedObject->getEntity() == $connectedEntity and $parsedObject->getId() == $persistedConnectionId) { $alreadyParsedObject = $parsedObject; break; } } // Do nothing if the existing connected object is already present in the set of // ParsedObjects. if ($alreadyParsedObject != NULL) { continue; } if ($isOwnerEntity) { $deletedObject = new ParsedObject($connectedEntity, $persistedConnectionId, array(), ParsedObject::DELETED); $this->deletedObjects[] = $deletedObject; } else { $propertyValues = $objectFetcher->getPropertyValues($connectedEntity, $persistedConnectionId); $propertyValues[$relationship->getFkColumnName($changedEntity)] = NULL; $additionalChangedObject = new ParsedObject($connectedEntity, $persistedConnectionId, $propertyValues, ParsedObject::CHANGED); $additionalChangedObject->adjustForeignIdProperties(); $this->changedObjects[] = $additionalChangedObject; } } } } } } } }
public function __construct($doc, $name, $namespace, $methods = array()) { parent::__construct($doc, $name); $this->namespace = $namespace; $this->methods = $methods; }
public function __construct($doc, $visibility, $name) { parent::__construct($doc, $name); $this->visibility = $visibility; }