summaryrefslogtreecommitdiffstats
path: root/library/Director/Data/Db/DbObjectStore.php
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--library/Director/Data/Db/DbObjectStore.php169
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;
+ }
+}