diff --git a/application/controllers/BasketController.php b/application/controllers/BasketController.php index 8db0a4a7..8ef3a47b 100644 --- a/application/controllers/BasketController.php +++ b/application/controllers/BasketController.php @@ -178,6 +178,10 @@ class BasketController extends ActionController $this->addSingleTab($this->translate('Snapshot')); $all = Json::decode($json); foreach ($all as $type => $objects) { + if ($type === 'Datafield') { + // $this->content()->add(Html::tag('h2', sprintf('+%d Datafield(s)', count($objects)))); + continue; + } $table = new NameValueTable(); $table->setAttribute('data-base-target', '_next'); foreach ($objects as $key => $object) { @@ -225,6 +229,7 @@ class BasketController extends ActionController $this->content()->add(Html::tag('h2', $type)); $this->content()->add($table); } + $this->content()->add(Html::tag('div', ['style' => 'height: 5em'])); } /** diff --git a/library/Director/DirectorObject/Automation/BasketSnapshot.php b/library/Director/DirectorObject/Automation/BasketSnapshot.php index 3acc770c..b048b8c6 100644 --- a/library/Director/DirectorObject/Automation/BasketSnapshot.php +++ b/library/Director/DirectorObject/Automation/BasketSnapshot.php @@ -9,6 +9,7 @@ use Icinga\Module\Director\Objects\DirectorDatafield; use Icinga\Module\Director\Objects\IcingaCommand; use Icinga\Module\Director\Objects\IcingaObject; use RuntimeException; +use Zend_Db_Adapter_Abstract as ZfDbAdapter; class BasketSnapshot extends DbObject { @@ -70,6 +71,12 @@ class BasketSnapshot extends DbObject return $types[$type]; } + /** + * @param Basket $basket + * @param Db $db + * @return BasketSnapshot + * @throws \Icinga\Exception\NotFoundError + */ public static function createForBasket(Basket $basket, Db $db) { $snapshot = static::create([ @@ -102,7 +109,7 @@ class BasketSnapshot extends DbObject $this->objects['Datafield'] = []; } $fields = & $this->objects['Datafield']; - foreach ($requiredIds as $id) { + foreach (array_keys($requiredIds) as $id) { if (! isset($fields[$id])) { $fields[$id] = DirectorDatafield::loadWithAutoIncId((int) $id, $connection)->export(); } @@ -148,19 +155,21 @@ class BasketSnapshot extends DbObject * @param bool $replace * @throws \Icinga\Module\Director\Exception\DuplicateKeyException * @throws \Icinga\Exception\NotFoundError + * @throws \Zend_Db_Adapter_Exception */ public function restoreTo(Db $connection, $replace = true) { $all = Json::decode($this->getJsonDump()); $db = $connection->getDbAdapter(); $db->beginTransaction(); + $fieldMap = []; foreach ($this->restoreOrder as $typeName) { if (isset($all->$typeName)) { $objects = $all->$typeName; $class = static::getClassForType($typeName); $changed = []; - foreach ($objects as $object) { + foreach ($objects as $key => $object) { /** @var DbObject $new */ $new = $class::import($object, $connection, $replace); if ($new->hasBeenModified()) { @@ -170,6 +179,13 @@ class BasketSnapshot extends DbObject $new->store(); } } + if ($new instanceof DirectorDatafield) { + $fieldMap[(int) $key] = (int) $new->get('id'); + } + + if ($new instanceof IcingaObject) { + $this->relinkObjectFields($db, $new, $object, $fieldMap); + } } /** @var IcingaObject $object */ @@ -181,6 +197,53 @@ class BasketSnapshot extends DbObject $db->commit(); } + /** + * @param ZfDbAdapter $db + * @param IcingaObject $new + * @param $object + * @param $fieldMap + * @throws \Zend_Db_Adapter_Exception + */ + protected function relinkObjectFields(ZfDbAdapter $db, IcingaObject $new, $object, $fieldMap) + { + if (! $new->supportsFields() || ! isset($object->fields)) { + return; + } + + $objectId = (int) $new->get('id'); + $table = $new->getTableName() . '_field'; + $objectKey = $new->getShortTableName() . '_id'; + $existingFields = []; + + foreach ($db->fetchAll( + $db->select()->from($table)->where("$objectKey = ?", $objectId) + ) as $mapping) { + $existingFields[(int) $mapping->datafield_id] = $mapping; + } + foreach ($object->fields as $field) { + $id = $fieldMap[(int) $field->datafield_id]; + if (isset($existingFields[$id])) { + unset($existingFields[$id]); + } else { + $db->insert($table, [ + $objectKey => $objectId, + 'datafield_id' => $id, + 'is_required' => $field->is_required, + 'var_filter' => $field->var_filter, + ]); + } + } + if (! empty($existingFields)) { + $db->delete( + $table, + $db->quoteInto( + "$objectKey = $objectId AND datafield_id IN (?)", + array_keys($existingFields) + ) + ); + } + } + /** * @param IcingaObject $object * @param $list diff --git a/library/Director/Objects/DirectorDatafield.php b/library/Director/Objects/DirectorDatafield.php index 5bcfd2a2..c6a41c72 100644 --- a/library/Director/Objects/DirectorDatafield.php +++ b/library/Director/Objects/DirectorDatafield.php @@ -93,17 +93,32 @@ class DirectorDatafield extends DbObjectWithSettings $id = null; } + $encoded = Json::encode($properties); if ($id) { if (static::exists($id, $db)) { $existing = static::loadWithAutoIncId($id, $db); $existingProperties = (array) $existing->export(); unset($existingProperties['originalId']); - if (Json::encode($properties) === Json::encode($existingProperties)) { + if ($encoded === Json::encode($existingProperties)) { return $existing; } } } + $dba = $db->getDbAdapter(); + $query = $dba->select() + ->from('director_datafield') + ->where('varname = ?', $plain->varname); + $candidates = DirectorDatafield::loadAll($db, $query); + + foreach ($candidates as $candidate) { + $export = $candidate->export(); + unset($export->originalId); + if (Json::encode($export) === $encoded) { + return $candidate; + } + } + return static::create($properties, $db); }