nur-sery/nur_src/b/coll/ArrayViewStack.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--
}