modifs.mineures sans commentaires

This commit is contained in:
Jephté Clain 2025-03-06 11:26:59 +04:00
parent f8eec57055
commit a705dd61c4
10 changed files with 157 additions and 97 deletions

View File

@ -1,14 +1,19 @@
# nulib\schema
* dans la définition, `[type]` est remplacé par l'instance de IType lors de sa
résolution? --> NON, sauf si c'est un type union
* newInput dans Schema
* ScalarSchema::from_property()
* dans AssocSchema, support `[key_prefix]` qui permet de spécifier un préfixe
commun aux champs dans le tableau destination, e.g
~~~php
$value = Schema::ns($schema, [
$wrapper = Schema::ns($schema, [
"a" => "?string",
"b" => "?int",
])->newValue();
])->newWrapper();
$dest = ["x_a" => 5, "x_b" => "10"],
$value->reset($dest, null, [
$wrapper->reset($dest, null, [
"key_prefix" => "x_",
]);
# $dest vaut ["x_a" => "5", "x_b" => 10];
@ -19,18 +24,16 @@
alternative: c'est lors de la *définition* du schéma que le préfixe est ajouté
e.g
~~~php
$value = Schema::ns($schema, [
$wrapper = Schema::ns($schema, [
"a" => "?string",
"b" => "?int",
], [
"key_prefix" => "x_",
])->newValue();
])->newWrapper();
$dest = ["x_a" => 5, "x_b" => "10"],
$value->reset($dest);
$wrapper->reset($dest);
# $dest vaut ["x_a" => "5", "x_b" => 10];
~~~
* dans la définition, `[type]` est remplacé par l'instance de IType lors de sa
résolution?
* implémenter l'instanciation de types avec des paramètres particuliers. *si*
des paramètres sont fournis, le type est instancié avec la signature
`IType($typeDefinition, $schemaDefinition)` e.g

View File

@ -1,11 +1,13 @@
<?php
namespace nur\sery\wip\schema\_scalar;
use Exception;
use nulib\cl;
use nulib\ref\schema\ref_analyze;
use nulib\ref\schema\ref_schema;
use nulib\ValueException;
use nur\sery\wip\schema\Result;
use Throwable;
/**
* Class ScalarResult: résultat de l'analyse ou de la normalisation d'une valeur
@ -16,12 +18,20 @@ use nur\sery\wip\schema\Result;
* @property bool $null si la valeur est disponible, est-elle nulle?
* @property bool $valid si la valeur est disponible, est-elle valide?
* @property bool $normalized si la valeur est valide, est-elle normalisée?
* @property string|null $orig valeur originale avant extraction et analyse
* @property string|null $messageKey clé de message si la valeur n'est pas valide
* @property string|null $message message si la valeur n'est pas valide
* @property string|null $origValue valeur originale avant extraction et analyse
* @property mixed|null $normalizedValue la valeur normalisée si elle est
* disponible, null sinon. ce champ est utilisé comme optimisation si la valeur
* normalisée a déjà été calculée
*/
class ScalarResult extends Result {
const KEYS = ["resultAvailable", "present", "available", "null", "valid", "normalized", "orig", "messageKey", "message"];
const KEYS = [
"resultAvailable",
"present", "available", "null", "valid", "normalized",
"messageKey", "message",
"origValue", "normalizedValue",
];
function isScalar(?ScalarResult &$scalar=null): bool { $scalar = $this; return true; }
@ -66,8 +76,8 @@ class ScalarResult extends Result {
}
}
protected static function replace_orig(string &$message, $orig): void {
$message = str_replace("{orig}", strval($orig), $message);
protected static function replace_orig(string &$message, $origValue): void {
$message = str_replace("{orig}", strval($origValue), $message);
}
protected function getMessage(string $key, ScalarSchema $schema): string {
@ -130,27 +140,32 @@ class ScalarResult extends Result {
}
}
function setInvalid($value, ScalarSchema $schema): int {
function setInvalid($value, ScalarSchema $schema, ?Throwable $t=null): int {
$this->resultAvailable = true;
$this->present = true;
$this->available = true;
$this->null = false;
$this->valid = false;
$this->orig = $value;
$this->origValue = $value;
$messageKey = $this->messageKey = "invalid";
$message = $this->getMessage($messageKey, $schema);
self::replace_key($message, $schema->name);
self::replace_orig($message, $schema->orig);
if ($t !== null) {
$tmessage = ValueException::get_message($t);
if ($tmessage) $message .= ": $tmessage";
}
$this->message = $message;
return ref_analyze::INVALID;
}
function setValid(): int {
function setValid($normalizedValue=null): int {
$this->resultAvailable = true;
$this->present = true;
$this->available = true;
$this->null = false;
$this->valid = true;
$this->normalizedValue = $normalizedValue;
return ref_analyze::VALID;
}

View File

@ -9,22 +9,23 @@ use nur\sery\wip\schema\input\Input;
use nur\sery\wip\schema\types;
use nur\sery\wip\schema\types\IType;
use nur\sery\wip\schema\Wrapper;
use PHPUnit\Event\Code\Throwable;
class ScalarWrapper extends Wrapper {
function __construct(ScalarSchema $schema, &$dest=null, $destKey=null, ?array $params=null) {
$defaultVerifix = $params["verifix"] ?? true;
$defaultThrow = $params["throw"] ?? null;
if ($dest !== null && $defaultThrow === null) {
$verifix = $params["verifix"] ?? true;
$throw = $params["throw"] ?? null;
if ($dest !== null && $throw === null) {
# Si $dest est null, ne pas lancer d'exception, parce qu'on considère que
# c'est une initialisation sans conséquences
$defaultThrow = true;
$throw = true;
}
$this->schema = $schema;
$this->verifix = $defaultVerifix;
$this->throw = $defaultThrow ?? false;
$this->verifix = $verifix;
$this->throw = $throw ?? false;
$this->result = new ScalarResult();
$this->reset($dest, $destKey);
$this->throw = $defaultThrow ?? true;
$this->throw = $throw ?? true;
}
function isScalar(?ScalarWrapper &$scalar=null): bool { $scalar = $this; return true; }
@ -137,19 +138,6 @@ class ScalarWrapper extends Wrapper {
}
}
function _extract(AnalyzerContext $context): bool {
return $context->type->extract($context->dest);
}
function _parse(AnalyzerContext $context): bool {
try {
$context->dest = $context->type->parse($context->dest);
return true;
} catch (ValueException $e) {
return false;
}
}
function analyzeExtractParse(): int {
$schema = $this->schema;
$input = $this->input;
@ -164,42 +152,41 @@ class ScalarWrapper extends Wrapper {
else $what = $this->_analyze($context);
if ($what !== ref_analyze::STRING) return $what;
/** @var func $extractorFunc */
$extractorFunc = $schema->extractorFunc;
if ($extractorFunc !== null) $valid = $extractorFunc->invoke([$context]);
else $valid = $this->_extract($context);
if (!$valid) return $result->setInvalid($context->orig, $schema);
if ($context->type->isNull($context->dest)) return $result->setNull($schema);
$extracted = $context->dest;
/** @var func $parserFunc */
$parserFunc = $schema->parserFunc;
if ($parserFunc !== null) $valid = $parserFunc->invoke([$context]);
else $valid = $this->_parse($context);
if ($valid) {
$normalized = $context->dest === $context->orig;
if ($normalized) {
$input->set($context->dest, $destKey);
return $result->setNormalized();
} else {
$input->set($extracted, $destKey);
return $result->setValid();
}
$dest = $context->dest;
try {
/** @var func $extractorFunc */
$extractorFunc = $schema->extractorFunc;
if ($extractorFunc !== null) $extracted = $extractorFunc->invoke([$dest, $context]);
else $extracted = $context->type->extract($dest);
$context->dest = $extracted;
} catch (ValueException $e) {
return $result->setInvalid($context->orig, $schema, $e);
}
if ($context->type->isNull($extracted)) return $result->setNull($schema);
try {
/** @var func $parserFunc */
$parserFunc = $schema->parserFunc;
if ($parserFunc !== null) $parsed = $parserFunc->invoke([$extracted, $context]);
else $parsed = $context->type->parse($extracted);
$context->dest = $parsed;
} catch (ValueException $e) {
return $result->setInvalid($context->orig, $schema, $e);
}
$normalized = $parsed === $context->orig;
if ($normalized) {
$input->set($parsed, $destKey);
return $result->setNormalized();
} else {
$input->set($extracted, $destKey);
return $result->setValid($parsed);
}
return $result->setInvalid($context->orig, $schema);
}
function verifix(?bool $throw=null): bool {
$schema = $this->schema;
$input = $this->input;
$destKey = $this->destKey;
$result = $this->result;
$context = new AnalyzerContext($schema, $this, $input, $destKey, $result);
/** @var func $normalizerFunc */
$normalizerFunc = $schema->normalizerFunc;
if ($normalizerFunc !== null) return $normalizerFunc->invoke([$context]);
if ($throw === null) $throw = $this->throw;
$destKey = $this->destKey;
$verifix = false;
$modified = false;
if ($result->resultAvailable) {
@ -208,18 +195,37 @@ class ScalarWrapper extends Wrapper {
# valeur assimilée à null
$this->input->set(null, $destKey);
} elseif ($result->valid && !$result->normalized) {
# normaliser la valeur
$verifix = true;
$normalizedValue = $result->normalizedValue;
if ($normalizedValue !== null) {
# la valeur normalisée est disponible
$this->input->set($normalizedValue);
$result->normalizedValue = null;
$modified = true;
} else {
# normaliser la valeur
$verifix = true;
}
}
} else {
$verifix = true;
}
if ($verifix) {
$value = $this->input->get($destKey);
$modified = $this->type->verifix($value, $result, $this->schema);
$schema = $this->schema;
/** @var func $normalizerFunc */
$normalizerFunc = $schema->normalizerFunc;
if ($normalizerFunc !== null) {
$context = new AnalyzerContext($schema, $this, $this->input, $destKey, $result);
$orig = $value;
$value = $normalizerFunc->invoke([$orig, $context]);
$modified = $value !== $orig;
} else {
$modified = $this->type->verifix($value, $result, $this->schema);
}
if ($result->valid) $this->input->set($value, $destKey);
}
if (!$result->valid) $result->throw($throw);
if (!$result->valid) $result->throw($throw ?? $this->throw);
return $modified;
}

View File

@ -24,8 +24,12 @@ interface IType {
*/
function isValid($value, ?bool &$normalized=null): bool;
/** extraire de la chaine la valeur à analyser */
function extract(string &$value): bool;
/**
* extraire de la chaine la valeur à analyser
*
* @throws ValueException en cas d'erreur d'analyse
*/
function extract(string $value): string;
/**
* analyser la chaine et retourner la valeur "convertie"

View File

@ -22,7 +22,7 @@ abstract class _tsimple implements IType {
return $value === null || $value === "";
}
function extract(string &$value): bool {
return true;
function extract(string $value): string {
return $value;
}
}

View File

@ -18,9 +18,9 @@ abstract class _tstring extends _tsimple {
return $params;
}
function extract(string &$value): bool {
function extract(string $value): string {
if ($this->params["trim"] ?? static::TRIM) $value = trim($value);
if ($this->params["norm_nl"] ?? static::NORM_NL) $value = str::norm_nl($value);
return true;
return $value;
}
}

View File

@ -60,9 +60,8 @@ class tbool extends _tformatable {
return is_scalar($value);
}
function extract(string &$value): bool {
$value = trim($value);
return true;
function extract(string $value): string {
return trim($value);
}
function parse(string $value) {

View File

@ -21,9 +21,8 @@ class tfloat extends _tformatable {
return is_scalar($value);
}
function extract(string &$value): bool {
$value = trim($value);
return true;
function extract(string $value): string {
return trim($value);
}
function parse(string $value) {

View File

@ -23,9 +23,8 @@ class tint extends _tformatable {
return is_scalar($value);
}
function extract(string &$value): bool {
$value = trim($value);
return true;
function extract(string $value): string {
return trim($value);
}
function parse(string $value) {

View File

@ -1,7 +1,6 @@
<?php
namespace nur\sery\wip\schema\_scalar;
use Exception;
use nulib\tests\TestCase;
use nulib\ValueException;
use nur\sery\wip\schema\input\Input;
@ -34,6 +33,9 @@ class ScalarValueTest extends TestCase {
function testRawstring() {
$schema = new ScalarSchema("rawstring");
$this->checkVerifix($schema, false, false, null, true, false, true, true);
$this->checkVerifix($schema, false, true, null, true, false, true, true);
$this->checkVerifix($schema, null, false, null, true, true, false, false);
$this->checkException($schema, null, true, ValueException::class);
@ -49,9 +51,6 @@ class ScalarValueTest extends TestCase {
$this->checkVerifix($schema, " text ", false, " text ", true, true, true, true);
$this->checkVerifix($schema, " text ", true, " text ", true, true, true, true);
$this->checkVerifix($schema, false, false, null, true, false, true, true);
$this->checkVerifix($schema, false, true, null, true, false, true, true);
$this->checkVerifix($schema, true, false, true, true, true, true, false);
$this->checkVerifix($schema, true, true, "1", true, true, true, false);
@ -95,6 +94,9 @@ class ScalarValueTest extends TestCase {
function testString() {
$schema = new ScalarSchema("string");
$this->checkVerifix($schema, false, false, null, true, false, true, true);
$this->checkVerifix($schema, false, true, null, true, false, true, true);
$this->checkVerifix($schema, null, false, null, true, true, false, false);
$this->checkException($schema, null, true, ValueException::class);
@ -102,16 +104,13 @@ class ScalarValueTest extends TestCase {
$this->checkVerifix($schema, "", true, "", true, true, true, true);
$this->checkVerifix($schema, " ", false, "", true, true, true, false);
$this->checkVerifix($schema, " ", true, "", true, true, true, true);
$this->checkVerifix($schema, " ", true, "", true, true, true, false);
$this->checkVerifix($schema, "text", false, "text", true, true, true, true);
$this->checkVerifix($schema, "text", true, "text", true, true, true, true);
$this->checkVerifix($schema, " text ", false, "text", true, true, true, false);
$this->checkVerifix($schema, " text ", true, "text", true, true, true, true);
$this->checkVerifix($schema, false, false, null, true, false, true, true);
$this->checkVerifix($schema, false, true, null, true, false, true, true);
$this->checkVerifix($schema, " text ", true, "text", true, true, true, false);
$this->checkVerifix($schema, true, false, true, true, true, true, false);
$this->checkVerifix($schema, true, true, "1", true, true, true, false);
@ -133,11 +132,32 @@ class ScalarValueTest extends TestCase {
$this->checkVerifix($schema, false, false, null, true, false, false, false);
$this->checkException($schema, false, true, ValueException::class);
## Tester allow_empty === false
$inputParams = ["allow_empty" => false];
$schema = new ScalarSchema("string");
$this->checkVerifix($schema, null, false, null, true, true, false, false, $inputParams);
$this->checkException($schema, null, true, ValueException::class, $inputParams);
$this->checkVerifix($schema, "", false, null, true, false, true, true, $inputParams);
$this->checkVerifix($schema, "", true, null, true, false, true, true, $inputParams);
$schema = new ScalarSchema("?string");
$this->checkVerifix($schema, null, false, null, true, true, true, true, $inputParams);
$this->checkVerifix($schema, null, true, null, true, true, true, true, $inputParams);
$this->checkVerifix($schema, "", false, null, true, false, true, true, $inputParams);
$this->checkVerifix($schema, "", true, null, true, false, true, true, $inputParams);
}
function testInt() {
$schema = new ScalarSchema("int");
$this->checkVerifix($schema, false, false, null, true, false, true, true);
$this->checkVerifix($schema, false, true, null, true, false, true, true);
$this->checkVerifix($schema, null, false, null, true, true, false, false);
$this->checkException($schema, null, true, ValueException::class);
@ -165,9 +185,6 @@ class ScalarValueTest extends TestCase {
$this->checkVerifix($schema, "text", false, "text", true, true, false, false);
$this->checkException($schema, "text", true, ValueException::class);
$this->checkVerifix($schema, false, false, null, true, false, true, true);
$this->checkVerifix($schema, false, true, null, true, false, true, true);
$this->checkVerifix($schema, true, false, true, true, true, true, false);
$this->checkVerifix($schema, true, true, 1, true, true, true, false);
@ -185,5 +202,23 @@ class ScalarValueTest extends TestCase {
$this->checkVerifix($schema, false, false, null, true, false, false, false);
$this->checkException($schema, false, true, ValueException::class);
## Tester allow_empty === false
$inputParams = ["allow_empty" => false];
$schema = new ScalarSchema("int");
$this->checkVerifix($schema, null, false, null, true, true, false, false, $inputParams);
$this->checkException($schema, null, true, ValueException::class, $inputParams);
$this->checkVerifix($schema, "", false, null, true, false, true, true, $inputParams);
$this->checkVerifix($schema, "", true, null, true, false, true, true, $inputParams);
$schema = new ScalarSchema("?int");
$this->checkVerifix($schema, null, false, null, true, true, true, true, $inputParams);
$this->checkVerifix($schema, null, true, null, true, true, true, true, $inputParams);
$this->checkVerifix($schema, "", false, null, true, false, true, true, $inputParams);
$this->checkVerifix($schema, "", true, null, true, false, true, true, $inputParams);
}
}