diff options
Diffstat (limited to 'library/Director/Data/Db/DbObjectStore.php')
-rw-r--r-- | library/Director/Data/Db/DbObjectStore.php | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/library/Director/Data/Db/DbObjectStore.php b/library/Director/Data/Db/DbObjectStore.php new file mode 100644 index 0000000..bc69b5a --- /dev/null +++ b/library/Director/Data/Db/DbObjectStore.php @@ -0,0 +1,169 @@ +<?php + +namespace Icinga\Module\Director\Data\Db; + +use Icinga\Module\Director\Db; +use Icinga\Module\Director\Db\Branch\Branch; +use Icinga\Module\Director\Db\Branch\BranchActivity; +use Icinga\Module\Director\Db\Branch\BranchedObject; +use Icinga\Module\Director\Db\Branch\MergeErrorDeleteMissingObject; +use Icinga\Module\Director\Db\Branch\MergeErrorModificationForMissingObject; +use Icinga\Module\Director\Db\Branch\MergeErrorRecreateOnMerge; +use Icinga\Module\Director\Db\DbUtil; +use Icinga\Module\Director\Objects\IcingaObject; +use Ramsey\Uuid\UuidInterface; + +/** + * Loader for Icinga/DbObjects + * + * Is aware of branches and prefetching. I would prefer to see a StoreInterface, + * with one of the above wrapping the other. But for now, this helps to clean things + * up + */ +class DbObjectStore +{ + /** @var Db */ + protected $connection; + + /** @var ?Branch */ + protected $branch; + + public function __construct(Db $connection, Branch $branch = null) + { + $this->connection = $connection; + $this->branch = $branch; + } + + /** + * @param $tableName + * @param UuidInterface $uuid + * @return DbObject|null + * @throws \Icinga\Exception\NotFoundError + */ + public function load($tableName, UuidInterface $uuid) + { + $branchedObject = BranchedObject::load($this->connection, $tableName, $uuid, $this->branch); + $object = $branchedObject->getBranchedDbObject($this->connection); + if ($object === null) { + return null; + } + + $object->setBeingLoadedFromDb(); + + return $object; + } + + /** + * @param string $tableName + * @param string $arrayIdx + * @return DbObject[]|IcingaObject[] + * @throws MergeErrorRecreateOnMerge + * @throws MergeErrorDeleteMissingObject + * @throws MergeErrorModificationForMissingObject + */ + public function loadAll($tableName, $arrayIdx = 'uuid') + { + $db = $this->connection->getDbAdapter(); + $class = DbObjectTypeRegistry::classByType($tableName); + $query = $db->select()->from($tableName)->order($arrayIdx); + $result = []; + foreach ($db->fetchAll($query) as $row) { + $row->uuid = DbUtil::binaryResult($row->uuid); + $result[$row->uuid] = $class::create((array) $row, $this->connection); + $result[$row->uuid]->setBeingLoadedFromDb(); + } + if ($this->branch && $this->branch->isBranch()) { + $query = $db->select() + ->from(BranchActivity::DB_TABLE) + ->where('branch_uuid = ?', $this->connection->quoteBinary($this->branch->getUuid()->getBytes())) + ->order('timestamp_ns ASC'); + $rows = $db->fetchAll($query); + foreach ($rows as $row) { + $activity = BranchActivity::fromDbRow($row); + if ($activity->getObjectTable() !== $tableName) { + continue; + } + $uuid = $activity->getObjectUuid(); + $binaryUuid = $uuid->getBytes(); + + $exists = isset($result[$binaryUuid]); + if ($activity->isActionCreate()) { + if ($exists) { + throw new MergeErrorRecreateOnMerge($activity); + } else { + $new = $activity->createDbObject($this->connection); + $new->setBeingLoadedFromDb(); + $result[$binaryUuid] = $new; + } + } elseif ($activity->isActionDelete()) { + if ($exists) { + unset($result[$binaryUuid]); + } else { + throw new MergeErrorDeleteMissingObject($activity); + } + } else { + if ($exists) { + $activity->applyToDbObject($result[$binaryUuid])->setBeingLoadedFromDb(); + } else { + throw new MergeErrorModificationForMissingObject($activity); + } + } + } + } + + if ($arrayIdx === 'uuid') { + return $result; + } + + $indexedResult = []; + foreach ($result as $object) { + $indexedResult[$object->get($arrayIdx)] = $object; + } + + return $indexedResult; + } + + public function exists($tableName, UuidInterface $uuid) + { + return BranchedObject::exists($this->connection, $tableName, $uuid, $this->branch->getUuid()); + } + + public function store(DbObject $object) + { + if ($this->branch && $this->branch->isBranch()) { + $activity = BranchActivity::forDbObject($object, $this->branch); + $this->connection->runFailSafeTransaction(function () use ($activity) { + $activity->store($this->connection); + BranchedObject::withActivity($activity, $this->connection)->store($this->connection); + }); + + return true; + } else { + return $object->store($this->connection); + } + } + + public function delete(DbObject $object) + { + if ($this->branch && $this->branch->isBranch()) { + $activity = BranchActivity::deleteObject($object, $this->branch); + $this->connection->runFailSafeTransaction(function () use ($activity) { + $activity->store($this->connection); + BranchedObject::load( + $this->connection, + $activity->getObjectTable(), + $activity->getObjectUuid(), + $this->branch + )->delete($this->connection); + }); + return true; + } + + return $object->delete(); + } + + public function getBranch() + { + return $this->branch; + } +} |