diff --git a/application/forms/IcingaObjectFieldForm.php b/application/forms/IcingaObjectFieldForm.php index 91db7d4d6..f4823b5fb 100644 --- a/application/forms/IcingaObjectFieldForm.php +++ b/application/forms/IcingaObjectFieldForm.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Forms; +use Icinga\Module\Director\DataType\DataTypeBoolean; +use Icinga\Module\Director\DataType\DataTypeString; use Icinga\Module\Director\Field\FormFieldSuggestion; use Icinga\Module\Director\Objects\IcingaCommand; use Icinga\Module\Director\Objects\IcingaHost; @@ -17,7 +19,7 @@ class IcingaObjectFieldForm extends DirectorObjectForm protected $icingaObject; /** @var FormFieldSuggestion */ - protected $formFieldSuggestion; + protected $fieldSuggestion; public function setIcingaObject($object) { @@ -28,7 +30,6 @@ public function setIcingaObject($object) public function setup() { - $this->formFieldSuggestion = new FormFieldSuggestion(); $object = $this->icingaObject; $type = $object->getShortTableName(); $this->addHidden($type . '_id', $object->get('id')); @@ -52,12 +53,13 @@ public function setup() $command = null; } - $descriptions = []; - $fields = $command ? $this->formFieldSuggestion->getCommandFields( - $command, - $this->db->enumDatafields(), - $descriptions - ) : []; + if ($command) { + $suggestions = $this->fieldSuggestion = new FormFieldSuggestion($command, $this->db->enumDatafields()); + $fields = $suggestions->getCommandFields(); + } else { + $suggestions = null; + $fields = []; + } $this->addElement('select', 'datafield_id', [ 'label' => 'Field', @@ -95,7 +97,7 @@ public function setup() . ' user puts the focus on this field' ), 'ignore' => true, - 'value' => array_key_exists($id, $descriptions) ? $descriptions[$id] : null, + 'value' => $suggestions ? $suggestions->getDescription($id) : null, 'rows' => '3', ]); } @@ -153,7 +155,9 @@ public function onSuccess() 'varname' => trim($fieldId, '$'), 'caption' => $this->getValue('caption'), 'description' => $this->getValue('description'), - 'datatype' => 'Icinga\Module\Director\DataType\DataTypeString', + 'datatype' => $this->fieldSuggestion && $this->fieldSuggestion->isBoolean($fieldId) + ? DataTypeBoolean::class + : DataTypeString::class ]); $field->store($this->getDb()); $this->setElementValue('datafield_id', $field->get('id')); diff --git a/doc/82-Changelog.md b/doc/82-Changelog.md index 8f71bfd78..e50cd29bc 100644 --- a/doc/82-Changelog.md +++ b/doc/82-Changelog.md @@ -17,6 +17,7 @@ This version hasn't been released yet * FEATURE: Sort Template trees by name (#2691) * FEATURE: Branch and Sync diff/preview now shows related host for services (#2736) * FEATURE: Show more details for assign filter parsing errors (#2667) +* FEATURE: Fields from set_if are now being proposed (#514) * FIX: do not fail for (some) Service Dependencies (#2669, #1142) * FIX: Service Sets can now be searched by Service name in branches too (#2738) * FIX: Template usage table had no header (#2780) @@ -45,7 +46,6 @@ This version hasn't been released yet * FIX: complaint about overdue jobs was not correct (#2680, #2681) ### Internals - * FIX: group membership is no longer resolved when not needed (#2048) ### Fixed issues diff --git a/library/Director/Field/FormFieldSuggestion.php b/library/Director/Field/FormFieldSuggestion.php index 72db096d2..4fa5f33dd 100644 --- a/library/Director/Field/FormFieldSuggestion.php +++ b/library/Director/Field/FormFieldSuggestion.php @@ -9,84 +9,149 @@ class FormFieldSuggestion { use TranslationHelper; - public function getCommandFields( + /** + * Macro/Argument names used in command argument values + * + * @var array + */ + protected $argumentVars = []; + protected $suggestedFields = []; + protected $blacklistedVars = []; + protected $descriptions = []; + protected $booleans = []; + + /** @var IcingaCommand */ + protected $command; + + /** @var array */ + protected $existingFields; + + protected $fields = null; + + public function __construct( IcingaCommand $command, - array $existingFields, - array &$descriptions - ): array + array $existingFields + ) { + $this->command = $command; + $this->existingFields = $existingFields; + } + + public function getCommandFields(): array + { + if ($this->fields === null) { + $this->fields = $this->prepareFields(); + } + + return $this->fields; + } + + protected function prepareFields(): array { // TODO: remove assigned ones! - $argumentVars = []; - $blacklistedVars = []; - $suggestedFields = []; - $booleans = []; - foreach ($existingFields as $id => $field) { + foreach ($this->existingFields as $id => $field) { if (preg_match('/ \(([^)]+)\)$/', $field, $m)) { - $blacklistedVars['$' . $m[1] . '$'] = $id; + $this->blacklistedVars['$' . $m[1] . '$'] = $id; } } - foreach ($command->arguments() as $arg) { + foreach ($this->command->arguments() as $arg) { if ($arg->argument_format === 'string') { foreach (self::extractMacroNamesFromString($arg->argument_value) as $val) { - self::addSuggestion( - $val, - $arg->description, - $blacklistedVars, - $existingFields, - $suggestedFields, - $argumentVars, - $descriptions - ); + $this->addSuggestion($val, $arg->description, $this->argumentVars); } } + + if (($arg->set_if_format === 'string' || $arg->set_if_format === null) + && $val = self::getMacroIfStringIsSingleMacro($arg->set_if) + ) { + $this->addSuggestion($val, $arg->description, $this->booleans); + } } + asort($this->suggestedFields, SORT_NATURAL | SORT_FLAG_CASE); + ksort($this->argumentVars); + ksort($this->booleans); + asort($this->existingFields, SORT_NATURAL | SORT_FLAG_CASE); // Prepare combined fields array $fields = []; - if (! empty($suggestedFields)) { - asort($suggestedFields, SORT_NATURAL | SORT_FLAG_CASE); - $fields[$this->translate('Suggested fields')] = $suggestedFields; + if (! empty($this->suggestedFields)) { + $fields[$this->translate('Suggested fields')] = $this->suggestedFields; + } + + if (! empty($this->argumentVars)) { + $fields[$this->translate('Argument macros')] = $this->argumentVars; } - if (! empty($argumentVars)) { - ksort($argumentVars); - $fields[$this->translate('Argument macros')] = $argumentVars; + if (! empty($this->booleans)) { + $fields[$this->translate('Flags (boolean) arguments')] = $this->booleans; } - if (! empty($existingFields)) { - asort($existingFields, SORT_NATURAL | SORT_FLAG_CASE); - $fields[$this->translate('Other available fields')] = $existingFields; + if (! empty($this->existingFields)) { + $fields[$this->translate('Other available fields')] = $this->existingFields; } return $fields; } - protected static function addSuggestion( + public function getDescription($id) + { + if (array_key_exists($id, $this->descriptions)) { + return $this->descriptions[$id]; + } + + return null; + } + + public function isBoolean(string $macro): bool + { + return isset($this->booleans[$macro]); + } + + protected function addSuggestion( string $val, ?string $description, - array $blacklistedVars, - array &$existingFields, - array &$suggestedFields, - array &$targetList, - array &$descriptions + array &$targetList ) { - if (array_key_exists($val, $blacklistedVars)) { - $id = $blacklistedVars[$val]; + if (array_key_exists($val, $this->blacklistedVars)) { + $id = $this->blacklistedVars[$val]; // Hint: if not set it might already have been // removed in this loop - if (array_key_exists($id, $existingFields)) { - $suggestedFields[$id] = $existingFields[$id]; - unset($existingFields[$id]); + if (array_key_exists($id, $this->existingFields)) { + $this->suggestedFields[$id] = $this->existingFields[$id]; + unset($this->existingFields[$id]); } } else { $targetList[$val] = $val; - $descriptions[$val] = $description; + $this->descriptions[$val] = $description; + } + } + + /** + * Returns a macro name string ($macro_name$), if the given string is such, null otherwise + * + * @param ?string $string + * @return ?string + */ + protected static function getMacroIfStringIsSingleMacro(?string $string): ?string + { + if ($string === null) { + return null; + } + + if (preg_match('/^(\$[a-z0-9_]+\$)$/i', $string, $matches)) { + return $matches[1]; } + return null; } + /** + * Extracts all macro names ($macro_name$) from a given string + * + * @param ?string $string + * @return array + */ protected static function extractMacroNamesFromString(?string $string): array { if ($string !== null && preg_match_all('/(\$[a-z0-9_]+\$)/i', $string, $matches, PREG_PATTERN_ORDER)) {