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); }
/** * Recursively fetches all objects-to-be-deleted and puts them in a map with a list of id's per entity. * It also fetches links-to-be-deleted in another map with per link entity a list fkIds per fkColumnName. * * @param Schema $schema * @param ObjectEntity $oneEntity * @param <type> $id * @param array $objectsToBeDeleted [ * entityName => [ id, ... ] * ] * @param array $linksToBeDeleted [ * entityName => [ * fkColumnName => [ fkId, ... ] * ] * ] */ private function fetchTerminatedObjectsAndLinks(Schema $schema, ObjectEntity $oneEntity, $oneId, array &$objectsVisited, array &$objectsToBeDeleted, array &$linksToBeDeleted) { $mySQLi = $schema->getMySQLi(); $oneEntityName = $oneEntity->getName(); // Find any related object that is 'owned' by the current object. foreach ($oneEntity->getRelationships() as $relationship) { if ($relationship->getOwnerEntity() != $oneEntity) { // Do nothing if $oneEntity is not the owner of the other entity. continue; } // Get the 'other' entity of the relationship. $otherEntity = $relationship->getOppositeEntity($oneEntity); $otherEntityName = $otherEntity->getName(); if (!$otherEntity->isObjectEntity()) { // Deal with many-to-many relationships. $fkColumnNameOne = $relationship->getFkColumnName($oneEntity); // Prepare to add any fetched links to the map. if (!array_key_exists($otherEntityName, $linksToBeDeleted)) { $linksToBeDeleted[$otherEntityName] = array(); } $fksOfEntityToBeDeleted =& $linksToBeDeleted[$otherEntityName]; // Prepare to add the fkId. if (!array_key_exists($fkColumnNameOne, $fksOfEntityToBeDeleted)) { $fksOfEntityToBeDeleted[$fkColumnNameOne] = array(); } $fkIdsToBeDeleted =& $fksOfEntityToBeDeleted[$fkColumnNameOne]; $fkIdsToBeDeleted[] = $oneId; } else { // Deal with one-to-many relationships. $fetchedOtherIds = array(); // Prepare to add any fetched objects to the map. if (!array_key_exists($otherEntityName, $objectsToBeDeleted)) { $objectsToBeDeleted[$otherEntityName] = array(); } $otherIdsToBeDeleted =& $objectsToBeDeleted[$otherEntityName]; if ($relationship->getFkEntity() == $oneEntity) { // If the object at hand holds the foreign key, then fetch those foreign keys. $fkColumnName = $relationship->getFkColumnName($otherEntity); $oneObjectIdColumnName = $oneEntity->getObjectIdColumnName(); $queryString = "SELECT DISTINCT d.{$fkColumnName}"; if ($oneEntity->getStateIdColumnName() != NULL) { $queryString .= ", s.id_terminated"; } $queryString .= " FROM {$oneEntityName} d"; if ($oneEntity->getStateIdColumnName() != NULL) { $queryString .= ", " . DbConstants::TABLE_STATE . " s"; } $queryString .= " WHERE d.{$oneObjectIdColumnName} = {$oneId}"; if ($oneEntity->getStateIdColumnName() != NULL) { $queryString .= " AND s.id = d.{$oneObjectIdColumnName}"; } // Execute the query $queryResult = $mySQLi->query($queryString); if (!$queryResult) { throw new Exception("Error fetching foreign key '{$fkColumnName}' of {$oneEntityName}" . "[{$oneId}] - {$mySQLi->error}\n<!--\n{$queryString}\n-->"); } while ($queryData = $queryResult->fetch_assoc()) { $otherId = $queryData[$fkColumnName]; if ($otherId != NULL) { $fetchedOtherIds[] = $otherId; if ($queryData['id_terminated'] != NULL) { $otherIdsToBeDeleted[] = $otherId; } } } $queryResult->close(); } else { // The related objects hold the foreign keys, so fetch their ids. $fkColumnName = $relationship->getFkColumnName($oneEntity); $otherObjectIdColumnName = $otherEntity->getObjectIdColumnName(); $queryString = "SELECT DISTINCT d.{$otherObjectIdColumnName}"; if ($otherEntity->getStateIdColumnName() != NULL) { $queryString .= ", s.id_terminated"; } $queryString .= " FROM {$otherEntityName} d"; if ($otherEntity->getStateIdColumnName() != NULL) { $queryString .= ", " . DbConstants::TABLE_STATE . " s"; } $queryString .= " WHERE d.{$fkColumnName} = {$oneId}"; if ($otherEntity->getStateIdColumnName() != NULL) { $queryString .= " AND s.id = d." . $otherEntity->getStateIdColumnName(); } // Execute the query $queryResult = $mySQLi->query($queryString); if (!$queryResult) { throw new Exception("Error fetching terminated object ids of entity '{$otherEntityName}'" . " referring to {$oneEntityName}" . "[{$oneId}]" . " - {$mySQLi->error}\n<!--\n{$queryString}\n-->"); } while ($queryData = $queryResult->fetch_assoc()) { $otherId = $queryData[$otherObjectIdColumnName]; if ($otherId != NULL) { $fetchedOtherIds[] = $otherId; if ($queryData['id_terminated'] != NULL) { $otherIdsToBeDeleted[] = $otherId; } } } $queryResult->close(); } // If the other entity is not a link... if (count($fetchedOtherIds) > 0 && $relationship->getFkEntity()->isObjectEntity()) { // ...then continue recursing down the object hierarchy. // Keep track of all visited objects to prevent endless recursion. if (!array_key_exists($otherEntityName, $objectsVisited)) { $objectsVisited[$otherEntityName] = array(); } $otherIdsVisited =& $objectsVisited[$otherEntityName]; foreach ($fetchedOtherIds as $otherId) { if (!in_array($otherId, $otherIdsVisited)) { $otherIdsVisited[] = $otherId; $this->fetchTerminatedObjectsAndLinks($schema, $otherEntity, $otherId, $objectsVisited, $objectsToBeDeleted, $linksToBeDeleted); } } } } } }