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(); }
 | |
| }
 |