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--
|
|
}
|