mirror of
https://github.com/Icinga/icingaweb2-module-director.git
synced 2026-06-04 22:32:55 -04:00
238 lines
7.2 KiB
PHP
238 lines
7.2 KiB
PHP
<?php
|
|
|
|
namespace Icinga\Module\Director\Forms\DictionaryElements;
|
|
|
|
use Icinga\Module\Director\Db\DbUtil;
|
|
use ipl\Html\FormElement\FieldsetElement;
|
|
use ipl\Html\Html;
|
|
use ipl\Web\Widget\EmptyStateBar;
|
|
|
|
/**
|
|
* @phpstan-type DictionaryDataType array<string, mixed>
|
|
*/
|
|
class Dictionary extends FieldsetElement
|
|
{
|
|
protected $defaultAttributes = ['class' => 'dictionary'];
|
|
|
|
/** @var array Dictionary items */
|
|
protected array $items = [];
|
|
|
|
/** @var bool Whether to allow removal of item */
|
|
protected bool $allowItemRemoval = false;
|
|
|
|
/** @var bool Whether the dictionary is an array */
|
|
protected bool $isArray = false;
|
|
|
|
/** @var bool Whether the dictionary is the root */
|
|
|
|
public function __construct(string $name, array $items, $attributes = null)
|
|
{
|
|
$this->items = $items;
|
|
|
|
parent::__construct($name, $attributes);
|
|
}
|
|
|
|
public function setAllowItemRemoval(bool $allow = false): static
|
|
{
|
|
$this->allowItemRemoval = $allow;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getAllowItemRemoval(): bool
|
|
{
|
|
return $this->allowItemRemoval;
|
|
}
|
|
|
|
protected function assemble(): void
|
|
{
|
|
$expectedCount = (int) $this->getPopulatedValue('item-count', 0);
|
|
$count = 0;
|
|
|
|
// Load previously removed items from the hidden field (no session)
|
|
$removedItemsPopulated = $this->getPopulatedValue('items_removed', '');
|
|
$removedItems = $removedItemsPopulated !== ''
|
|
? array_fill_keys(explode(', ', $removedItemsPopulated), true)
|
|
: [];
|
|
|
|
$remove = null;
|
|
if ($this->allowItemRemoval) {
|
|
while ($count < $expectedCount) {
|
|
$remove = $this->createElement(
|
|
'submitButton',
|
|
'remove_' . $count,
|
|
[
|
|
'label' => 'Remove Item',
|
|
'class' => ['remove-property'],
|
|
'formnovalidate' => true
|
|
]
|
|
);
|
|
|
|
$this->registerElement($remove);
|
|
if ($remove->hasBeenPressed()) {
|
|
$removedValue = $this->getPopulatedValue($count);
|
|
if (isset($removedValue['name'])) {
|
|
$clearedItemName = $removedValue['name'];
|
|
if (isset($this->items[$clearedItemName])) {
|
|
$removedItems[$clearedItemName] = true;
|
|
} elseif (isset($this->items[$clearedItemName]['new'])) {
|
|
unset($this->items[$clearedItemName]);
|
|
}
|
|
}
|
|
|
|
$this->clearPopulatedValue('items_removed');
|
|
$this->clearPopulatedValue($remove->getName());
|
|
$this->clearPopulatedValue($count);
|
|
$this->populate(['items_removed' => implode(', ', array_keys($removedItems))]);
|
|
|
|
// Re-index populated values to ensure proper association with form data
|
|
foreach (range($count + 1, $expectedCount) as $i) {
|
|
$this->populate([$i - 1 => $this->getPopulatedValue($i) ?? []]);
|
|
}
|
|
}
|
|
|
|
$count++;
|
|
}
|
|
}
|
|
|
|
$addedItems = [];
|
|
foreach ($this->items as $key => $item) {
|
|
if (array_key_exists($key, $removedItems)) {
|
|
unset($this->items[$key]);
|
|
} elseif (isset($item['new'])) {
|
|
$addedItems[] = $key;
|
|
}
|
|
}
|
|
|
|
$this->addElement('hidden', 'items_removed', ['value' => implode(', ', array_keys($removedItems))]);
|
|
$this->addElement('hidden', 'items_added', ['value' => implode(', ', $addedItems)]);
|
|
$count = 0;
|
|
foreach ($this->items as $item) {
|
|
$item['uuid'] = DbUtil::binaryResult($item['uuid']);
|
|
if (isset($item['parent_uuid'])) {
|
|
$item['parent_uuid'] = DbUtil::binaryResult($item['parent_uuid']);
|
|
}
|
|
|
|
$element = new DictionaryItem((string) $count, $item);
|
|
|
|
// Only allow removal of items if the dictionary allows it and the item allows it
|
|
if (
|
|
$this->allowItemRemoval
|
|
&& $item['allow_removal']
|
|
&& $this->hasElement('remove_' . $count)
|
|
) {
|
|
$element->setRemoveButton($this->getElement('remove_' . $count));
|
|
}
|
|
|
|
$this->addElement($element);
|
|
$count++;
|
|
}
|
|
|
|
$this->clearPopulatedValue('item-count');
|
|
$itemCountInput = $this->createElement('hidden', 'item-count', ['ignore' => true, 'value' => $count]);
|
|
$this->registerElement($itemCountInput);
|
|
$this->addHtml(Html::tag('div', ['id' => $this->getName() . '-item-count'], $itemCountInput));
|
|
|
|
|
|
$newVarSlot = Html::tag('div', ['id' => 'new-var-slot-' . $count]);
|
|
|
|
if ($this->allowItemRemoval) {
|
|
$this->addHtml($newVarSlot);
|
|
}
|
|
|
|
if ($count === 0) {
|
|
if ($this->allowItemRemoval) {
|
|
$message = $this->translate('No custom variables have been added yet');
|
|
} else {
|
|
$message = $this->translate('No fields configured');
|
|
}
|
|
|
|
$this->addHtml(new EmptyStateBar($message));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Prepare the dictionary for display
|
|
*
|
|
* @param array $items
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function prepare(array $items): array
|
|
{
|
|
$values = [];
|
|
foreach ($items as $item) {
|
|
if (isset($item['removed'])) {
|
|
continue;
|
|
}
|
|
|
|
$values[] = DictionaryItem::prepare($item);
|
|
}
|
|
|
|
return $values;
|
|
}
|
|
|
|
public function populate($values): static
|
|
{
|
|
if (! isset($values['item-count'])) {
|
|
$values['item-count'] = count($values);
|
|
}
|
|
|
|
return parent::populate($values);
|
|
}
|
|
|
|
/**
|
|
* Get the items to remove from the dictionary
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getItemsToRemove(): array
|
|
{
|
|
$this->ensureAssembled();
|
|
$itemsToRemove = $this->getPopulatedValue('items_removed');
|
|
if (! empty($itemsToRemove)) {
|
|
$itemsToRemove = explode(', ', $itemsToRemove);
|
|
} else {
|
|
$itemsToRemove = [];
|
|
}
|
|
|
|
return $itemsToRemove;
|
|
}
|
|
|
|
/**
|
|
* Get the number of rendered DictionaryItem children
|
|
*/
|
|
public function getItemCount(): int
|
|
{
|
|
$count = 0;
|
|
foreach ($this->ensureAssembled()->getElements() as $element) {
|
|
if ($element instanceof DictionaryItem) {
|
|
$count++;
|
|
}
|
|
}
|
|
|
|
return $count;
|
|
}
|
|
|
|
/**
|
|
* Get the dictionary value
|
|
*
|
|
* @return DictionaryDataType
|
|
*/
|
|
public function getDictionary(): array
|
|
{
|
|
$items = [];
|
|
|
|
/** @var DictionaryItem $element */
|
|
foreach ($this->ensureAssembled()->getElements() as $element) {
|
|
if ($element instanceof DictionaryItem) {
|
|
$item = $element->ensureAssembled()->getItem();
|
|
if (isset($item['name']) && array_key_exists('value', $item)) {
|
|
$items[$item['name']] = $item['value'];
|
|
}
|
|
}
|
|
}
|
|
|
|
return $items;
|
|
}
|
|
}
|