nur-ture/src/php/access/KeyAccess.php

204 lines
5.7 KiB
PHP

<?php
namespace nulib\php\access;
use ArrayAccess;
use nulib\cl;
use nulib\ref\schema\ref_schema;
/**
* Class KeyAccess: accès
* - soit à une valeur d'un chemin de clé dans un tableau (si $key !== null)
* - soit à une valeur scalaire (si $key === null)
*/
class KeyAccess extends AbstractAccess {
const ALLOW_NULL = null;
const ALLOW_FALSE = null;
const PROTECT_DEST = false;
function __construct(&$dest, $key=null, ?array $params=null) {
parent::__construct($params);
$this->protectDest = $params["protect_dest"] ?? static::PROTECT_DEST;
$this->dest =& $dest;
$this->key = $key;
$this->allowNull = $params["allow_null"] ?? static::ALLOW_NULL;
$this->allowFalse = $params["allow_false"] ?? static::ALLOW_FALSE;
}
protected bool $protectDest;
/** @var mixed|array|ArrayAccess */
protected $dest;
/** @var null|int|string|array */
protected $key;
function reset(&$dest, $key=null): self {
$this->dest =& $dest;
$this->key = $key;
return $this;
}
function resetKey($key=null): self {
$this->key = $key;
return $this;
}
protected ?bool $allowNull;
protected function isAllowNull(): bool {
$allowNull = $this->allowNull;
if ($allowNull !== null) return $allowNull;
return $this->key !== null;
}
protected ?bool $allowFalse;
protected function isAllowFalse(): bool {
$allowFalse = $this->allowFalse;
if ($allowFalse !== null) return $allowFalse;
return $this->key === null;
}
function exists(): bool {
$key = $this->key;
if ($key === null) {
return $this->isAllowNull() || $this->dest !== null;
} else {
return cl::phas($this->dest, $key);
}
}
function available(): bool {
if (!$this->exists()) return false;
$key = $this->key;
if ($key === null) $value = $this->dest;
else $value = cl::pget($this->dest, $key);
if ($value === "") return $this->allowEmpty;
if ($value === null) return $this->isAllowNull();
if ($value === false) return $this->isAllowFalse();
return true;
}
function get($default=null) {
$key = $this->key;
if ($key === null) $value = $this->dest;
else $value = cl::pget($this->dest, $key, $default);
if ($value === "" && !$this->allowEmpty) return $default;
if ($value === null && !$this->isAllowNull()) return $default;
if ($value === false && !$this->isAllowFalse()) return $default;
return $value;
}
function set($value): void {
$key = $this->key;
if ($key === null) {
if (!$this->protectDest) $this->dest = $value;
} else {
cl::pset($this->dest, $key, $value);
}
}
function del(): void {
$key = $this->key;
if ($key === null) {
if (!$this->protectDest) $this->dest = null;
} else {
cl::pdel($this->dest, $key);
}
}
function addKey($key): self {
if ($key === null) return $this;
if ($this->key !== null) $key = cl::merge($this->key, $key);
return new KeyAccess($this->dest, $key, [
"allow_empty" => $this->allowEmpty,
"allow_null" => $this->allowNull,
"allow_false" => $this->allowFalse,
"protect_dest" => $this->protectDest,
]);
}
function ensureAssoc(array $keys, ?array $params=null): void {
$dest =& $this->dest;
$prefix = $params["key_prefix"] ?? null;
$suffix = $params["key_suffix"] ?? null;
$index = 0;
foreach ($keys as $key) {
if ($prefix !== null || $suffix !== null) {
$destKey = "$prefix$key$suffix";
} else {
# préserver les clés numériques
$destKey = $key;
}
if ($dest !== null && array_key_exists($destKey, $dest)) continue;
while (in_array($index, $keys, true)) {
$index++;
}
if ($dest !== null && array_key_exists($index, $dest)) {
$dest[$destKey] = $dest[$index];
unset($dest[$index]);
$index++;
}
}
}
function ensureKeys(array $defaults, ?array $missings, ?array $params=null): void {
$dest =& $this->dest;
$keys = array_keys($defaults);
$prefix = $params["key_prefix"] ?? null;
$suffix = $params["key_suffix"] ?? null;
foreach ($keys as $key) {
$destKey = "$prefix$key$suffix";
$haveMissing = $missings !== null && array_key_exists($key, $missings);
if ($dest === null || !array_key_exists($destKey, $dest)) {
$dest[$destKey] = $defaults[$key];
} elseif ($haveMissing && $dest[$destKey] === $missings[$key]) {
$dest[$destKey] = $defaults[$key];
}
}
}
function deleteMissings(array $missings, ?array $params=null): void {
$dest =& $this->dest;
$prefix = $params["key_prefix"] ?? null;
$suffix = $params["key_suffix"] ?? null;
foreach ($missings as $key => $missing) {
$destKey = "$prefix$key$suffix";
if (array_key_exists($destKey, $dest) && $dest[$destKey] === $missing) {
unset($dest[$destKey]);
}
}
}
function ensureOrder(array $keys, ?array $params=null): void {
$dest =& $this->dest;
if ($dest === null) return;
$prefix = $params["key_prefix"] ?? null;
$suffix = $params["key_suffix"] ?? null;
if ($prefix !== null || $suffix !== null) {
foreach ($keys as &$key) {
$key = "$prefix$key$suffix";
}; unset($key);
}
$destKeys = array_keys($dest);
$keyCount = count($keys);
if (array_slice($destKeys, 0, $keyCount) === $keys) {
# si le tableau a déjà les bonnes clés dans le bon ordre, rien à faire
return;
}
$ordered = [];
foreach ($keys as $key) {
if (array_key_exists($key, $dest)) {
$ordered[$key] = $dest[$key];
unset($dest[$key]);
}
}
$preserveKeys = $params["preserve_keys"] ?? false;
if ($preserveKeys) $dest = cl::merge2($ordered, $dest);
else $dest = array_merge($ordered, $dest);
}
}