mirror of
https://github.com/Icinga/icingaweb2-module-director.git
synced 2025-07-29 16:54:06 +02:00
MultiEdit: code cleanup, add custom var support
fixes #12465 fixes #12906 fixes #11614
This commit is contained in:
parent
856e574c26
commit
6a54e00402
@ -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 '<pre>';
|
||||
print_r($this->getVariants('imports'));
|
||||
print_r($this->getValues());
|
||||
echo '</pre>';
|
||||
*/
|
||||
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<br>", $property, $valueSum, $objectsSum);
|
||||
|
||||
$found = false;
|
||||
foreach ($this->getVariants($property) as $json => $objects) {
|
||||
@ -49,6 +67,9 @@ echo '</pre>';
|
||||
}
|
||||
|
||||
$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 '</pre>';
|
||||
}
|
||||
|
||||
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 '</pre>';
|
||||
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 '</pre>';
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
protected function object()
|
||||
{
|
||||
if ($this->object === null) {
|
||||
$this->object = current($this->objects);
|
||||
}
|
||||
|
||||
return $this->object;
|
||||
}
|
||||
}
|
||||
|
@ -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_');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user