178 lines
4.7 KiB
PHP
178 lines
4.7 KiB
PHP
|
<?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(); }
|
||
|
}
|