184 lines
5.0 KiB
PHP
184 lines
5.0 KiB
PHP
<?php
|
|
namespace nur\sery\wip\php\access;
|
|
|
|
use nulib\StateException;
|
|
use nulib\str;
|
|
use ReflectionClass;
|
|
use ReflectionException;
|
|
use ReflectionNamedType;
|
|
use ReflectionProperty;
|
|
use stdClass;
|
|
|
|
class PropertyAccess extends AbstractAccess {
|
|
const PROTECT_DEST = true;
|
|
const MAP_NAMES = true;
|
|
const ALLOW_NULL = true;
|
|
const ALLOW_FALSE = false;
|
|
|
|
function __construct(?object $dest, ?string $name=null, ?array $params=null) {
|
|
parent::__construct($params);
|
|
$this->protectDest = $params["protect_dest"] ?? static::PROTECT_DEST;
|
|
$this->mapNames = $params["map_names"] ?? static::MAP_NAMES;
|
|
$this->_setName($name);
|
|
$this->_setDest($dest);
|
|
$this->allowNull = $params["allow_null"] ?? static::ALLOW_NULL;
|
|
$this->allowFalse = $params["allow_false"] ?? static::ALLOW_FALSE;
|
|
}
|
|
|
|
protected bool $protectDest;
|
|
|
|
protected ?object $dest;
|
|
protected bool $mapNames;
|
|
|
|
protected ?string $name;
|
|
|
|
protected ?ReflectionProperty $property;
|
|
|
|
private function _getName(string $key): string {
|
|
return $this->mapNames? str::us2camel($key): $key;
|
|
}
|
|
private function _setName(?string $name): void {
|
|
if ($name !== null) $name = $this->_getName($name);
|
|
$this->name = $name;
|
|
}
|
|
|
|
private function _getProperty(?string $name, ?ReflectionClass $class, ?object $object=null): ?ReflectionProperty {
|
|
$property = null;
|
|
if ($class === null && $object !== null) {
|
|
$class = new ReflectionClass($object);
|
|
}
|
|
if ($class !== null && $name !== null) {
|
|
try {
|
|
$property = $class->getProperty($name);
|
|
$property->setAccessible(true);
|
|
} catch (ReflectionException $e) {
|
|
}
|
|
}
|
|
return $property;
|
|
}
|
|
|
|
private function _setDest(?object $dest): void {
|
|
$this->dest = $dest;
|
|
$this->property = $this->_getProperty($this->name, null, $dest);
|
|
}
|
|
|
|
function reset(?object $dest, ?string $name=null): self {
|
|
$this->_setName($name);
|
|
$this->_setDest($dest);
|
|
return $this;
|
|
}
|
|
|
|
function resetKey($name=null): self {
|
|
$this->_setName($name);
|
|
return $this;
|
|
}
|
|
|
|
protected bool $allowNull;
|
|
|
|
protected bool $allowFalse;
|
|
|
|
function exists(): bool {
|
|
$name = $this->name;
|
|
if ($this->dest === null) return false;
|
|
return $name === null
|
|
|| $this->property !== null
|
|
|| property_exists($this->dest, $name);
|
|
}
|
|
|
|
protected function _get($default=null) {
|
|
$name = $this->name;
|
|
$property = $this->property;
|
|
if ($this->dest === null) {
|
|
return $default;
|
|
} elseif ($name === null) {
|
|
return $this->dest;
|
|
} elseif ($property !== null) {
|
|
return $property->getValue($this->dest);
|
|
} elseif (property_exists($this->dest, $name)) {
|
|
return $this->dest->$name;
|
|
} else {
|
|
return $default;
|
|
}
|
|
}
|
|
|
|
function available(): bool {
|
|
if (!$this->exists()) return false;
|
|
$value = $this->_get();
|
|
if ($value === "") return $this->allowEmpty;
|
|
if ($value === null) return $this->allowNull;
|
|
if ($value === false) return $this->allowFalse;
|
|
return true;
|
|
}
|
|
|
|
function get($default=null) {
|
|
if (!$this->exists()) return $default;
|
|
$value = $this->_get();
|
|
if ($value === "" && !$this->allowEmpty) return $default;
|
|
if ($value === null && !$this->allowNull) return $default;
|
|
if ($value === false && !$this->allowFalse) return $default;
|
|
return $value;
|
|
}
|
|
|
|
protected function _set($value): void {
|
|
$name = $this->name;
|
|
$property = $this->property;
|
|
if ($this->dest === null) {
|
|
throw StateException::unexpected_state("dest is null");
|
|
} elseif ($name === null) {
|
|
if (!$this->protectDest) $this->_setDest($value);
|
|
} elseif ($property !== null) {
|
|
$property->setValue($this->dest, $value);
|
|
} else {
|
|
$this->dest->$name = $value;
|
|
}
|
|
}
|
|
|
|
function set($value): void {
|
|
$this->_set($value);
|
|
}
|
|
|
|
function del(): void {
|
|
$this->_set(null);
|
|
}
|
|
|
|
function addKey($key): IAccess {
|
|
if ($key === null) return $this;
|
|
return new ChainAccess($this, $key);
|
|
}
|
|
|
|
function ensureAssoc(array $keys, ?array $params=null): void {
|
|
# NOP
|
|
}
|
|
|
|
function ensureKeys(array $defaults, ?array $params=null): void {
|
|
$dest = $this->dest;
|
|
if ($dest === null) {
|
|
# comme ne connait pas la classe de l'objet destination, on n'essaie pas
|
|
# de le créer
|
|
return;
|
|
}
|
|
$class = new ReflectionClass($dest);
|
|
$keys = array_keys($defaults);
|
|
$prefix = $params["key_prefix"] ?? null;
|
|
$suffix = $params["key_suffix"] ?? null;
|
|
foreach ($keys as $key) {
|
|
$name = $this->_getName("$prefix$key$suffix");
|
|
$property = $this->_getProperty($name, $class);
|
|
if ($property !== null) {
|
|
$type = $property->getType();
|
|
if ($type !== null && !$property->isInitialized($dest) && $type->allowsNull()) {
|
|
# initialiser avec null au lieu de $defaults[$key] pour respecter le
|
|
# type de la propriété
|
|
$property->setValue($dest, null);
|
|
}
|
|
} elseif (!property_exists($dest, $name)) {
|
|
$dest->$name = $defaults[$key];
|
|
}
|
|
}
|
|
}
|
|
|
|
function ensureOrder(array $keys, ?array $params=null): void {
|
|
# NOP
|
|
}
|
|
}
|