From 1fc4e7637b9686e8f821bd7e58c2db93eb70ae87 Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Wed, 19 Mar 2025 16:10:26 +0400 Subject: [PATCH] modifs.mineures sans commentaires --- src/php/access/AbstractAccess.php | 10 +++ src/php/access/ChainAccess.php | 57 ++++++++++++++ src/php/access/FormAccess.php | 84 +++++++++++++-------- src/php/access/GetAccess.php | 30 ++------ src/php/access/IAccess.php | 3 + src/php/access/IGetter.php | 6 ++ src/php/access/KeyAccess.php | 36 +++++---- src/php/access/PostAccess.php | 30 ++------ src/php/access/ShadowAccess.php | 9 +++ src/php/access/ValueAccess.php | 20 +++-- src/schema/Wrapper.php | 8 +- src/schema/WrapperContext.php | 10 ++- src/schema/_assoc/AssocWrapper.php | 28 +++++-- src/schema/_assoc/AssocWrapperContext.php | 10 ++- src/schema/_scalar/ScalarResult.php | 24 ++++++ src/schema/_scalar/ScalarWrapper.php | 4 +- src/schema/input/ChainInput.php | 5 ++ src/schema/input/IInput.php | 18 +++++ src/schema/input/Input.php | 6 +- tests/wip/schema/_assoc/AssocSchemaTest.php | 13 ++++ 20 files changed, 288 insertions(+), 123 deletions(-) create mode 100644 src/php/access/ChainAccess.php create mode 100644 src/schema/input/ChainInput.php create mode 100644 src/schema/input/IInput.php diff --git a/src/php/access/AbstractAccess.php b/src/php/access/AbstractAccess.php index 21dda22..f162ca5 100644 --- a/src/php/access/AbstractAccess.php +++ b/src/php/access/AbstractAccess.php @@ -8,6 +8,16 @@ use nulib\cl; * de {@link IAccess} */ abstract class AbstractAccess implements IAccess { + function __construct(?array $params=null) { + $this->allowEmpty = $params["allow_empty"] ?? true; + } + + protected bool $allowEmpty; + + function isAllowEmpty(): bool { + return $this->allowEmpty; + } + function inc(): int { $value = (int)$this->get(); $this->set(++$value); diff --git a/src/php/access/ChainAccess.php b/src/php/access/ChainAccess.php new file mode 100644 index 0000000..d08be7f --- /dev/null +++ b/src/php/access/ChainAccess.php @@ -0,0 +1,57 @@ +access = $access; + $this->key = $key; + } + + protected IAccess $access; + + /** @var int|string|array */ + protected $key; + + function isAllowEmpty(): bool { + return $this->access->isAllowEmpty(); + } + + function exists(): bool { + $key = $this->key; + if ($key === null) return false; + if (!$this->access->exists()) return false; + return cl::phas($this->access->get(), $key); + } + + function available(): bool { + $key = $this->key; + if ($key === null) return false; + if (!$this->access->available()) return false; + $array = $this->access->get(); + if (!cl::phas($array, $key)) return false; + return $this->isAllowEmpty() || cl::pget($array, $key) !== ""; + } + + function get($default=null) { + return cl::pget($this->access->get($default), $this->key); + } + + function set($value): void { + $array = $this->access->get(); + cl::pset($array, $this->key, $value); + $this->access->set($array); + } + + function del(): void { + $array = $this->access->get(); + cl::pdel($array, $this->key); + $this->access->set($array); + } + + function addKey($key): IAccess { + return new ChainAccess($this->access, cl::merge($this->key, $key)); + } +} diff --git a/src/php/access/FormAccess.php b/src/php/access/FormAccess.php index 7b3840d..db8d09a 100644 --- a/src/php/access/FormAccess.php +++ b/src/php/access/FormAccess.php @@ -8,66 +8,88 @@ use nulib\cl; */ class FormAccess extends AbstractAccess { function __construct($key, ?array $params=null) { + parent::__construct($params); $this->key = $key; - $this->allowEmpty = $params["allow_empty"] ?? false; } - /** @var int|string */ + /** @var int|string|array */ protected $key; - protected bool $allowEmpty; - - function exists(): bool { + protected function _exists(array $first, ?array $second=null): bool { $key = $this->key; if ($key === null) return false; - return array_key_exists($key, $_POST) || array_key_exists($key, $_GET); + if (cl::phas($first, $key)) return true; + return $second !== null && cl::phas($second, $key); } - public function available(): bool { + function exists(): bool { + return $this->_exists($_POST, $_GET); + } + + protected function _available(array $first, ?array $second=null): bool { $key = $this->key; if ($key === null) return false; - if (array_key_exists($key, $_POST)) { - return $this->allowEmpty || $_POST[$key] !== ""; - } elseif (array_key_exists($key, $_GET)) { - return $this->allowEmpty || $_GET[$key] !== ""; + if (cl::phas($first, $key)) { + return $this->allowEmpty || cl::pget($first, $key) !== ""; + } elseif ($second !== null && cl::phas($second, $key)) { + return $this->allowEmpty || cl::pget($second, $key) !== ""; } else { return false; } } - function get($default=null) { + public function available(): bool { + return $this->_available($_POST, $_GET); + } + + protected function _get($default, array $first, ?array $second=null) { $key = $this->key; if ($key === null) return $default; - if (array_key_exists($key, $_POST)) { - $value = $_POST[$key]; - if ($value === "" && !$this->allowEmpty) return $default; - return $value; - } elseif (array_key_exists($key, $_GET)) { - $value = $_GET[$key]; - if ($value === "" && !$this->allowEmpty) return $default; - return $value; + if (cl::phas($first, $key)) { + $value = cl::pget($first, $key); + if ($value !== "" || $this->allowEmpty) return $value; + } elseif ($second !== null && cl::phas($second, $key)) { + $value = cl::pget($second, $key); + if ($value !== "" || $this->allowEmpty) return $value; + } + return $default; + } + + function get($default=null) { + return $this->_get($default, $_POST, $_GET); + } + + function _set($value, array &$first, ?array &$second=null): void { + $key = $this->key; + if ($key === null) return; + if ($second !== null && !cl::phas($first, $key) && cl::phas($second, $key)) { + cl::pset($second, $key, $value); } else { - return $default; + cl::pset($first, $key, $value); } } function set($value): void { + $this->_set($value, $_POST, $_GET); + } + + function _del(array &$first, ?array &$second=null): void { $key = $this->key; if ($key === null) return; - if (!array_key_exists($key, $_POST) && array_key_exists($key, $_GET)) { - cl::set($_GET, $key, $value); + if ($second !== null && !cl::phas($first, $key) && cl::phas($second, $key)) { + cl::pdel($second, $key); } else { - cl::set($_POST, $key, $value); + cl::pdel($first, $key); } } function del(): void { - $key = $this->key; - if ($key === null) return; - if (!array_key_exists($key, $_POST) && array_key_exists($key, $_GET)) { - cl::del($_GET, $key); - } else { - cl::del($_POST, $key); - } + $this->_del($_POST, $_GET); + } + + function addKey($key): self { + return new static(cl::merge($this->key, $key), [ + "allow_empty" => $this->allowEmpty + ]); } } diff --git a/src/php/access/GetAccess.php b/src/php/access/GetAccess.php index 4b67367..ed42023 100644 --- a/src/php/access/GetAccess.php +++ b/src/php/access/GetAccess.php @@ -8,42 +8,22 @@ use nulib\cl; */ class GetAccess extends FormAccess { function exists(): bool { - $key = $this->key; - if ($key === null) return false; - return array_key_exists($key, $_GET); + return $this->_exists($_GET); } public function available(): bool { - $key = $this->key; - if ($key === null) return false; - if (array_key_exists($key, $_GET)) { - return $this->allowEmpty || $_GET[$key] !== ""; - } else { - return false; - } + return $this->_available($_GET); } function get($default=null) { - $key = $this->key; - if ($key === null) return $default; - if (array_key_exists($key, $_GET)) { - $value = $_GET[$key]; - if ($value === "" && !$this->allowEmpty) return $default; - return $value; - } else { - return $default; - } + return $this->_get($default, $_GET); } function set($value): void { - $key = $this->key; - if ($key === null) return; - cl::set($_GET, $key, $value); + $this->_set($value, $_GET); } function del(): void { - $key = $this->key; - if ($key === null) return; - cl::del($_GET, $key); + $this->_del($_GET); } } diff --git a/src/php/access/IAccess.php b/src/php/access/IAccess.php index 2581c8b..7987c4c 100644 --- a/src/php/access/IAccess.php +++ b/src/php/access/IAccess.php @@ -25,4 +25,7 @@ interface IAccess extends IGetter, ISetter, IDeleter { * tableau si $key===null */ function append($value, $key=null): void; + + /** retourner une instance permettant d'accéder à $value[$key] */ + function addKey($key): IAccess; } diff --git a/src/php/access/IGetter.php b/src/php/access/IGetter.php index d4b1b9c..430d908 100644 --- a/src/php/access/IGetter.php +++ b/src/php/access/IGetter.php @@ -11,6 +11,12 @@ interface IGetter { */ function exists(): bool; + /** + * @return bool true si cet objet autorise les chaines vides. si c'est le cas, + * {@link exists()} et {@link available()} sont fonctionnellement identiques + */ + function isAllowEmpty(): bool; + /** @return bool true si la valeur existe et est utilisable, false sinon */ function available(): bool; diff --git a/src/php/access/KeyAccess.php b/src/php/access/KeyAccess.php index 2421c5a..2f7b4c4 100644 --- a/src/php/access/KeyAccess.php +++ b/src/php/access/KeyAccess.php @@ -9,61 +9,67 @@ use nulib\cl; */ class KeyAccess extends AbstractAccess { function __construct(&$array, $key, ?array $params=null) { + parent::__construct($params); $this->array =& $array; $this->key = $key; $this->allowNull = $params["allow_null"] ?? true; $this->allowFalse = $params["allow_false"] ?? false; - $this->allowEmpty = $params["allow_empty"] ?? true; } /** @var array|ArrayAccess */ protected $array; - function reset(&$array): self { - $this->array =& $array; - return $this; - } - - /** @var int|string */ + /** @var int|string|array */ protected $key; protected bool $allowNull; protected bool $allowFalse; - protected bool $allowEmpty; + function reset(&$array): self { + $this->array =& $array; + return $this; + } function exists(): bool { $key = $this->key; if ($key === null) return false; - return cl::has($this->array, $key); + return cl::phas($this->array, $key); } function available(): bool { if (!$this->exists()) return false; - $value = cl::get($this->array, $this->key); + $value = cl::pget($this->array, $this->key); + if ($value === "") return $this->allowEmpty; if ($value === null) return $this->allowNull; if ($value === false) return $this->allowFalse; - if ($value === "") return $this->allowEmpty; return true; } function get($default=null) { if ($this->key === null) return $default; - $value = cl::get($this->array, $this->key, $default); + $value = cl::pget($this->array, $this->key, $default); + if ($value === "" && !$this->allowEmpty) return $default; if ($value === null && !$this->allowNull) return $default; if ($value === false && !$this->allowFalse) return $default; - if ($value === "" && !$this->allowEmpty) return $default; return $value; } function set($value): void { if ($this->key === null) return; - cl::set($this->array, $this->key, $value); + cl::pset($this->array, $this->key, $value); } function del(): void { if ($this->key === null) return; - cl::del($this->array, $this->key); + cl::pdel($this->array, $this->key); + } + + function addKey($key): self { + return new KeyAccess($this->array, cl::merge($this->key, $key), [ + "allow_empty" => $this->allowEmpty, + "allow_null" => $this->allowNull, + "allow_false" => $this->allowFalse, + ]); } } diff --git a/src/php/access/PostAccess.php b/src/php/access/PostAccess.php index 1756964..e9c7f13 100644 --- a/src/php/access/PostAccess.php +++ b/src/php/access/PostAccess.php @@ -8,42 +8,22 @@ use nulib\cl; */ class PostAccess extends FormAccess { function exists(): bool { - $key = $this->key; - if ($key === null) return false; - return array_key_exists($key, $_POST); + return $this->_exists($_POST); } public function available(): bool { - $key = $this->key; - if ($key === null) return false; - if (array_key_exists($key, $_POST)) { - return $this->allowEmpty || $_POST[$key] !== ""; - } else { - return false; - } + return $this->_available($_POST); } function get($default=null) { - $key = $this->key; - if ($key === null) return $default; - if (array_key_exists($key, $_POST)) { - $value = $_POST[$key]; - if ($value === "" && !$this->allowEmpty) return $default; - return $value; - } else { - return $default; - } + return $this->_get($default, $_POST); } function set($value): void { - $key = $this->key; - if ($key === null) return; - cl::set($_POST, $key, $value); + $this->_set($value, $_POST); } function del(): void { - $key = $this->key; - if ($key === null) return; - cl::del($_POST, $key); + $this->_del($_POST); } } diff --git a/src/php/access/ShadowAccess.php b/src/php/access/ShadowAccess.php index 229bad1..e4f1211 100644 --- a/src/php/access/ShadowAccess.php +++ b/src/php/access/ShadowAccess.php @@ -16,6 +16,7 @@ namespace nur\sery\wip\php\access; */ class ShadowAccess extends AbstractAccess { function __construct(IAccess $reader, IAccess $writer) { + parent::__construct(); $this->reader = $reader; $this->writer = $writer; $this->getter = $reader; @@ -27,6 +28,10 @@ class ShadowAccess extends AbstractAccess { protected IGetter $getter; + public function isAllowEmpty(): bool { + return $this->getter->isAllowEmpty(); + } + function exists(): bool { return $this->getter->exists(); } @@ -48,4 +53,8 @@ class ShadowAccess extends AbstractAccess { $this->writer->del(); $this->getter = $this->reader; } + + function addKey($key): IAccess { + return new ChainAccess($this, $key); + } } diff --git a/src/php/access/ValueAccess.php b/src/php/access/ValueAccess.php index 624092f..3b95431 100644 --- a/src/php/access/ValueAccess.php +++ b/src/php/access/ValueAccess.php @@ -6,25 +6,23 @@ namespace nur\sery\wip\php\access; */ class ValueAccess extends AbstractAccess { function __construct(&$value, ?array $params=null) { + parent::__construct($params); $this->value =& $value; $this->allowNull = $params["allow_null"] ?? false; $this->allowFalse = $params["allow_false"] ?? true; - $this->allowEmpty = $params["allow_empty"] ?? true; } /** @var mixed */ protected $value; - function reset(&$value): self { - $this->value =& $value; - return $this; - } - protected bool $allowNull; protected bool $allowFalse; - protected bool $allowEmpty; + function reset(&$value): self { + $this->value =& $value; + return $this; + } function exists(): bool { return $this->allowNull || $this->value !== null; @@ -53,4 +51,12 @@ class ValueAccess extends AbstractAccess { function del(): void { $this->value = null; } + + function addKey($key): KeyAccess { + return new KeyAccess($this->value, $key, [ + "allow_empty" => $this->allowEmpty, + "allow_null" => $this->allowNull, + "allow_false" => $this->allowFalse, + ]); + } } diff --git a/src/schema/Wrapper.php b/src/schema/Wrapper.php index 43cc54b..7c558e8 100644 --- a/src/schema/Wrapper.php +++ b/src/schema/Wrapper.php @@ -65,20 +65,20 @@ abstract class Wrapper implements ArrayAccess, IteratorAggregate { } /** analyser la valeur */ - abstract static function _analyze(?array $params, WrapperContext $context, Wrapper $wrapper): int; + abstract static function _analyze(WrapperContext $context, Wrapper $wrapper, ?array $params): int; function analyze(?array $params=null): bool { $context = $this->context; $reanalyze = $params["reanalyze"] ?? false; if ($context->analyzed && !$reanalyze) return false; - static::_analyze($params, $context, $this); + static::_analyze($context, $this, $params); $context->analyzed = true; return true; } /** normaliser la valeur */ - abstract static function _normalize(?array $params, WrapperContext $context, Wrapper $wrapper): bool; + abstract static function _normalize(WrapperContext $context, Wrapper $wrapper, ?array $params): bool; function normalize(?array $params=null): bool { $context = $this->context; @@ -89,7 +89,7 @@ abstract class Wrapper implements ArrayAccess, IteratorAggregate { $renormalize = $params["renormalize"] ?? false; if ($renormalize || !$context->normalized) { - $modified = static::_normalize($params, $context, $this); + $modified = static::_normalize($context, $this, $params); $context->normalized = true; } else { $modified = false; diff --git a/src/schema/WrapperContext.php b/src/schema/WrapperContext.php index 58a7fe8..d22a81f 100644 --- a/src/schema/WrapperContext.php +++ b/src/schema/WrapperContext.php @@ -5,6 +5,10 @@ use nur\sery\wip\schema\input\Input; use nur\sery\wip\schema\types\IType; class WrapperContext { + const DEFAULT_ANALYZE = true; + const DEFAULT_NORMALIZE = true; + const DEFAULT_THROW = true; + function __construct(Schema $schema, ?Input $input, $valueKey, ?array $params) { $this->resetParams($params); $this->schema = $schema; @@ -19,9 +23,9 @@ class WrapperContext { function resetParams(?array $params): void { $this->params = $params; - $this->analyze = $params["analyze"] ?? true; - $this->normalize = $params["normalize"] ?? true; - $this->throw = $params["throw"] ?? true; + $this->analyze = $params["analyze"] ?? self::DEFAULT_ANALYZE; + $this->normalize = $params["normalize"] ?? self::DEFAULT_NORMALIZE; + $this->throw = $params["throw"] ?? self::DEFAULT_THROW; } /** schéma de la valeur */ diff --git a/src/schema/_assoc/AssocWrapper.php b/src/schema/_assoc/AssocWrapper.php index 05fad7d..5b71446 100644 --- a/src/schema/_assoc/AssocWrapper.php +++ b/src/schema/_assoc/AssocWrapper.php @@ -1,9 +1,11 @@ selectedKey = null; } + function reset(&$value, $valueKey=null, ?array $params=null): Wrapper { + $context = $this->context; + if ($value instanceof Input) $input = $value; + else $input = $this->newInput($value); + $context->input = $input; + $context->valueKey = $valueKey; + foreach ($context->keyWrappers as $key => $wrapper) { + $wrapper->reset($input->subInput($valueKey), $key); + } + $this->afterModify($params, true); + return $this; + } + function getKeys(): array { return $this->context->keys; } @@ -71,28 +86,27 @@ class AssocWrapper extends Wrapper { * @param AssocWrapperContext $context * @param AssocWrapper $wrapper */ - static function _analyze(?array $params, WrapperContext $context, Wrapper $wrapper): int { + static function _analyze(WrapperContext $context, Wrapper $wrapper, ?array $params): int { if ($context->ensureArray) { $array = $context->input->get(); if ($array === null) $context->input->set([]); } - $what = ScalarWrapper::_analyze($params, $context, $wrapper); + $what = ScalarWrapper::_analyze($context, $wrapper, $params); /** @var ScalarResult $result */ $result = $context->result; if (!$result->valid) return $what; foreach ($context->keyWrappers as $wrapper) { $wrapper->analyze($params); if (!$wrapper->isValid()) { - $result->setInvalid(null, $context->schema, $wrapper->getResult()->exception); - break; - #XXX + $what = ref_analyze::INVALID; + $result->addInvalidMessage($wrapper); } } return $what; } - static function _normalize(?array $params, WrapperContext $context, Wrapper $wrapper): bool { - return ScalarWrapper::_normalize($params, $context, $wrapper); + static function _normalize(WrapperContext $context, Wrapper $wrapper, ?array $params): bool { + return ScalarWrapper::_normalize($context, $wrapper, $params); } function getResult($key=false): Result { diff --git a/src/schema/_assoc/AssocWrapperContext.php b/src/schema/_assoc/AssocWrapperContext.php index 07b9f79..c504197 100644 --- a/src/schema/_assoc/AssocWrapperContext.php +++ b/src/schema/_assoc/AssocWrapperContext.php @@ -8,11 +8,15 @@ use nur\sery\wip\schema\Wrapper; use nur\sery\wip\schema\WrapperContext; class AssocWrapperContext extends WrapperContext { + const DEFAULT_ENSURE_ARRAY = false; + const DEFAULT_ENSURE_KEYS = true; + const DEFAULT_ENSURE_ORDER = true; + function __construct(Schema $schema, ?Input $input, $valueKey, ?array $params) { parent::__construct($schema, $input, $valueKey, $params); - $this->ensureArray = $params["ensure_array"] ?? false; - $this->ensureKeys = $params["ensure_keys"] ?? true; - $this->ensureOrder = $params["ensure_order"] ?? true; + $this->ensureArray = $params["ensure_array"] ?? self::DEFAULT_ENSURE_ARRAY; + $this->ensureKeys = $params["ensure_keys"] ?? self::DEFAULT_ENSURE_KEYS; + $this->ensureOrder = $params["ensure_order"] ?? self::DEFAULT_ENSURE_ORDER; } public bool $ensureArray; diff --git a/src/schema/_scalar/ScalarResult.php b/src/schema/_scalar/ScalarResult.php index caf4c31..59453eb 100644 --- a/src/schema/_scalar/ScalarResult.php +++ b/src/schema/_scalar/ScalarResult.php @@ -7,6 +7,7 @@ use nulib\ref\schema\ref_schema; use nulib\ValueException; use nur\sery\wip\schema\Result; use nur\sery\wip\schema\Schema; +use nur\sery\wip\schema\Wrapper; use Throwable; /** @@ -118,6 +119,29 @@ class ScalarResult extends Result { return ref_analyze::INVALID; } + function addInvalidMessage(Wrapper $wrapper): void { + $this->resultAvailable = true; + $this->present = true; + $this->available = true; + $this->null = false; + $this->valid = false; + $this->messageKey = "invalid"; + $result = $wrapper->getResult(); + $resultException = $result->exception; + $resultMessage = $result->message; + if ($resultException !== null) { + $tmessage = ValueException::get_message($resultException); + if ($tmessage) { + if ($resultMessage !== null) $resultMessage .= ": "; + $resultMessage .= $tmessage; + } + } + $message = $this->message; + if ($message) $message .= "\n"; + $message .= $resultMessage; + $this->message = $message; + } + function setValid($normalizedValue=null): int { $this->resultAvailable = true; $this->present = true; diff --git a/src/schema/_scalar/ScalarWrapper.php b/src/schema/_scalar/ScalarWrapper.php index 31f9ba9..f9ba7db 100644 --- a/src/schema/_scalar/ScalarWrapper.php +++ b/src/schema/_scalar/ScalarWrapper.php @@ -147,7 +147,7 @@ class ScalarWrapper extends Wrapper { /** * @param ScalarWrapper $wrapper */ - static function _analyze(?array $params, WrapperContext $context, Wrapper $wrapper): int { + static function _analyze(WrapperContext $context, Wrapper $wrapper, ?array $params): int { /** @var ScalarSchema $schema */ $schema = $context->schema; $input = $context->input; @@ -196,7 +196,7 @@ class ScalarWrapper extends Wrapper { /** * @param ScalarWrapper $wrapper */ - static function _normalize(?array $params, WrapperContext $context, Wrapper $wrapper): bool { + static function _normalize(WrapperContext $context, Wrapper $wrapper, ?array $params): bool { /** @var ScalarSchema $schema */ $schema = $context->schema; $input = $context->input; diff --git a/src/schema/input/ChainInput.php b/src/schema/input/ChainInput.php new file mode 100644 index 0000000..6e26061 --- /dev/null +++ b/src/schema/input/ChainInput.php @@ -0,0 +1,5 @@ +access($key)->del(); } + + function addKey($key): IInput { + return new ChainInput($this, $key); + } } diff --git a/tests/wip/schema/_assoc/AssocSchemaTest.php b/tests/wip/schema/_assoc/AssocSchemaTest.php index 38586bd..0ab3763 100644 --- a/tests/wip/schema/_assoc/AssocSchemaTest.php +++ b/tests/wip/schema/_assoc/AssocSchemaTest.php @@ -101,6 +101,19 @@ class AssocSchemaTest extends TestCase { } function testWrapper() { + $schema = new AssocSchema([ + "a" => "?string", + "b" => "?int", + "c" => "?bool", + ]); + $array = ["a" => " string ", "b" => " 42 ", "c" => false]; + $schema->getWrapper($array); + self::assertSame([ + "a" => "string", + "b" => 42, + "c" => false, + ], $array); + $schema = new AssocSchema([ "a" => "string", "b" => "int",