diff options
Diffstat (limited to 'library/Director/CustomVariable/CustomVariable.php')
-rw-r--r-- | library/Director/CustomVariable/CustomVariable.php | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/library/Director/CustomVariable/CustomVariable.php b/library/Director/CustomVariable/CustomVariable.php new file mode 100644 index 0000000..98eda84 --- /dev/null +++ b/library/Director/CustomVariable/CustomVariable.php @@ -0,0 +1,286 @@ +<?php + +namespace Icinga\Module\Director\CustomVariable; + +use Exception; +use Icinga\Module\Director\Db\Cache\PrefetchCache; +use Icinga\Module\Director\IcingaConfig\IcingaConfigHelper as c; +use Icinga\Module\Director\IcingaConfig\IcingaConfigRenderer; +use InvalidArgumentException; +use LogicException; + +abstract class CustomVariable implements IcingaConfigRenderer +{ + protected $key; + + protected $value; + + protected $storedValue; + + protected $type; + + protected $modified = false; + + protected $loadedFromDb = false; + + protected $deleted = false; + + protected $checksum; + + protected function __construct($key, $value = null) + { + $this->key = $key; + $this->setValue($value); + } + + public function is($type) + { + return $this->getType() === $type; + } + + public function getType() + { + if ($this->type === null) { + $parts = explode('\\', get_class($this)); + $class = end($parts); + // strlen('CustomVariable') === 14 + $this->type = substr($class, 14); + } + + return $this->type; + } + + // TODO: implement delete() + public function hasBeenDeleted() + { + return $this->deleted; + } + + public function delete() + { + $this->deleted = true; + return $this; + } + + // TODO: abstract + public function getDbValue() + { + return $this->getValue(); + } + + public function toJson() + { + if ($this->getDbFormat() === 'string') { + return json_encode($this->getDbValue()); + } else { + return $this->getDbValue(); + } + } + + // TODO: abstract + public function getDbFormat() + { + return 'string'; + } + + public function getKey() + { + return $this->key; + } + + /** + * @param $value + * @return $this + */ + abstract public function setValue($value); + + abstract public function getValue(); + + /** + * @param bool $renderExpressions + * @return string + */ + public function toConfigString($renderExpressions = false) + { + // TODO: this should be an abstract method once we deprecate PHP < 5.3.9 + throw new LogicException(sprintf( + '%s has no toConfigString() implementation', + get_class($this) + )); + } + + public function flatten(array &$flat, $prefix) + { + $flat[$prefix] = $this->getDbValue(); + } + + public function render($renderExpressions = false) + { + return c::renderKeyValue( + $this->renderKeyName($this->getKey()), + $this->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 checksum() + { + // TODO: remember checksum, invalidate on change + return sha1($this->getKey() . '=' . $this->toJson(), true); + } + + public function isNew() + { + return ! $this->loadedFromDb; + } + + public function hasBeenModified() + { + return $this->modified; + } + + public function toConfigStringPrefetchable($renderExpressions = false) + { + if (PrefetchCache::shouldBeUsed()) { + return PrefetchCache::instance()->renderVar($this, $renderExpressions); + } else { + return $this->toConfigString($renderExpressions); + } + } + + public function setModified($modified = true) + { + $this->modified = $modified; + if (! $this->modified) { + if (is_object($this->value)) { + $this->storedValue = clone($this->value); + } else { + $this->storedValue = $this->value; + } + } + + return $this; + } + + public function setUnmodified() + { + return $this->setModified(false); + } + + public function setLoadedFromDb($loaded = true) + { + $this->loadedFromDb = $loaded; + return $this; + } + + abstract public function equals(CustomVariable $var); + + public function differsFrom(CustomVariable $var) + { + return ! $this->equals($var); + } + + protected function setChecksum($checksum) + { + $this->checksum = $checksum; + return $this; + } + + public function getChecksum() + { + return $this->checksum; + } + + public static function wantCustomVariable($key, $value) + { + if ($value instanceof CustomVariable) { + return $value; + } + + return self::create($key, $value); + } + + public static function create($key, $value) + { + if (is_null($value)) { + return new CustomVariableNull($key, $value); + } + + if (is_bool($value)) { + return new CustomVariableBoolean($key, $value); + } + + if (is_int($value) || is_float($value)) { + return new CustomVariableNumber($key, $value); + } + + if (is_string($value)) { + return new CustomVariableString($key, $value); + } elseif (is_array($value)) { + foreach (array_keys($value) as $k) { + if (! (is_int($k) || ctype_digit($k))) { + return new CustomVariableDictionary($key, $value); + } + } + + return new CustomVariableArray($key, array_values($value)); + } elseif (is_object($value)) { + // TODO: check for specific class/stdClass/interface? + return new CustomVariableDictionary($key, $value); + } else { + throw new LogicException(sprintf('WTF (%s): %s', $key, var_export($value, 1))); + } + } + + public static function fromDbRow($row) + { + switch ($row->format) { + case 'string': + $var = new CustomVariableString($row->varname, $row->varvalue); + break; + case 'json': + $var = self::create($row->varname, json_decode($row->varvalue)); + break; + case 'expression': + throw new InvalidArgumentException( + 'Icinga code expressions are not yet supported' + ); + default: + throw new InvalidArgumentException(sprintf( + '%s is not a supported custom variable format', + $row->format + )); + } + if (property_exists($row, 'checksum')) { + $var->setChecksum($row->checksum); + } + + $var->loadedFromDb = true; + $var->setUnmodified(); + return $var; + } + + 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(); + } + } +} |