128 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			128 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| namespace nur\b\coll;
 | |
| 
 | |
| use nur\A;
 | |
| use nur\b\ValueException;
 | |
| use nur\data\types\Metadata;
 | |
| 
 | |
| /**
 | |
|  * Class ArrayViewStack: une vue vers un ensemble de tableaux organisés en pile.
 | |
|  * seul le tableau sur la pile du haut est modifiable.
 | |
|  */
 | |
| class ArrayViewStack implements IArray {
 | |
|   use TBaseArray, TGenericArray, TArrayMdBasic, TAutomethods;
 | |
| 
 | |
|   const _AUTO_GETTERS = null;
 | |
|   const _AUTO_SETTERS = null;
 | |
|   const _AUTO_DELETERS = null;
 | |
|   const _AUTO_CI_GETTERS = null;
 | |
|   const _AUTO_CI_SETTERS = null;
 | |
|   const _AUTOGEN_LITERALS = null;
 | |
|   const _AUTOGEN_METHODS = null;
 | |
| 
 | |
|   /** @var array schéma des données de cette vue */
 | |
|   const SCHEMA = null;
 | |
| 
 | |
|   function __construct(&$source=null, $pkeys=null) {
 | |
|     if ($source !== null) $this->push($source, $pkeys);
 | |
|   }
 | |
| 
 | |
|   protected $stack = [];
 | |
| 
 | |
|   function stackDepth(): int {
 | |
|     return count($this->stack);
 | |
|   }
 | |
| 
 | |
|   function &root(): array {
 | |
|     return $this->stack;
 | |
|   }
 | |
| 
 | |
|   function push(&$source, $pkeys=null): self {
 | |
|     if ($source === null) $source = [];
 | |
|     if (is_array($source)) $root =& $source;
 | |
|     elseif ($source instanceof IArray) $root =& $source->array();
 | |
|     else throw ValueException::unexpected_type(["array", IArray::class], $source);
 | |
|     if ($pkeys === "" || $pkeys === null) $pkeys = [];
 | |
|     if (is_string($pkeys)) $pkeys = explode(".", $pkeys);
 | |
|     if (!is_array($pkeys)) throw ValueException::unexpected_type(["array", "string"], $pkeys);
 | |
| 
 | |
|     $data =& $root;
 | |
|     foreach ($pkeys as $pkey) {
 | |
|       if (!is_array($data)) $data = [$data];
 | |
|       elseif (!array_key_exists($pkey, $data)) $data[$pkey] = null;
 | |
|       $data =& $data[$pkey];
 | |
|     }
 | |
|     $key = A::last($pkeys);
 | |
|     $md = $this->md();
 | |
|     if ($md !== null) $md->ensureSchema($data, $key);
 | |
| 
 | |
|     array_unshift($this->stack, null);
 | |
|     $this->stack[0] =& $data;
 | |
|     return $this;
 | |
|   }
 | |
| 
 | |
|   function &pop(): array {
 | |
|     $data =& $this->stack[0];
 | |
|     array_shift($this->stack);
 | |
|     return $data;
 | |
|   }
 | |
| 
 | |
|   function &peek(int $index=1): array {
 | |
|     $count = count($this->stack);
 | |
|     if ($count > 0) {
 | |
|       while ($index < 0) $index += $count;
 | |
|     }
 | |
|     return $this->stack[$index];
 | |
|   }
 | |
| 
 | |
|   function __toString(): string { return var_export($this->stack, true); }
 | |
|   function &array(): ?array { return $this->stack[0]; }
 | |
|   function keys(): array {
 | |
|     $keys = [];
 | |
|     foreach ($this->stack as $data) {
 | |
|       $dataKeys = array_fill_keys(array_keys($data), true);
 | |
|       A::merge2($keys, $dataKeys);
 | |
|     }
 | |
|     return array_keys($keys);
 | |
|   }
 | |
|   function count(): int { return count($this->keys()); }
 | |
| 
 | |
|   function _has($key): bool {
 | |
|     foreach ($this->stack as $data) {
 | |
|       if (array_key_exists($key, $data)) return true;
 | |
|     }
 | |
|     return false;
 | |
|   }
 | |
|   function &_get($key, $default=null) {
 | |
|     foreach ($this->stack as $data) {
 | |
|       if (array_key_exists($key, $data)) return $data[$key];
 | |
|     }
 | |
|     return $default;
 | |
|   }
 | |
|   function _set($key, $value) {
 | |
|     if ($key === null) $this->stack[0][] = $value;
 | |
|     else $this->stack[0][$key] = $value;
 | |
|     return $this;
 | |
|   }
 | |
|   function _del($key) {
 | |
|     unset($this->stack[0][$key]);
 | |
|     return $this;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * retourner le gestionnaire de schéma. le mieux dans les classes dérivées est
 | |
|    * d'utiliser le trait {@link TArrayMd} qui maintient un cache partagé entre
 | |
|    * toutes les instances de la classe.
 | |
|    */
 | |
|   protected function md(): ?Metadata {
 | |
|     $schema = static::SCHEMA;
 | |
|     if ($schema === null) return null;
 | |
|     else return new Metadata($schema);
 | |
|   }
 | |
| 
 | |
|   # Rajouter ceci dans les classes dérivées:
 | |
|   #use TArrayMd, TAutoconstsStatic; // ou TArrayMdDynamic, TAutoconstsDynamic
 | |
|   #const _AUTOGEN_CONSTS = ["" => [self::class, "_AUTOGEN_CONSTS"]];
 | |
|   ##--autogen-dynamic--
 | |
| }
 |