DataTypeDatalist: allow to customize behavior

Available options:
* strict: select box
* suggest_strict: auto-completion, allow only list values
* suggest_optional: Allow for values not on the list
* suggest_extend: Extend the list with new values

fixes #1846
This commit is contained in:
Thomas Gelf 2019-04-18 17:30:52 +02:00
parent 7177d489ec
commit db8895ae10
3 changed files with 163 additions and 16 deletions

View File

@ -258,6 +258,22 @@ class SuggestController extends ActionController
]);
}
protected function suggestDataListValuesForListId($id)
{
$db = $this->db()->getDbAdapter();
$select = $db->select()
->from('director_datalist_entry', ['entry_name', 'entry_value'])
->where('list_id = ?', $id)
->order('entry_value ASC');
$result = $db->fetchPairs($select);
if ($result) {
return $result;
} else {
return [];
}
}
protected function suggestDataListValues($field = null)
{
if ($field === null) {

View File

@ -3,28 +3,87 @@
namespace Icinga\Module\Director\DataType;
use Icinga\Module\Director\Acl;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Hook\DataTypeHook;
use Icinga\Module\Director\Objects\DirectorDatalistEntry;
use Icinga\Module\Director\Web\Form\DirectorForm;
use Icinga\Module\Director\Web\Form\QuickForm;
use Icinga\Module\Director\Web\Form\DirectorObjectForm;
use Icinga\Module\Director\Web\Form\Validate\IsDataListEntry;
class DataTypeDatalist extends DataTypeHook
{
/**
* @param $name
* @param QuickForm $form
* @return \Zend_Form_Element
* @throws \Zend_Form_Exception
*/
public function getFormElement($name, QuickForm $form)
{
$enum = $this->getEntries($form);
$params = [];
if ($this->getSetting('data_type') === 'array') {
$type = 'extensibleSet';
$params['sorted'] = true;
$params = ['multiOptions' => $enum];
$behavior = $this->getSetting('behavior', 'strict');
$targetDataType = $this->getSetting('data_type');
$listId = $this->getSetting('datalist_id');
if ($behavior === 'strict') {
$enum = $this->getEntries($form);
if ($targetDataType === 'string') {
$params['sorted'] = true;
$params = ['multiOptions' => $enum];
$type = 'select';
} else {
$params = ['multiOptions' => $form->optionalEnum($enum)];
$type = 'extensibleSet';
}
} else {
$params = ['multiOptions' => [
null => $form->translate('- please choose -'),
] + $enum];
$type = 'select';
if ($targetDataType === 'string') {
$type = 'text';
} else {
$type = 'extensibleSet';
}
$params['class'] = 'director-suggest';
$params['data-suggestion-context'] = "dataListValuesForListId!$listId";
}
$element = $form->createElement($type, $name, $params);
if ($behavior === 'suggest_strict') {
$element->addValidator(new IsDataListEntry($listId, $form->getDb()));
}
return $form->createElement($type, $name, $params);
if ($behavior === 'suggest_extend') {
$form->callOnSucess(function (DirectorForm $form) use ($name, $listId) {
$value = (array) $form->getValue($name);
if ($value === null) {
return;
}
$db = $form->getDb();
foreach ($value as $entry) {
$this->createEntryIfNotExists($db, $listId, $entry);
}
});
}
return $element;
}
/**
* @param Db $db
* @param $listId
* @param $entry
*/
protected function createEntryIfNotExists(Db $db, $listId, $entry)
{
if (! DirectorDatalistEntry::exists([
'list_id' => $listId,
'entry_name' => $entry,
], $db)) {
DirectorDatalistEntry::create([
'list_id' => $listId,
'entry_name' => $entry,
'entry_value' => $entry,
])->store($db);
}
}
protected function getEntries(QuickForm $form)
@ -34,7 +93,7 @@ class DataTypeDatalist extends DataTypeHook
$roles = array_map('json_encode', Acl::instance()->listRoleNames());
$select = $db->select()
->from('director_datalist_entry', array('entry_name', 'entry_value'))
->from('director_datalist_entry', ['entry_name', 'entry_value'])
->where('list_id = ?', $this->getSetting('datalist_id'))
->order('entry_value ASC');
@ -47,17 +106,20 @@ class DataTypeDatalist extends DataTypeHook
return $db->fetchPairs($select);
}
/**
* @param QuickForm $form
* @throws \Zend_Form_Exception
*/
public static function addSettingsFormFields(QuickForm $form)
{
/** @var DirectorObjectForm $form */
$db = $form->getDb();
$form->addElement('select', 'datalist_id', array(
$form->addElement('select', 'datalist_id', [
'label' => 'List name',
'required' => true,
'multiOptions' => array(null => '- please choose -') +
$db->enumDatalist(),
));
'multiOptions' => $form->optionalEnum($db->enumDatalist()),
]);
$form->addElement('select', 'data_type', [
'label' => $form->translate('Target data type'),
@ -68,6 +130,20 @@ class DataTypeDatalist extends DataTypeHook
'required' => true,
]);
return $form;
$form->addElement('select', 'behavior', [
'label' => $form->translate('Element behavior'),
'value' => 'strict',
'description' => $form->translate(
'This allows to show either a drop-down list or an auto-completion'
),
'multiOptions' => [
'strict' => $form->translate('Dropdown (list values only)'),
$form->translate('Autocomplete') => [
'suggest_strict' => $form->translate('Strict, list values only'),
'suggest_optional' => $form->translate('Allow for values not on the list'),
'suggest_extend' => $form->translate('Extend the list with new values'),
]
]
]);
}
}

View File

@ -0,0 +1,55 @@
<?php
namespace Icinga\Module\Director\Web\Form\Validate;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Objects\DirectorDatalistEntry;
use Zend_Validate_Abstract;
class IsDataListEntry extends Zend_Validate_Abstract
{
const INVALID = 'intInvalid';
/** @var Db */
private $db;
/** @var int */
private $dataListId;
public function __construct($dataListId, Db $db)
{
$this->db = $db;
$this->dataListId = (int) $dataListId;
}
public function isValid($value)
{
if (is_array($value)) {
foreach ($value as $name) {
if (! $this->isListEntry($name)) {
$this->_error(self::INVALID, $value);
return false;
}
}
return true;
}
if ($this->isListEntry($value)) {
return true;
} else {
$this->_error(self::INVALID, $value);
return false;
}
}
protected function isListEntry($name)
{
return DirectorDatalistEntry::exists([
'list_id' => $this->dataListId,
'entry_name' => $name,
], $this->db);
}
}