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)