<?php namespace nur\m\base; use nur\b\coll\BaseArray; use nur\iter; use nur\m\IRowIterator; abstract class AbstractRowIterator extends BaseArray implements IRowIterator { /** * @var bool faut-il réinitialiser l'itérateur après l'appel des méthodes * {@link first()} et {@link one()} */ const AUTO_REWIND = true; private $setup = false; private $valid = false; private $toredown = true; private $index = -1; private $key = null; private $row = null; function __construct() { # ne pas appeler le constructeur parent, $data sera initialisé dans les # classes dérivées #parent::__construct(null); } /** initialiser cet objet et les resources dont il a besoin */ protected function _setup(): void {} /** * retourner l'élément suivant, ou false s'il n'y a plus d'éléments * disponibles */ abstract protected function _next(); /** * corriger le cas échéant un élément avant de le présenter à l'utilisateur. * si $key est initialisé, alors cette valeur sera retournée en tant que clé * à l'utilisateur */ protected function _cook(&$row, &$key): void {} /** retourner la clé associée à l'élément courant */ function _key() { $key = $this->key; return $key !== null? $key: $this->index; } /** retourner l'élément courant */ function _current() { return $this->row; } /** fermer toutes les resources utilisées par cet objet */ protected function _teardown(): void {} /** * méthode appelée avant l'initialisation de l'objet par {@link _setup()}. * * Cette méthode est prévue pour être surchargée par l'utilisateur */ protected function beforeSetup(): void {} /** * méthode appelée avant le début de l'itération: après l'initialisation de * l'objet par {@link _setup()} mais avant que le premier élément soit * retourné par {@link _next()}. * * Cette méthode est prévue pour être surchargée par l'utilisateur */ protected function beforeIter(): void {} /** * méthode appelée pour corriger le cas échéant les lignes retournées. * * Cette méthode est prévue pour être surchargée par l'utilisateur */ protected function cook(&$row, &$key): void {} function rewind() { if ($this->setup) { if (!$this->toredown) $this->_teardown(); $this->setup = false; $this->valid = false; $this->toredown = true; $this->index = -1; $this->key = null; $this->row = null; } } function next() { if ($this->toredown) return; $key = null; $row = $this->_next(); if ($row !== false) { $this->key = null; $this->_cook($row, $key); $this->cook($row, $key); $this->index++; $this->key = $key; $this->row = $row; $this->valid = true; } else { $this->_teardown(); $this->valid = false; $this->toredown = true; } } function valid() { if (!$this->setup) { $this->beforeSetup(); $this->_setup(); $this->setup = true; $this->toredown = false; $this->beforeIter(); $this->next(); } return $this->valid; } function isClosed(): bool { return $this->toredown; } function all(): array { return iterator_to_array($this, true); } function allVals(?string $name=null): array { return rows::vals($this->all(), $name); } function first($default=null) { return iter::first($this, $default); } function firstVal(?string $name=null, $default=null) { return rows::val($this->first(), $name, $default); } function numRows(): int { return $this->first()["num_rows"]; } function insertId(): int { return $this->first()["insert_id"]; } function one($default=null, ?bool $rewind=null): array { if ($rewind === null) $rewind = static::AUTO_REWIND; return iter::one($this, $default, $rewind); } function peek($default=null, ?bool $rewind=false): array { if ($rewind === null) $rewind = static::AUTO_REWIND; return iter::peek($this, $default, $rewind); } # BaseArray function has($key): bool { return $this->_has($key); } function &get($key, $default=null) { return $this->_get($key, $default); } function set($key, $value): self { return $this->_set($key, $value); } function add($value): self { return $this->_set(null, $value); } function del($key): self { return $this->_del($key); } # Modèle d'implémentation dans une classe dérivée: ## Iterator #function key(): KeyType { return $this->_key(); } #function current(): ?ValueType { return $this->_current(); } # Par exemple, pour un iterateur générique, on aurait: ## Iterator #function key() { return $this->_key(); } #function current() { return $this->_current(); } }