204 lines
5.7 KiB
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);
|
|
}
|
|
}
|