diff --git a/application/forms/SyncPropertyForm.php b/application/forms/SyncPropertyForm.php index 151fc7eb..cf08b197 100644 --- a/application/forms/SyncPropertyForm.php +++ b/application/forms/SyncPropertyForm.php @@ -5,8 +5,10 @@ namespace Icinga\Module\Director\Forms; use Icinga\Module\Director\Web\Form\DirectorObjectForm; use Icinga\Exception\InvalidPropertyException; use Icinga\Module\Director\Objects\SyncRule; +use Icinga\Module\Director\Objects\IcingaObject; use Icinga\Module\Director\Objects\ImportSource; use Icinga\Module\Director\Web\Hook\ImportSourceHook; +use Exception; class SyncPropertyForm extends DirectorObjectForm { @@ -17,53 +19,288 @@ class SyncPropertyForm extends DirectorObjectForm private $importSource; + private $dummyObject; + + const EXPRESSION = '__EXPRESSION__'; + public function setup() { - $this->addElement('select', 'rule_id', array( - 'label' => $this->translate('Rule Name'), - 'multiOptions' => $this->optionalEnum($this->db->enumSyncRule()), - 'required' => true, - )); + $this->addHtml(sprintf('

%s

', $this->getView()->escape($this->rule->rule_name))); + $this->addHidden('rule_id', $this->rule_id); $this->addElement('select', 'source_id', array( 'label' => $this->translate('Source Name'), - 'multiOptions' => $this->optionalEnum($this->db->enumImportSource()), + 'multiOptions' => $this->enumImportSource(), 'required' => true, + 'class' => 'autosubmit', + )); + if (! $this->hasObject() && ! $this->getSentValue('source_id')) { + return; + } + + $this->addElement('select', 'destination_field', array( + 'label' => $this->translate('Destination Field'), + 'multiOptions' => $this->optionalEnum($this->listDestinationFields()), + 'required' => true, + 'class' => 'autosubmit', )); - $this->addElement('text', 'source_expression', array( - 'label' => $this->translate('Source Expression'), - 'required' => true, - )); + if ($this->getSentValue('destination_field')) { + $destination = $this->getSentValue('destination_field'); + } elseif ($this->hasObject()) { + $destination = $this->getObject()->destination_field; + } else { + return; + } - $this->addElement('text', 'destination_field', array( - 'label' => $this->translate('Destination Field'), - 'required' => true, - )); + $isCustomvar = substr($destination, 0, 5) === 'vars.'; - $this->addElement('text', 'priority', array( - 'label' => $this->translate('Priority'), - 'description' => $this->translate('Priority for the specified source expression'), - 'required' => true, + if ($isCustomvar) { + $varname = substr($destination, 5); + $this->addElement('text', 'customvar', array( + 'label' => $this->translate('Custom variable'), + 'required' => true, + 'ignore' => true, + )); + + if ($varname !== '*') { + $this->setElementValue('destination_field', 'vars.*'); + $this->setElementValue('customvar', $varname); + if ($this->hasObject()) { + $this->getObject()->destination_field = 'vars.*'; + } + } + } + + if ($destination === 'import') { + $templates = $this->db->enumHostTemplates(); // ERR. type! + $templates = array_combine($templates, $templates); + $this->addElement('select', 'source_expression', array( + 'label' => $this->translate('Template'), // Objecttype? + 'multiOptions' => $this->optionalEnum($templates), + 'required' => true, + 'class' => 'autosubmit', + )); + } else { + $this->addSourceColumnElement(); + } + + if ($this->hasObject()) { + if (($col = $this->getObject()->getSourceColumn()) === null) { + $this->setElementValue('source_column', self::EXPRESSION); + $this->addElement('text', 'source_expression', array( + 'label' => $this->translate('Source Expression'), + 'required' => true, + )); + if ($this->getSentValue('source_column') === '${' . self::EXPRESSION . '}') { + unset($this->source_column); + } + } else { + $this->setElementValue('source_column', $col); + } + } + + if ($this->getSentValue('source_column') === self::EXPRESSION) { + $this->addElement('text', 'source_expression', array( + 'label' => $this->translate('Source Expression'), + 'required' => true, + )); + if ($this->getSentValue('source_column') === '${' . self::EXPRESSION . '}') { + unset($this->source_column); + } + } + + /* + if ($this->hasObject()) { + // TODO: Add up/down links to table + $this->addElement('text', 'priority', array( + 'label' => $this->translate('Priority'), + 'description' => $this->translate('Priority for the specified source expression'), + 'required' => true, + )); + } + */ + + /* + TODO: Filter should be a modifier + $this->addElement('select', 'use_filter', array( + 'label' => $this->translate('Filter values'), + 'description' => $this->translate('Whether you want to merge or replace the destination field. Makes no difference for strings'), + 'required' => true, + 'multiOptions' => $this->optionalEnum(array( + 'y' => 'merge', + 'n' => 'replace' + )) )); $this->addElement('text', 'filter_expression', array( 'label' => $this->translate('Filter Expression'), 'description' => $this->translate('This allows to filter for specific parts within the given source expression'), 'required' => false, - )); - - $this->addElement('select', 'merge_policy', array( - 'label' => $this->translate('Merge Policy'), - 'description' => $this->translate('Whether you want to merge or override the destination field'), + // TODO: validate filter + )); + */ + + if ($isCustomvar) { + $this->addElement('select', 'merge_policy', array( + 'label' => $this->translate('Merge Policy'), + 'description' => $this->translate('Whether you want to merge or replace the destination field. Makes no difference for strings'), + 'required' => true, + 'multiOptions' => $this->optionalEnum(array( + 'merge' => 'merge', + 'override' => 'replace' + )) + )); + } else { + $this->addHidden('merge_policy', 'override'); + } + + $this->setButtons(); + + } + + protected function addSourceColumnElement() + { + $error = false; + try { + $data = $this->listSourceColumns(); + } catch (Exception $e) { + $data = array(); + $error = sprintf( + $this->translate('Unable to fetch data: %s'), + $e->getMessage() + ); + } + + $this->addElement('select', 'source_column', array( + 'label' => $this->translate('Source Column'), + // TODO: List them as ${} ? + 'multiOptions' => $this->optionalEnum($data), 'required' => true, - 'multiOptions' => array( - 'null' => '- please choose -', - 'merge' => 'merge', - 'override' => 'override' - ) + 'class' => 'autosubmit', )); + if ($error) { + $this->getElement('source_column')->addError($error); + } + + return $this; + } + + protected function enumImportSource() + { + $sources = $this->db->enumImportSource(); + $usedIds = $this->rule->listInvolvedSourceIds(); + if (empty($usedIds)) { + return $this->optionalEnum($sources); + } + $usedSources = array(); + foreach ($usedIds as $id) { + $usedSources[$id] = $sources[$id]; + unset($sources[$id]); + } + + if (empty($sources)) { + return $this->optionalEnum($usedSources); + } + + return $this->optionalEnum( + array( + $this->translate('Used sources') => $usedSources, + $this->translate('Other sources') => $sources + ) + ); + } + + protected function listSourceColumns() + { + $columns = $this->getImportSource()->listColumns(); + $columns = array_combine($columns, $columns); + $columns[self::EXPRESSION] = $this->translate('Custom expression'); + return $columns; + } + + protected function listDestinationFields() + { + $fields = array(); + $dummy = $this->dummyObject(); + + if ($dummy instanceof IcingaObject) { + if ($dummy->supportsCustomvars()) { + $fields['vars.*'] = $this->translate('Custom variable (vars.)'); + } + if ($dummy->supportsImports()) { + $fields['import'] = $this->translate('Inheritance (import)'); + } + } + + foreach ($dummy->listProperties() as $prop) { + if ($prop === 'id') continue; + + // TODO: allow those fields, but munge them (store ids) + //if (preg_match('~_id$~', $prop)) continue; + + $fields[$prop] = $prop; + } + + return $fields; + } + + protected function getImportSource() + { + if ($this->importSource === null) { + if ($this->hasObject()) { + $src = ImportSource::load($this->object->source_id, $this->db); + } else { + $src = ImportSource::load($this->getSentValue('source_id'), $this->db); + } + $this->importSource = ImportSourceHook::loadByName($src->source_name, $this->db); + } + + return $this->importSource; + } + + public function onSuccess() + { + $sourceColumn = $this->getValue('source_column'); + if ($sourceColumn === self::EXPRESSION) { + unset($this->source_column); + $this->removeElement('source_column'); + } else { + if (! $this->getElement('source_expression')) { + $this->addHidden('source_expression', '${' . $sourceColumn . '}'); + } + } + $object = $this->getObject(); + $object->rule_id = $this->rule->id; // ?! + + $destination = $this->getValue('destination_field'); + if ($destination === 'vars.*') { + $destination = $this->getValue('customvar'); + $object->destination_field = 'vars.' . $destination; + } + + if ($object->hasBeenModified()) { + if (! $object->hasBeenLoadedFromDb()) { + $object->priority = $this->rule->getPriorityForNextProperty(); + } + } + + + return parent::onSuccess(); + } + + protected function dummyObject() + { + if ($this->dummyObject === null) { + $this->dummyObject = IcingaObject::createByType( + $this->rule->object_type, + array(), + $this->db + ); + } + + return $this->dummyObject; } public function setRule(SyncRule $rule)