public static function getAccount(Schema $schema, $accountId) { if (!array_key_exists($accountId, self::$accounts)) { $queryString = "SELECT a.id,a.name FROM " . DbConstants::TABLE_ACCOUNT . " a WHERE a.id = '{$accountId}'"; $queryResult = $schema->getMySQLi()->query($queryString); if (!$queryResult) { throw new Exception("Error fetching account for [{$accountId}] - " . $schema->getMySQLi()->error . "\n<-- {$queryString} -->"); } $account = NULL; $queryData = $queryResult->fetch_assoc(); if ($queryData) { $account = new PersistentAccount($queryData['id'], $queryData['name']); } $queryResult->close(); if ($account == NULL) { throw new Exception("Cannot find account for '{$accountId}'."); } self::$accounts[$accountId] = $account; } return self::$accounts[$accountId]; }
function __construct(Schema $schema, Account $account) { $this->accountId = $account->getId(); $mySQLi = $schema->getMySQLi(); $queryString = "INSERT " . DbConstants::TABLE_AUDIT . " (id_account) VALUES('" . $this->accountId . "')"; $queryResult = $mySQLi->query($queryString); if (!$queryResult) { throw new Exception("Error creating audit object for account[" . $this->accountId . "] - " . $mySQLi->error . "\n<!--\n{$queryString}\n-->"); } $this->id = $mySQLi->insert_id; // Get the timestamp of the created audit object. $queryString = "SELECT a.at FROM " . DbConstants::TABLE_AUDIT . " a WHERE a.id = {$this->id}"; $queryResult = $mySQLi->query($queryString); if (!$queryResult) { throw new Exception("Error fetching audit[" . $this->accountId . "] - " . $mySQLi->error . "\n<!--\n{$queryString}\n-->"); } $audit = $queryResult->fetch_assoc(); $this->at = $audit['at']; $queryResult->close(); }
private function purgeObsoleteAudits(Schema $schema, Audit $audit) { $mySQLi = $schema->getMySQLi(); $queryString = "DELETE a FROM " . DbConstants::TABLE_AUDIT . " a" . " WHERE a.id_account IN(1, " . $audit->getAccountId() . ")" . " AND NOT EXISTS (SELECT 1 FROM " . DbConstants::TABLE_STATE . " WHERE id_created = a.id)" . " AND NOT EXISTS (SELECT 1 FROM " . DbConstants::TABLE_STATE . " WHERE id_published = a.id)" . " AND NOT EXISTS (SELECT 1 FROM " . DbConstants::TABLE_STATE . " WHERE id_terminated = a.id)"; $queryResult = $mySQLi->query($queryString); if (!$queryResult) { throw new Exception("Error purging '" . DbConstants::TABLE_AUDIT . "' - {$mySQLi->error}\n<!--\n{$queryString}\n-->"); } return $mySQLi->affected_rows; }
private function getOwnedObjectRefs(Schema $schema, ObjectEntity $entity, $id, $isPublished) { // Find any related objects that are (still) published. // First create a set of entities that are 'owned' by the given one... $ownedEntities = array(); foreach ($entity->getRelationships() as $relationship) { if ($relationship->getOwnerEntity() == $entity) { $oppositeEntity = $relationship->getOppositeEntity($entity); if ($oppositeEntity->isObjectEntity()) { $ownedEntities[] = $oppositeEntity; } } } // ...and then fetch the published ObjectRefs. if (count($ownedEntities) == 0) { return NULL; } $objectRef = new ObjectRef($entity, $id); $params = array(RestUrlParams::PUBLISHED => $isPublished ? 'true' : 'false'); $queryContext = new QueryContext($params, NULL); $scope = Scope::parseValue(Scope::VALUE_C_REF . Scope::VALUE_A_REF . Scope::VALUE_O_REF); return $objectRef->fetchAllRelatedObjectRefs($schema->getMySQLi(), $ownedEntities, $queryContext, $scope); }
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; } } } } } } } }