diff --git a/src/schema/Schema.php b/src/schema/Schema.php index 02365cb..55f1304 100644 --- a/src/schema/Schema.php +++ b/src/schema/Schema.php @@ -17,6 +17,29 @@ use nur\sery\wip\schema\types\tcontent; use nur\sery\wip\schema\types\tpkey; use nur\sery\wip\schema\types\trawstring; +/** + * Class Schema + * + * @property-read array|IType $type + * @property-read mixed $default + * @property-read string|null $title + * @property-read bool $required + * @property-read bool $nullable + * @property-read string|array|null $desc + * @property-read callable|null $analyzerFunc + * @property-read callable|null $extractorFunc + * @property-read callable|null $parserFunc + * @property-read callable|null $normalizerFunc + * @property-read array|null $messages + * @property-read callable|null $formatterFunc + * @property-read mixed $format + * @property-read array $nature + * @property-read array|null $schema + * @property-read string|int|null $name + * @property-read string|array|null $pkey + * @property-read string|null $header + * @property-read bool|null $computed + */ abstract class Schema implements ArrayAccess { /** * créer le cas échéant une nouvelle instance de {@link Schema} à partir d'une @@ -253,6 +276,8 @@ abstract class Schema implements ArrayAccess { /** retourner true si le schéma est de nature scalaire */ function isScalar(?ScalarSchema &$schema=null): bool { return false; } + abstract protected function newWrapper(): Wrapper; + abstract function getWrapper(&$value=null, $valueKey=null, ?Wrapper &$wrapper=null): Wrapper; ############################################################################# @@ -272,7 +297,15 @@ abstract class Schema implements ArrayAccess { throw AccessException::read_only(null, $offset); } - const _PROPERTY_PKEYS = []; + const _PROPERTY_PKEYS = [ + "analyzerFunc" => "analyzer_func", + "extractorFunc" => "extractor_func", + "parserFunc" => "parser_func", + "normalizerFunc" => "normalizer_func", + "formatterFunc" => "formatter_func", + "nature" => ["", 0], + ]; + function __get($name) { $pkey = cl::get(static::_PROPERTY_PKEYS, $name, $name); return cl::pget($this->definition, $pkey); diff --git a/src/schema/TODO.md b/src/schema/TODO.md index 5f50801..46e80ce 100644 --- a/src/schema/TODO.md +++ b/src/schema/TODO.md @@ -1,6 +1,5 @@ # nulib\schema -* instance de WrapperContext directement dans le schéma * plus de {key} ni {orig} dans messages * les messages standard ne sont utilisés que s'il n'y a pas de message dans l'exception diff --git a/src/schema/WrapperContext.php b/src/schema/WrapperContext.php index 5ee0d37..071ed7b 100644 --- a/src/schema/WrapperContext.php +++ b/src/schema/WrapperContext.php @@ -5,26 +5,31 @@ use nur\sery\wip\schema\input\Input; use nur\sery\wip\schema\types\IType; class WrapperContext { - function __construct(Schema $schema, Wrapper $wrapper, Input $input, $valueKey, Result $result) { + function __construct(Schema $schema, Wrapper $wrapper, ?Input $input, $valueKey, Result $result) { $this->schema = $schema; $this->wrapper = $wrapper; - $this->input = $input; - $this->result = $result; + if ($input !== null) $this->input = $input; + $this->valueKey = $valueKey; $this->type = null; + $this->result = $result; $this->origValue = null; $this->value = null; - $this->valueKey = $valueKey; } + /** schéma de la valeur */ public Schema $schema; + /** instance de Wrapper associé à ce contexte */ public Wrapper $wrapper; + /** source et destination de la valeur */ public Input $input; - public Result $result; + /** @var string|int|null clé de la valeur dans le tableau destination */ + public $valueKey; + /** type de la valeur après analyse */ public ?IType $type; + /** résultat de l'analyse de la valeur */ + public Result $result; /** @var mixed */ public $origValue; /** @var mixed */ public $value; - /** @var int|string|null */ - public $valueKey; } diff --git a/src/schema/_scalar/ScalarSchema.php b/src/schema/_scalar/ScalarSchema.php index a4c11bf..44e2ac5 100644 --- a/src/schema/_scalar/ScalarSchema.php +++ b/src/schema/_scalar/ScalarSchema.php @@ -8,26 +8,6 @@ use nur\sery\wip\schema\Wrapper; /** * Class ScalarSchema - * - * @property-read array|IType $type - * @property-read mixed $default - * @property-read string|null $title - * @property-read bool $required - * @property-read bool $nullable - * @property-read string|array|null $desc - * @property-read callable|null $analyzerFunc - * @property-read callable|null $extractorFunc - * @property-read callable|null $parserFunc - * @property-read callable|null $normalizerFunc - * @property-read array|null $messages - * @property-read callable|null $formatterFunc - * @property-read mixed $format - * @property-read array $nature - * @property-read array|null $schema - * @property-read string|int|null $name - * @property-read string|array|null $pkey - * @property-read string|null $header - * @property-read bool|null $composite */ class ScalarSchema extends Schema { /** @var array meta-schema d'un schéma de nature scalaire */ @@ -97,16 +77,4 @@ class ScalarSchema extends Schema { if (!($wrapper instanceof ScalarWrapper)) $wrapper = $this->newWrapper(); return $wrapper->reset($value, $valueKey, $verifix); } - - ############################################################################# - # key & properties - - const _PROPERTY_PKEYS = [ - "analyzerFunc" => "analyzer_func", - "extractorFunc" => "extractor_func", - "parserFunc" => "parser_func", - "normalizerFunc" => "normalizer_func", - "formatterFunc" => "formatter_func", - "nature" => ["", 0], - ]; } diff --git a/src/schema/_scalar/ScalarWrapper.php b/src/schema/_scalar/ScalarWrapper.php index 0ea9596..5bcb847 100644 --- a/src/schema/_scalar/ScalarWrapper.php +++ b/src/schema/_scalar/ScalarWrapper.php @@ -19,35 +19,21 @@ class ScalarWrapper extends Wrapper { # c'est une initialisation sans conséquences $throw = true; } + $this->context = new WrapperContext($schema, $this, null, null, new ScalarResult()); $this->verifix = $verifix; $this->throw = $throw ?? false; - $this->schema = $schema; - $this->result = new ScalarResult(); $this->reset($value, $valueKey); $this->throw = $throw ?? true; } function isScalar(?ScalarWrapper &$wrapper=null): bool { $wrapper = $this; return true; } + protected WrapperContext $context; + protected bool $verifix; protected bool $throw; - /** schéma de cette valeur */ - protected ScalarSchema $schema; - - /** source et destination de la valeur */ - protected Input $input; - - /** @var string|int|null clé de la valeur dans le tableau destination */ - protected $valueKey; - - /** type de la valeur après analyse */ - protected ?IType $type; - - /** résultat de l'analyse de la valeur */ - protected ScalarResult $result; - protected function newInput(&$value): Input { return new Input($value); } @@ -55,9 +41,9 @@ class ScalarWrapper extends Wrapper { function reset(&$value, $valueKey=null, ?bool $verifix=null): Wrapper { if ($value instanceof Input) $input = $value; else $input = $this->newInput($value); - $this->input = $input; - $this->valueKey = $valueKey; - $this->type = null; + $this->context->input = $input; + $this->context->valueKey = $valueKey; + $this->context->type = null; $this->analyze(); if ($verifix ?? $this->verifix) $this->verifix(); return $this; @@ -74,7 +60,8 @@ class ScalarWrapper extends Wrapper { } /** analyser la valeur et résoudre son type */ - protected function analyze0(WrapperContext $context): int { + protected function analyze0(): int { + $context = $this->context; /** @var ScalarSchema $schema */ $schema = $context->schema; $input = $context->input; @@ -112,7 +99,7 @@ class ScalarWrapper extends Wrapper { $args = $name; $name = $key; } - $type = types::get($schema->nullable, $name, $args, $this->schema->getDefinition()); + $type = types::get($schema->nullable, $name, $args, $schema->getDefinition()); if ($firstType === null) $firstType = $type; $types[] = $type; if ($type->isAvailable($input, $valueKey)) { @@ -166,17 +153,19 @@ class ScalarWrapper extends Wrapper { } protected function analyze(): int { - $schema = $this->schema; - $input = $this->input; - $valueKey = $this->valueKey; - $result = $this->result; + $context = $this->context; + /** @var ScalarSchema $schema */ + $schema = $context->schema; + $input = $context->input; + $valueKey = $context->valueKey; + /** @var ScalarResult $result */ + $result = $context->result; $result->reset(); - $context = new WrapperContext($schema, $this, $input, $valueKey, $result); /** @var func $analyzerFunc */ $analyzerFunc = $schema->analyzerFunc; if ($analyzerFunc !== null) $what = $analyzerFunc->invoke([$context]); - else $what = $this->analyze0($context); + else $what = $this->analyze0(); if ($what !== ref_analyze::STRING) return $what; $value = $context->value; @@ -212,20 +201,27 @@ class ScalarWrapper extends Wrapper { } function verifix(?bool $throw=null): bool { - $result = $this->result; - $valueKey = $this->valueKey; + $context = $this->context; + /** @var ScalarSchema $schema */ + $schema = $context->schema; + $input = $context->input; + $valueKey = $context->valueKey; + /** @var ScalarResult $result */ + $result = $context->result; + + $verifix = false; $modified = false; if ($result->resultAvailable) { if ($result->null) { # forcer la valeur null, parce que la valeur actuelle est peut-être une # valeur assimilée à null - $this->input->set(null, $valueKey); + $input->set(null, $valueKey); } elseif ($result->valid && !$result->normalized) { $normalizedValue = $result->normalizedValue; if ($normalizedValue !== null) { # la valeur normalisée est disponible - $this->input->set($normalizedValue); + $input->set($normalizedValue); $result->normalizedValue = null; $modified = true; } else { @@ -238,75 +234,80 @@ class ScalarWrapper extends Wrapper { } if ($verifix) { - $value = $this->input->get($valueKey); - $schema = $this->schema; + $value = $input->get($valueKey); /** @var func $normalizerFunc */ $normalizerFunc = $schema->normalizerFunc; if ($normalizerFunc !== null) { - $context = new WrapperContext($schema, $this, $this->input, $valueKey, $result); + $context = new WrapperContext($schema, $this, $input, $valueKey, $result); $orig = $value; $value = $normalizerFunc->invoke([$orig, $context]); $modified = $value !== $orig; } else { - $modified = $this->type->verifix($value, $result, $this->schema); + $modified = $this->type->verifix($value, $result, $schema); } - if ($result->valid) $this->input->set($value, $valueKey); + if ($result->valid) $input->set($value, $valueKey); } if (!$result->valid) $result->throw($throw ?? $this->throw); return $modified; } function getResult(): ScalarResult { - return $this->result; + /** @var ScalarResult $result */ + $result = $this->context->result; + return $result; } function isPresent(): bool { - return $this->result->present; + return $this->context->result->present; } function getType(): IType { - return $this->type; + return $this->context->type; } function isAvailable(): bool { - return $this->result->available; + return $this->context->result->available; } function isValid(): bool { - return $this->result->valid; + return $this->context->result->valid; } function isNormalized(): bool { - return $this->result->normalized; + return $this->context->result->normalized; } function get($default=null) { - if ($this->result->available) return $this->input->get($this->valueKey); + $context = $this->context; + if ($context->result->available) return $context->input->get($context->valueKey); else return $default; } function set($value, ?bool $verifix=null): ScalarWrapper { - $this->input->set($value, $this->valueKey); + $context = $this->context; + $context->input->set($value, $context->valueKey); $this->analyze(); if ($verifix ?? $this->verifix) $this->verifix(); return $this; } function unset(?bool $verifix=null): ScalarWrapper { - $this->input->unset($this->valueKey); + $context = $this->context; + $context->input->unset($context->valueKey); $this->analyze(); if ($verifix ?? $this->verifix) $this->verifix(); return $this; } function format($format=null): string { - $value = $this->input->get($this->valueKey); + $context = $this->context; + $value = $context->input->get($context->valueKey); /** @var func $formatterFunc */ - $formatterFunc = $this->schema->formatterFunc; + $formatterFunc = $context->schema->formatterFunc; if ($formatterFunc !== null) { # la fonction formatter n'a pas forcément accès au format de la définition # le lui fournir ici - $format ??= $this->schema->format; + $format ??= $context->schema->format; return $formatterFunc->invoke([$value, $format]); } else { # on assume que le type a été initialisé avec le format de la définition