2015-06-26 10:39:30 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace Icinga\Module\Director\Objects;
|
|
|
|
|
|
|
|
use Icinga\Exception\ProgrammingError;
|
|
|
|
use Iterator;
|
|
|
|
use Countable;
|
|
|
|
use Icinga\Module\Director\IcingaConfig\IcingaConfigRenderer;
|
|
|
|
use Icinga\Module\Director\IcingaConfig\IcingaConfigHelper as c;
|
2016-07-28 08:57:27 +02:00
|
|
|
use Icinga\Module\Director\IcingaConfig\IcingaLegacyConfigHelper as c1;
|
2015-06-26 10:39:30 +02:00
|
|
|
|
|
|
|
class IcingaObjectImports implements Iterator, Countable, IcingaConfigRenderer
|
|
|
|
{
|
|
|
|
protected $storedImports = array();
|
|
|
|
|
|
|
|
protected $imports = array();
|
|
|
|
|
2016-03-07 02:05:10 +01:00
|
|
|
protected $objects = array();
|
|
|
|
|
2015-06-26 10:39:30 +02:00
|
|
|
protected $modified = false;
|
|
|
|
|
|
|
|
protected $object;
|
|
|
|
|
|
|
|
private $position = 0;
|
|
|
|
|
|
|
|
protected $idx = array();
|
|
|
|
|
|
|
|
public function __construct(IcingaObject $object)
|
|
|
|
{
|
|
|
|
$this->object = $object;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function count()
|
|
|
|
{
|
|
|
|
return count($this->imports);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function rewind()
|
|
|
|
{
|
|
|
|
$this->position = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function hasBeenModified()
|
|
|
|
{
|
|
|
|
return $this->modified;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function current()
|
|
|
|
{
|
|
|
|
if (! $this->valid()) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2016-03-07 02:05:10 +01:00
|
|
|
return $this->getObject(
|
|
|
|
$this->imports[$this->idx[$this->position]]
|
|
|
|
);
|
2015-06-26 10:39:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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->imports)) {
|
2016-03-07 02:05:10 +01:00
|
|
|
return $this->getObject($this->imports[$key]);
|
2015-06-26 10:39:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function set($import)
|
|
|
|
{
|
2016-05-20 08:12:46 +02:00
|
|
|
if ($import === null) {
|
|
|
|
if (empty($this->imports)) {
|
|
|
|
return $this;
|
|
|
|
} else {
|
|
|
|
return $this->clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-05 10:49:37 +01:00
|
|
|
if (! is_array($import)) {
|
|
|
|
$import = array($import);
|
|
|
|
}
|
2016-05-20 08:12:46 +02:00
|
|
|
|
2015-06-26 10:39:30 +02:00
|
|
|
$existing = array_keys($this->imports);
|
|
|
|
$new = array();
|
|
|
|
$class = $this->getImportClass();
|
|
|
|
foreach ($import as $i) {
|
|
|
|
|
|
|
|
if ($i instanceof $class) {
|
2016-08-23 16:08:51 +02:00
|
|
|
$this->objects[$i->object_name] = $i;
|
2015-06-26 10:39:30 +02:00
|
|
|
$new[] = $i->object_name;
|
|
|
|
} else {
|
|
|
|
$new[] = $i;
|
|
|
|
}
|
|
|
|
}
|
2015-06-26 15:54:00 +02:00
|
|
|
|
2015-06-26 10:39:30 +02:00
|
|
|
if ($existing === $new) {
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2015-06-29 12:50:59 +02:00
|
|
|
if (count($new) === 0) {
|
|
|
|
return $this->clear();
|
|
|
|
}
|
|
|
|
|
2015-06-26 10:39:30 +02:00
|
|
|
$this->imports = array();
|
|
|
|
return $this->add($import);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Magic isset check
|
|
|
|
*
|
|
|
|
* @return boolean
|
|
|
|
*/
|
|
|
|
public function __isset($import)
|
|
|
|
{
|
|
|
|
return array_key_exists($import, $this->imports);
|
|
|
|
}
|
|
|
|
|
2015-06-29 12:50:59 +02:00
|
|
|
public function clear()
|
|
|
|
{
|
2016-03-05 10:49:37 +01:00
|
|
|
if ($this->imports === array()) {
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2015-06-29 12:50:59 +02:00
|
|
|
$this->imports = array();
|
|
|
|
|
|
|
|
$this->modified = true;
|
|
|
|
$this->refreshIndex();
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2015-06-26 10:39:30 +02:00
|
|
|
public function remove($import)
|
|
|
|
{
|
|
|
|
if (array_key_exists($import, $this->imports)) {
|
|
|
|
unset($this->imports[$import]);
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->modified = true;
|
|
|
|
$this->refreshIndex();
|
2015-06-29 12:50:59 +02:00
|
|
|
|
|
|
|
return $this;
|
2015-06-26 10:39:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
protected function refreshIndex()
|
|
|
|
{
|
|
|
|
$this->idx = array_keys($this->imports);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function add($import)
|
|
|
|
{
|
2016-03-05 12:56:29 +01:00
|
|
|
$class = $this->getImportClass();
|
|
|
|
|
2015-06-26 10:39:30 +02:00
|
|
|
// TODO: only one query when adding array
|
|
|
|
if (is_array($import)) {
|
|
|
|
foreach ($import as $i) {
|
2016-03-05 12:56:29 +01:00
|
|
|
// Gracefully ignore null members or empty strings
|
|
|
|
if (! $i instanceof $class && strlen($i) === 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-06-26 10:39:30 +02:00
|
|
|
$this->add($i);
|
|
|
|
}
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($import instanceof $class) {
|
2016-06-16 21:20:11 +02:00
|
|
|
if (array_key_exists($import->object_name, $this->imports)) {
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2016-03-07 02:05:10 +01:00
|
|
|
$this->imports[$import->object_name] = $import->object_name;
|
|
|
|
$this->objects[$import->object_name] = $import;
|
2015-06-26 10:39:30 +02:00
|
|
|
} elseif (is_string($import)) {
|
2016-06-16 21:20:11 +02:00
|
|
|
if (array_key_exists($import, $this->imports)) {
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2016-03-07 02:05:10 +01:00
|
|
|
$this->imports[$import] = $import;
|
2015-06-26 10:39:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$this->modified = true;
|
|
|
|
$this->refreshIndex();
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2016-06-16 21:40:22 +02:00
|
|
|
public function getObjects()
|
|
|
|
{
|
|
|
|
$list = array();
|
|
|
|
foreach ($this->listImportNames() as $name) {
|
|
|
|
$list[$name] = $this->getObject($name);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $list;
|
|
|
|
}
|
|
|
|
|
2016-03-07 02:05:10 +01:00
|
|
|
protected function getObject($name)
|
|
|
|
{
|
|
|
|
if (array_key_exists($name, $this->objects)) {
|
|
|
|
return $this->objects[$name];
|
|
|
|
}
|
|
|
|
|
|
|
|
$connection = $this->object->getConnection();
|
|
|
|
$class = $this->getImportClass();
|
|
|
|
if (is_array($this->object->getKeyName())) {
|
|
|
|
// Services only
|
|
|
|
$import = $class::load(array('object_name' => $name), $connection);
|
|
|
|
} else {
|
|
|
|
$import = $class::load($name, $connection);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this->objects[$import->object_name] = $import;
|
|
|
|
}
|
|
|
|
|
2015-06-26 10:39:30 +02:00
|
|
|
protected function getImportTableName()
|
|
|
|
{
|
|
|
|
return $this->object->getTableName() . '_inheritance';
|
|
|
|
}
|
|
|
|
|
|
|
|
public function listImportNames()
|
|
|
|
{
|
|
|
|
return array_keys($this->imports);
|
|
|
|
}
|
|
|
|
|
2015-08-28 17:11:51 +02:00
|
|
|
public function listOriginalImportNames()
|
|
|
|
{
|
|
|
|
return array_keys($this->storedImports);
|
|
|
|
}
|
|
|
|
|
2015-06-26 10:39:30 +02:00
|
|
|
public function getType()
|
|
|
|
{
|
|
|
|
return $this->object->getShortTableName();
|
|
|
|
}
|
|
|
|
|
2015-12-02 02:48:15 +01:00
|
|
|
// TODO: prefetch
|
2015-06-26 10:39:30 +02:00
|
|
|
protected function loadFromDb()
|
|
|
|
{
|
|
|
|
$db = $this->object->getDb();
|
|
|
|
$connection = $this->object->getConnection();
|
|
|
|
|
|
|
|
$type = $this->getType();
|
|
|
|
|
|
|
|
$table = $this->object->getTableName();
|
|
|
|
$query = $db->select()->from(
|
|
|
|
array('o' => $table),
|
|
|
|
array()
|
|
|
|
)->join(
|
|
|
|
array('oi' => $table . '_inheritance'),
|
|
|
|
'oi.' . $type . '_id = o.id',
|
|
|
|
array()
|
|
|
|
)->join(
|
|
|
|
array('i' => $table),
|
|
|
|
'i.id = oi.parent_' . $type . '_id',
|
|
|
|
'*'
|
|
|
|
)->where('o.id = ?', (int) $this->object->id)
|
|
|
|
->order('oi.weight');
|
|
|
|
|
|
|
|
$class = $this->getImportClass();
|
2016-03-07 02:05:10 +01:00
|
|
|
$this->objects = $class::loadAll($connection, $query, 'object_name');
|
|
|
|
foreach ($this->objects as $k => $obj) {
|
|
|
|
$this->imports[$k] = $k;
|
|
|
|
}
|
|
|
|
|
2015-08-28 17:11:51 +02:00
|
|
|
$this->storedImports = array();
|
2016-03-07 02:05:10 +01:00
|
|
|
foreach ($this->objects as $k => $v) {
|
2015-08-28 17:11:51 +02:00
|
|
|
$this->storedImports[$k] = clone($v);
|
|
|
|
}
|
2015-06-26 10:39:30 +02:00
|
|
|
|
2015-08-28 17:11:51 +02:00
|
|
|
$this->cloneStored();
|
2015-06-26 10:39:30 +02:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function store()
|
|
|
|
{
|
|
|
|
$objectId = $this->object->id;
|
|
|
|
$type = $this->getType();
|
|
|
|
|
|
|
|
$objectCol = $type . '_id';
|
2015-06-26 15:54:00 +02:00
|
|
|
$importCol = 'parent_' . $type . '_id';
|
2015-06-26 10:39:30 +02:00
|
|
|
|
2015-06-30 10:46:15 +02:00
|
|
|
if (! $this->hasBeenModified()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->object->hasBeenLoadedFromDb()) {
|
|
|
|
|
|
|
|
$this->object->db->delete($this->getImportTableName(), $objectCol . ' = ' . $objectId);
|
|
|
|
}
|
2015-06-26 10:39:30 +02:00
|
|
|
|
2015-06-26 15:54:00 +02:00
|
|
|
$weight = 1;
|
2016-03-07 02:05:10 +01:00
|
|
|
foreach ($this->imports as $importName) {
|
|
|
|
$import = $this->getObject($importName);
|
2015-06-26 10:39:30 +02:00
|
|
|
$this->object->db->insert(
|
2015-06-26 15:54:00 +02:00
|
|
|
$this->getImportTableName(),
|
2015-06-26 10:39:30 +02:00
|
|
|
array(
|
|
|
|
$objectCol => $objectId,
|
2015-06-26 15:54:00 +02:00
|
|
|
$importCol => $import->id,
|
|
|
|
'weight' => $weight++
|
2015-06-26 10:39:30 +02:00
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
2015-06-26 15:54:00 +02:00
|
|
|
|
2015-08-28 17:11:51 +02:00
|
|
|
$this->cloneStored();
|
2015-06-26 10:39:30 +02:00
|
|
|
|
2015-06-30 10:46:15 +02:00
|
|
|
return true;
|
2015-06-26 10:39:30 +02:00
|
|
|
}
|
|
|
|
|
2015-08-28 17:11:51 +02:00
|
|
|
protected function cloneStored()
|
|
|
|
{
|
|
|
|
$this->storedImports = array();
|
2016-03-07 02:05:10 +01:00
|
|
|
foreach ($this->objects as $k => $v) {
|
2015-08-28 17:11:51 +02:00
|
|
|
$this->storedImports[$k] = clone($v);
|
|
|
|
}
|
2016-05-20 08:12:46 +02:00
|
|
|
$this->modified = false;
|
2015-08-28 17:11:51 +02:00
|
|
|
}
|
|
|
|
|
2015-06-26 10:39:30 +02:00
|
|
|
protected function getImportClass()
|
|
|
|
{
|
|
|
|
return get_class($this->object);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static function loadForStoredObject(IcingaObject $object)
|
|
|
|
{
|
|
|
|
$imports = new static($object);
|
|
|
|
return $imports->loadFromDb();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function toConfigString()
|
|
|
|
{
|
|
|
|
$ret = '';
|
|
|
|
|
2016-03-07 02:05:10 +01:00
|
|
|
foreach ($this->imports as $name => $o) {
|
|
|
|
$ret .= ' import ' . c::renderString($name) . "\n";
|
2015-06-26 10:39:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ($ret !== '') {
|
|
|
|
$ret .= "\n";
|
|
|
|
}
|
|
|
|
return $ret;
|
|
|
|
}
|
|
|
|
|
2016-07-28 08:57:27 +02:00
|
|
|
public function toLegacyConfigString()
|
|
|
|
{
|
|
|
|
$ret = '';
|
|
|
|
|
|
|
|
foreach ($this->imports as $name => $o) {
|
|
|
|
$ret .= c1::renderKeyValue('use', c1::renderString($name));
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($ret !== '') {
|
|
|
|
$ret .= "\n";
|
|
|
|
}
|
|
|
|
return $ret;
|
|
|
|
}
|
|
|
|
|
2015-06-26 10:39:30 +02:00
|
|
|
public function __toString()
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
return $this->toConfigString();
|
|
|
|
} catch (Exception $e) {
|
|
|
|
trigger_error($e);
|
2016-02-26 11:58:37 +01:00
|
|
|
$previousHandler = set_exception_handler(
|
|
|
|
function () {
|
|
|
|
}
|
|
|
|
);
|
2015-06-26 10:39:30 +02:00
|
|
|
restore_error_handler();
|
|
|
|
if ($previousHandler !== null) {
|
|
|
|
call_user_func($previousHandler, $e);
|
|
|
|
die();
|
|
|
|
} else {
|
|
|
|
die($e->getMessage());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-06-30 09:34:27 +02:00
|
|
|
|
|
|
|
public function __destruct()
|
|
|
|
{
|
|
|
|
unset($this->storedImport);
|
|
|
|
unset($this->imports);
|
|
|
|
unset($this->objects);
|
|
|
|
unset($this->object);
|
|
|
|
}
|
2015-06-26 10:39:30 +02:00
|
|
|
}
|