From e9d38103f091107e0a18c0bbf3a2ca8a1f7e823e Mon Sep 17 00:00:00 2001 From: Alexander Fuhr Date: Wed, 1 Jul 2015 15:15:49 +0200 Subject: [PATCH] TimePeriodRanges: Implement the TimePeriodRanges support --- library/Director/Objects/IcingaObject.php | 65 ++++- library/Director/Objects/IcingaTimePeriod.php | 14 +- .../Objects/IcingaTimePeriodRange.php | 20 ++ .../Objects/IcingaTimePeriodRanges.php | 243 ++++++++++++++++++ .../Director/Web/Form/DirectorObjectForm.php | 42 ++- 5 files changed, 373 insertions(+), 11 deletions(-) create mode 100644 library/Director/Objects/IcingaTimePeriodRange.php create mode 100644 library/Director/Objects/IcingaTimePeriodRanges.php diff --git a/library/Director/Objects/IcingaObject.php b/library/Director/Objects/IcingaObject.php index 3fc5f129..c18a18b0 100644 --- a/library/Director/Objects/IcingaObject.php +++ b/library/Director/Objects/IcingaObject.php @@ -19,6 +19,8 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer protected $supportsGroups = false; + protected $supportsRanges = false; + protected $supportsImports = false; private $type; @@ -29,6 +31,8 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer private $imports; + private $ranges; + public function supportsCustomVars() { return $this->supportsCustomVars; @@ -39,6 +43,11 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer return $this->supportsGroups; } + public function supportsRanges() + { + return $this->supportsRanges; + } + public function supportsImports() { return $this->supportsImports; @@ -58,6 +67,10 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer return true; } + if ($this->supportsRanges() && $this->ranges !== null && $this->ranges()->hasBeenModified()) { + return true; + } + return parent::hasBeenModified(); } @@ -75,6 +88,20 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer return $this->groups; } + public function ranges() + { + $this->assertRangesSupport(); + if ($this->ranges === null) { + if ($this->hasBeenLoadedFromDb()) { + $this->ranges = IcingaTimePeriodRanges::loadForStoredObject($this); + } else { + $this->ranges = new IcingaTimePeriodRanges($this); + } + } + + return $this->ranges; + } + public function imports() { $this->assertImportsSupport(); @@ -113,6 +140,18 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer return $this; } + protected function assertRangesSupport() + { + if (! $this->supportsRanges()) { + throw new ProgrammingError( + 'Objects of type "%s" have no ranges', + $this->getType() + ); + } + + return $this; + } + protected function assertImportsSupport() { if (! $this->supportsImports()) { @@ -169,13 +208,13 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer public function onInsert() { - $this->storeCustomVars()->storeGroups()->storeImports(); + $this->storeCustomVars()->storeGroups()->storeImports()->storeRanges(); DirectorActivityLog::logCreation($this, $this->connection); } public function onUpdate() { - $this->storeCustomVars()->storeGroups()->storeImports(); + $this->storeCustomVars()->storeGroups()->storeImports()->storeRanges(); DirectorActivityLog::logModification($this, $this->connection); } @@ -197,6 +236,15 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer return $this; } + protected function storeRanges() + { + if ($this->supportsRanges()) { + $this->ranges !== null && $this->ranges()->store(); + } + + return $this; + } + protected function storeImports() { if ($this->supportsImports()) { @@ -280,6 +328,18 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer } } + /** + * @return string + */ + protected function renderRanges() + { + if ($this->supportsRanges()) { + return $this->ranges()->toConfigString(); + } else { + return ''; + } + } + protected function renderCommandProperty($commandId, $propertyName = 'check_command') { return c::renderKeyValue( @@ -317,6 +377,7 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer $this->renderObjectHeader(), $this->renderImports(), $this->renderProperties(), + $this->renderRanges(), $this->renderGroups(), $this->renderCustomVars(), $this->renderSuffix() diff --git a/library/Director/Objects/IcingaTimePeriod.php b/library/Director/Objects/IcingaTimePeriod.php index 70807478..f3c9f79a 100644 --- a/library/Director/Objects/IcingaTimePeriod.php +++ b/library/Director/Objects/IcingaTimePeriod.php @@ -7,13 +7,15 @@ class IcingaTimePeriod extends IcingaObject protected $table = 'icinga_timeperiod'; protected $defaultProperties = array( - 'id' => null, - 'zone_id' => null, - 'object_name' => null, - 'display_name' => null, - 'update_method' => null, - 'object_type' => null, + 'id' => null, + 'zone_id' => null, + 'object_name' => null, + 'display_name' => null, + 'update_method' => null, + 'object_type' => null, ); protected $supportsImports = true; + + protected $supportsRanges = true; } diff --git a/library/Director/Objects/IcingaTimePeriodRange.php b/library/Director/Objects/IcingaTimePeriodRange.php new file mode 100644 index 00000000..5ebd2a06 --- /dev/null +++ b/library/Director/Objects/IcingaTimePeriodRange.php @@ -0,0 +1,20 @@ + null, + 'timeperiod_key' => null, + 'timeperiod_value' => null, + 'range_type' => 'include', + 'merge_behaviour' => 'set', + ); +} diff --git a/library/Director/Objects/IcingaTimePeriodRanges.php b/library/Director/Objects/IcingaTimePeriodRanges.php new file mode 100644 index 00000000..6e5ee51a --- /dev/null +++ b/library/Director/Objects/IcingaTimePeriodRanges.php @@ -0,0 +1,243 @@ +object = $object; + } + + public function count() + { + return count($this->ranges); + } + + public function rewind() + { + $this->position = 0; + } + + public function hasBeenModified() + { + return $this->modified; + } + + public function current() + { + if (! $this->valid()) { + return null; + } + + return $this->ranges[$this->idx[$this->position]]; + } + + public function key() + { + return $this->idx[$this->position]; + } + + public function next() + { + ++$this->position; + } + + public function valid() + { + return array_key_exists($this->position, $this->idx); + } + + public function get($key) + { + if (array_key_exists($key, $this->ranges)) { + return $this->ranges[$key]; + } + + return null; + } + + public function getRanges() + { + return $this->ranges; + } + + protected function modify($range, $value) + { + $this->ranges[$range]->timeperiod_key = $value; + } + + public function set($ranges) + { + foreach ($ranges as $range => $value) { + if (array_key_exists($range, $this->ranges)) { + $this->ranges[$range]->timeperiod_value = $value; + } else { + $this->ranges[$range] = IcingaTimePeriodRange::create(array( + 'timeperiod_id' => $this->object->id, + 'timeperiod_key' => $range, + 'timeperiod_value' => $value, + )); + } + } + + $toDelete = array_diff(array_keys($this->ranges), array_keys($ranges)); + foreach ($toDelete as $range) { + $this->remove($range); + } + + return $this; + } + + /** + * Magic isset check + * + * @return boolean + */ + public function __isset($range) + { + return array_key_exists($range, $this->ranges); + } + + public function remove($range) + { + if (array_key_exists($range, $this->ranges)) { + unset($this->ranges[$range]); + } + + $this->modified = true; + $this->refreshIndex(); + } + + public function clear() + { + $this->ranges = array(); + $this->modified = true; + $this->refreshIndex(); + } + + protected function refreshIndex() + { + ksort($this->ranges); + $this->idx = array_keys($this->ranges); + } + + protected function getRangeClass() + { + return __NAMESPACE__ . '\\Icinga' .ucfirst($this->object->getShortTableName()) . 'Range'; + } + + public function listRangesNames() + { + return array_keys($this->ranges); + } + + public function getType() + { + return $this->object->getShortTableName(); + } + + public function getRangeTableName() + { + return $this->object->getTableName() . '_range'; + } + + protected function loadFromDb() + { + $db = $this->object->getDb(); + $connection = $this->object->getConnection(); + + $table = $this->getRangeTableName(); + + $query = $db->select()->from( + array('o' => $table) + )->where('o.timeperiod_id = ?', (int) $this->object->id) + ->order('o.timeperiod_key'); + + $class = $this->getClass(); + $this->ranges = $class::loadAll($connection, $query, 'timeperiod_key'); + $this->storedRanges = $this->ranges; + + return $this; + } + + public function store() + { + foreach ($this->ranges as $range) { + $range->store($this->object->getConnection()); + } + + foreach (array_diff(array_keys($this->storedRanges), array_keys($this->ranges)) as $delete) { + $this->storedRanges[$delete]->delete(); + } + + $this->storedRanges = $this->ranges; + + return true; + } + + protected function getClass() + { + return __NAMESPACE__ . '\\IcingaTimePeriodRange'; + } + + public static function loadForStoredObject(IcingaObject $object) + { + $ranges = new static($object); + return $ranges->loadFromDb(); + } + + public function toConfigString() + { + if (empty($this->ranges) && $this->object->object_type == 'template') { + return ''; + } + + $string = " ranges = {\n"; + + foreach ($this->ranges as $range) { + $string .= sprintf( + " %s\t= %s\n", + c::renderString($range->timeperiod_key), + c::renderString($range->timeperiod_value) + ); + } + + return $string . " }\n"; + } + + 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()); + } + } + } +} diff --git a/library/Director/Web/Form/DirectorObjectForm.php b/library/Director/Web/Form/DirectorObjectForm.php index 13ebd826..1c187fc2 100644 --- a/library/Director/Web/Form/DirectorObjectForm.php +++ b/library/Director/Web/Form/DirectorObjectForm.php @@ -39,6 +39,18 @@ abstract class DirectorObjectForm extends QuickForm 'multiOptions' => array('string' => $this->translate('String')) )); } + + if (false && $this->object()->supportsRanges()) { + /* TODO implement when new logic is there + $this->addElement('note', '_newrange_hint', array('label' => 'New range')); + $this->addElement('text', '_newrange_name', array( + 'label' => 'Name' + )); + $this->addElement('text', '_newrange_value', array( + 'label' => 'Value' + )); + */ + } } public function onSuccess() @@ -94,6 +106,14 @@ abstract class DirectorObjectForm extends QuickForm } } + if ($object->supportsRanges()) { + $object->ranges()->set(array( + 'monday' => 'eins', + 'tuesday' => '00:00-24:00', + 'sunday' => 'zwei', + )); + } + foreach ($handled as $key => $value) { unset($values[$key]); } @@ -201,17 +221,33 @@ abstract class DirectorObjectForm extends QuickForm } } + if ($this->object->supportsRanges()) { + /* TODO implement when new logic for customvars is there + foreach ($this->object->ranges()->getRanges() as $key => $value) { + $this->addRange($key, $value); + } + */ + } + if (! $this->hasBeenSubmitted()) { $this->beforeValidation($this->object->getProperties()); } return $this; } - protected function addCustomVar($key, $var) + protected function addCustomVar($key, $range) { $this->addElement('text', 'var_' . $key, array( - 'label' => 'vars.' . $key, - 'value' => $var->getValue() + 'label' => 'ranges.' . $key, + 'value' => $range->getValue() + )); + } + + protected function addRange($key, $range) + { + $this->addElement('text', 'range_' . $key, array( + 'label' => 'range.' . $key, + 'value' => $range->timeperiod_value )); }