summaryrefslogtreecommitdiffstats
path: root/library/Director/CustomVariable/CustomVariables.php
diff options
context:
space:
mode:
Diffstat (limited to 'library/Director/CustomVariable/CustomVariables.php')
-rw-r--r--library/Director/CustomVariable/CustomVariables.php488
1 files changed, 488 insertions, 0 deletions
diff --git a/library/Director/CustomVariable/CustomVariables.php b/library/Director/CustomVariable/CustomVariables.php
new file mode 100644
index 0000000..cdcc4bd
--- /dev/null
+++ b/library/Director/CustomVariable/CustomVariables.php
@@ -0,0 +1,488 @@
+<?php
+
+namespace Icinga\Module\Director\CustomVariable;
+
+use Icinga\Module\Director\Db;
+use Icinga\Module\Director\IcingaConfig\IcingaConfigHelper as c;
+use Icinga\Module\Director\IcingaConfig\IcingaLegacyConfigHelper as c1;
+use Icinga\Module\Director\IcingaConfig\IcingaConfigRenderer;
+use Icinga\Module\Director\Objects\IcingaObject;
+use Countable;
+use Exception;
+use Iterator;
+
+class CustomVariables implements Iterator, Countable, IcingaConfigRenderer
+{
+ /** @var CustomVariable[] */
+ protected $storedVars = array();
+
+ /** @var CustomVariable[] */
+ protected $vars = array();
+
+ protected $modified = false;
+
+ private $position = 0;
+
+ private $overrideKeyName;
+
+ protected $idx = array();
+
+ protected static $allTables = array(
+ 'icinga_command_var',
+ 'icinga_host_var',
+ 'icinga_notification_var',
+ 'icinga_service_set_var',
+ 'icinga_service_var',
+ 'icinga_user_var',
+ );
+
+ public static function countAll($varname, Db $connection)
+ {
+ $db = $connection->getDbAdapter();
+ $parts = array();
+ $where = $db->quoteInto('varname = ?', $varname);
+ foreach (static::$allTables as $table) {
+ $parts[] = "SELECT COUNT(*) as cnt FROM $table WHERE $where";
+ }
+
+ $sub = implode(' UNION ALL ', $parts);
+ $query = "SELECT SUM(sub.cnt) AS cnt FROM ($sub) sub";
+
+ return (int) $db->fetchOne($query);
+ }
+
+ public static function deleteAll($varname, Db $connection)
+ {
+ $db = $connection->getDbAdapter();
+ $where = $db->quoteInto('varname = ?', $varname);
+ foreach (static::$allTables as $table) {
+ $db->delete($table, $where);
+ }
+ }
+
+ public static function renameAll($oldname, $newname, Db $connection)
+ {
+ $db = $connection->getDbAdapter();
+ $where = $db->quoteInto('varname = ?', $oldname);
+ foreach (static::$allTables as $table) {
+ $db->update($table, ['varname' => $newname], $where);
+ }
+ }
+
+ #[\ReturnTypeWillChange]
+ public function count()
+ {
+ $count = 0;
+ foreach ($this->vars as $var) {
+ if (! $var->hasBeenDeleted()) {
+ $count++;
+ }
+ }
+
+ return $count;
+ }
+
+ #[\ReturnTypeWillChange]
+ public function rewind()
+ {
+ $this->position = 0;
+ }
+
+ #[\ReturnTypeWillChange]
+ public function current()
+ {
+ if (! $this->valid()) {
+ return null;
+ }
+
+ return $this->vars[$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);
+ }
+
+ /**
+ * Generic setter
+ *
+ * @param string $key
+ * @param mixed $value
+ *
+ * @return self
+ */
+ public function set($key, $value)
+ {
+ $key = (string) $key;
+
+ if ($value instanceof CustomVariable) {
+ $value = clone($value);
+ } else {
+ if ($value === null) {
+ $this->__unset($key);
+ return $this;
+ }
+ $value = CustomVariable::create($key, $value);
+ }
+
+ // Hint: isset($this->$key) wouldn't conflict with protected properties
+ if ($this->__isset($key)) {
+ if ($value->equals($this->get($key))) {
+ return $this;
+ } else {
+ if (get_class($this->vars[$key]) === get_class($value)) {
+ $this->vars[$key]->setValue($value->getValue())->setModified();
+ } else {
+ $this->vars[$key] = $value->setLoadedFromDb()->setModified();
+ }
+ }
+ } else {
+ $this->vars[$key] = $value->setModified();
+ }
+
+ $this->modified = true;
+ $this->refreshIndex();
+
+ return $this;
+ }
+
+ protected function refreshIndex()
+ {
+ $this->idx = array();
+ ksort($this->vars);
+ foreach ($this->vars as $name => $var) {
+ if (! $var->hasBeenDeleted()) {
+ $this->idx[] = $name;
+ }
+ }
+ }
+
+ public static function loadForStoredObject(IcingaObject $object)
+ {
+ $db = $object->getDb();
+
+ $query = $db->select()->from(
+ array('v' => $object->getVarsTableName()),
+ array(
+ 'v.varname',
+ 'v.varvalue',
+ 'v.format',
+ )
+ )->where(sprintf('v.%s = ?', $object->getVarsIdColumn()), $object->get('id'));
+
+ $vars = new CustomVariables;
+ foreach ($db->fetchAll($query) as $row) {
+ $vars->vars[$row->varname] = CustomVariable::fromDbRow($row);
+ }
+ $vars->refreshIndex();
+ $vars->setBeingLoadedFromDb();
+ return $vars;
+ }
+
+ public static function forStoredRows($rows)
+ {
+ $vars = new CustomVariables;
+ foreach ($rows as $row) {
+ $vars->vars[$row->varname] = CustomVariable::fromDbRow($row);
+ }
+ $vars->refreshIndex();
+ $vars->setBeingLoadedFromDb();
+
+ return $vars;
+ }
+
+ public function storeToDb(IcingaObject $object)
+ {
+ $db = $object->getDb();
+ $table = $object->getVarsTableName();
+ $foreignColumn = $object->getVarsIdColumn();
+ $foreignId = $object->get('id');
+
+
+ foreach ($this->vars as $var) {
+ if ($var->isNew()) {
+ $db->insert(
+ $table,
+ array(
+ $foreignColumn => $foreignId,
+ 'varname' => $var->getKey(),
+ 'varvalue' => $var->getDbValue(),
+ 'format' => $var->getDbFormat()
+ )
+ );
+ $var->setLoadedFromDb();
+ continue;
+ }
+
+ $where = $db->quoteInto(sprintf('%s = ?', $foreignColumn), (int) $foreignId)
+ . $db->quoteInto(' AND varname = ?', $var->getKey());
+
+ if ($var->hasBeenDeleted()) {
+ $db->delete($table, $where);
+ } elseif ($var->hasBeenModified()) {
+ $db->update(
+ $table,
+ array(
+ 'varvalue' => $var->getDbValue(),
+ 'format' => $var->getDbFormat()
+ ),
+ $where
+ );
+ }
+ }
+
+ $this->setBeingLoadedFromDb();
+ }
+
+ public function get($key)
+ {
+ if (array_key_exists($key, $this->vars)) {
+ return $this->vars[$key];
+ }
+
+ return null;
+ }
+
+ public function hasBeenModified()
+ {
+ if ($this->modified) {
+ return true;
+ }
+
+ foreach ($this->vars as $var) {
+ if ($var->hasBeenModified()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public function setBeingLoadedFromDb()
+ {
+ $this->modified = false;
+ $this->storedVars = array();
+ foreach ($this->vars as $key => $var) {
+ $this->storedVars[$key] = clone($var);
+ $var->setUnmodified();
+ $var->setLoadedFromDb();
+ }
+
+ return $this;
+ }
+
+ public function restoreStoredVar($key)
+ {
+ if (array_key_exists($key, $this->storedVars)) {
+ $this->vars[$key] = clone($this->storedVars[$key]);
+ $this->vars[$key]->setUnmodified();
+ $this->recheckForModifications();
+ $this->refreshIndex();
+ } elseif (array_key_exists($key, $this->vars)) {
+ unset($this->vars[$key]);
+ $this->recheckForModifications();
+ $this->refreshIndex();
+ }
+ }
+
+ protected function recheckForModifications()
+ {
+ $this->modified = false;
+ foreach ($this->vars as $var) {
+ if ($var->hasBeenModified()) {
+ $this->modified = true;
+
+ return;
+ }
+ }
+ }
+
+ public function getOriginalVars()
+ {
+ return $this->storedVars;
+ }
+
+ public function flatten()
+ {
+ $flat = array();
+ foreach ($this->vars as $key => $var) {
+ $var->flatten($flat, $key);
+ }
+
+ return $flat;
+ }
+
+ public function checksum()
+ {
+ $sums = array();
+ foreach ($this->vars as $key => $var) {
+ $sums[] = $key . '=' . $var->checksum();
+ }
+
+ return sha1(implode('|', $sums), true);
+ }
+
+ public function setOverrideKeyName($name)
+ {
+ $this->overrideKeyName = $name;
+ return $this;
+ }
+
+ public function toConfigString($renderExpressions = false)
+ {
+ $out = '';
+
+ foreach ($this as $key => $var) {
+ // TODO: ctype_alnum + underscore?
+ $out .= $this->renderSingleVar($key, $var, $renderExpressions);
+ }
+
+ return $out;
+ }
+
+ public function toLegacyConfigString()
+ {
+ $out = '';
+
+ ksort($this->vars);
+ foreach ($this->vars as $key => $var) {
+ // TODO: ctype_alnum + underscore?
+ // vars with ARGn will be handled by IcingaObject::renderLegacyCheck_command
+ if (substr($key, 0, 3) == 'ARG') {
+ continue;
+ }
+
+ switch ($type = $var->getType()) {
+ case 'String':
+ case 'Number':
+ # TODO: Make Prefetchable
+ $out .= c1::renderKeyValue(
+ '_' . $key,
+ $var->toLegacyConfigString()
+ );
+ break;
+ default:
+ $out .= c1::renderKeyValue(
+ '# _' . $key,
+ sprintf('(unsupported: %s)', $type)
+ );
+ }
+ }
+
+ if ($out !== '') {
+ $out = "\n".$out;
+ }
+
+ return $out;
+ }
+
+ /**
+ * @param string $key
+ * @param CustomVariable $var
+ * @param bool $renderExpressions
+ *
+ * @return string
+ */
+ protected function renderSingleVar($key, $var, $renderExpressions = false)
+ {
+ if ($key === $this->overrideKeyName) {
+ return c::renderKeyOperatorValue(
+ $this->renderKeyName($key),
+ '+=',
+ $var->toConfigStringPrefetchable($renderExpressions)
+ );
+ } else {
+ return c::renderKeyValue(
+ $this->renderKeyName($key),
+ $var->toConfigStringPrefetchable($renderExpressions)
+ );
+ }
+ }
+
+ protected function renderKeyName($key)
+ {
+ if (preg_match('/^[a-z][a-z0-9_]*$/i', $key)) {
+ return 'vars.' . c::escapeIfReserved($key);
+ } else {
+ return 'vars[' . c::renderString($key) . ']';
+ }
+ }
+
+ public function __get($key)
+ {
+ return $this->get($key);
+ }
+
+ /**
+ * Magic setter
+ *
+ * @param string $key Key
+ * @param mixed $val Value
+ *
+ * @return void
+ */
+ public function __set($key, $val)
+ {
+ $this->set($key, $val);
+ }
+
+ /**
+ * Magic isset check
+ *
+ * @param string $key
+ *
+ * @return boolean
+ */
+ public function __isset($key)
+ {
+ return array_key_exists($key, $this->vars);
+ }
+
+ /**
+ * Magic unsetter
+ *
+ * @param string $key
+ *
+ * @return void
+ */
+ public function __unset($key)
+ {
+ if (! array_key_exists($key, $this->vars)) {
+ return;
+ }
+
+ $this->vars[$key]->delete();
+ $this->modified = true;
+
+ $this->refreshIndex();
+ }
+
+ public function __toString()
+ {
+ try {
+ return $this->toConfigString();
+ } catch (Exception $e) {
+ trigger_error($e);
+ $previousHandler = set_exception_handler(
+ function () {
+ }
+ );
+ restore_error_handler();
+ call_user_func($previousHandler, $e);
+ die();
+ }
+ }
+}