modifs.mineures sans commentaires

This commit is contained in:
Jephté Clain 2023-12-28 22:48:06 +04:00
parent 4e379ac5d8
commit 6266d3020d
10 changed files with 174 additions and 53 deletions

View File

@ -68,7 +68,7 @@ abstract class Schema implements ArrayAccess {
/** retourner true si le schéma est de nature scalaire */ /** retourner true si le schéma est de nature scalaire */
function isScalar(?ScalarSchema &$scalar=null): bool { return false; } function isScalar(?ScalarSchema &$scalar=null): bool { return false; }
abstract function newValue(?Value &$value=null, &$dest=null, $key=null): Value; abstract function newValue(?Value &$value=null, &$dest=null, $destKey=null): Value;
############################################################################# #############################################################################
# key & properties # key & properties

View File

@ -45,10 +45,10 @@ class AssocSchema extends Schema {
return true; return true;
} }
function newValue(?Value &$value=null, &$dest=null, $key=null): Value { function newValue(?Value &$value=null, &$dest=null, $destKey=null): Value {
if (!($value instanceof AssocValue)) $value = new AssocValue($this); if (!($value instanceof AssocValue)) $value = new AssocValue($this);
if ($dest instanceof Input) $input = $dest; if ($dest instanceof Input) $input = $dest;
else $input = new Input($dest); else $input = new Input($dest);
return $value->reset($input, $key); return $value->reset($input, $destKey);
} }
} }

View File

@ -45,8 +45,8 @@ class ListSchema extends Schema {
return true; return true;
} }
function newValue(?Value &$value=null, &$dest=null, $key=null): Value { function newValue(?Value &$value=null, &$dest=null, $destKey=null): Value {
if (!($value instanceof ListValue)) $value = new ListValue($this); if (!($value instanceof ListValue)) $value = new ListValue($this);
return $value->reset($dest, $key); return $value->reset($dest, $destKey);
} }
} }

View File

@ -10,6 +10,7 @@ use nur\sery\schema\Result;
/** /**
* Class ScalarResult: résultat de l'analyse ou de la normalisation d'une valeur * Class ScalarResult: résultat de l'analyse ou de la normalisation d'une valeur
* *
* @property bool $resultAvailable le résultat est-il disponible?
* @property bool $present la valeur existe-t-elle? * @property bool $present la valeur existe-t-elle?
* @property bool $available si la valeur existe, est-elle disponible? * @property bool $available si la valeur existe, est-elle disponible?
* @property bool $null si la valeur est disponible, est-elle nulle? * @property bool $null si la valeur est disponible, est-elle nulle?
@ -19,7 +20,7 @@ use nur\sery\schema\Result;
* @property string|null $message message si la valeur n'est pas valide * @property string|null $message message si la valeur n'est pas valide
*/ */
class ScalarResult extends Result { class ScalarResult extends Result {
const KEYS = ["present", "available", "null", "valid", "normalized", "orig", "message"]; const KEYS = ["resultAvailable", "present", "available", "null", "valid", "normalized", "orig", "message"];
function isScalar(?ScalarResult &$scalar=null): bool { $scalar = $this; return true; } function isScalar(?ScalarResult &$scalar=null): bool { $scalar = $this; return true; }
@ -38,6 +39,7 @@ class ScalarResult extends Result {
function reset(): void { function reset(): void {
$this->result = array_merge( $this->result = array_merge(
array_fill_keys(static::KEYS, null), [ array_fill_keys(static::KEYS, null), [
"resultAvailable" => false,
"present" => false, "present" => false,
"available" => false, "available" => false,
"null" => false, "null" => false,
@ -67,18 +69,14 @@ class ScalarResult extends Result {
$message = str_replace("{orig}", strval($orig), $message); $message = str_replace("{orig}", strval($orig), $message);
} }
protected function getMessages(ScalarSchema $schema): ?array {
return $schema->messages;
}
protected function getMessage(string $key, ScalarSchema $schema): string { protected function getMessage(string $key, ScalarSchema $schema): string {
$messages = $this->getMessages($schema); $message = cl::get($schema->messages, $key);
$message = cl::get($messages, $key);
if ($message !== null) return $message; if ($message !== null) return $message;
return cl::get(ref_schema::MESSAGES, $key); return cl::get(ref_schema::MESSAGES, $key);
} }
function setMissing(ScalarSchema $schema): int { function setMissing(ScalarSchema $schema): int {
$this->resultAvailable = true;
$this->present = false; $this->present = false;
$this->available = false; $this->available = false;
if (!$schema->required) { if (!$schema->required) {
@ -95,6 +93,7 @@ class ScalarResult extends Result {
} }
function setUnavailable(ScalarSchema $schema): int { function setUnavailable(ScalarSchema $schema): int {
$this->resultAvailable = true;
$this->present = true; $this->present = true;
$this->available = false; $this->available = false;
if (!$schema->required) { if (!$schema->required) {
@ -111,6 +110,7 @@ class ScalarResult extends Result {
} }
function setNull(ScalarSchema $schema): int { function setNull(ScalarSchema $schema): int {
$this->resultAvailable = true;
$this->present = true; $this->present = true;
$this->available = true; $this->available = true;
$this->null = true; $this->null = true;
@ -127,6 +127,7 @@ class ScalarResult extends Result {
} }
function setInvalid($value, ScalarSchema $schema): int { function setInvalid($value, ScalarSchema $schema): int {
$this->resultAvailable = true;
$this->present = true; $this->present = true;
$this->available = true; $this->available = true;
$this->null = false; $this->null = false;
@ -140,6 +141,7 @@ class ScalarResult extends Result {
} }
function setValid(): int { function setValid(): int {
$this->resultAvailable = true;
$this->present = true; $this->present = true;
$this->available = true; $this->available = true;
$this->null = false; $this->null = false;
@ -148,6 +150,7 @@ class ScalarResult extends Result {
} }
function setNormalized(): int { function setNormalized(): int {
$this->resultAvailable = true;
$this->present = true; $this->present = true;
$this->available = true; $this->available = true;
$this->null = false; $this->null = false;

View File

@ -180,9 +180,9 @@ class ScalarSchema extends Schema {
return true; return true;
} }
function newValue(?Value &$value=null, &$dest=null, $key=null): Value { function newValue(?Value &$value=null, &$dest=null, $destKey=null): Value {
if (!($value instanceof ScalarValue)) $value = new ScalarValue($this); if ($value instanceof ScalarValue) return $value->reset($dest, $destKey);
return $value->reset($dest, $key); else return ($value = new ScalarValue($this, $dest, $destKey));
} }
############################################################################# #############################################################################

View File

@ -72,16 +72,38 @@ class ScalarValue extends Value {
$result->reset(); $result->reset();
if (!$input->isPresent($destKey)) return $result->setMissing($schema); if (!$input->isPresent($destKey)) return $result->setMissing($schema);
$haveType = false; $haveType = false;
$firstType = null; $types = [];
$type = $firstType = null;
$haveValue = false;
$value = null;
# d'abord chercher un type pour lequel c'est une valeur normalisée
foreach ($schema->type as $name) { foreach ($schema->type as $name) {
$type = types::get($name); $type = types::get($name);
if ($firstType === null) $firstType = $type; if ($firstType === null) $firstType = $type;
if ($type->canAnalyze($input, $destKey)) { $types[] = $type;
if ($type->isAvailable($input, $destKey)) {
if (!$haveValue) {
$value = $input->get($destKey);
$haveValue = true;
}
if ($type->isValid($value, $normalized) && $normalized) {
$haveType = true; $haveType = true;
$this->type = $type; $this->type = $type;
break; break;
} }
} }
}
if (!$haveType) {
# ensuite chercher un type pour lequel la valeur est valide
foreach ($types as $type) {
if ($type->isAvailable($input, $destKey) && $type->isValid($value)) {
$haveType = true;
$this->type = $type;
break;
}
}
}
# sinon prendre le premier type
if (!$haveType) $type = $this->type = $firstType; if (!$haveType) $type = $this->type = $firstType;
if (!$type->isAvailable($input, $destKey)) return $result->setUnavailable($schema); if (!$type->isAvailable($input, $destKey)) return $result->setUnavailable($schema);
$value = $input->get($destKey); $value = $input->get($destKey);
@ -91,17 +113,33 @@ class ScalarValue extends Value {
else return $result->setValid(); else return $result->setValid();
} }
if (is_string($value)) return ref_analyze::STRING; if (is_string($value)) return ref_analyze::STRING;
else return $result->setInvalid($schema, $schema); else return $result->setInvalid($value, $schema);
} }
function verifix(?bool $throw=null): bool { function verifix(?bool $throw=null): bool {
$type = $this->getType();
$destKey = $this->destKey;
$value = $this->input->get($destKey);
$modified = $type->verifix($value, $this->result, $this->schema);
if ($throw === null) $throw = $this->defaultThrow; if ($throw === null) $throw = $this->defaultThrow;
if ($this->result->valid) $this->input->set($value, $destKey); $destKey = $this->destKey;
else $this->result->throw($throw); $verifix = false;
$result =& $this->result;
$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, $destKey);
} elseif ($result->valid && !$result->normalized) {
# normaliser la valeur
$verifix = true;
}
} else {
$verifix = true;
}
if ($verifix) {
$value = $this->input->get($destKey);
$modified = $this->type->verifix($value, $result, $this->schema);
if ($result->valid) $this->input->set($value, $destKey);
}
if (!$result->valid) $result->throw($throw);
return $modified; return $modified;
} }
@ -151,6 +189,6 @@ class ScalarValue extends Value {
} }
function format($format=null): string { function format($format=null): string {
return $this->getType()->format($this->input->get($this->destKey), $format); return $this->type->format($this->input->get($this->destKey), $format);
} }
} }

View File

@ -9,9 +9,6 @@ use nur\sery\schema\Schema;
* Interface IType: un type de données * Interface IType: un type de données
*/ */
interface IType { interface IType {
/** ce type peut-il analyser la donnée dans $input[$destKey] ? */
function canAnalyze(Input $input, $destKey): bool;
/** la donnée $input[$destKey] est-elle disponible? */ /** la donnée $input[$destKey] est-elle disponible? */
function isAvailable(Input $input, $destKey): bool; function isAvailable(Input $input, $destKey): bool;

View File

@ -16,19 +16,12 @@ class tint implements IType {
if ($int !== null) self::ensure_int($int); if ($int !== null) self::ensure_int($int);
} }
function canAnalyze(Input $input, $destKey): bool {
if (!$input->isAvailable()) return true;
$value = $input->get($destKey);
if ($value === false || $value === null) return true;
return is_scalar($value);
}
function isAvailable(Input $input, $destKey): bool { function isAvailable(Input $input, $destKey): bool {
return $input->isAvailable($destKey) && $input->get($destKey) !== false; return $input->isAvailable($destKey) && $input->get($destKey) !== false;
} }
function isNull($value): bool { function isNull($value): bool {
return $value === null; return $value === null || (is_string($value) && trim($value) === "");
} }
const INT_PATTERN = '/^[-+]?[0-9]+(?:\.[0-9]*)?$/'; const INT_PATTERN = '/^[-+]?[0-9]+(?:\.[0-9]*)?$/';

View File

@ -1,10 +1,8 @@
<?php <?php
namespace nur\sery\schema\types; namespace nur\sery\schema\types;
use nur\b\ValueException;
use nur\sery\schema\_scalar\ScalarResult; use nur\sery\schema\_scalar\ScalarResult;
use nur\sery\schema\_scalar\ScalarSchema; use nur\sery\schema\_scalar\ScalarSchema;
use nur\sery\schema\_scalar\ScalarValue;
use nur\sery\schema\input\Input; use nur\sery\schema\input\Input;
use nur\sery\schema\Result; use nur\sery\schema\Result;
use nur\sery\schema\Schema; use nur\sery\schema\Schema;
@ -18,13 +16,6 @@ class tstring implements IType {
if ($string !== null) self::ensure_string($string); if ($string !== null) self::ensure_string($string);
} }
function canAnalyze(Input $input, $destKey): bool {
if (!$input->isAvailable()) return true;
$value = $input->get($destKey);
if ($value === false || $value === null) return true;
return is_scalar($value);
}
function isAvailable(Input $input, $destKey): bool { function isAvailable(Input $input, $destKey): bool {
return $input->isAvailable($destKey) && $input->get($destKey) !== false; return $input->isAvailable($destKey) && $input->get($destKey) !== false;
} }

View File

@ -23,7 +23,7 @@ class schemaTest extends TestCase {
self::assertSame(12, $intv->get()); self::assertSame(12, $intv->get());
self::assertSame(12, $int); self::assertSame(12, $int);
self::assertSame("12", $intv->format()); self::assertSame("12", $intv->format());
self::assertSame("0012", $intv->format("%4u")); self::assertSame("0012", $intv->format("%04u"));
$intv->set("12"); $intv->set("12");
self::assertSame(12, $intv->get()); self::assertSame(12, $intv->get());
@ -31,8 +31,52 @@ class schemaTest extends TestCase {
$intv->set(" 12 "); $intv->set(" 12 ");
self::assertSame(12, $intv->get()); self::assertSame(12, $intv->get());
self::assertException(Exception::class, $intvSetter(true)); $intv->set(true);
self::assertSame(1, $intv->get());
// valeur non requise donc retourne null
$intv->set(false);
self::assertNull($intv->get());
self::assertException(Exception::class, $intvSetter("a"));
self::assertException(Exception::class, $intvSetter([]));
self::assertException(Exception::class, $intvSetter(["a"]));
}
function testRequiredInt() {
/** @var ScalarValue $intv */
Schema::nv($intv, $int, null, $schema, [
"int", null,
"required" => true,
]);
$intvSetter = function($value) use($intv) {
return function() use($intv, $value) {
$intv->set($value);
};
};
self::assertException(Exception::class, $intvSetter(null));
self::assertException(Exception::class, $intvSetter(""));
self::assertException(Exception::class, $intvSetter(" "));
$intv->set(12);
self::assertSame(12, $intv->get());
self::assertSame(12, $int);
self::assertSame("12", $intv->format());
self::assertSame("0012", $intv->format("%04u"));
$intv->set("12");
self::assertSame(12, $intv->get());
$intv->set(" 12 ");
self::assertSame(12, $intv->get());
$intv->set(true);
self::assertSame(1, $intv->get());
// valeur requise donc lance une exception
self::assertException(Exception::class, $intvSetter(false)); self::assertException(Exception::class, $intvSetter(false));
self::assertException(Exception::class, $intvSetter("a")); self::assertException(Exception::class, $intvSetter("a"));
self::assertException(Exception::class, $intvSetter([])); self::assertException(Exception::class, $intvSetter([]));
self::assertException(Exception::class, $intvSetter(["a"])); self::assertException(Exception::class, $intvSetter(["a"]));
@ -66,7 +110,7 @@ class schemaTest extends TestCase {
self::assertSame(12, $intv->get()); self::assertSame(12, $intv->get());
self::assertSame(12, $int); self::assertSame(12, $int);
self::assertSame("12", $intv->format()); self::assertSame("12", $intv->format());
self::assertSame("0012", $intv->format("%4u")); self::assertSame("0012", $intv->format("%04u"));
$intv->set("12"); $intv->set("12");
self::assertSame(12, $int); self::assertSame(12, $int);
@ -74,8 +118,63 @@ class schemaTest extends TestCase {
$intv->set(" 12 "); $intv->set(" 12 ");
self::assertSame(12, $int); self::assertSame(12, $int);
self::assertException(Exception::class, $intvSetter(true)); $intv->set(true);
self::assertSame(1, $int);
// valeur non requise donc retourne null
$intv->set(false);
self::assertNull($intv->get());
self::assertException(Exception::class, $intvSetter("a"));
self::assertException(Exception::class, $intvSetter([]));
self::assertException(Exception::class, $intvSetter(["a"]));
}
function testRequiredNint() {
/** @var ScalarValue $intv */
Schema::nv($intv, $int, null, $schema, [
"?int", null,
"required" => true,
]);
$intvSetter = function($value) use($intv) {
return function() use($intv, $value) {
$intv->set($value);
};
};
$intv->set(null);
self::assertNull($intv->get());
self::assertNull($int);
self::assertSame("", $intv->format());
$intv->set("");
self::assertNull($intv->get());
self::assertNull($int);
self::assertSame("", $intv->format());
$intv->set(" ");
self::assertNull($intv->get());
self::assertNull($int);
self::assertSame("", $intv->format());
$intv->set(12);
self::assertSame(12, $intv->get());
self::assertSame(12, $int);
self::assertSame("12", $intv->format());
self::assertSame("0012", $intv->format("%04u"));
$intv->set("12");
self::assertSame(12, $int);
$intv->set(" 12 ");
self::assertSame(12, $int);
$intv->set(true);
self::assertSame(1, $int);
// valeur requise donc lance une exception
self::assertException(Exception::class, $intvSetter(false)); self::assertException(Exception::class, $intvSetter(false));
self::assertException(Exception::class, $intvSetter("a")); self::assertException(Exception::class, $intvSetter("a"));
self::assertException(Exception::class, $intvSetter([])); self::assertException(Exception::class, $intvSetter([]));
self::assertException(Exception::class, $intvSetter(["a"])); self::assertException(Exception::class, $intvSetter(["a"]));
@ -97,7 +196,7 @@ class schemaTest extends TestCase {
Schema::nv($isv, $is, null, $iss, "int|string"); Schema::nv($isv, $is, null, $iss, "int|string");
$isv->set("12"); $isv->set("12");
self::assertSame(12, $is); self::assertSame("12", $is);
$isv->set(12); $isv->set(12);
self::assertSame(12, $is); self::assertSame(12, $is);
} }