203 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			203 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| namespace nulib\php\access;
 | |
| 
 | |
| use ArrayAccess;
 | |
| use nulib\cl;
 | |
| 
 | |
| /**
 | |
|  * 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);
 | |
|   }
 | |
| }
 |