["?iterable", null, "source des éléments à afficher"], "filter_func" => ["?callable", null, "fonction permettant de filtrer les éléments à afficher"], "map_func" => ["?callable", null, "fonction permettant de mapper les éléments"], "show_empty" => ["bool", false, "afficher même s'il n'y a pas d'éléments?"], "autoprint" => ["bool", false, "faut-il afficher automatiquement les éléments"], "data" => ["?array", null, "donnés supplémentaires utilisées pour l'affichage"], ]; function __construct(?iterable $items=null, ?array $params=null) { self::set_parametrable_params_defaults($params, [ "show_empty" => static::SHOW_EMPTY, "autoprint" => static::AUTOPRINT, ]); A::set_nn($params, "items", $items); [$params, $data] = $this->splitParametrableParams($params); A::merge($params["data"], $data); $this->initParametrableParams($params); if ($this->ppItems === null) $this->ppItems = $this->ITEMS(); if ($this->ppAutoprint) $this->print(); } /** * retourner la liste des éléments à afficher si elle n'est pas fournie par * l'utilisateur */ protected function ITEMS(): ?iterable { return null; } /** @var ?iterable */ protected $ppItems; /** @var array */ protected $filterCtx; function pp_setFilterFunc(?callable $filterFunc): void { if ($filterFunc === null) $this->filterCtx = null; else $this->filterCtx = func::_prepare($filterFunc); } /** @var array */ protected $mapCtx; function pp_setMapFunc(?callable $mapFunc): void { if ($mapFunc === null) $this->mapCtx = null; else $this->mapCtx = func::_prepare($mapFunc); } /** @var bool */ protected $ppShowEmpty; /** @var bool */ protected $ppAutoprint; /** @var Metadata */ private $dataSchema; /** @var mixed données supplémentaires utilisées pour l'affichage */ protected $data; function pp_setData($data): self { $dataSchema = static::DATA_SCHEMA; if ($dataSchema !== null && $this->dataSchema === null) { md_utils::ensure_md($this->dataSchema, $dataSchema); } if ($this->dataSchema !== null) { $this->dataSchema->ensureSchema($data); } $this->data = $data; return $this; } /** @var iterable */ protected $items; /** * construire la liste brute effective des éléments. le filtrage et le mapping * se fait dans print() */ protected function buildItems(): void { $this->items = $this->ppItems; } function haveItems(): bool { if ($this->items === null) { return false; } elseif ($this->items instanceof Traversable) { # on doit forcer l'énumération pour savoir s'il y a des éléments $this->items = iterator_to_array($this->items); } return boolval($this->items); } protected function rewindItems(): bool { return iter::rewind($this->items); } protected function validItem(): bool { return iter::valid($this->items); } protected function currentItem(&$key=null) { return iter::current($this->items, $key); } protected function nextItem(): void { iter::next($this->items); } protected function ensureArray($item): array { if (!is_array($item)) { if ($item instanceof BaseArray) $item = $item->array(); elseif ($item instanceof Iterator) $item = iterator_to_array($item); else throw ValueException::unexpected_type("array", $item); } return $item; } /** @var int index de l'élément courant */ protected $index; /** @var string|int clé de l'élément courant */ protected $key; function print(): void { $this->buildItems(); $filterCtx = $this->filterCtx; $mapCtx = $this->mapCtx; $this->rewindItems(); $this->index = 0; $first = true; while ($this->validItem()) { try { $item = $this->currentItem($this->key); if ($filterCtx !== null) { if (!func::_call($filterCtx, [$item, $this->key])) continue; } if ($mapCtx !== null) $item = func::_call($mapCtx, [$item, $this->key]); else $item = $this->ensureArray($item); if ($first) { $first = false; $this->printStartContainer(); } $this->printItem($item); $this->index++; } finally { $this->nextItem(); } } if ($first && $this->ppShowEmpty) { $first = false; $this->printStartContainer(); } if (!$first) { $this->printEndContainer(); } } function printStartContainer(): void { } function printItem($item): void { } function printEndContainer(): void { } }