branchUuid = $branchUuid; $this->db = $connection->getDbAdapter(); $this->connection = $connection; } /** * Skip a delete operation, when the object to be deleted does not exist * * @param bool $ignore */ public function ignoreDeleteWhenMissing($ignore = true) { $this->ignoreDeleteWhenMissing = $ignore; } /** * Skip a modification, when the related object does not exist * @param bool $ignore */ public function ignoreModificationWhenMissing($ignore = true) { $this->ignoreModificationWhenMissing = $ignore; } /** * @param int $key */ public function ignoreActivity($key) { $this->ignoreActivities[$key] = true; } /** * @param BranchActivity $activity * @return bool */ public function ignoresActivity(BranchActivity $activity) { return isset($this->ignoreActivities[$activity->getTimestampNs()]); } /** * @throws MergeError */ public function merge() { $this->connection->runFailSafeTransaction(function () { $query = $this->db->select() ->from(BranchActivity::DB_TABLE) ->where('branch_uuid = ?', $this->connection->quoteBinary($this->branchUuid->getBytes())) ->order('timestamp_ns ASC'); $rows = $this->db->fetchAll($query); foreach ($rows as $row) { $activity = BranchActivity::fromDbRow($row); $this->applyModification($activity); } (new BranchStore($this->connection))->deleteByUuid($this->branchUuid); }); } /** * @param BranchActivity $activity * @throws MergeError * @throws \Icinga\Exception\NotFoundError * @throws \Icinga\Module\Director\Exception\DuplicateKeyException */ protected function applyModification(BranchActivity $activity) { /** @var string|DbObject $class */ $class = DbObjectTypeRegistry::classByType($activity->getObjectTable()); $uuid = $activity->getObjectUuid(); $exists = $class::uniqueIdExists($uuid, $this->connection); if ($activity->isActionCreate()) { if ($exists) { if (! $this->ignoresActivity($activity)) { throw new MergeErrorRecreateOnMerge($activity); } } else { $activity->createDbObject()->store($this->connection); } } elseif ($activity->isActionDelete()) { if ($exists) { $activity->deleteDbObject($this->connection); } elseif (! $this->ignoreDeleteWhenMissing && ! $this->ignoresActivity($activity)) { throw new MergeErrorDeleteMissingObject($activity); } } else { if ($exists) { $activity->applyToDbObject($class::requireWithUniqueId($uuid, $this->connection))->store(); // TODO: you modified an object, and related properties have been changed in the meantime. // We're able to detect this with the given data, and might want to offer a rebase. } elseif (! $this->ignoreModificationWhenMissing && ! $this->ignoresActivity($activity)) { throw new MergeErrorModificationForMissingObject($activity); } } } }