From 6a54e00402f0fafe93c8b755d77137a736253fa0 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Fri, 14 Oct 2016 17:17:07 +0000 Subject: [PATCH] MultiEdit: code cleanup, add custom var support fixes #12465 fixes #12906 fixes #11614 --- application/forms/IcingaMultiEditForm.php | 163 +++++++----- .../Director/Web/Form/DirectorObjectForm.php | 6 +- .../Web/Form/IcingaObjectFieldLoader.php | 236 ++++++++++++------ 3 files changed, 264 insertions(+), 141 deletions(-) diff --git a/application/forms/IcingaMultiEditForm.php b/application/forms/IcingaMultiEditForm.php index 35d8638e..3de689ab 100644 --- a/application/forms/IcingaMultiEditForm.php +++ b/application/forms/IcingaMultiEditForm.php @@ -2,41 +2,59 @@ namespace Icinga\Module\Director\Forms; -use Icinga\Module\Director\Web\Form\QuickForm; +use Icinga\Module\Director\Web\Form\IcingaObjectFieldLoader; +use Icinga\Module\Director\Web\Form\DirectorObjectForm; +use Zend_Form_Element as ZfElement; -class IcingaMultiEditForm extends QuickForm +class IcingaMultiEditForm extends DirectorObjectForm { private $objects; - private $object; - - private $db; + private $elementGroupMap; public function setObjects($objects) { $this->objects = $objects; + $this->object = current($this->objects); + $this->db = $this->object()->getConnection(); return $this; } public function setup() { - $this->addImportsElements();//->setButtons(); + $object = $this->object; + $this->addImportsElement(); + // $this->addDisabledElement(); + + $loader = new IcingaObjectFieldLoader($object); + $loader->addFieldsToForm($this); + + $this->makeVariants($this->getElement('imports')); + // $this->makeVariants($this->getElement('disabled')); + foreach ($this->getElements() as $el) { + $name =$el->getName(); + if (substr($name, 0, 4) === 'var_') { + $this->makeVariants($el); + } + } + + $this->setButtons(); + } + + /** + * No default objects behaviour + */ + protected function onRequest() + { } public function onSuccess() { -/* -echo '
';
-print_r($this->getVariants('imports'));
-print_r($this->getValues());
-echo '
'; -*/ foreach ($this->getValues() as $key => $value) { $parts = preg_split('/_/', $key); $objectsSum = array_pop($parts); $valueSum = array_pop($parts); $property = implode('_', $parts); -//printf("Got %s: %s -> %s
", $property, $valueSum, $objectsSum); $found = false; foreach ($this->getVariants($property) as $json => $objects) { @@ -49,6 +67,9 @@ echo ''; } $found = true; + if (substr($property, 0, 4) === 'var_') { + $property = 'vars.' . substr($property, 4); + } foreach ($this->getObjects($objects) as $object) { $object->$property = $value; @@ -65,24 +86,80 @@ echo ''; } if ($modified === 0) { - $this->setSuccessMessage($this->translate('No object has been modified')); + $msg = $this->translate('No object has been modified'); } elseif ($modified === 1) { - $this->setSuccessMessage($this->translate('One object has been modified')); + $msg = $this->translate('One object has been modified'); } else { - $this->setSuccessMessage( - sprintf( - $this->translate('%d objects have been modified'), - $modified - ) + $msg = sprintf( + $this->translate('%d objects have been modified'), + $modified ); } - parent::onSuccess(); + $this->redirectOnSuccess($msg); + } + + protected function getDisplayGroupForElement(ZfElement $element) + { + if ($this->elementGroupMap === null) { + $this->resolveDisplayGroups(); + } + + $name = $element->getName(); + if (array_key_exists($name, $this->elementGroupMap)) { + return $this->getDisplayGroup($this->elementGroupMap[$name]); + } else { + return null; + } + } + + protected function resolveDisplayGroups() + { + $this->elementGroupMap = array(); + + foreach ($this->getDisplayGroups() as $group) { + $groupName = $group->getName(); + foreach ($group->getElements() as $name => $e) { + $this->elementGroupMap[$name] = $groupName; + } + } + } + + protected function makeVariants(ZfElement $element) + { + if (! $element) { + return $this; + } + + $key = $element->getName(); + $this->removeElement($key); + $label = $element->getLabel(); + $group = $this->getDisplayGroupForElement($element); + $description = $element->getDescription(); + + foreach ($this->getVariants($key) as $json => $objects) { + $value = json_decode($json); + $checksum = sha1($json) . '_' . sha1(json_encode($objects)); + + $v = clone($element); + $v->setName($key . '_' . $checksum); + $v->setDescription($description . '. ' . $this->descriptionForObjects($objects)); + $v->setLabel($label . $this->labelCount($objects)); + $v->setValue($value); + if ($group) { + $group->addElement($v); + } + $this->addElement($v); + } } protected function getVariants($key) { $variants = array(); + if (substr($key, 0, 4) === 'var_') { + $key = 'vars.' . substr($key, 4); + } + foreach ($this->objects as $name => $object) { $value = json_encode($object->$key); if (! array_key_exists($value, $variants)) { @@ -113,41 +190,6 @@ echo ''; return ' (' . count($list) . ')'; } - protected function addImportsElements() - { - $enum = $this->enumTemplates(); - if (empty($enum)) { - return $this; - } - - foreach ($this->getVariants('imports') as $json => $objects) { - $value = json_decode($json); - $checksum = sha1($json) . '_' . sha1(json_encode($objects)); - $this->addElement('extensibleSet', 'imports_' . $checksum, array( - 'label' => $this->translate('Imports') . $this->labelCount($objects), - 'description' => $this->translate( - 'Importable templates, add as many as you want. Please note that order' - . ' matters when importing properties from multiple templates: last one' - . ' wins' - ) . '. ' . $this->descriptionForObjects($objects), - 'required' => !$this->object()->isTemplate(), - 'multiOptions' => $this->optionallyAddFromEnum($enum), - 'value' => $value, - 'sorted' => true, - 'class' => 'autosubmit' - )); - } - - return $this; - } - - public function optionallyAddFromEnum($enum) - { - return array( - null => $this->translate('- click to add more -') - ) + $enum; - } - protected function enumTemplates() { $object = $this->object(); @@ -182,13 +224,4 @@ echo ''; return $res; } - - protected function object() - { - if ($this->object === null) { - $this->object = current($this->objects); - } - - return $this->object; - } } diff --git a/library/Director/Web/Form/DirectorObjectForm.php b/library/Director/Web/Form/DirectorObjectForm.php index 69b505bc..5ad71c06 100644 --- a/library/Director/Web/Form/DirectorObjectForm.php +++ b/library/Director/Web/Form/DirectorObjectForm.php @@ -257,7 +257,11 @@ abstract class DirectorObjectForm extends QuickForm protected function handleCustomVars($object, & $values) { if ($this->assertResolvedImports()) { - IcingaObjectFieldLoader::addFieldsToForm($this, $object, $values); + $loader = new IcingaObjectFieldLoader($object); + $loader->addFieldsToForm($this); + if ($values) { + $loader->setValues($values, 'var_'); + } } } diff --git a/library/Director/Web/Form/IcingaObjectFieldLoader.php b/library/Director/Web/Form/IcingaObjectFieldLoader.php index 5076dac5..640c2417 100644 --- a/library/Director/Web/Form/IcingaObjectFieldLoader.php +++ b/library/Director/Web/Form/IcingaObjectFieldLoader.php @@ -2,10 +2,11 @@ namespace Icinga\Module\Director\Web\Form; +use stdClass; use Icinga\Module\Director\Objects\IcingaObject; use Icinga\Module\Director\Objects\IcingaServiceSet; use Icinga\Module\Director\Objects\DirectorDatafield; -use stdClass; +use Zend_Form_Element as ZfElement; class IcingaObjectFieldLoader { @@ -13,95 +14,172 @@ class IcingaObjectFieldLoader protected $object; - protected function __construct(DirectorObjectForm $form, IcingaObject $object) + protected $fields; + + protected $elements; + + public function __construct(IcingaObject $object) { - $this->form = $form; $this->object = $object; } - public static function addFieldsToForm(DirectorObjectForm $form, IcingaObject $object, & $values) + public function addFieldsToForm(QuickForm $form) { - if (! $object->supportsCustomVars()) { - return $form; + if ($this->object->supportsCustomVars()) { + $this->attachFieldsToForm($form); } - $loader = new static($form, $object); - $loader->addFields(); - if ($values !== null) { - $loader->setValues($loader->stripKeyPrefix($values, 'var_')); - } - - return $form; + return $this; } - protected function stripKeyPrefix($array, $prefix) + /** + * Set a list of values + * + * Works in a failsafe way, when a field does not exist the value will be + * silently ignored + * + * @param Array $values key/value pairs with variable names and their value + * @param String $prefix An optional prefix that would be stripped from keys + * + * @return self + */ + public function setValues($values, $prefix = null) { - $new = array(); - $len = strlen($prefix); - foreach ($array as $key => $value) { - if (substr($key, 0, $len) === $prefix) { - $new[substr($key, $len)] = $value; - } + if ($prefix !== null) { + $len = strlen($prefix); } - - return $new; - } - - protected function setValues($values) - { $vars = $this->object->vars(); - $form = $this->form; foreach ($values as $key => $value) { - if ($el = $form->getElement('var_' . $key)) { - if ($value === '' || $value === null) { + if ($prefix) { + if (substr($key, 0, $len) === $prefix) { + $key = substr($key, $len); + } else { continue; } + } + + if ($el = $this->getElement($key)) { $el->setValue($value); - $vars->set($key, $el->getValue()); + $value = $el->getValue(); + + if ($value === '') { + $value = null; + } + + $vars->set($key, $value); + } + } + + return $this; + } + + /** + * Get the fields for our object + * + * @return DirectorDatafield[] + */ + public function getFields() + { + if ($this->fields === null) { + $this->fields = $this->prepareObjectFields($this->object); + } + + return $this->fields; + } + + /** + * Get the form elements for our fields + * + * @param QuickForm $form Optional + * + * @return ZfElement[] + */ + public function getElements(QuickForm $form = null) + { + if ($this->elements === null) { + $this->elements = $this->createElements($form); + $this->setValuesFromObject($this->object); + } + + return $this->elements; + } + + /** + * Attach our form fields to the given form + * + * This will also create a 'Custom properties' display group + */ + protected function attachFieldsToForm(QuickForm $form) + { + $elements = $this->getElements($form); + + if (! empty($elements)) { + $form->addElementsToGroup( + $elements, + 'custom_fields', + 50, + $form->translate('Custom properties') + ); + } + } + + /** + * Get the form element for a specific field by it's variable name + * + * @return ZfElement|null + */ + protected function getElement($name) + { + $elements = $this->getElements(); + if (array_key_exists($name, $elements)) { + return $this->elements[$name]; + } + + return null; + } + + /** + * Get the form elements based on the given form + * + * @return ZfElement[] + */ + protected function createElements(QuickForm $form) + { + $elements = array(); + + foreach ($this->getFields() as $name => $field) { + $elements[$name] = $field->getFormElement($form); + } + + return $elements; + } + + protected function setValuesFromObject(IcingaObject $object) + { + foreach ($object->getVars() as $k => $v) { + if ($v !== null && $el = $this->getElement($k)) { + $el->setValue($v); } } } - protected function addFields() + protected function mergeFields($listOfFields) { - $object = $this->object; - if ($object instanceof IcingaServiceSet) { - } else { - $this->attachFields( - $this->prepareObjectFields($object) - ); - } - - $this->setValues($object->getVars()); - } - - protected function attachFields($fields) - { - $form = $this->form; - $elements = array(); - foreach ($fields as $field) { - $elements[] = $field->getFormElement($form); - } - - if (empty($elements)) { - return $this; - } - - return $form->addElementsToGroup( - $elements, - 'custom_fields', - 50, - $form->translate('Custom properties') - ); + // TODO: Merge field for different object, mostly sets } + /** + * Create the fields for our object + * + * + * @return DirectorDatafield[] + */ protected function prepareObjectFields($object) { $fields = $this->loadResolvedFieldsForObject($object); - - if ($object->hasProperty('command_id')) { - $command = $object->getResolvedRelated('command'); + if ($object->hasRelation('check_command')) { + $command = $object->getResolvedRelated('check_command'); if ($command) { $cmdFields = $this->loadResolvedFieldsForObject($command); foreach ($cmdFields as $varname => $field) { @@ -115,11 +193,14 @@ class IcingaObjectFieldLoader return $fields; } - protected function mergeFields($listOfFields) - { - // TODO: Merge field for different object, mostly sets - } - + /** + * Create the fields for our object + * + * Follows the inheritance logic, resolves all fields and keeps the most + * specific ones. Returns a list of fields indexed by variable name + * + * @return DirectorDatafield[] + */ protected function loadResolvedFieldsForObject($object) { $result = $this->loadDataFieldsForObjects( @@ -139,11 +220,16 @@ class IcingaObjectFieldLoader return $fields; } - protected function getDb() - { - return $this->form->getDb(); - } - + /** + * Fetches fields for a given List of objects from the database + * + * Gives a list indexed by object id, with each entry being a list of that + * objects DirectorDatafield instances indexed by variable name + * + * @param IcingaObject[] $objectList List of objects + * + * @return Array + */ protected function loadDataFieldsForObjects($objectList) { $ids = array(); @@ -163,7 +249,7 @@ class IcingaObjectFieldLoader $db = $connection->getDbAdapter(); $idColumn = 'f.' . $object->getShortTableName() . '_id'; - + $query = $db->select()->from( array('df' => 'director_datafield'), array( @@ -193,7 +279,7 @@ class IcingaObjectFieldLoader if (! array_key_exists($id, $result)) { $result[$id] = new stdClass; } - + $result[$id]->{$r->varname} = DirectorDatafield::fromDbRow( $r, $connection