DirectorObjectForm: add unique error message...

...without adding an error in case we detect a loop. Also improve
resolve cache invalidation and clean up old imports-related code

refs #11803
This commit is contained in:
Thomas Gelf 2016-10-12 15:22:11 +00:00
parent 05f991c585
commit e99568fffc
4 changed files with 75 additions and 72 deletions

View File

@ -117,6 +117,8 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
private $cachedPlainUnmodified; private $cachedPlainUnmodified;
private $templateResolver;
public function propertyIsBoolean($property) public function propertyIsBoolean($property)
{ {
return array_key_exists($property, $this->booleans); return array_key_exists($property, $this->booleans);
@ -774,8 +776,11 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
public function templateResolver() public function templateResolver()
{ {
// preserve object if ($this->templateResolver === null) {
return new IcingaTemplateResolver($this); $this->templateResolver = new IcingaTemplateResolver($this);
}
return $this->templateResolver;
} }
public function getResolvedProperty($key, $default = null) public function getResolvedProperty($key, $default = null)
@ -917,6 +922,10 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
public function invalidateResolveCache() public function invalidateResolveCache()
{ {
$this->resolveCache = array(); $this->resolveCache = array();
if ($this->templateResolver) {
$this->templateResolver()->clearCache();
}
return $this; return $this;
} }

View File

@ -41,6 +41,12 @@ class IcingaObjectImports implements Iterator, Countable, IcingaConfigRenderer
$this->position = 0; $this->position = 0;
} }
public function setModified()
{
$this->modified = true;
return $this;
}
public function hasBeenModified() public function hasBeenModified()
{ {
return $this->modified; return $this->modified;
@ -83,7 +89,7 @@ class IcingaObjectImports implements Iterator, Countable, IcingaConfigRenderer
public function set($import) public function set($import)
{ {
if ($import === null) { if (empty($import)) {
if (empty($this->imports)) { if (empty($this->imports)) {
return $this; return $this;
} else { } else {
@ -95,31 +101,33 @@ class IcingaObjectImports implements Iterator, Countable, IcingaConfigRenderer
$import = array($import); $import = array($import);
} }
$existing = array_keys($this->imports); $existing = $this->listImportNames();
$new = array(); $new = $this->listNamesForGivenImports($import);
$class = $this->getImportClass();
foreach ($import as $i) {
if ($i instanceof $class) {
$this->objects[$i->object_name] = $i;
$new[] = $i->object_name;
} else {
$new[] = $i;
}
}
if ($existing === $new) { if ($existing === $new) {
return $this; return $this;
} }
if (count($new) === 0) {
return $this->clear();
}
$this->imports = array(); $this->imports = array();
return $this->add($import); return $this->add($import);
} }
protected function listNamesForGivenImports($imports)
{
$list = array();
$class = $this->getImportClass();
foreach ($imports as $i) {
if ($i instanceof $class) {
$list[] = $i->object_name;
} else {
$list[] = $i;
}
}
return $list;
}
/** /**
* Magic isset check * Magic isset check
* *
@ -137,11 +145,9 @@ class IcingaObjectImports implements Iterator, Countable, IcingaConfigRenderer
} }
$this->imports = array(); $this->imports = array();
$this->modified = true; $this->modified = true;
$this->refreshIndex();
return $this; return $this->refreshIndex();
} }
public function remove($import) public function remove($import)
@ -151,21 +157,20 @@ class IcingaObjectImports implements Iterator, Countable, IcingaConfigRenderer
} }
$this->modified = true; $this->modified = true;
$this->refreshIndex();
return $this; return $this->refreshIndex();
} }
protected function refreshIndex() protected function refreshIndex()
{ {
$this->idx = array_keys($this->imports); $this->idx = array_keys($this->imports);
return $this;
} }
public function add($import) public function add($import)
{ {
$class = $this->getImportClass(); $class = $this->getImportClass();
// TODO: only one query when adding array
if (is_array($import)) { if (is_array($import)) {
foreach ($import as $i) { foreach ($import as $i) {
// Gracefully ignore null members or empty strings // Gracefully ignore null members or empty strings
@ -179,12 +184,13 @@ class IcingaObjectImports implements Iterator, Countable, IcingaConfigRenderer
} }
if ($import instanceof $class) { if ($import instanceof $class) {
if (array_key_exists($import->object_name, $this->imports)) { $name = $import->object_name;
if (array_key_exists($name, $this->imports)) {
return $this; return $this;
} }
$this->imports[$import->object_name] = $import->object_name; $this->imports[$name] = $name;
$this->objects[$import->object_name] = $import; $this->objects[$name] = $import;
} elseif (is_string($import)) { } elseif (is_string($import)) {
if (array_key_exists($import, $this->imports)) { if (array_key_exists($import, $this->imports)) {
return $this; return $this;
@ -219,7 +225,13 @@ class IcingaObjectImports implements Iterator, Countable, IcingaConfigRenderer
$class = $this->getImportClass(); $class = $this->getImportClass();
if (is_array($this->object->getKeyName())) { if (is_array($this->object->getKeyName())) {
// Services only // Services only
$import = $class::load(array('object_name' => $name, 'object_type' => 'template'), $connection); $import = $class::load(
array(
'object_name' => $name,
'object_type' => 'template'
),
$connection
);
} else { } else {
$import = $class::load($name, $connection); $import = $class::load($name, $connection);
} }
@ -250,37 +262,17 @@ class IcingaObjectImports implements Iterator, Countable, IcingaConfigRenderer
// TODO: prefetch // TODO: prefetch
protected function loadFromDb() protected function loadFromDb()
{ {
$db = $this->object->getDb(); $resolver = $this->object->templateResolver();
$connection = $this->object->getConnection(); // Force nesting error
$resolver->listResolvedParentIds();
$type = $this->getType(); $this->objects = $resolver->fetchParents();
$this->imports = array();
$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();
$this->objects = $class::loadAll($connection, $query, 'object_name');
foreach ($this->objects as $k => $obj) { foreach ($this->objects as $k => $obj) {
$this->imports[$k] = $k; $this->imports[$k] = $k;
} }
$this->storedImports = array(); $this->cloneStored();
foreach ($this->objects as $k => $v) {
$this->storedImports[$k] = clone($v);
}
return $this; return $this;
} }
@ -297,19 +289,21 @@ class IcingaObjectImports implements Iterator, Countable, IcingaConfigRenderer
public function store() public function store()
{ {
$objectId = $this->object->id; if (! $this->hasBeenModified()) {
return true;
}
$objectId = (int) $this->object->id;
$type = $this->getType(); $type = $this->getType();
$objectCol = $type . '_id'; $objectCol = $type . '_id';
$importCol = 'parent_' . $type . '_id'; $importCol = 'parent_' . $type . '_id';
if (! $this->hasBeenModified()) {
return true;
}
if ($this->object->hasBeenLoadedFromDb()) { if ($this->object->hasBeenLoadedFromDb()) {
$this->object->db->delete(
$this->object->db->delete($this->getImportTableName(), $objectCol . ' = ' . $objectId); $this->getImportTableName(),
$objectCol . ' = ' . $objectId
);
} }
$weight = 1; $weight = 1;
@ -358,7 +352,7 @@ class IcingaObjectImports implements Iterator, Countable, IcingaConfigRenderer
{ {
$ret = ''; $ret = '';
foreach ($this->imports as $name => $o) { foreach ($this->listImportNames() as $name) {
$ret .= ' import ' . c::renderString($name) . "\n"; $ret .= ' import ' . c::renderString($name) . "\n";
} }
@ -372,8 +366,8 @@ class IcingaObjectImports implements Iterator, Countable, IcingaConfigRenderer
{ {
$ret = ''; $ret = '';
foreach ($this->imports as $name => $o) { foreach ($this->listImportNames() as $name) {
$ret .= c1::renderKeyValue('use', c1::renderString($name)); $ret .= c1::renderKeyValue('use', c1::renderString($name)) . "\n";
} }
if ($ret !== '') { if ($ret !== '') {

View File

@ -49,8 +49,8 @@ class IcingaTemplateResolver
*/ */
public function clearCache() public function clearCache()
{ {
$type = $object->getShortTableName(); unset(self::$templates[$this->type]);
unset(self::$templates[$type]); return $this;
} }
/** /**

View File

@ -244,7 +244,7 @@ abstract class DirectorObjectForm extends QuickForm
false // Do not resolve IDs false // Do not resolve IDs
); );
} catch (NestingError $e) { } catch (NestingError $e) {
$this->addUniqueError($e->getMessage()); $this->addUniqueErrorMessage($e->getMessage());
$props = $object->getProperties(); $props = $object->getProperties();
} }
@ -273,7 +273,7 @@ abstract class DirectorObjectForm extends QuickForm
$inherited = $object->getInheritedProperties(); $inherited = $object->getInheritedProperties();
$origins = $object->getOriginsProperties(); $origins = $object->getOriginsProperties();
} catch (NestingError $e) { } catch (NestingError $e) {
$this->addUniqueError($e->getMessage()); $this->addUniqueErrorMessage($e->getMessage());
} }
} }
@ -968,7 +968,7 @@ abstract class DirectorObjectForm extends QuickForm
try { try {
$objectProperty = $object->getResolvedProperty($name); $objectProperty = $object->getResolvedProperty($name);
} catch (NestingError $e) { } catch (NestingError $e) {
$this->addUniqueError($e->getMessage()); $this->addUniqueErrorMessage($e->getMessage());
$objectProperty = $object->$name; $objectProperty = $object->$name;
} }
} else { } else {
@ -989,10 +989,10 @@ abstract class DirectorObjectForm extends QuickForm
return $default; return $default;
} }
protected function addUniqueError($msg) protected function addUniqueErrorMessage($msg)
{ {
if (! in_array($msg, $this->getErrorMessages())) { if (! in_array($msg, $this->getErrorMessages())) {
$this->addError($msg); $this->addErrorMessage($msg);
} }
return $this; return $this;