summaryrefslogtreecommitdiffstats
path: root/library/Director/Objects/IcingaObjectGroups.php
diff options
context:
space:
mode:
Diffstat (limited to 'library/Director/Objects/IcingaObjectGroups.php')
-rw-r--r--library/Director/Objects/IcingaObjectGroups.php408
1 files changed, 408 insertions, 0 deletions
diff --git a/library/Director/Objects/IcingaObjectGroups.php b/library/Director/Objects/IcingaObjectGroups.php
new file mode 100644
index 0000000..8bef1b1
--- /dev/null
+++ b/library/Director/Objects/IcingaObjectGroups.php
@@ -0,0 +1,408 @@
+<?php
+
+namespace Icinga\Module\Director\Objects;
+
+use Countable;
+use Exception;
+use Icinga\Exception\NotFoundError;
+use Icinga\Module\Director\Db\Cache\PrefetchCache;
+use Icinga\Module\Director\IcingaConfig\IcingaConfigRenderer;
+use Icinga\Module\Director\IcingaConfig\IcingaConfigHelper as c;
+use Icinga\Module\Director\IcingaConfig\IcingaLegacyConfigHelper as c1;
+use Iterator;
+use RuntimeException;
+
+class IcingaObjectGroups implements Iterator, Countable, IcingaConfigRenderer
+{
+ protected $storedGroups = array();
+
+ protected $groups = array();
+
+ protected $modified = false;
+
+ protected $object;
+
+ private $position = 0;
+
+ protected $idx = array();
+
+ public function __construct(IcingaObject $object)
+ {
+ $this->object = $object;
+
+ if (! $object->hasBeenLoadedFromDb() && PrefetchCache::shouldBeUsed()) {
+ /** @var IcingaObjectGroup $class */
+ $class = $this->getGroupClass();
+ $class::prefetchAll($this->object->getConnection());
+ }
+ }
+
+ #[\ReturnTypeWillChange]
+ public function count()
+ {
+ return count($this->groups);
+ }
+
+ #[\ReturnTypeWillChange]
+ public function rewind()
+ {
+ $this->position = 0;
+ }
+
+ public function hasBeenModified()
+ {
+ return $this->modified;
+ }
+
+ #[\ReturnTypeWillChange]
+ public function current()
+ {
+ if (! $this->valid()) {
+ return null;
+ }
+
+ return $this->groups[$this->idx[$this->position]];
+ }
+
+ #[\ReturnTypeWillChange]
+ public function key()
+ {
+ return $this->idx[$this->position];
+ }
+
+ #[\ReturnTypeWillChange]
+ public function next()
+ {
+ ++$this->position;
+ }
+
+ #[\ReturnTypeWillChange]
+ public function valid()
+ {
+ return array_key_exists($this->position, $this->idx);
+ }
+
+ public function get($key)
+ {
+ if (array_key_exists($key, $this->groups)) {
+ return $this->groups[$key];
+ }
+
+ return null;
+ }
+
+ /**
+ * @param $group
+ * @return $this
+ * @throws NotFoundError
+ */
+ public function set($group)
+ {
+ if (! is_array($group)) {
+ $group = array($group);
+ }
+
+ $existing = array_keys($this->groups);
+ $new = array();
+ $class = $this->getGroupClass();
+ $unset = array();
+
+ foreach ($group as $k => $g) {
+ if ($g instanceof $class) {
+ $new[] = $g->object_name;
+ } else {
+ if (empty($g)) {
+ $unset[] = $k;
+ continue;
+ }
+
+ $new[] = $g;
+ }
+ }
+
+ foreach ($unset as $k) {
+ unset($group[$k]);
+ }
+
+ sort($existing);
+ sort($new);
+ if ($existing === $new) {
+ return $this;
+ }
+
+ $this->groups = array();
+ if (empty($group)) {
+ $this->modified = true;
+ $this->refreshIndex();
+ return $this;
+ }
+
+ return $this->add($group);
+ }
+
+ /**
+ * Magic isset check
+ *
+ * @return boolean
+ */
+ public function __isset($group)
+ {
+ return array_key_exists($group, $this->groups);
+ }
+
+ public function remove($group)
+ {
+ if (array_key_exists($group, $this->groups)) {
+ unset($this->groups[$group]);
+ }
+
+ $this->modified = true;
+ $this->refreshIndex();
+ }
+
+ protected function refreshIndex()
+ {
+ ksort($this->groups);
+ $this->idx = array_keys($this->groups);
+ }
+
+ /**
+ * @param $group
+ * @param string $onError
+ * @return $this
+ * @throws NotFoundError
+ * @throws \Icinga\Module\Director\Exception\DuplicateKeyException
+ */
+ public function add($group, $onError = 'fail')
+ {
+ // TODO: only one query when adding array
+ if (is_array($group)) {
+ foreach ($group as $g) {
+ $this->add($g, $onError);
+ }
+ return $this;
+ }
+
+ /** @var IcingaObjectGroup $class */
+ $class = $this->getGroupClass();
+
+ if ($group instanceof $class) {
+ if (array_key_exists($group->getObjectName(), $this->groups)) {
+ return $this;
+ }
+
+ $this->groups[$group->object_name] = $group;
+ } elseif (is_string($group)) {
+ if (array_key_exists($group, $this->groups)) {
+ return $this;
+ }
+
+ $connection = $this->object->getConnection();
+
+ try {
+ $this->groups[$group] = $class::load($group, $connection);
+ } catch (NotFoundError $e) {
+ switch ($onError) {
+ case 'autocreate':
+ $newGroup = $class::create(array(
+ 'object_type' => 'object',
+ 'object_name' => $group
+ ));
+ $newGroup->store($connection);
+ $this->groups[$group] = $newGroup;
+ break;
+ case 'fail':
+ throw new NotFoundError(
+ 'The group "%s" doesn\'t exist.',
+ $group
+ );
+ break;
+ case 'ignore':
+ return $this;
+ }
+ }
+ } else {
+ throw new RuntimeException(
+ 'Invalid group object: %s',
+ var_export($group, 1)
+ );
+ }
+
+ $this->modified = true;
+ $this->refreshIndex();
+
+ return $this;
+ }
+
+ protected function getGroupTableName()
+ {
+ return $this->object->getTableName() . 'group';
+ }
+
+
+ protected function getGroupMemberTableName()
+ {
+ return $this->object->getTableName() . 'group_' . $this->getType();
+ }
+
+ public function listGroupNames()
+ {
+ return array_keys($this->groups);
+ }
+
+ public function listOriginalGroupNames()
+ {
+ return array_keys($this->storedGroups);
+ }
+
+ public function getType()
+ {
+ return $this->object->getShortTableName();
+ }
+
+ protected function loadFromDb()
+ {
+ $db = $this->object->getDb();
+ $connection = $this->object->getConnection();
+
+ $type = $this->getType();
+
+ $table = $this->object->getTableName();
+ $query = $db->select()->from(
+ array('go' => $table . 'group_' . $type),
+ array()
+ )->join(
+ array('g' => $table . 'group'),
+ 'go.' . $type . 'group_id = g.id',
+ '*'
+ )->where('go.' . $type . '_id = ?', $this->object->id)
+ ->order('g.object_name');
+
+ $class = $this->getGroupClass();
+ $this->groups = $class::loadAll($connection, $query, 'object_name');
+ $this->setBeingLoadedFromDb();
+
+ return $this;
+ }
+
+ public function store()
+ {
+ $storedGroups = array_keys($this->storedGroups);
+ $groups = array_keys($this->groups);
+
+ $objectId = $this->object->id;
+ $type = $this->getType();
+
+ $objectCol = $type . '_id';
+ $groupCol = $type . 'group_id';
+
+ $toDelete = array_diff($storedGroups, $groups);
+ foreach ($toDelete as $group) {
+ $where = sprintf(
+ $objectCol . ' = %d AND ' . $groupCol . ' = %d',
+ $objectId,
+ $this->storedGroups[$group]->id
+ );
+
+ $this->object->db->delete(
+ $this->getGroupMemberTableName(),
+ $where
+ );
+ }
+
+ $toAdd = array_diff($groups, $storedGroups);
+ foreach ($toAdd as $group) {
+ $this->object->db->insert(
+ $this->getGroupMemberTableName(),
+ array(
+ $objectCol => $objectId,
+ $groupCol => $this->groups[$group]->id
+ )
+ );
+ }
+ $this->setBeingLoadedFromDb();
+
+ return true;
+ }
+
+ public function setBeingLoadedFromDb()
+ {
+ $this->storedGroups = array();
+ foreach ($this->groups as $k => $v) {
+ $this->storedGroups[$k] = clone($v);
+ $this->storedGroups[$k]->id = $v->id;
+ }
+
+ $this->modified = false;
+ }
+
+ protected function getGroupClass()
+ {
+ return __NAMESPACE__ . '\\Icinga' .ucfirst($this->object->getShortTableName()) . 'Group';
+ }
+
+ public static function loadForStoredObject(IcingaObject $object)
+ {
+ $groups = new static($object);
+
+ if (PrefetchCache::shouldBeUsed()) {
+ $groups->groups = PrefetchCache::instance()->groups($object);
+ $groups->setBeingLoadedFromDb();
+ } else {
+ $groups->loadFromDb();
+ }
+
+ return $groups;
+ }
+
+ public function toConfigString()
+ {
+ $groups = array_keys($this->groups);
+
+ if (empty($groups)) {
+ return '';
+ }
+
+ return c::renderKeyValue('groups', c::renderArray($groups));
+ }
+
+ public function toLegacyConfigString($additionalGroups = array())
+ {
+ $groups = array_merge(array_keys($this->groups), $additionalGroups);
+ $groups = array_unique($groups);
+
+ if (empty($groups)) {
+ return '';
+ }
+
+ $type = $this->object->getLegacyObjectType();
+ return c1::renderKeyValue($type.'groups', c1::renderArray($groups));
+ }
+
+ public function __toString()
+ {
+ try {
+ return $this->toConfigString();
+ } catch (Exception $e) {
+ trigger_error($e);
+ $previousHandler = set_exception_handler(
+ function () {
+ }
+ );
+ restore_error_handler();
+ if ($previousHandler !== null) {
+ call_user_func($previousHandler, $e);
+ die();
+ } else {
+ die($e->getMessage());
+ }
+ }
+ }
+
+ public function __destruct()
+ {
+ unset($this->storedGroups);
+ unset($this->groups);
+ unset($this->object);
+ }
+}