["?iterable"], "rows_func" => ["?callable"], "filter" => ["?array"], "filter_func" => ["?callable"], "map" => ["?array"], "map_func" => ["?callable"], "cols" => ["?array"], "cols_func" => ["?callable"], ]; function __construct(?iterable $rows=null, ?array $params=null) { if ($rows !== null) $params["rows"] = $rows; $rows = $params["rows"] ?? null; $rowsGenerator = null; $rowsFunc = $params["rows_func"] ?? null; if ($rowsFunc !== null) { if ($rowsFunc instanceof Traversable) { $rowsGenerator = $rowsFunc; $rowsFunc = null; } else { $rowsFunc = func::with($rowsFunc, [$rows, $this]); } } elseif ($rows instanceof Traversable) { $rowsGenerator = $rows; } else { $rowsFunc = func::with(function() use ($rows) { return $rows; }); } $this->rowsGenerator = $rowsGenerator; $this->rowsFunc = $rowsFunc; $filter = $params["filter"] ?? null; $filterFunc = $params["filter_func"] ?? null; if ($filterFunc !== null) $this->setFilterFunc($filterFunc); elseif ($filter !== null) $this->setFilter($filter); $map = $params["map"] ?? null; $mapFunc = $params["map_func"] ?? null; if ($mapFunc !== null) $this->setMapFunc($mapFunc); elseif ($map !== null) $this->setMap($map); $this->cols = $params["cols"] ?? null; $this->setColsFunc($params["cols_func"] ?? null); } /** un générateur de lignes */ private ?Traversable $rowsGenerator; /** une fonction de signature function(mixed $rows, Cursor): ?iterable */ private ?func $rowsFunc; /** une fonction de signature function(?array $row, Cursor): bool */ private ?func $filterFunc = null; function setFilter(array $filter): self { $this->filterFunc = func::with(function(?array $row) use ($filter) { return cl::filter($row, $filter); }); return $this; } function setFilterFunc(?callable $func): self { if ($func === null) $this->filterFunc = null; else $this->filterFunc = func::with($func)->bind($this); return $this; } /** une fonction de signature function(?array $row, Cursor): ?array */ private ?func $mapFunc = null; function setMap(array $map): self { $this->mapFunc = func::with(function(?array $row) use ($map) { return cl::map($row, $map); }); return $this; } function setMapFunc(?callable $func): self { if ($func === null) $this->mapFunc = null; else $this->mapFunc = func::with($func)->bind($this); return $this; } /** une fonction de signature function(?array $row, Cursor): ?array */ private ?func $colsFunc = null; function setColsFunc(?callable $func): self { $this->cols = null; if ($func === null) $this->colsFunc = null; else $this->colsFunc = func::with($func)->bind($this); return $this; } /** @var iterable|null source des éléments */ protected ?iterable $rows; /** @var array|null listes des colonnes de chaque enregistrement */ public ?array $cols; /** * @var int index de l'enregistrement (en ne comptant pas les éléments filtrés) */ public int $index; /** * @var int index original de l'enregistrement (en tenant compte des éléments * filtrés) */ public int $origIndex; /** @var string|int clé de l'enregistrement */ public $key; /** @var mixed élément original récupéré depuis la source */ public $raw; /** * @var array|null enregistrement après conversion en tableau et application * du mapping */ public ?array $row; function __get($name) { if ($name === "value") return $this->row; elseif ($name == "rows") return $this->rows; trigger_error("Undefined property $name"); return null; } protected function convertToRow($raw): ?array { return cl::withn($raw); } protected function filterFunc(?array $row): bool { return false; } protected function mapFunc(?array $row): ?array { return $this->row; } protected function colsFunc(?array $row): ?array { return $this->row !== null? array_keys($this->row): null; } ############################################################################# # Iterator function rewind() { $this->cols = null; $this->index = 0; $this->origIndex = 0; $this->key = null; $this->raw = null; $this->row = null; if ($this->rowsGenerator !== null) { $rows = $this->rowsGenerator; if ($rows instanceof IteratorAggregate) $rows = $rows->getIterator(); $rows->rewind(); $this->rows = $rows; } else { $this->rows = $this->rowsFunc->invoke(); } } function valid(): bool { $colsFunc = $this->colsFunc; $filterFunc = $this->filterFunc; $mapFunc = $this->mapFunc; while ($valid = iter::valid($this->rows)) { $this->raw = iter::current($this->rows, $this->key); # conversion en enregistrement $this->key ??= $this->origIndex; $this->row = $this->convertToRow($this->raw); # filtrage if ($filterFunc === null) $filtered = $this->filterFunc($this->row); else $filtered = $filterFunc->invoke([$this->row, $this]); if ($filtered) { iter::next($this->rows); $this->origIndex++; } else { # l'enregistrement n'as pas été filtré: faire le mapping if ($mapFunc === null) $this->row = $this->mapFunc($this->row); else $this->row = $mapFunc->invoke([$this->row, $this]); # calculer la liste des colonnes le cas échéant if ($this->cols === null) { if ($colsFunc === null) $this->cols = $this->colsFunc($this->row); else $this->cols = $colsFunc->invoke([$this->row, $this]); } break; } } if (!$valid) { iter::close($this->rows); $this->rows = null; $this->cols = null; $this->index = -1; $this->origIndex = -1; $this->key = null; $this->raw = null; $this->row = null; } return $valid; } function current(): ?array { return $this->row; } function key() { return $this->key; } function next() { iter::next($this->rows); $this->index++; $this->origIndex++; } ############################################################################# function each(callable $func): void { $func = func::with($func); $this->rewind(); while ($this->valid()) { $func->invoke([$this]); $this->next(); } } }