modifs.mineures sans commentaires

This commit is contained in:
Jephté Clain 2025-03-04 14:04:09 +04:00
parent 1aa266b509
commit 68023b72ee
11 changed files with 261 additions and 57 deletions

View File

@ -12,12 +12,16 @@ DIST=
NOAUTO=
AFTER_CREATE_RELEASE='
set -x
pman --composer-select-profile dist
composer u
composer u || exit 1
git commit -am "<pman>deps de dist"
true
'
AFTER_MERGE_RELEASE='
set -x
pman --composer-select-profile dev
composer u
composer u || exit 1
git commit -am "<pman>deps de dev"
true
'

View File

@ -0,0 +1,25 @@
<?php
namespace nur\sery\wip\schema;
use nur\sery\wip\schema\input\Input;
use nur\sery\wip\schema\types\IType;
class AnalyzerContext {
function __construct(Schema $schema, Input $input, $destKey, Result $result) {
$this->schema = $schema;
$this->input = $input;
$this->destKey = $destKey;
$this->result = $result;
$this->type = null;
$this->value = null;
}
public Schema $schema;
public Input $input;
/** @var int|string|null */
public $destKey;
public Result $result;
public ?IType $type;
/** @var mixed */
public $value;
}

View File

@ -57,8 +57,11 @@ abstract class Schema implements ArrayAccess {
*/
const SCHEMA = null;
/** @var array */
protected $definition;
protected array $definition;
function getDefinition(): array {
return $this->definition;
}
/** retourner true si le schéma est de nature tableau associatif */
function isAssoc(?AssocSchema &$assoc=null): bool { return false; }

View File

@ -16,11 +16,12 @@ 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 analyse avec parse()
* @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
*/
class ScalarResult extends Result {
const KEYS = ["resultAvailable", "present", "available", "null", "valid", "normalized", "orig", "message"];
const KEYS = ["resultAvailable", "present", "available", "null", "valid", "normalized", "orig", "messageKey", "message"];
function isScalar(?ScalarResult &$scalar=null): bool { $scalar = $this; return true; }
@ -85,7 +86,8 @@ class ScalarResult extends Result {
$this->normalized = true;
return ref_analyze::NORMALIZED;
} else {
$message = $this->getMessage("missing", $schema);
$messageKey = $this->messageKey = "missing";
$message = $this->getMessage($messageKey, $schema);
self::replace_key($message, $schema->name);
$this->message = $message;
return ref_analyze::MISSING;
@ -102,7 +104,8 @@ class ScalarResult extends Result {
$this->normalized = true;
return ref_analyze::NORMALIZED;
} else {
$message = $this->getMessage("unavailable", $schema);
$messageKey = $this->messageKey = "unavailable";
$message = $this->getMessage($messageKey, $schema);
self::replace_key($message, $schema->name);
$this->message = $message;
return ref_analyze::UNAVAILABLE;
@ -119,7 +122,8 @@ class ScalarResult extends Result {
$this->normalized = true;
return ref_analyze::NORMALIZED;
} else {
$message = $this->getMessage("null", $schema);
$messageKey = $this->messageKey = "null";
$message = $this->getMessage($messageKey, $schema);
self::replace_key($message, $schema->name);
$this->message = $message;
return ref_analyze::NULL;
@ -133,7 +137,8 @@ class ScalarResult extends Result {
$this->null = false;
$this->valid = false;
$this->orig = $value;
$message = $this->getMessage("invalid", $schema);
$messageKey = $this->messageKey = "invalid";
$message = $this->getMessage($messageKey, $schema);
self::replace_key($message, $schema->name);
self::replace_orig($message, $schema->orig);
$this->message = $message;

View File

@ -1,9 +1,13 @@
<?php
namespace nur\sery\wip\schema\_scalar;
use nulib\php\func;
use nulib\ref\schema\ref_analyze;
use nulib\ValueException;
use nur\sery\wip\schema\AnalyzerContext;
use nur\sery\wip\schema\input\Input;
use nur\sery\wip\schema\Result;
use nur\sery\wip\schema\Schema;
use nur\sery\wip\schema\types;
use nur\sery\wip\schema\types\IType;
use nur\sery\wip\schema\Value;
@ -52,7 +56,7 @@ class ScalarValue extends Value {
$this->input = $input;
$this->destKey = $destKey;
$this->type = null;
$this->_analyze();
$this->analyzeExtractParse();
if ($verifix === null) $verifix = $this->defaultVerifix;
if ($verifix) $this->verifix();
return $this;
@ -68,12 +72,12 @@ class ScalarValue extends Value {
}
/** analyser la valeur et résoudre son type */
function _analyze(): int {
function _analyze(AnalyzerContext $context): int {
$schema = $this->schema;
$input = $this->input;
$destKey = $this->destKey;
$result = $this->result;
$result->reset();
if (!$input->isPresent($destKey)) return $result->setMissing($schema);
$haveType = false;
@ -82,8 +86,16 @@ class ScalarValue extends Value {
$haveValue = false;
$value = null;
# d'abord chercher un type pour lequel c'est une valeur normalisée
foreach ($schema->type as $name) {
$type = types::get($name);
$index = 0;
foreach ($schema->type as $key => $name) {
if ($key === $index) {
$index++;
$params = null;
} else {
$params = $name;
$name = $key;
}
$type = types::get($name, $params, $this->schema->getDefinition());
if ($firstType === null) $firstType = $type;
$types[] = $type;
if ($type->isAvailable($input, $destKey)) {
@ -113,7 +125,7 @@ class ScalarValue extends Value {
if (!$haveType) $type = $this->type = $firstType;
if (!$type->isAvailable($input, $destKey)) return $result->setUnavailable($schema);
$value = $input->get($destKey);
$value = $context->value = $input->get($destKey);
if ($type->isNull($value)) return $result->setNull($schema);
if ($type->isValid($value, $normalized)) {
if ($normalized) return $result->setNormalized();
@ -124,6 +136,44 @@ class ScalarValue extends Value {
else return $result->setInvalid($value, $schema);
}
function _extract(AnalyzerContext $context): void {
$value = $context->value;
$value = $context->type->extract($value);
$context->value = $value;
}
function _parse(AnalyzerContext $context): void {
$value = $context->value;
$value = $context->type->parse($value);
$context->value = $value;
}
function analyzeExtractParse(): void {
$schema = $this->schema;
$input = $this->input;
$destKey = $this->destKey;
$result = $this->result;
$result->reset();
$context = new AnalyzerContext($schema, $input, $destKey, $result);
/** @var func $analyzerFunc */
$analyzerFunc = $schema->analyzerFunc;
if ($analyzerFunc !== null) $what = $analyzerFunc->invoke([$context]);
else $what = $this->_analyze($context);
if ($what === ref_analyze::STRING) {
/** @var func $extractorFunc */
$extractorFunc = $schema->extractorFunc;
if ($extractorFunc !== null) $extractorFunc->invoke([$context]);
else $this->_extract($context);
/** @var func $parserFunc */
$parserFunc = $schema->parserFunc;
if ($parserFunc !== null) $parserFunc->invoke([$context]);
else $this->_parse($context);
}
}
function verifix(?bool $throw=null): bool {
if ($throw === null) $throw = $this->defaultThrow;
$destKey = $this->destKey;
@ -182,7 +232,7 @@ class ScalarValue extends Value {
function set($value, ?bool $verifix=null): ScalarValue {
$this->input->set($value, $this->destKey);
$this->_analyze();
$this->analyzeExtractParse();
if ($verifix === null) $verifix = $this->defaultVerifix;
if ($verifix) $this->verifix();
return $this;
@ -190,7 +240,7 @@ class ScalarValue extends Value {
function unset(?bool $verifix=null): ScalarValue {
$this->input->unset($this->destKey);
$this->_analyze();
$this->analyzeExtractParse();
if ($verifix === null) $verifix = $this->defaultVerifix;
if ($verifix) $this->verifix();
return $this;

View File

@ -24,8 +24,8 @@ class types {
return self::$registry;
}
static function get(string $name): IType {
return self::registry()->get($name);
static function get(string $name, ?array $params=null, ?array $definition=null): IType {
return self::registry()->get($name, $params, $definition);
}
static function rawstring(): trawstring { return self::get("rawstring"); }

View File

@ -18,6 +18,12 @@ interface IType {
/** la valeur $value est-elle valide et normalisée le cas échéant? */
function isValid($value, ?bool &$normalized=null): bool;
/** extraire de la chaine la valeur à analyser */
function extract(string $value): string;
/** analyser la chaine et retourner la valeur "convertie" */
function parse(string $value);
/**
* analyser, corriger éventuellement et normaliser la valeur
*

View File

@ -27,16 +27,14 @@ class Registry {
/** @var IType[] */
protected $types;
function get(string $name, ?array $params=null): IType {
function get(string $name, ?array $params=null, ?array $definition=null): IType {
$class = self::TYPES[$name];
$params = cl::merge($class::get_params($definition), $params);
if ($params !== null) {
$class = self::TYPES[$name];
return func::with([$class, false, $params])->invoke();
}
$type = cl::get($this->types, $name);
if ($type === null) {
$class = self::TYPES[$name];
$type = $this->types[$name] = new $class();
}
if ($type === null) $type = $this->types[$name] = new $class();
return $type;
}
}

View File

@ -4,6 +4,10 @@ namespace nur\sery\wip\schema\types;
use nur\sery\wip\schema\input\Input;
abstract class _tsimple implements IType {
static function get_params(?array $definition): ?array {
return null;
}
function __construct(?array $params=null) {
$this->params = $params;
}
@ -17,4 +21,12 @@ abstract class _tsimple implements IType {
function isNull($value): bool {
return $value === null || (is_string($value) && trim($value) === "");
}
function extract(string $value): string {
return $value;
}
function parse(string $value) {
return $value;
}
}

View File

@ -7,6 +7,13 @@ use nur\sery\wip\schema\Result;
use nur\sery\wip\schema\Schema;
class tint extends _tsimple {
static function get_params(?array $definition): ?array {
if ($definition === null) return null;
$format = $definition["format"] ?? null;
if ($format === null) return null;
return ["format" => $format];
}
static function ensure_int(&$int): void {
if (!is_int($int)) $int = intval($int);
}
@ -15,12 +22,16 @@ class tint extends _tsimple {
if ($int !== null) self::ensure_int($int);
}
const INT_PATTERN = '/^[-+]?[0-9]+(?:\.[0-9]*)?$/';
//const INT_PATTERN = '/^[-+]?[0-9]+(?:\.[0-9]*)?$/';
function isValid($value, ?bool &$normalized=null): bool {
$normalized = is_int($value);
if (is_string($value)) $valid = is_numeric(trim($value));
else $valid = is_scalar($value);
if (is_string($value)) {
$value = str_replace(",", ".", trim($value));
$valid = is_numeric($value);
} else {
$valid = is_scalar($value);
}
return $valid;
}
@ -33,7 +44,7 @@ class tint extends _tsimple {
$result->setNormalized();
return false;
} elseif (is_string($value)) {
$int = trim($value);
$int = str_replace(",", ".", trim($value));
if (is_numeric($int)) $value = intval($int);
else return $result->setInvalid($value, $schema);
} elseif (is_scalar($value)) {
@ -41,11 +52,12 @@ class tint extends _tsimple {
} else {
return $result->setInvalid($value, $schema);
}
$result->setValid();
$result->setNormalized();
return true;
}
function format($value, $format=null): string {
$format ??= $this->params["format"] ?? null;
if ($format !== null) return sprintf($format, $value);
else return strval($value);
}

View File

@ -35,26 +35,26 @@ class ScalarValueTest extends TestCase {
$string = " "; $value->reset($string);
$this->checkValue($value, " ", true, true, true, true);
$string = "value"; $value->reset($string, null, false);
$this->checkValue($value, "value", true, true, true, true);
$string = "value"; $value->reset($string);
$this->checkValue($value, "value", true, true, true, true);
$string = "text"; $value->reset($string, null, false);
$this->checkValue($value, "text", true, true, true, true);
$string = "text"; $value->reset($string);
$this->checkValue($value, "text", true, true, true, true);
$string = " value "; $value->reset($string, null, false);
$this->checkValue($value, " value ", true, true, true, true);
$string = " value "; $value->reset($string);
$this->checkValue($value, " value ", true, true, true, true);
$string = true; $value->reset($string, null, false);
$this->checkValue($value, true, true, true, true, false);
$string = true; $value->reset($string);
$this->checkValue($value, "1", true, true, true, true);
$string = " text "; $value->reset($string, null, false);
$this->checkValue($value, " text ", true, true, true, true);
$string = " text "; $value->reset($string);
$this->checkValue($value, " text ", true, true, true, true);
$string = false; $value->reset($string, null, false);
$this->checkValue($value, null, true, false, true, true);
$string = false; $value->reset($string);
$this->checkValue($value, null, true, false, true, true);
$string = true; $value->reset($string, null, false);
$this->checkValue($value, true, true, true, true, false);
$string = true; $value->reset($string);
$this->checkValue($value, "1", true, true, true, true);
$string = 42; $value->reset($string, null, false);
$this->checkValue($value, 42, true, true, true, false);
$string = 42; $value->reset($string);
@ -108,26 +108,26 @@ class ScalarValueTest extends TestCase {
$string = " "; $value->reset($string);
$this->checkValue($value, "", true, true, true, true);
$string = "value"; $value->reset($string, null, false);
$this->checkValue($value, "value", true, true, true, true);
$string = "value"; $value->reset($string);
$this->checkValue($value, "value", true, true, true, true);
$string = "text"; $value->reset($string, null, false);
$this->checkValue($value, "text", true, true, true, true);
$string = "text"; $value->reset($string);
$this->checkValue($value, "text", true, true, true, true);
$string = " value "; $value->reset($string, null, false);
$this->checkValue($value, " value ", true, true, true, false);
$string = " value "; $value->reset($string);
$this->checkValue($value, "value", true, true, true, true);
$string = true; $value->reset($string, null, false);
$this->checkValue($value, true, true, true, true, false);
$string = true; $value->reset($string);
$this->checkValue($value, "1", true, true, true, true);
$string = " text "; $value->reset($string, null, false);
$this->checkValue($value, " text ", true, true, true, false);
$string = " text "; $value->reset($string);
$this->checkValue($value, "text", true, true, true, true);
$string = false; $value->reset($string, null, false);
$this->checkValue($value, null, true, false, true, true);
$string = false; $value->reset($string);
$this->checkValue($value, null, true, false, true, true);
$string = true; $value->reset($string, null, false);
$this->checkValue($value, true, true, true, true, false);
$string = true; $value->reset($string);
$this->checkValue($value, "1", true, true, true, true);
$string = 42; $value->reset($string, null, false);
$this->checkValue($value, 42, true, true, true, false);
$string = 42; $value->reset($string);
@ -159,4 +159,93 @@ class ScalarValueTest extends TestCase {
$string = false; $value->reset($string);
});
}
function testInt() {
$schema = new ScalarSchema("int");
$value = $schema->newValue();
$int = null; $value->reset($int, null, false);
$this->checkValue($value, null, true, true, false, false);
self::assertException(ValueException::class, function() use (&$value) {
$int = null;
$value->reset($int);
});
$int = 42; $value->reset($int, null, false);
$this->checkValue($value, 42, true, true, true, true);
$int = 42; $value->reset($int);
$this->checkValue($value, 42, true, true, true, true);
$int = "42"; $value->reset($int, null, false);
$this->checkValue($value, "42", true, true, true, false);
$int = "42"; $value->reset($int);
$this->checkValue($value, 42, true, true, true, true);
$int = "42.5"; $value->reset($int, null, false);
$this->checkValue($value, "42.5", true, true, true, false);
$int = "42.5"; $value->reset($int);
$this->checkValue($value, 42, true, true, true, true);
$int = "42,5"; $value->reset($int, null, false);
$this->checkValue($value, "42,5", true, true, true, false);
$int = "42,5"; $value->reset($int);
$this->checkValue($value, 42, true, true, true, true);
$int = ""; $value->reset($int, null, false);
$this->checkValue($value, "", true, true, false, false);
self::assertException(ValueException::class, function() use (&$value) {
$int = "";
$value->reset($int);
});
$int = " "; $value->reset($int, null, false);
$this->checkValue($value, " ", true, true, false, false);
self::assertException(ValueException::class, function() use (&$value) {
$int = " ";
$value->reset($int);
});
$int = "text"; $value->reset($int, null, false);
$this->checkValue($value, "text", true, true, false, true);
self::assertException(ValueException::class, function() use (&$value) {
$int = "text";
$value->reset($int);
});
$int = false; $value->reset($int, null, false);
$this->checkValue($value, null, true, false, true, true);
$int = false; $value->reset($int);
$this->checkValue($value, null, true, false, true, true);
$int = true; $value->reset($int, null, false);
$this->checkValue($value, true, true, true, true, false);
$int = true; $value->reset($int);
$this->checkValue($value, 1, true, true, true, true);
$int = []; $value->reset($int, null, false);
$this->checkValue($value, [], true, true, false, false);
self::assertException(ValueException::class, function() use (&$value) {
$string = null;
$value->reset($string);
});
## Tester nullable
$schema = new ScalarSchema("?int");
$value = $schema->newValue();
$int = null; $value->reset($int, null, false);
$this->checkValue($value, null, true, true, true, true);
$int = null; $value->reset($int, null);
$this->checkValue($value, null, true, true, true, true);
## Tester required
$schema = new ScalarSchema(["int", "required" => true]);
$value = $schema->newValue();
$int = false; $value->reset($int, null, false);
$this->checkValue($value, null, true, false, false, false);
self::assertException(ValueException::class, function() use (&$value) {
$string = false; $value->reset($string);
});
}
}