private function getAccountIdByNameFromDB($accountName) { $id = NULL; try { $schema = MetaData::getInstance()->getSchema($this->appName); $mySQLi = $schema->getMySQLi(); $queryString = "SELECT id FROM " . DbConstants::TABLE_ACCOUNT . " WHERE name LIKE '" . $accountName . "'"; $queryResult = $mySQLi->query($queryString); if (!$queryResult) { throw new Exception("Error fetching account ID for '{$accountName}' - {$mySQLi->error}\n<!--\n{$queryString}\n-->"); } $queryData = $queryResult->fetch_assoc(); if (isset($queryData['id'])) { $id = $queryData['id']; } $queryResult->close(); } catch (Exception $e) { Bootstrap::logException($e); } return $id; }
/** * Accepts a list of XML nodes, each representing an object that must be either created, updated or deleted, * depending on the presence of respectively a @created or @deleted attribute. The node names must be equal to that * of an entity and the names of the child nodes must be equal to the property names applicable to that entity. * Node names are compared case-insensitive. * * Special attributes are * deleted - Change-index indicating that this is an existing (persisted) object that must be deleted. * id - Object identifier (primary key). * * Every object-node must have an @id, either permanent (numerical value) or temporary (starting with a non-digit). * Temporary ID's will be substituted with the permanent (persisted) ID lateron. * * Child nodes who's name equals that of an entity are NOT recursively parsed and processed. Only their @id * attribute is used to add or update foreign keys. * * RETURN * A map of (temporary and) permanent id's per entity is returned. This map enables the caller to substitute * temporary id's at the client side. * * ERROR * It is an error if the name of a given node doesn't match that of an entity, or if the names of child nodes * don't match that of properties of the entity. * * HOW IT WORKS * The nodes are scanned recursively (so $xmlElements can be a 'flat' list of object nodes or a nested xml tree or * a combination of both) and grouped in three arrays, one with nodes of objects that must be created, changed or * deleted. The 'created' group is processed first. The nodes in this group are sorted based on their entity, so the * order of creation allows for substituting any foreign key of successively created objects. This is to prevent * violating foreign key constraints. * Then the 'changed' group is processed. Foreign keys are substitued before updating each object in the database. * Foreign keys of objects that are in the 'deleted' group will be set to NULL. * Finally the objects in the 'deleted' group are deleted. */ private function processXmlObjects($appName, array $xmlElements, $restResponseCode) { $schema = $this->metaData->getSchema($appName); $this->processQueryParams($schema, NULL); $mySQLi = $schema->getMySQLi(); try { $account = PersistentAccount::getAccount($schema, AuthHandler::getSignedInAccountId($appName)); $audit = new PersistentAudit($schema, $account); $objectFetcher = $this->getObjectFetcher($appName); $restParser = new RestParser(); // Parse all nodes... $restParser->parse($schema, $xmlElements, $this->temporaryIdMap, $objectFetcher); // ...set the foreign key id's... $restParser->applyParsedRelationships(); // ...and divide the ParsedObjects in groups (CREATED, CHANGED, DELETED). $restParser->groupParsedObjects($schema, $objectFetcher); // Any CHANGED object can have existing (persisted) relationships that don't exist in the parsed dataset. // Detect these now. $restParser->detectObsoleteConnections($schema, $objectFetcher); // Create all CREATED objects. foreach ($restParser->getCreatedObjects() as $createdObject) { $entity = $createdObject->getEntity(); // Note: the id of a $createdParsedObject is always a temporary id. $temporaryId = $createdObject->getId(); // Substitute any temporary id's in foreign key properties. $createdObject->substituteTemporaryIds($this->temporaryIdMap); // Create the object and add the newly created object id to the temporaryIdMap. $persistedId = $this->objectModifier->createObject($schema, $entity, $createdObject->getPropertyValues(), $audit); $createdObject->setId($persistedId); $this->temporaryIdMap->setId($entity, $temporaryId, $persistedId); } // Update all objects in the CHANGED group. foreach ($restParser->getChangedObjects() as $changedObject) { if ($changedObject->getScope()->includes(Scope::TAG_PROPERTIES) != Scope::INCLUDES_ALL) { continue; } $changedObject->substituteTemporaryIds($this->temporaryIdMap); $isPersisted = $this->objectModifier->modifyObject($schema, $changedObject->getEntity(), $changedObject->getId(), $changedObject->getPropertyValues(), $audit); if ($isPersisted) { $this->temporaryIdMap->setId($changedObject->getEntity(), NULL, $changedObject->getId()); } } // Create and/or delete all link-relationships. foreach ($restParser->getChangedAndTouchedObjects() as $changedObject) { $changedObject->establishLinks($schema, $this->objectModifier, $audit); } foreach ($restParser->getCreatedObjects() as $createdObject) { $createdObject->establishLinks($schema, $this->objectModifier, $audit); } // Delete all objects in the DELETED group. foreach ($restParser->getDeletedObjects() as $deletedObject) { $this->objectModifier->deleteObjectTree($schema, $deletedObject->getEntity(), $deletedObject->getId(), $audit); } // Update the PUBLISHED state. foreach ($restParser->getPublishedObjects() as $publishedObject) { $this->objectPublisher->publish($schema, $publishedObject->getEntity(), $publishedObject->getId(), $audit); // Purge - permanently delete - all 'terminated' objects that are not part of the published data. $this->objectModifier->purge($schema, $publishedObject->getEntity(), $publishedObject->getId(), $audit); } // Commit the database transaction. $mySQLi->commit(); // Save temporaryIds in the session. $_SESSION[$this->sessionId] = $this->temporaryIdMap->serializeTemporaryIds(); return new RestResponse($restResponseCode, $this->temporaryIdMap); } catch (Exception $e) { Bootstrap::logException($e); $mySQLi->rollback(); return new RestResponse(RestResponse::SERVER_ERROR, $e); } }