nur-sery/nur_src/m/base/AbstractRowIterator.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(); }
}