modifs.mineures sans commentaires
This commit is contained in:
parent
1aa266b509
commit
68023b72ee
@ -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
|
||||
'
|
||||
|
25
src/schema/AnalyzerContext.php
Normal file
25
src/schema/AnalyzerContext.php
Normal 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;
|
||||
}
|
@ -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; }
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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"); }
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user