206 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			206 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| namespace nur\v\bs3\fo;
 | |
| 
 | |
| use nur\A;
 | |
| use nur\b\params\Tparametrable;
 | |
| use nur\b\values\Breaker;
 | |
| 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"],
 | |
|     "item_value_pkey" => ["?key", null, "chemin de clé de la valeur d'un élément"],
 | |
|     "item_value_func" => ["?callable", null, "fonction fournissant la valeur d'un élément"],
 | |
|     "item_text_key" => ["?key", null, "clé du libellé d'un élément"],
 | |
|     "item_text_pkey" => ["?key", null, "chemin de clé du libellé d'un élément"],
 | |
|     "item_text_func" => ["?callable", null, "fonction fournissant le libellé d'un élément"],
 | |
|     "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é"],
 | |
|     "group_key" => ["?key", null, "clé d'une valeur sur laquelle grouper les éléments"],
 | |
|     "group_pkey" => ["?key", null, "chemin de clé d'une valeur sur laquelle grouper les éléments"],
 | |
|     "group_func" => ["?callable", null, "fonction fournissant une valeur sur laquelle grouper les éléments"],
 | |
|     "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;
 | |
| 
 | |
|   /** @var string|int|null */
 | |
|   protected $ppItemValuePkey;
 | |
| 
 | |
|   /** @var ?callable */
 | |
|   protected $ppItemValueFunc;
 | |
| 
 | |
|   /** @var string|int|null */
 | |
|   protected $ppItemTextKey;
 | |
| 
 | |
|   /** @var string|int|null */
 | |
|   protected $ppItemTextPkey;
 | |
| 
 | |
|   /** @var ?callable */
 | |
|   protected $ppItemTextFunc;
 | |
| 
 | |
|   /** @var ?string */
 | |
|   protected $ppNoItemValue;
 | |
| 
 | |
|   /** @var array|string */
 | |
|   protected $ppNoItemText;
 | |
| 
 | |
|   /** @var string|int|null */
 | |
|   protected $ppGroupKey;
 | |
| 
 | |
|   /** @var string|int|null */
 | |
|   protected $ppGroupPkey;
 | |
| 
 | |
|   /** @var ?callable */
 | |
|   protected $ppGroupFunc;
 | |
| 
 | |
|   /** @var ?bool */
 | |
|   protected $ppRequired;
 | |
| 
 | |
|   /** @var ?bool */
 | |
|   protected $ppShowRequired;
 | |
| 
 | |
|   /** @var array|string */
 | |
|   protected $ppOptionPrefix;
 | |
| 
 | |
|   /** @var array|string */
 | |
|   protected $ppOptionSuffix;
 | |
| 
 | |
|   protected function vof(
 | |
|     $value, ?callable $func,
 | |
|     $item=null, $itemKey=null, $itemPkey = null, ?int $itemIndex=null,
 | |
|     ...$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;
 | |
|       }
 | |
|       if ($itemPkey !== null) {
 | |
|         $value = A::pget($item, $itemPkey);
 | |
|         if ($value !== null) return $value;
 | |
|       }
 | |
|       if ($itemIndex !== null) {
 | |
|         $itemKeys = array_keys($item);
 | |
|         return $item[$itemKeys[$itemIndex]] ?? null;
 | |
|       }
 | |
|       return "(unknown)";
 | |
|     }
 | |
|     return $item;
 | |
|   }
 | |
| 
 | |
|   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,
 | |
|         "group" => false,
 | |
|       ];
 | |
|     }
 | |
|     $haveGroups = $this->ppGroupKey !== null || $this->ppGroupFunc !== null;
 | |
|     foreach ($items as $key => $item) {
 | |
|       $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);
 | |
|       $itemGroup = null;
 | |
|       if ($haveGroups) {
 | |
|         $itemGroup = $this->vof(null, $this->ppGroupFunc, $item, $this->ppGroupKey, $this->ppGroupPkey, null, $item, $key);
 | |
|       }
 | |
|       if (!$itemText) $itemText = $itemValue;
 | |
|       $options[] = array(
 | |
|         "value" => $itemValue,
 | |
|         "text" => $itemText,
 | |
|         "selected" => $value == $itemValue,
 | |
|         "group" => $itemGroup,
 | |
|       );
 | |
|     }
 | |
| 
 | |
|     $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,
 | |
|     ]);
 | |
|     $breaker = new Breaker();
 | |
|     $firstGroup = true;
 | |
|     foreach ($options as $option) {
 | |
|       $group = $option["group"];
 | |
|       if ($haveGroups && $group !== false && $breaker->shouldBreakOn($group)) {
 | |
|         if ($firstGroup) $firstGroup = false;
 | |
|         else $control[] = v::end("optgroup");
 | |
|         $control[] = v::start("optgroup", ["label" => $group]);
 | |
|       }
 | |
|       $control[] = $this->ppOptionPrefix;
 | |
|       $control[] = v::tag("option", [
 | |
|         "value" => $option["value"],
 | |
|         "selected" => $option["selected"]? "selected": false,
 | |
|         q($option["text"]),
 | |
|       ]);
 | |
|       $control[] = $this->ppOptionSuffix;
 | |
|     }
 | |
|     if (!$firstGroup) {
 | |
|       $control[] = v::end("optgroup");
 | |
|     }
 | |
|     $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);
 | |
|     }
 | |
| 
 | |
|     if ($name !== null) {
 | |
|       [$fgClass, $feedback] = $this->getStdFeedback($name, $value);
 | |
|     } else {
 | |
|       $fgClass = $feedback = null;
 | |
|     }
 | |
|     return $this->getFglcLayout($label, true, $control, $fgClass, $feedback);
 | |
|   }
 | |
| }
 |