nur-sery/nur_src/v/bs3/vc/_CItemList.php

195 lines
5.1 KiB
PHP
Raw Normal View History

2023-12-03 22:10:18 +04:00
<?php
namespace nur\v\bs3\vc;
use Iterator;
use nur\A;
use nur\b\coll\BaseArray;
use nur\b\params\IParametrable;
use nur\b\params\Tparametrable1;
use nur\b\ValueException;
use nur\data\types\md_utils;
use nur\data\types\Metadata;
use nur\func;
use nur\iter;
use nur\v\base\ComponentPrintable;
use Traversable;
class _CItemList extends ComponentPrintable implements IParametrable {
use Tparametrable1;
/** @var ?array schéma des informations supplémentaires */
const DATA_SCHEMA = null;
const SHOW_EMPTY = null;
const AUTOPRINT = null;
const PARAMETRABLE_PARAMS_SCHEMA = [
"items" => ["?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 {
}
}