modifs.mineures sans commentaires

This commit is contained in:
Jephté Clain 2025-03-18 13:30:02 +04:00
parent 91e6c0dcd2
commit 189c7aba68
13 changed files with 206 additions and 131 deletions

View File

@ -269,6 +269,13 @@ abstract class Schema implements ArrayAccess {
return $this->_definition;
}
/**
* retourner la liste des clés valides pour l'accès aux valeurs et résultats
*/
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 */

View File

@ -1,15 +1,12 @@
# nulib\schema
* 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
* si instance de UserException, prendre le message "non technique" pour
résultat
* valeurs composite/computed
* analyse / vérification de la valeur complète après calcul du résultat, si
tous les résultats sont bons
* calcul des valeurs composites/computed par une fonction avant/après l'analyse
globale si résultat ok
* fonction getter_func, setter_func, deleter_func pour les propriétés de type
computed
* tdate et tdatetime. qu'en est-il des autres classes (delay, etc.)
* possibilité de spécifier le format de la date à analyser
* ScalarSchema::from_property()

View File

@ -3,6 +3,7 @@ namespace nur\sery\wip\schema;
use ArrayAccess;
use IteratorAggregate;
use nulib\php\func;
use nur\sery\wip\schema\_assoc\AssocWrapper;
use nur\sery\wip\schema\_list\ListWrapper;
use nur\sery\wip\schema\_scalar\ScalarWrapper;
@ -67,6 +68,22 @@ abstract class Wrapper implements ArrayAccess, IteratorAggregate {
/** supprimer la valeur */
abstract function unset(): self;
protected function _format(WrapperContext $context, $format=null): string {
$value = $context->input->get($context->valueKey);
/** @var func $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 ??= $context->schema->format;
return $formatterFunc->invoke([$value, $format, $context, $this]);
} else {
# on assume que le type a été initialisé avec le format de la définition
# le cas échéant
return $context->type->format($value, $format);
}
}
/** formatter la valeur pour affichage */
abstract function format($format=null): string;

View File

@ -5,21 +5,29 @@ 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, ?Input $input, $valueKey, ?Result $result, ?array $params) {
$this->params = $params;
$this->verifix = $params["verifix"] ?? true;
$this->throw = $params["throw"] ?? null;
$this->schema = $schema;
$this->wrapper = $wrapper;
//$this->wrapper = $wrapper;
if ($input !== null) $this->input = $input;
$this->valueKey = $valueKey;
$this->type = null;
$this->result = $result;
if ($result !== null) $this->result = $result;
$this->origValue = null;
$this->value = null;
}
public ?array $params;
public bool $verifix;
public ?bool $throw;
/** schéma de la valeur */
public Schema $schema;
/** instance de Wrapper associé à ce contexte */
public Wrapper $wrapper;
//public Wrapper $wrapper;
/** source et destination de la valeur */
public Input $input;
/** @var string|int|null clé de la valeur dans le tableau destination */

View File

@ -5,41 +5,38 @@ use nulib\ValueException;
use nur\sery\wip\schema\Result;
class AssocResult extends Result {
function __construct(Result $arrayResult, array &$keyResults) {
$this->arrayResult = $arrayResult;
$this->keyResults =& $keyResults;
$this->result =& $this->arrayResult;
function __construct(AssocWrapperContext $context) {
$this->context = $context;
parent::__construct();
}
function isAssoc(?AssocResult &$result=null): bool { $result = $this; return true;}
protected Result $arrayResult;
/** @var Result[] */
protected array $keyResults;
protected AssocWrapperContext $context;
function getKeys(): array {
return array_keys($this->keyResults);
return $this->context->keys;
}
protected Result $result;
function select($key): Result {
function select($key): AssocResult {
$context = $this->context;
if ($key === null) {
$this->result =& $this->arrayResult;
} elseif (array_key_exists($key, $this->keyResults)) {
$this->result =& $this->keyResults[$key];
} else {
throw ValueException::invalid_key($key);
$this->result = $context->arrayResult;
return $this;
}
$wrapper = $context->keyWrappers[$key] ?? null;
if ($wrapper === null) throw ValueException::invalid_key($key);
$this->result = $wrapper->getResult();
return $this;
}
function reset(): void {
$this->arrayResult->reset();
foreach ($this->keyResults as $result) {
$result->reset();
$context = $this->context;
$context->arrayResult->reset();
foreach ($context->keyWrappers as $wrapper) {
$wrapper->getResult()->reset();
}
}

View File

@ -3,6 +3,8 @@ namespace nur\sery\wip\schema\_assoc;
use nulib\cl;
use nulib\ref\schema\ref_schema;
use nulib\ValueException;
use nur\sery\wip\schema\_scalar\ScalarWrapper;
use nur\sery\wip\schema\Schema;
use nur\sery\wip\schema\Wrapper;
@ -50,6 +52,11 @@ class AssocSchema extends Schema {
self::_ensure_schema_instances($definition);
}
$this->definition = $definition;
$keys = [];
foreach ($definition["schema"] as $key => $schema) {
if (!$schema["computed"]) $keys[] = $key;
}
$this->keys = $keys;
}
function isAssoc(?AssocSchema &$schema=null): bool {
@ -57,12 +64,28 @@ class AssocSchema extends Schema {
return true;
}
protected array $keys;
function getKeys(): array {
return $this->keys;
}
function getSchema($key): Schema {
if ($key === null) return $this;
$schema = $this->definition["schema"][$key] ?? null;
if ($schema === null) throw ValueException::invalid_key($key);
return $schema;
}
protected function newWrapper(): AssocWrapper {
return new AssocWrapper($this);
}
function getWrapper(&$array=null, $arrayKey=null, ?Wrapper &$wrapper=null): AssocWrapper {
# si pas de valeur ni de wrapper, pas de vérification et donc pas d'exception
# cf le code similaire dans ScalarWrapper::__construct()
$verifix = $array !== null || $wrapper !== null;
if (!($wrapper instanceof AssocWrapper)) $wrapper = $this->newWrapper();
return $wrapper->reset($array, $arrayKey);
return $wrapper->reset($array, $arrayKey, $verifix);
}
}

View File

@ -3,59 +3,43 @@ namespace nur\sery\wip\schema\_assoc;
use nulib\ValueException;
use nur\sery\wip\schema\_scalar\ScalarResult;
use nur\sery\wip\schema\_scalar\ScalarWrapper;
use nur\sery\wip\schema\input\Input;
use nur\sery\wip\schema\Result;
use nur\sery\wip\schema\types\IType;
use nur\sery\wip\schema\Wrapper;
use nur\sery\wip\schema\WrapperContext;
class AssocWrapper extends Wrapper {
function __construct(AssocSchema $schema, &$array=null, $arrayKey=null, ?array $params=null) {
$verifix = $params["verifix"] ?? true;
$throw = $params["throw"] ?? null;
$definitionSchema = $schema->getDefinition()["schema"];
$keys = $schema->getKeys();
$keyTypes = [];
$keyWrappers = [];
foreach ($keys as $key) {
$keyTypes[$key] = null;
$keyWrappers[$key] = $schema->getSchema($key)->getWrapper();
}
$this->context = $context = new AssocWrapperContext($schema, null, null, null, $params);
$context->arrayResult = new ScalarResult();
$context->keys = $keys;
$context->keyTypes = $keyTypes;
$context->keyWrappers = $keyWrappers;
$context->result = new AssocResult($context);
$throw = $context->throw;
if ($array !== null && $throw === null) {
# Si $value est null, ne pas lancer d'exception, parce qu'on considère que
# c'est une initialisation sans conséquences
$throw = true;
}
$this->schema = $schema;
$this->verifix = $verifix;
$this->throw = $throw ?? false;
$this->result = new AssocResult();
$context->throw = $throw ?? false;
$this->reset($array, $arrayKey);
$this->throw = $throw ?? true;
$context->throw = $throw ?? true;
}
function isAssoc(?AssocWrapper &$wrapper=null): bool { $wrapper = $this; return true; }
protected bool $verifix;
protected bool $throw;
/** schéma de ce tableau */
protected AssocSchema $schema;
/** source et destination de la valeur */
protected Input $input;
/** @var string|int|null clé du tableau dans le tableau destination */
protected $arrayKey;
protected IType $arrayType;
protected ScalarResult $arrayResult;
/** @var IType[] */
protected array $keyTypes;
/** @var Result[] */
protected array $keyResults;
protected AssocResult $result;
protected ?array $keys;
protected ?array $wrappers;
/** @var AssocWrapperContext */
protected WrapperContext $context;
protected function newInput(&$value): Input {
return new Input($value);
@ -64,73 +48,84 @@ class AssocWrapper extends Wrapper {
function reset(&$array, $arrayKey=null, ?bool $verifix=null): Wrapper {
if ($array instanceof Input) $input = $array;
else $input = $this->newInput($array);
$this->input = $input;
$this->arrayKey = $arrayKey;
$context = $this->context;
$context->input = $input;
$context->valueKey = $arrayKey;
$this->analyze();
if ($verifix ?? $this->verifix) $this->verifix();
if ($verifix ?? $context->verifix) $this->verifix();
return $this;
}
function getKeys(): array {
return $this->keys;
return $this->context->keys;
}
function select($key=null): ScalarWrapper {
$wrapper = $this->wrappers[$key] ?? null;
if ($key !== null) return $wrapper;
throw ValueException::invalid_key($key);
/** @param string|int|null $key */
function select($key=null): Wrapper {
if ($key === null) return $this;
$wrapper = $this->context->keyWrappers[$key] ?? null;
if ($wrapper === null) throw ValueException::invalid_key($key);
return $wrapper;
}
/** @param Result[] $results */
function verifix(?bool $throw=null, ?array &$results=null): bool {
protected function analyze(): int {
return 0; #XXX
}
function verifix(?bool $throw=null): bool {
return false; #XXX
}
function getResult(): AssocResult {
return $this->result;
/** @var AssocResult $result */
$result = $this->context->result;
return $result;
}
function isPresent(): bool {
return $this->result->present;
return $this->context->result->present;
}
function getType(): IType {
return $this->arrayType;
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->arrayKey);
$context = $this->context;
if ($context->result->available) return $context->input->get($context->valueKey);
else return $default;
}
function set($value, ?bool $verifix=null): AssocWrapper {
$this->input->set($value, $this->arrayKey);
$context = $this->context;
$context->input->set($value, $context->valueKey);
$this->analyze();
if ($verifix ?? $this->verifix) $this->verifix();
if ($verifix ?? $context->verifix) $this->verifix();
return $this;
}
function unset(?bool $verifix=null): AssocWrapper {
$this->input->unset($this->arrayKey);
$context = $this->context;
$context->input->unset($context->valueKey);
$this->analyze();
if ($verifix ?? $this->verifix) $this->verifix();
if ($verifix ?? $context->verifix) $this->verifix();
return $this;
}
function format($format = null): string {
// TODO: Implement format() method.
return $this->_format($this->context, $format);
}
function ensureKeys(): bool {

View File

@ -0,0 +1,21 @@
<?php
namespace nur\sery\wip\schema\_assoc;
use nur\sery\wip\schema\_scalar\ScalarResult;
use nur\sery\wip\schema\types\IType;
use nur\sery\wip\schema\Wrapper;
use nur\sery\wip\schema\WrapperContext;
class AssocWrapperContext extends WrapperContext {
/** résultat de l'analyse du tableau */
public ScalarResult $arrayResult;
/** liste des clés valides */
public array $keys;
/** @var ?IType[] */
public array $keyTypes;
/** @var Wrapper[] */
public array $keyWrappers;
}

View File

@ -2,6 +2,7 @@
namespace nur\sery\wip\schema\_list;
use nulib\ref\schema\ref_schema;
use nulib\ValueException;
use nur\sery\wip\schema\Schema;
use nur\sery\wip\schema\Wrapper;
@ -55,12 +56,26 @@ class ListSchema extends Schema {
return true;
}
const KEYS = [null];
function getKeys(): array {
return self::KEYS;
}
public function getSchema($key): Schema {
if ($key !== null) throw ValueException::invalid_key($key);
return $this;
}
protected function newWrapper(): ListWrapper {
return new ListWrapper($this);
}
function getWrapper(&$value=null, $valueKey=null, ?Wrapper &$wrapper=null): ListWrapper {
# si pas de valeur ni de wrapper, pas de vérification et donc pas d'exception
# cf le code similaire dans ScalarWrapper::__construct()
$verifix = $value !== null || $wrapper !== null;
if (!($wrapper instanceof ListWrapper)) $wrapper = $this->newWrapper();
return $wrapper->reset($value, $valueKey);
return $wrapper->reset($value, $valueKey, $verifix);
}
}

View File

@ -15,7 +15,7 @@ class ScalarResult extends Result {
function isScalar(?ScalarResult &$result=null): bool { $result = $this; return true; }
function getKeys(): array {
return [null];
return ScalarSchema::KEYS;
}
function select($key): Result {
@ -23,8 +23,7 @@ class ScalarResult extends Result {
return $this;
}
/** @var array */
protected $result;
protected array $result;
function reset(): void {
$this->result = array_merge(

View File

@ -2,6 +2,7 @@
namespace nur\sery\wip\schema\_scalar;
use nulib\ref\schema\ref_schema;
use nulib\ValueException;
use nur\sery\wip\schema\Schema;
use nur\sery\wip\schema\types\IType;
use nur\sery\wip\schema\Wrapper;
@ -66,6 +67,17 @@ class ScalarSchema extends Schema {
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;
}
protected function newWrapper(): ScalarWrapper {
return new ScalarWrapper($this);
}

View File

@ -12,28 +12,23 @@ use nur\sery\wip\schema\Wrapper;
class ScalarWrapper extends Wrapper {
function __construct(ScalarSchema $schema, &$value=null, $valueKey=null, ?array $params=null) {
$verifix = $params["verifix"] ?? true;
$throw = $params["throw"] ?? null;
$this->context = $context = new WrapperContext($schema, null, null, new ScalarResult(), $params);
$throw = $context->throw;
if ($value !== null && $throw === null) {
# Si $value est null, ne pas lancer d'exception, parce qu'on considère que
# 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;
$context->throw = $throw ?? false;
$this->reset($value, $valueKey);
$this->throw = $throw ?? true;
$context->throw = $throw ?? true;
}
function isScalar(?ScalarWrapper &$wrapper=null): bool { $wrapper = $this; return true; }
protected WrapperContext $context;
protected bool $verifix;
protected bool $throw;
protected function newInput(&$value): Input {
return new Input($value);
}
@ -41,16 +36,17 @@ 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->context->input = $input;
$this->context->valueKey = $valueKey;
$this->context->type = null;
$context = $this->context;
$context->input = $input;
$context->valueKey = $valueKey;
$context->type = null;
$this->analyze();
if ($verifix ?? $this->verifix) $this->verifix();
if ($verifix ?? $context->verifix) $this->verifix();
return $this;
}
function getKeys(): array {
return [null];
return ScalarSchema::KEYS;
}
/** @param string|int|null $key */
@ -164,7 +160,7 @@ class ScalarWrapper extends Wrapper {
/** @var func $analyzerFunc */
$analyzerFunc = $schema->analyzerFunc;
if ($analyzerFunc !== null) $what = $analyzerFunc->invoke([$context]);
if ($analyzerFunc !== null) $what = $analyzerFunc->invoke([$context, $this]);
else $what = $this->analyze0();
if ($what !== ref_analyze::STRING) return $what;
@ -172,7 +168,7 @@ class ScalarWrapper extends Wrapper {
try {
/** @var func $extractorFunc */
$extractorFunc = $schema->extractorFunc;
if ($extractorFunc !== null) $extracted = $extractorFunc->invoke([$value, $context]);
if ($extractorFunc !== null) $extracted = $extractorFunc->invoke([$value, $context, $this]);
else $extracted = $context->type->extract($value);
$context->value = $extracted;
} catch (ValueException $e) {
@ -183,7 +179,7 @@ class ScalarWrapper extends Wrapper {
try {
/** @var func $parserFunc */
$parserFunc = $schema->parserFunc;
if ($parserFunc !== null) $parsed = $parserFunc->invoke([$extracted, $context]);
if ($parserFunc !== null) $parsed = $parserFunc->invoke([$extracted, $context, $this]);
else $parsed = $context->type->parse($extracted);
$context->value = $parsed;
} catch (ValueException $e) {
@ -209,7 +205,6 @@ class ScalarWrapper extends Wrapper {
/** @var ScalarResult $result */
$result = $context->result;
$verifix = false;
$modified = false;
if ($result->resultAvailable) {
@ -238,16 +233,15 @@ class ScalarWrapper extends Wrapper {
/** @var func $normalizerFunc */
$normalizerFunc = $schema->normalizerFunc;
if ($normalizerFunc !== null) {
$context = new WrapperContext($schema, $this, $input, $valueKey, $result);
$orig = $value;
$value = $normalizerFunc->invoke([$orig, $context]);
$value = $normalizerFunc->invoke([$orig, $context, $this]);
$modified = $value !== $orig;
} else {
$modified = $this->type->verifix($value, $result, $schema);
$modified = $context->type->verifix($value, $result, $schema);
}
if ($result->valid) $input->set($value, $valueKey);
}
if (!$result->valid) $result->throw($throw ?? $this->throw);
if (!$result->valid) $result->throw($throw ?? $context->throw);
return $modified;
}
@ -287,7 +281,7 @@ class ScalarWrapper extends Wrapper {
$context = $this->context;
$context->input->set($value, $context->valueKey);
$this->analyze();
if ($verifix ?? $this->verifix) $this->verifix();
if ($verifix ?? $context->verifix) $this->verifix();
return $this;
}
@ -295,24 +289,11 @@ class ScalarWrapper extends Wrapper {
$context = $this->context;
$context->input->unset($context->valueKey);
$this->analyze();
if ($verifix ?? $this->verifix) $this->verifix();
if ($verifix ?? $context->verifix) $this->verifix();
return $this;
}
function format($format=null): string {
$context = $this->context;
$value = $context->input->get($context->valueKey);
/** @var func $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 ??= $context->schema->format;
return $formatterFunc->invoke([$value, $format]);
} else {
# on assume que le type a été initialisé avec le format de la définition
# le cas échéant
return $this->type->format($value, $format);
}
return $this->_format($this->context, $format);
}
}

View File

@ -90,6 +90,9 @@ class AssocSchemaTest extends TestCase {
"name" => "c", "pkey" => "c", "header" => "c",
],
]), $schema->getDefinition());
yaml::dump($schema->getDefinition());
//yaml::dump($schema->getDefinition());
$wrapper = $schema->getWrapper();
$wrapper->getKeys();
}
}