2023-12-03 22:10:18 +04:00
|
|
|
<?php
|
|
|
|
namespace nur\v\bs3\fo;
|
|
|
|
|
|
|
|
use nur\A;
|
|
|
|
use nur\b\params\Tparametrable;
|
2024-05-27 18:11:17 +04:00
|
|
|
use nur\b\values\Breaker;
|
2023-12-03 22:10:18 +04:00
|
|
|
use nur\base;
|
|
|
|
use nur\func;
|
|
|
|
use nur\v\v;
|
|
|
|
|
|
|
|
class ControlSelect extends ControlVisual {
|
|
|
|
use Tparametrable;
|
|
|
|
|
|
|
|
const PARAMETRABLE_PARAMS_SCHEMA = [
|
|
|
|
"label" => ["?content", null, "libellé du champ"],
|
|
|
|
"items" => ["?iterable", null, "liste d'éléments à afficher"],
|
|
|
|
"items_func" => ["?callable", null, "fonction fournissant une liste d'éléments à afficher"],
|
|
|
|
"item_value_key" => ["?key", null, "clé de la valeur d'un élément"],
|
2024-05-30 07:00:59 +04:00
|
|
|
"item_value_pkey" => ["?key", null, "chemin de clé de la valeur d'un élément"],
|
2024-05-27 18:11:17 +04:00
|
|
|
"item_value_func" => ["?callable", null, "fonction fournissant la valeur d'un élément"],
|
2023-12-03 22:10:18 +04:00
|
|
|
"item_text_key" => ["?key", null, "clé du libellé d'un élément"],
|
2024-05-30 07:00:59 +04:00
|
|
|
"item_text_pkey" => ["?key", null, "chemin de clé du libellé d'un élément"],
|
2024-05-27 18:11:17 +04:00
|
|
|
"item_text_func" => ["?callable", null, "fonction fournissant le libellé d'un élément"],
|
2023-12-03 22:10:18 +04:00
|
|
|
"no_item_value" => ["?string", null, "valeur si aucun élément n'est sélectionné"],
|
|
|
|
"no_item_text" => ["?content", null, "libellé si aucun élément n'est sélectionné"],
|
2024-05-27 18:11:17 +04:00
|
|
|
"group_key" => ["?key", null, "clé d'une valeur sur laquelle grouper les éléments"],
|
2024-05-30 07:00:59 +04:00
|
|
|
"group_pkey" => ["?key", null, "chemin de clé d'une valeur sur laquelle grouper les éléments"],
|
2024-05-27 18:11:17 +04:00
|
|
|
"group_func" => ["?callable", null, "fonction fournissant une valeur sur laquelle grouper les éléments"],
|
2023-12-03 22:10:18 +04:00
|
|
|
"required" => ["?bool", null, "ce champ est-il requis?"],
|
|
|
|
"show_required" => ["?bool", null, "faut-il afficher la marque de champ requis?"],
|
|
|
|
"option_prefix" => ["?content", "\n", "contenu à afficher avant chaque option"],
|
|
|
|
"option_suffix" => ["?content", null, "contenu à afficher après chaque option"],
|
|
|
|
];
|
|
|
|
|
|
|
|
function __construct(Form $form, ?array $params=null) {
|
|
|
|
parent::__construct($form, $params);
|
|
|
|
base::update_n($this->ppShowRequired, $this->ppRequired);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @var array|string */
|
|
|
|
protected $ppLabel;
|
|
|
|
|
|
|
|
/** @var ?iterable */
|
|
|
|
protected $ppItems;
|
|
|
|
|
|
|
|
/** @var ?callable */
|
|
|
|
protected $ppItemsFunc;
|
|
|
|
|
|
|
|
/** @var string|int|null */
|
|
|
|
protected $ppItemValueKey;
|
|
|
|
|
2024-05-30 07:00:59 +04:00
|
|
|
/** @var string|int|null */
|
|
|
|
protected $ppItemValuePkey;
|
|
|
|
|
2023-12-03 22:10:18 +04:00
|
|
|
/** @var ?callable */
|
|
|
|
protected $ppItemValueFunc;
|
|
|
|
|
|
|
|
/** @var string|int|null */
|
|
|
|
protected $ppItemTextKey;
|
|
|
|
|
2024-05-30 07:00:59 +04:00
|
|
|
/** @var string|int|null */
|
|
|
|
protected $ppItemTextPkey;
|
|
|
|
|
2023-12-03 22:10:18 +04:00
|
|
|
/** @var ?callable */
|
|
|
|
protected $ppItemTextFunc;
|
|
|
|
|
|
|
|
/** @var ?string */
|
|
|
|
protected $ppNoItemValue;
|
|
|
|
|
|
|
|
/** @var array|string */
|
|
|
|
protected $ppNoItemText;
|
|
|
|
|
2024-05-27 18:11:17 +04:00
|
|
|
/** @var string|int|null */
|
|
|
|
protected $ppGroupKey;
|
|
|
|
|
2024-05-30 07:00:59 +04:00
|
|
|
/** @var string|int|null */
|
|
|
|
protected $ppGroupPkey;
|
|
|
|
|
2024-05-27 18:11:17 +04:00
|
|
|
/** @var ?callable */
|
|
|
|
protected $ppGroupFunc;
|
|
|
|
|
2023-12-03 22:10:18 +04:00
|
|
|
/** @var ?bool */
|
|
|
|
protected $ppRequired;
|
|
|
|
|
|
|
|
/** @var ?bool */
|
|
|
|
protected $ppShowRequired;
|
|
|
|
|
|
|
|
/** @var array|string */
|
|
|
|
protected $ppOptionPrefix;
|
|
|
|
|
|
|
|
/** @var array|string */
|
|
|
|
protected $ppOptionSuffix;
|
|
|
|
|
|
|
|
protected function vof(
|
|
|
|
$value, ?callable $func,
|
2024-05-30 07:00:59 +04:00
|
|
|
$item=null, $itemKey=null, $itemPkey = null, ?int $itemIndex=null,
|
2023-12-03 22:10:18 +04:00
|
|
|
...$funcArgs) {
|
|
|
|
if ($value !== null) return $value;
|
|
|
|
if ($func !== null) {
|
|
|
|
func::ensure_func($func, $this, $funcArgs);
|
|
|
|
$value = func::call($func, ...$funcArgs);
|
|
|
|
if ($value !== null) return $value;
|
|
|
|
}
|
|
|
|
if (A::is_array($item)) {
|
|
|
|
$item = A::with($item);
|
|
|
|
if ($itemKey !== null) {
|
|
|
|
$value = A::get($item, $itemKey);
|
|
|
|
if ($value !== null) return $value;
|
|
|
|
}
|
2024-05-30 07:00:59 +04:00
|
|
|
if ($itemPkey !== null) {
|
|
|
|
$value = A::pget($item, $itemPkey);
|
|
|
|
if ($value !== null) return $value;
|
|
|
|
}
|
2023-12-03 22:10:18 +04:00
|
|
|
if ($itemIndex !== null) {
|
2024-05-30 07:00:59 +04:00
|
|
|
$itemKeys = array_keys($item);
|
|
|
|
return $item[$itemKeys[$itemIndex]] ?? null;
|
2023-12-03 22:10:18 +04:00
|
|
|
}
|
2024-05-30 22:14:34 +04:00
|
|
|
return "(unknown)";
|
2023-12-03 22:10:18 +04:00
|
|
|
}
|
2024-05-30 22:14:34 +04:00
|
|
|
return $item;
|
2023-12-03 22:10:18 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
function getControl(): array {
|
|
|
|
$name = $this->ppName;
|
|
|
|
$value = $this->ppValue;
|
|
|
|
$items = $this->vof($this->ppItems, $this->ppItemsFunc);
|
|
|
|
$noItemValue = $this->ppNoItemValue;
|
|
|
|
$noItemText = $this->ppNoItemText;
|
|
|
|
|
|
|
|
$options = [];
|
|
|
|
if ($noItemValue !== null) {
|
|
|
|
$options[] = [
|
|
|
|
"value" => $noItemValue,
|
|
|
|
"text" => $noItemText,
|
|
|
|
"selected" => $value == $noItemValue,
|
|
|
|
];
|
|
|
|
}
|
2024-05-27 18:11:17 +04:00
|
|
|
$haveGroups = $this->ppGroupKey !== null || $this->ppGroupFunc !== null;
|
2023-12-03 22:10:18 +04:00
|
|
|
foreach ($items as $key => $item) {
|
2024-05-30 07:00:59 +04:00
|
|
|
$itemValue = $this->vof(null, $this->ppItemValueFunc, $item, $this->ppItemValueKey, $this->ppItemValuePkey, 0, $item, $key);
|
|
|
|
$itemText = $this->vof(null, $this->ppItemTextFunc, $item, $this->ppItemTextKey, $this->ppItemTextPkey, 1, $item, $key);
|
2024-05-27 18:11:17 +04:00
|
|
|
$itemGroup = null;
|
|
|
|
if ($haveGroups) {
|
2024-05-30 07:00:59 +04:00
|
|
|
$itemGroup = $this->vof(null, $this->ppGroupFunc, $item, $this->ppGroupKey, $this->ppGroupPkey, null, $item, $key);
|
2024-05-27 18:11:17 +04:00
|
|
|
}
|
2023-12-03 22:10:18 +04:00
|
|
|
if (!$itemText) $itemText = $itemValue;
|
|
|
|
$options[] = array(
|
|
|
|
"value" => $itemValue,
|
|
|
|
"text" => $itemText,
|
|
|
|
"selected" => $value == $itemValue,
|
2024-05-27 18:11:17 +04:00
|
|
|
"group" => $itemGroup,
|
2023-12-03 22:10:18 +04:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
$control = [];
|
|
|
|
$control[] = v::start("select", [
|
|
|
|
"id" => $this->ppId,
|
|
|
|
"name" => $name,
|
|
|
|
"value" => $value,
|
|
|
|
"readonly" => $this->ppReadonly? "readonly": false,
|
|
|
|
"disabled" => $this->ppDisabled? "disabled": false,
|
|
|
|
"required" => $this->ppRequired? "required": false,
|
|
|
|
"class" => ["form-control", $this->ppClass],
|
|
|
|
"style" => $this->ppStyle,
|
|
|
|
$this->ppAttrs,
|
|
|
|
]);
|
2024-05-27 18:11:17 +04:00
|
|
|
$breaker = new Breaker();
|
|
|
|
$firstGroup = true;
|
2023-12-03 22:10:18 +04:00
|
|
|
foreach ($options as $option) {
|
2024-05-27 18:11:17 +04:00
|
|
|
if ($haveGroups && $breaker->shouldBreakOn($option["group"])) {
|
|
|
|
if ($firstGroup) $firstGroup = false;
|
|
|
|
else $control[] = v::end("optgroup");
|
|
|
|
$control[] = v::start("optgroup", ["label" => $option["group"]]);
|
|
|
|
}
|
2023-12-03 22:10:18 +04:00
|
|
|
$control[] = $this->ppOptionPrefix;
|
|
|
|
$control[] = v::tag("option", [
|
|
|
|
"value" => $option["value"],
|
|
|
|
"selected" => $option["selected"]? "selected": false,
|
|
|
|
q($option["text"]),
|
|
|
|
]);
|
|
|
|
$control[] = $this->ppOptionSuffix;
|
|
|
|
}
|
2024-05-27 18:11:17 +04:00
|
|
|
if (!$firstGroup) {
|
|
|
|
$control[] = v::end("optgroup");
|
|
|
|
}
|
2023-12-03 22:10:18 +04:00
|
|
|
$control[] = v::end("select");
|
|
|
|
if ($this->ppNaked) return $control;
|
|
|
|
|
|
|
|
$label = $this->ppLabel;
|
|
|
|
if ($label && $this->ppRequired && $this->ppShowRequired) {
|
|
|
|
$label = [q($label), " <sup class=\"required\" title=\"required\">(*)</sup>"];
|
|
|
|
} else {
|
|
|
|
$label = q($label);
|
|
|
|
}
|
|
|
|
|
|
|
|
[$fgClass, $feedback] = $this->getStdFeedback($name, $value);
|
|
|
|
return $this->getFglcLayout($label, true, $control, $fgClass, $feedback);
|
|
|
|
}
|
|
|
|
}
|