From c274adb6e66d96b1cd607930e92ff469b36f1424 Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Fri, 28 Mar 2025 15:38:57 +0400 Subject: [PATCH] modifs.mineures sans commentaires --- src/php/access/ArrayAccess.php | 8 + src/php/access/PropertyAccess.php | 2 - src/php/access/ValueAccess.php | 8 + src/schema/Schema.php | 31 ++- src/schema/TODO.md | 1 + src/schema/Wrapper.php | 8 +- src/schema/_assoc/AssocSchema.php | 13 +- src/schema/_assoc/AssocWrapper.php | 59 ++++-- src/schema/_assoc/AssocWrapperContext.php | 15 +- src/schema/_list/ListSchema.php | 7 +- src/schema/_list/ListWrapper.php | 2 - src/schema/_scalar/ScalarSchema.php | 15 +- src/schema/_scalar/ScalarWrapper.php | 21 +- src/schema/input/Input.php | 25 ++- src/schema/types.php | 4 +- src/schema/types/IType.php | 3 + src/schema/types/Registry.php | 5 +- src/schema/types/tarray.php | 4 + src/schema/types/tbool.php | 4 + src/schema/types/tcontent.php | 4 + src/schema/types/tfloat.php | 4 + src/schema/types/{tcallable.php => tfunc.php} | 18 +- src/schema/types/tgeneric.php | 4 + src/schema/types/tint.php | 4 + src/schema/types/tkey.php | 4 + src/schema/types/tmixed.php | 4 + src/schema/types/tpkey.php | 4 + src/schema/types/trawstring.php | 4 + tests/wip/schema/_assoc/AssocSchemaTest.php | 196 +++++++++++++++++- tests/wip/schema/types/boolTest.php | 4 +- tests/wip/schema/types/floatTest.php | 12 +- tests/wip/schema/types/intTest.php | 12 +- tests/wip/schema/types/strTest.php | 12 +- tests/wip/schema/types/unionTest.php | 4 +- 34 files changed, 394 insertions(+), 131 deletions(-) create mode 100644 src/php/access/ArrayAccess.php create mode 100644 src/php/access/ValueAccess.php rename src/schema/types/{tcallable.php => tfunc.php} (76%) diff --git a/src/php/access/ArrayAccess.php b/src/php/access/ArrayAccess.php new file mode 100644 index 0000000..96ff505 --- /dev/null +++ b/src/php/access/ArrayAccess.php @@ -0,0 +1,8 @@ +getWrapper($value, $valueKey, null, $wrapper); + return self::ns($definition, null, $schema)->getWrapper($value, $valueKey, null, $wrapper); } protected static function have_nature(array $definition, ?string &$nature=null): bool { @@ -187,12 +187,12 @@ abstract class Schema implements ArrayAccess { tbool::ensure_bool($definition["required"]); tbool::ensure_bool($definition["nullable"]); tcontent::ensure_ncontent($definition["desc"]); - tcallable::ensure_ncallable($definition["analyzer_func"]); - tcallable::ensure_ncallable($definition["extractor_func"]); - tcallable::ensure_ncallable($definition["parser_func"]); - tcallable::ensure_ncallable($definition["normalizer_func"]); + tfunc::ensure_nfunc($definition["analyzer_func"]); + tfunc::ensure_nfunc($definition["extractor_func"]); + tfunc::ensure_nfunc($definition["parser_func"]); + tfunc::ensure_nfunc($definition["normalizer_func"]); tarray::ensure_narray($definition["messages"]); - tcallable::ensure_ncallable($definition["formatter_func"]); + tfunc::ensure_nfunc($definition["formatter_func"]); tbool::ensure_nbool($definition["computed"]); switch ($nature[0] ?? null) { @@ -252,11 +252,11 @@ abstract class Schema implements ArrayAccess { case "assoc": foreach ($definition["schema"] as &$keydef) { self::_ensure_schema_instances($keydef); - Schema::ns($keydef, null, null, false); + Schema::ns(null, null, $keydef, false); }; unset($keydef); break; case "list": - Schema::ns($definition["schema"], null, null, false); + Schema::ns(null, null, $definition["schema"], false); break; } } @@ -280,14 +280,7 @@ abstract class Schema implements ArrayAccess { */ abstract function getKeys(): array; - abstract function getSchema($key): Schema; - - /** retourner true si le schéma est de nature tableau associatif */ - function isAssoc(?AssocSchema &$schema=null): bool { return false; } - /** retourner true si le schéma est de nature liste */ - function isList(?ListSchema &$schema=null): bool { return false; } - /** retourner true si le schéma est de nature scalaire */ - function isScalar(?ScalarSchema &$schema=null): bool { return false; } + abstract function getSchema($key=false): Schema; abstract protected function newWrapper(): Wrapper; diff --git a/src/schema/TODO.md b/src/schema/TODO.md index 7c9cbb6..65c4212 100644 --- a/src/schema/TODO.md +++ b/src/schema/TODO.md @@ -5,6 +5,7 @@ schéma qui les génère. ensureKeys($values) * méthode ensureAssoc() transforme les clés séquentielles en clés associatives * l'ordre est `ensureAssoc [--> ensureKeys] [--> orderKeys]` +* si false, supprimer la clé du tableau sauf si ensureKeys * pour AssocResult, les clés suivantes sont supportées: * false pour la clé courante diff --git a/src/schema/Wrapper.php b/src/schema/Wrapper.php index 7c558e8..3dfc06b 100644 --- a/src/schema/Wrapper.php +++ b/src/schema/Wrapper.php @@ -12,10 +12,6 @@ use nur\sery\wip\schema\input\Input; use nur\sery\wip\schema\types\IType; abstract class Wrapper implements ArrayAccess, IteratorAggregate { - function isAssoc(?AssocWrapper &$wrapper=null): bool { return false; } - function isList(?ListWrapper &$wrapper=null): bool { return false; } - function isScalar(?ScalarWrapper &$wrapper=null): bool { return false; } - protected WrapperContext $context; /** changer les paramètres de gestion des valeurs */ @@ -25,7 +21,9 @@ abstract class Wrapper implements ArrayAccess, IteratorAggregate { protected function resetContext($resetSelectedKey): void { $context = $this->context; - $context->type = null; + $type = $context->schema->type; + if (is_array($type)) $type = $type[0]; + $context->type = $type; $context->result->reset(); $context->analyzed = false; $context->normalized = false; diff --git a/src/schema/_assoc/AssocSchema.php b/src/schema/_assoc/AssocSchema.php index b9fac49..4b6b753 100644 --- a/src/schema/_assoc/AssocSchema.php +++ b/src/schema/_assoc/AssocSchema.php @@ -47,6 +47,10 @@ class AssocSchema extends Schema { $this->_definition = $definition; self::_ensure_type($definition); self::_ensure_schema_instances($definition); + } else { + # ici, $definition contient un schema déjà instancié, mais c'est le mieux + # qu'on puisse faire + $this->_definition = $definition; } $this->definition = $definition; $keys = []; @@ -56,19 +60,14 @@ class AssocSchema extends Schema { $this->keys = $keys; } - function isAssoc(?AssocSchema &$schema=null): bool { - $schema = $this; - return true; - } - protected array $keys; function getKeys(): array { return $this->keys; } - function getSchema($key): Schema { - if ($key === null) return $this; + function getSchema($key=false): Schema { + if ($key === null || $key === false) return $this; $schema = $this->definition["schema"][$key] ?? null; if ($schema === null) throw ValueException::invalid_key($key); return $schema; diff --git a/src/schema/_assoc/AssocWrapper.php b/src/schema/_assoc/AssocWrapper.php index 1add86c..71210d1 100644 --- a/src/schema/_assoc/AssocWrapper.php +++ b/src/schema/_assoc/AssocWrapper.php @@ -1,6 +1,7 @@ getKeys(); + $keyParams = cl::merge($params, [ + "throw" => false, + ]); $keyWrappers = []; foreach ($keys as $key) { - $keyWrappers[$key] = $schema->getSchema($key)->getWrapper(); + $value = null; + $keyWrappers[$key] = $schema->getSchema($key)->getWrapper($value, null, $keyParams); } $this->context = $context = new AssocWrapperContext($schema, null, null, $params); - $context->arrayWrapper = new ScalarWrapper($schema, $dummy, null, null, $context); + $arrayParams = cl::merge($params, [ + "throw" => false, + ]); + $context->arrayWrapper = new ScalarWrapper($schema, $dummy, null, $arrayParams, $context); $context->keys = $keys; $context->keyWrappers = $keyWrappers; - # calculer manuellemet throw ici parce que WrapperContext le met à true par - # défaut. on veut pouvoir mettre temporairement throw à false si jamais il - # n'est pas spécifié par l'utilisateur - $throw = $params["throw"] ?? null; - # Si $value est null, ne pas lancer d'exception, parce qu'on considère que - # c'est une initialisation sans conséquences - if ($throw === null && $value !== null) $throw = true; - $context->throw = $throw ?? false; - $this->reset($value, $valueKey); - $context->throw = $throw ?? true; + if ($value !== null) { + # n'initialiser que si $value n'est pas null + $this->reset($value, $valueKey); + } } - function isAssoc(?AssocWrapper &$wrapper=null): bool { $wrapper = $this; return true; } - /** @var AssocWrapperContext */ protected WrapperContext $context; @@ -70,7 +70,8 @@ class AssocWrapper extends Wrapper { } protected function _getWrapper($key): Wrapper { - if ($key === null) return $this->context->arrayWrapper; + $context = $this->context; + if ($key === null) return $context->arrayWrapper; $wrapper = $context->keyWrappers[$key] ?? null; if ($wrapper === null) throw ValueException::invalid_key($key); return $wrapper; @@ -93,17 +94,26 @@ class AssocWrapper extends Wrapper { $array = $context->input->get($valueKey); if ($array === null) $context->input->set([], $valueKey); } + + if ($context->ensureAssoc) { + $context->input->ensureAssoc($context->schema->getKeys()); + } + $what = ScalarWrapper::_analyze($context, $wrapper, $params); /** @var ScalarResult $result */ $result = $context->result; if (!$result->valid) return $what; + foreach ($context->keyWrappers as $keyWrapper) { $keyWrapper->analyze($params); if (!$keyWrapper->isValid()) { + #XXX distinguer MISSING, UNAVAILABLE, NULL et !VALID $what = ref_analyze::INVALID; $result->addInvalidMessage($keyWrapper); } } + + #XXX supprimer les clés "missing" ou "unavailable" return $what; } @@ -112,6 +122,25 @@ class AssocWrapper extends Wrapper { * @param AssocWrapper $wrapper */ static function _normalize(WrapperContext $context, Wrapper $wrapper, ?array $params): bool { + $ensureKeys = $context->ensureKeys; + $ensureOrder = $context->ensureOrder; + if ($ensureKeys || $ensureOrder) { + $schema = $context->schema; + $keys = $schema->getKeys(); + if ($ensureKeys) { + $defaults = []; + foreach ($keys as $key) { + $default = $schema->getSchema($key)->default; + if ($default === null) { + $default = $wrapper->getType($key)->getNullValue(); + } + $defaults[$key] = $default; + } + } + if ($ensureKeys) $context->input->ensureKeys($defaults, $params); + if ($ensureOrder) $context->input->ensureOrder($keys, $params); + } + $modified = ScalarWrapper::_normalize($context, $wrapper, $params); foreach ($context->keyWrappers as $keyWrapper) { if ($keyWrapper->normalize($params)) $modified = true; diff --git a/src/schema/_assoc/AssocWrapperContext.php b/src/schema/_assoc/AssocWrapperContext.php index c504197..8512635 100644 --- a/src/schema/_assoc/AssocWrapperContext.php +++ b/src/schema/_assoc/AssocWrapperContext.php @@ -9,20 +9,23 @@ use nur\sery\wip\schema\WrapperContext; class AssocWrapperContext extends WrapperContext { const DEFAULT_ENSURE_ARRAY = false; + const DEFAULT_ENSURE_ASSOC = true; 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); + public bool $ensureArray; + public bool $ensureAssoc; + public bool $ensureKeys; + public bool $ensureOrder; + + public function resetParams(?array $params): void { + parent::resetParams($params); $this->ensureArray = $params["ensure_array"] ?? self::DEFAULT_ENSURE_ARRAY; + $this->ensureAssoc = $params["ensure_assoc"] ?? self::DEFAULT_ENSURE_ASSOC; $this->ensureKeys = $params["ensure_keys"] ?? self::DEFAULT_ENSURE_KEYS; $this->ensureOrder = $params["ensure_order"] ?? self::DEFAULT_ENSURE_ORDER; } - public bool $ensureArray; - public bool $ensureKeys; - public bool $ensureOrder; - public ?ScalarWrapper $arrayWrapper = null; /** liste des clés valides */ diff --git a/src/schema/_list/ListSchema.php b/src/schema/_list/ListSchema.php index 4887e95..cdc1024 100644 --- a/src/schema/_list/ListSchema.php +++ b/src/schema/_list/ListSchema.php @@ -51,18 +51,13 @@ class ListSchema extends Schema { $this->definition = $definition; } - function isList(?ListSchema &$schema=null): bool { - $schema = $this; - return true; - } - const KEYS = [null]; function getKeys(): array { return self::KEYS; } - public function getSchema($key): Schema { + public function getSchema($key=false): Schema { if ($key !== null) throw ValueException::invalid_key($key); return $this; } diff --git a/src/schema/_list/ListWrapper.php b/src/schema/_list/ListWrapper.php index cae167b..169dd98 100644 --- a/src/schema/_list/ListWrapper.php +++ b/src/schema/_list/ListWrapper.php @@ -5,8 +5,6 @@ use nur\sery\wip\schema\Result; use nur\sery\wip\schema\Wrapper; abstract/*XXX*/ class ListWrapper extends Wrapper { - function isList(?ListWrapper &$wrapper=null): bool { $wrapper = $this; return true; } - function ensureKeys(): bool { } diff --git a/src/schema/_scalar/ScalarSchema.php b/src/schema/_scalar/ScalarSchema.php index 597a34b..a9c2ad5 100644 --- a/src/schema/_scalar/ScalarSchema.php +++ b/src/schema/_scalar/ScalarSchema.php @@ -56,24 +56,23 @@ class ScalarSchema extends Schema { $this->_definition = $definition; self::_ensure_type($definition); self::_ensure_schema_instances($definition); + } else { + # ici, $definition contient un schema déjà instancié, mais c'est le mieux + # qu'on puisse faire + $this->_definition = $definition; } $this->definition = $definition; } - function isScalar(?ScalarSchema &$schema=null): bool { - $schema = $this; - return true; - } - const KEYS = [null]; function getKeys(): array { return self::KEYS; } - function getSchema($key): Schema { - if ($key !== null) throw ValueException::invalid_key($key); - return $this; + function getSchema($key=false): Schema { + if ($key === null || $key === false) return $this; + throw ValueException::invalid_key($key); } protected function newWrapper(): ScalarWrapper { diff --git a/src/schema/_scalar/ScalarWrapper.php b/src/schema/_scalar/ScalarWrapper.php index 588e8b3..c5b24c8 100644 --- a/src/schema/_scalar/ScalarWrapper.php +++ b/src/schema/_scalar/ScalarWrapper.php @@ -4,8 +4,6 @@ namespace nur\sery\wip\schema\_scalar; use nulib\php\func; use nulib\ref\schema\ref_analyze; use nulib\ValueException; -use nur\sery\wip\schema\_assoc\AssocWrapper; -use nur\sery\wip\schema\_assoc\AssocWrapperContext; use nur\sery\wip\schema\Schema; use nur\sery\wip\schema\types; use nur\sery\wip\schema\types\IType; @@ -26,20 +24,15 @@ class ScalarWrapper extends Wrapper { $context->result = new ScalarResult(); $this->context = $context; - # calculer manuellemet throw ici parce que WrapperContext le met à true par - # défaut. on veut pouvoir mettre temporairement throw à false si jamais il - # n'est pas spécifié par l'utilisateur - $throw = $params["throw"] ?? null; - # Si $value est null, ne pas lancer d'exception, parce qu'on considère que - # c'est une initialisation sans conséquences - if ($throw === null && $value !== null) $throw = true; - $context->throw = $throw ?? false; - $this->reset($value, $valueKey); - $context->throw = $throw ?? true; + if ($value !== null) { + # n'initialiser que si $value n'est pas null + $this->reset($value, $valueKey); + } else { + # il faut au moins que le type soit disponible + $this->resetContext(false); + } } - function isScalar(?ScalarWrapper &$wrapper=null): bool { $wrapper = $this; return true; } - protected WrapperContext $context; function getKeys(): array { diff --git a/src/schema/input/Input.php b/src/schema/input/Input.php index 799eb4a..4973195 100644 --- a/src/schema/input/Input.php +++ b/src/schema/input/Input.php @@ -1,6 +1,7 @@ access = new PropertyAccess($dest, null, [ "allow_empty" => $allowEmpty, "allow_null" => true, ]); - } elseif ($accessType == self::ACCESS_KEY) { + } elseif ($accessType == ref_input::ACCESS_KEY) { $this->access = new KeyAccess($dest, null, [ "allow_empty" => $allowEmpty, "allow_null" => true, @@ -72,4 +71,16 @@ class Input { $input->access = $this->access->addKey($key); return $input; } + + function ensureAssoc(array $keys, ?array $params=null): void { + $this->access->ensureAssoc($keys, $params); + } + + function ensureKeys(array $defaults, ?array $params=null): void { + $this->access->ensureKeys($defaults, $params); + } + + function ensureOrder(array $keys, ?array $params=null): void { + $this->access->ensureOrder($keys, $params); + } } diff --git a/src/schema/types.php b/src/schema/types.php index c1b618b..117e779 100644 --- a/src/schema/types.php +++ b/src/schema/types.php @@ -6,7 +6,7 @@ use nur\sery\wip\schema\types\IType; use nur\sery\wip\schema\types\Registry; use nur\sery\wip\schema\types\tarray; use nur\sery\wip\schema\types\tbool; -use nur\sery\wip\schema\types\tcallable; +use nur\sery\wip\schema\types\tfunc; use nur\sery\wip\schema\types\tcontent; use nur\sery\wip\schema\types\tfloat; use nur\sery\wip\schema\types\tint; @@ -47,7 +47,7 @@ class types { static function int(bool $nullable=true): tint { return self::get($nullable, "int"); } static function float(bool $nullable=true): tfloat { return self::get($nullable, "float"); } static function array(bool $nullable=true): tarray { return self::get($nullable, "array"); } - static function callable(bool $nullable=true): tcallable { return self::get($nullable, "callable"); } + static function callable(bool $nullable=true): tfunc { return self::get($nullable, "callable"); } static function raw(bool $nullable=true): traw { return self::get($nullable, "raw"); } static function mixed(bool $nullable=true): tmixed { return self::get($nullable, "mixed"); } static function key(bool $nullable=true): tkey { return self::get($nullable, "key"); } diff --git a/src/schema/types/IType.php b/src/schema/types/IType.php index 0fbe948..574d5e4 100644 --- a/src/schema/types/IType.php +++ b/src/schema/types/IType.php @@ -47,6 +47,9 @@ interface IType { */ function getPhpType(bool $allowNullable=true): ?string; + /** obtenir la valeur "nulle" pour les objets de ce type */ + function getNullValue(); + /** * indiquer si c'est le type d'une valeur qui ne peut prendre que 2 états: une * "vraie" et une "fausse" diff --git a/src/schema/types/Registry.php b/src/schema/types/Registry.php index fdaabde..f8373cf 100644 --- a/src/schema/types/Registry.php +++ b/src/schema/types/Registry.php @@ -12,10 +12,9 @@ class Registry { "text" => ttext::class, "bool" => tbool::class, "boolean" => tbool::class, "int" => tint::class, "integer" => tint::class, - "float" => tfloat::class, "flt" => tfloat::class, - "double" => tfloat::class, "dbl" => tfloat::class, + "float" => tfloat::class, "flt" => tfloat::class, "double" => tfloat::class, "dbl" => tfloat::class, "array" => tarray::class, - "callable" => tcallable::class, + "func" => tfunc::class, "function" => tfunc::class, "callable" => tfunc::class, # types spéciaux "raw" => traw::class, "mixed" => tmixed::class, diff --git a/src/schema/types/tarray.php b/src/schema/types/tarray.php index a6b2bf9..0f55ea3 100644 --- a/src/schema/types/tarray.php +++ b/src/schema/types/tarray.php @@ -35,6 +35,10 @@ class tarray extends _tstring { return "array"; } + function getNullValue() { + return $this->nullable? null: []; + } + function isValid($value, ?bool &$normalized=null): bool { $normalized = is_array($value); return $normalized || is_scalar($value); diff --git a/src/schema/types/tbool.php b/src/schema/types/tbool.php index dffa9c4..a8e9e3d 100644 --- a/src/schema/types/tbool.php +++ b/src/schema/types/tbool.php @@ -76,6 +76,10 @@ class tbool extends _tformatable { return [false, true, null]; } + function getNullValue() { + return $this->nullable? null: false; + } + function isAvailable(Input $input, $valueKey): bool { return $input->isAvailable($valueKey); } diff --git a/src/schema/types/tcontent.php b/src/schema/types/tcontent.php index 0a600f4..b885a56 100644 --- a/src/schema/types/tcontent.php +++ b/src/schema/types/tcontent.php @@ -23,6 +23,10 @@ abstract class tcontent extends _tunion { return "string|array"; } + function getNullValue() { + return $this->nullable? null: []; + } + function isValid($value, ?bool &$normalized=null): bool { $normalized = is_string($value) || is_array($value); return $normalized || is_scalar($value); diff --git a/src/schema/types/tfloat.php b/src/schema/types/tfloat.php index 85767b6..70118c5 100644 --- a/src/schema/types/tfloat.php +++ b/src/schema/types/tfloat.php @@ -24,6 +24,10 @@ class tfloat extends _tformatable { return "float"; } + function getNullValue() { + return $this->nullable? null: 0.0; + } + function isValid($value, ?bool &$normalized=null): bool { $normalized = is_float($value); return is_scalar($value); diff --git a/src/schema/types/tcallable.php b/src/schema/types/tfunc.php similarity index 76% rename from src/schema/types/tcallable.php rename to src/schema/types/tfunc.php index 76e2656..e13a39f 100644 --- a/src/schema/types/tcallable.php +++ b/src/schema/types/tfunc.php @@ -9,23 +9,27 @@ use nur\sery\wip\schema\_scalar\ScalarSchema; use nur\sery\wip\schema\Result; use nur\sery\wip\schema\Schema; -class tcallable extends _tsimple { - const NAME = "callable"; +class tfunc extends _tsimple { + const NAME = "func"; - const ALIASES = ["func", "function"]; + const ALIASES = ["function", "callable"]; - static function ensure_callable(&$callable): void { - $callable = func::ensure($callable); + static function ensure_func(&$func): void { + $func = func::ensure($func); } - static function ensure_ncallable(&$callable): void { - if ($callable !== null) self::ensure_callable($callable); + static function ensure_nfunc(&$func): void { + if ($func !== null) self::ensure_func($func); } function getClass(): string { return func::class; } + function getNullValue() { + return null; + } + function isValid($value, ?bool &$normalized=null): bool { $normalized = $value instanceof func; return func::check($value); diff --git a/src/schema/types/tgeneric.php b/src/schema/types/tgeneric.php index fe069b8..09a115d 100644 --- a/src/schema/types/tgeneric.php +++ b/src/schema/types/tgeneric.php @@ -20,6 +20,10 @@ class tgeneric extends _tsimple { return $this->class; } + function getNullValue() { + return null; + } + function isAvailable(Input $input, $valueKey): bool { return $input->isAvailable($valueKey); } diff --git a/src/schema/types/tint.php b/src/schema/types/tint.php index eddab99..a1a98e0 100644 --- a/src/schema/types/tint.php +++ b/src/schema/types/tint.php @@ -26,6 +26,10 @@ class tint extends _tformatable { return "int"; } + function getNullValue() { + return $this->nullable? null: 0; + } + function isValid($value, ?bool &$normalized=null): bool { $normalized = is_int($value); return is_scalar($value); diff --git a/src/schema/types/tkey.php b/src/schema/types/tkey.php index f1cca27..f3f0f5d 100644 --- a/src/schema/types/tkey.php +++ b/src/schema/types/tkey.php @@ -23,6 +23,10 @@ class tkey extends _tunion { return "string|int"; } + function getNullValue() { + return $this->nullable? null: ""; + } + function isValid($value, ?bool &$normalized=null): bool { $normalized = is_string($value) || is_int($value); return $normalized || is_scalar($value); diff --git a/src/schema/types/tmixed.php b/src/schema/types/tmixed.php index f549204..5fa3e85 100644 --- a/src/schema/types/tmixed.php +++ b/src/schema/types/tmixed.php @@ -14,6 +14,10 @@ class tmixed extends _tsimple { return "mixed"; } + function getNullValue() { + return null; + } + function isAvailable(Input $input, $valueKey): bool { return $input->isAvailable($valueKey); } diff --git a/src/schema/types/tpkey.php b/src/schema/types/tpkey.php index 7b2234b..20c9c77 100644 --- a/src/schema/types/tpkey.php +++ b/src/schema/types/tpkey.php @@ -28,6 +28,10 @@ class tpkey extends _tunion { return "string|int|array"; } + function getNullValue() { + return $this->nullable? null: []; + } + function isValid($value, ?bool &$normalized=null): bool { $normalized = is_string($value) || is_int($value) || is_array($value); return $normalized || is_scalar($value); diff --git a/src/schema/types/trawstring.php b/src/schema/types/trawstring.php index 674d430..938242d 100644 --- a/src/schema/types/trawstring.php +++ b/src/schema/types/trawstring.php @@ -24,6 +24,10 @@ class trawstring extends _tstring { return "string"; } + function getNullValue() { + return $this->nullable? null: ""; + } + function isNull($value): bool { return $value === null; } diff --git a/tests/wip/schema/_assoc/AssocSchemaTest.php b/tests/wip/schema/_assoc/AssocSchemaTest.php index 987e845..cdd1567 100644 --- a/tests/wip/schema/_assoc/AssocSchemaTest.php +++ b/tests/wip/schema/_assoc/AssocSchemaTest.php @@ -3,7 +3,9 @@ namespace nur\sery\wip\schema\_assoc; use nulib\ext\yaml; use nulib\tests\TestCase; +use nulib\ValueException; use nur\sery\wip\schema\_scalar\ScalarSchemaTest; +use nur\sery\wip\schema\Schema; class AssocSchemaTest extends TestCase { const NULL_SCHEMA = [ @@ -114,6 +116,7 @@ class AssocSchemaTest extends TestCase { "c" => false, ], $array); + ########################################################################### $schema = new AssocSchema([ "a" => "string", "b" => "int", @@ -124,15 +127,15 @@ class AssocSchemaTest extends TestCase { $schema->getWrapper($array); self::assertSame([ "a" => "string", - "b" => false, - "c" => null, + "b" => 0, + "c" => false, ], $array); $array = ["c" => false, "a" => " string "]; $schema->getWrapper($array); self::assertSame([ "a" => "string", - "b" => false, + "b" => 0, "c" => false, ], $array); @@ -140,8 +143,8 @@ class AssocSchemaTest extends TestCase { $schema->getWrapper($array, null, ["ensure_order" => false]); self::assertSame([ "a" => "string", - "b" => false, - "c" => null, + "b" => 0, + "c" => false, ], $array); $array = ["c" => false, "a" => " string "]; @@ -149,7 +152,7 @@ class AssocSchemaTest extends TestCase { self::assertSame([ "c" => false, "a" => "string", - "b" => false, + "b" => 0, ], $array); $array = ["a" => " string "]; @@ -165,4 +168,185 @@ class AssocSchemaTest extends TestCase { "c" => false, ], $array); } + + const STRING_SCHEMA = [ + "s" => "string", + "f" => "string", + "m" => "string", + ]; + + const NSTRING_SCHEMA = [ + "s" => "?string", + "f" => "?string", + "m" => "?string", + ]; + + const RSTRING_SCHEMA = [ + "s" => ["string", "required" => true], + "f" => ["string", "required" => true], + "m" => ["string", "required" => true], + ]; + + const RNSTRING_SCHEMA = [ + "s" => ["?string", "required" => true], + "f" => ["?string", "required" => true], + "m" => ["?string", "required" => true], + ]; + + const STRINGS = ["s" => "string", "f" => false]; + const NSTRINGS = ["s" => null, "f" => null]; + + function testString() { + /** @var AssocSchema $schema */ + $schema = Schema::ns(self::STRING_SCHEMA); + + $array = self::STRINGS; + $wrapper = $schema->getWrapper($array, null, ["throw" => false]); + self::assertSame(self::STRINGS, $array); + $result = $wrapper->getResult("s"); + self::assertTrue($result->normalized); + $result = $wrapper->getResult("f"); + self::assertTrue($result->present); + self::assertFalse($result->available); + $result = $wrapper->getResult("m"); + self::assertFalse($result->present); + + self::assertNotException(function() use ($schema) { + $array = self::STRINGS; + $schema->getWrapper($array); + }); + + $array = self::NSTRINGS; + $wrapper = $schema->getWrapper($array, null, ["throw" => false]); + self::assertSame(self::NSTRINGS, $array); + $result = $wrapper->getResult("s"); + self::assertFalse($result->valid); + self::assertSame("null", $result->messageKey); + $result = $wrapper->getResult("f"); + self::assertFalse($result->valid); + self::assertSame("null", $result->messageKey); + $result = $wrapper->getResult("m"); + self::assertFalse($result->present); + + self::assertException(ValueException::class, function() use ($schema) { + $array = self::NSTRINGS; + $schema->getWrapper($array); + }); + } + + function testNstring() { + /** @var AssocSchema $schema */ + $schema = Schema::ns(self::NSTRING_SCHEMA); + + $array = self::STRINGS; + $wrapper = $schema->getWrapper($array, null, ["throw" => false]); + self::assertSame(self::STRINGS, $array); + $result = $wrapper->getResult("s"); + self::assertTrue($result->normalized); + $result = $wrapper->getResult("f"); + self::assertTrue($result->present); + self::assertFalse($result->available); + $result = $wrapper->getResult("m"); + self::assertFalse($result->present); + + self::assertNotException(function() use ($schema) { + $array = self::STRINGS; + $schema->getWrapper($array); + }); + + $array = self::NSTRINGS; + $wrapper = $schema->getWrapper($array, null, ["throw" => false]); + self::assertSame(self::NSTRINGS, $array); + $result = $wrapper->getResult("s"); + self::assertTrue($result->normalized); + $result = $wrapper->getResult("f"); + self::assertTrue($result->normalized); + $result = $wrapper->getResult("m"); + self::assertFalse($result->present); + + self::assertNotException(function() use ($schema) { + $array = self::NSTRINGS; + $schema->getWrapper($array); + }); + } + + function testRstring() { + /** @var AssocSchema $schema */ + $schema = Schema::ns(self::RSTRING_SCHEMA); + + $array = self::STRINGS; + $wrapper = $schema->getWrapper($array, null, ["throw" => false]); + self::assertSame(self::STRINGS, $array); + $result = $wrapper->getResult("s"); + self::assertTrue($result->normalized); + $result = $wrapper->getResult("f"); + self::assertTrue($result->present); + self::assertFalse($result->available); + self::assertSame("unavailable", $result->messageKey); + $result = $wrapper->getResult("m"); + self::assertFalse($result->present); + self::assertSame("missing", $result->messageKey); + + self::assertException(ValueException::class, function() use ($schema) { + $array = self::STRINGS; + $schema->getWrapper($array); + }); + + $array = self::NSTRINGS; + $wrapper = $schema->getWrapper($array, null, ["throw" => false]); + self::assertSame(self::NSTRINGS, $array); + $result = $wrapper->getResult("s"); + self::assertFalse($result->valid); + self::assertSame("null", $result->messageKey); + $result = $wrapper->getResult("f"); + self::assertFalse($result->valid); + self::assertSame("null", $result->messageKey); + $result = $wrapper->getResult("m"); + self::assertFalse($result->present); + self::assertSame("missing", $result->messageKey); + + self::assertException(ValueException::class, function() use ($schema) { + $array = self::NSTRINGS; + $schema->getWrapper($array); + }); + } + + function testRnstring() { + /** @var AssocSchema $schema */ + $schema = Schema::ns(self::RNSTRING_SCHEMA); + + $array = self::STRINGS; + $wrapper = $schema->getWrapper($array, null, ["throw" => false]); + self::assertSame(self::STRINGS, $array); + $result = $wrapper->getResult("s"); + self::assertTrue($result->normalized); + $result = $wrapper->getResult("f"); + self::assertTrue($result->present); + self::assertFalse($result->available); + self::assertSame("unavailable", $result->messageKey); + $result = $wrapper->getResult("m"); + self::assertFalse($result->present); + self::assertSame("missing", $result->messageKey); + + self::assertException(ValueException::class, function() use ($schema) { + $array = self::STRINGS; + $schema->getWrapper($array); + }); + + $array = self::NSTRINGS; + $wrapper = $schema->getWrapper($array, null, ["throw" => false]); + self::assertSame(self::NSTRINGS, $array); + $result = $wrapper->getResult("s"); + self::assertTrue($result->normalized); + $result = $wrapper->getResult("f"); + self::assertTrue($result->normalized); + $result = $wrapper->getResult("m"); + self::assertFalse($result->present); + self::assertSame("missing", $result->messageKey); + + self::assertException(ValueException::class, function() use ($schema) { + $array = self::NSTRINGS; + $schema->getWrapper($array); + }); + } } diff --git a/tests/wip/schema/types/boolTest.php b/tests/wip/schema/types/boolTest.php index f4db6ce..8fa9308 100644 --- a/tests/wip/schema/types/boolTest.php +++ b/tests/wip/schema/types/boolTest.php @@ -59,7 +59,7 @@ class boolTest extends TestCase { function testBool() { /** @var ScalarWrapper $wrapper */ - Schema::nw($value, null, $schema, "bool", $wrapper); + Schema::nw($value, null, "bool", $schema, $wrapper); $wrapperSetter = function($value) use($wrapper) { return function() use($wrapper, $value) { $wrapper->set($value); @@ -75,7 +75,7 @@ class boolTest extends TestCase { function testNbool() { /** @var ScalarWrapper $wrapper */ - Schema::nw($value, null, $schema, "?bool", $wrapper); + Schema::nw($value, null, "?bool", $schema, $wrapper); $wrapperSetter = function($value) use($wrapper) { return function() use($wrapper, $value) { $wrapper->set($value); diff --git a/tests/wip/schema/types/floatTest.php b/tests/wip/schema/types/floatTest.php index a4679a4..f6340a2 100644 --- a/tests/wip/schema/types/floatTest.php +++ b/tests/wip/schema/types/floatTest.php @@ -33,7 +33,7 @@ class floatTest extends TestCase { function testFloat() { /** @var ScalarWrapper $wrapper */ - Schema::nw($value, null, $schema, "float", $wrapper); + Schema::nw($value, null, "float", $schema, $wrapper); $wrapperSetter = function($value) use($wrapper) { return function() use($wrapper, $value) { $wrapper->set($value); @@ -53,10 +53,10 @@ class floatTest extends TestCase { function testRequiredFloat() { /** @var ScalarWrapper $wrapper */ - Schema::nw($value, null, $schema, [ + Schema::nw($value, null, [ "float", null, "required" => true, - ], $wrapper); + ], $schema, $wrapper); $wrapperSetter = function($value) use($wrapper) { return function() use($wrapper, $value) { $wrapper->set($value); @@ -75,7 +75,7 @@ class floatTest extends TestCase { function testNfloat() { /** @var ScalarWrapper $wrapper */ - Schema::nw($value, null, $schema, "?float", $wrapper); + Schema::nw($value, null, "?float", $schema, $wrapper); $wrapperSetter = function($value) use($wrapper) { return function() use($wrapper, $value) { $wrapper->set($value); @@ -106,10 +106,10 @@ class floatTest extends TestCase { function testRequiredNfloat() { /** @var ScalarWrapper $wrapper */ - Schema::nw($value, null, $schema, [ + Schema::nw($value, null, [ "?float", null, "required" => true, - ], $wrapper); + ], $schema, $wrapper); $wrapperSetter = function($value) use($wrapper) { return function() use($wrapper, $value) { $wrapper->set($value); diff --git a/tests/wip/schema/types/intTest.php b/tests/wip/schema/types/intTest.php index c9cccbf..51cd7f9 100644 --- a/tests/wip/schema/types/intTest.php +++ b/tests/wip/schema/types/intTest.php @@ -33,7 +33,7 @@ class intTest extends TestCase { function testInt() { /** @var ScalarWrapper $wrapper */ - Schema::nw($value, null, $schema, "int", $wrapper); + Schema::nw($value, null, "int", $schema, $wrapper); $wrapperSetter = function($value) use($wrapper) { return function() use($wrapper, $value) { $wrapper->set($value); @@ -53,10 +53,10 @@ class intTest extends TestCase { function testRequiredInt() { /** @var ScalarWrapper $wrapper */ - Schema::nw($value, null, $schema, [ + Schema::nw($value, null, [ "int", null, "required" => true, - ], $wrapper); + ], $schema, $wrapper); $wrapperSetter = function($value) use($wrapper) { return function() use($wrapper, $value) { $wrapper->set($value); @@ -75,7 +75,7 @@ class intTest extends TestCase { function testNint() { /** @var ScalarWrapper $wrapper */ - Schema::nw($value, null, $schema, "?int", $wrapper); + Schema::nw($value, null, "?int", $schema, $wrapper); $wrapperSetter = function($value) use($wrapper) { return function() use($wrapper, $value) { $wrapper->set($value); @@ -106,10 +106,10 @@ class intTest extends TestCase { function testRequiredNint() { /** @var ScalarWrapper $wrapper */ - Schema::nw($value, null, $schema, [ + Schema::nw($value, null, [ "?int", null, "required" => true, - ], $wrapper); + ], $schema, $wrapper); $wrapperSetter = function($value) use($wrapper) { return function() use($wrapper, $value) { $wrapper->set($value); diff --git a/tests/wip/schema/types/strTest.php b/tests/wip/schema/types/strTest.php index 184d99c..fd8f142 100644 --- a/tests/wip/schema/types/strTest.php +++ b/tests/wip/schema/types/strTest.php @@ -41,7 +41,7 @@ class strTest extends TestCase { function testStr() { /** @var ScalarWrapper $wrapper */ - Schema::nw($value, null, $schema, "string", $wrapper); + Schema::nw($value, null, "string", $schema, $wrapper); $wrapperSetter = function($value) use($wrapper) { return function() use($wrapper, $value) { $wrapper->set($value); @@ -59,10 +59,10 @@ class strTest extends TestCase { function testRequiredStr() { /** @var ScalarWrapper $wrapper */ - Schema::nw($value, null, $schema, [ + Schema::nw($value, null, [ "string", null, "required" => true, - ], $wrapper); + ], $schema, $wrapper); $wrapperSetter = function($value) use($wrapper) { return function() use($wrapper, $value) { $wrapper->set($value); @@ -79,7 +79,7 @@ class strTest extends TestCase { function testNstr() { /** @var ScalarWrapper $wrapper */ - Schema::nw($value, null, $schema, "?string", $wrapper); + Schema::nw($value, null, "?string", $schema, $wrapper); $wrapperSetter = function($value) use($wrapper) { return function() use($wrapper, $value) { $wrapper->set($value); @@ -100,10 +100,10 @@ class strTest extends TestCase { function testRequiredNstr() { /** @var ScalarWrapper $wrapper */ - Schema::nw($value, null, $schema, [ + Schema::nw($value, null, [ "?string", null, "required" => true, - ], $wrapper); + ], $schema, $wrapper); $wrapperSetter = function($value) use($wrapper) { return function() use($wrapper, $value) { $wrapper->set($value); diff --git a/tests/wip/schema/types/unionTest.php b/tests/wip/schema/types/unionTest.php index 312d3d4..7557420 100644 --- a/tests/wip/schema/types/unionTest.php +++ b/tests/wip/schema/types/unionTest.php @@ -11,7 +11,7 @@ class unionTest extends TestCase { # string puis int /** @var ScalarWrapper $siw */ - Schema::nw($si, null, $sis, "string|int", $siw); + Schema::nw($si, null, "string|int", $sis, $siw); $siw->set("12"); self::assertSame("12", $si); @@ -20,7 +20,7 @@ class unionTest extends TestCase { # int puis string /** @var ScalarWrapper $isw */ - Schema::nw($is, null, $iss, "int|string", $isw); + Schema::nw($is, null, "int|string", $iss, $isw); $isw->set("12"); self::assertSame("12", $is);