195 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			195 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?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 {
 | |
|   }
 | |
| }
 |