modifs.mineures sans commentaires
This commit is contained in:
parent
a705dd61c4
commit
e1b4ef4cc3
@ -1,5 +1,7 @@
|
||||
# nulib\schema
|
||||
|
||||
* tenir compte de la valeur par défaut, qui *doit* être du bon type
|
||||
* type vaut soit une instance de IType, soit une tableau de types
|
||||
* 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
|
||||
|
@ -6,6 +6,7 @@ use nulib\ref\schema\ref_schema;
|
||||
use nulib\ref\schema\ref_types;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
use nur\sery\wip\schema\SchemaException;
|
||||
use nur\sery\wip\schema\types;
|
||||
use nur\sery\wip\schema\types\tarray;
|
||||
use nur\sery\wip\schema\types\tbool;
|
||||
use nur\sery\wip\schema\types\tcallable;
|
||||
@ -103,7 +104,7 @@ class ScalarSchema extends Schema {
|
||||
# type
|
||||
$types = [];
|
||||
$deftype = $definition["type"];
|
||||
$nullable = $definition["nullable"];
|
||||
$nullable = $definition["nullable"] ?? false;
|
||||
if ($deftype === null) {
|
||||
$types[] = null;
|
||||
$nullable = true;
|
||||
@ -164,6 +165,20 @@ class ScalarSchema extends Schema {
|
||||
tarray::ensure_narray($definition["messages"]);
|
||||
tcallable::ensure_ncallable($definition["formatter_func"]);
|
||||
tbool::ensure_nbool($definition["composite"]);
|
||||
|
||||
# s'il n'y a qu'une seul type, l'instancier tout de suite
|
||||
if (count($types) == 1 && $types[0] !== null) {
|
||||
foreach ($types as $key => $name) {
|
||||
if ($key === 0) {
|
||||
$params = null;
|
||||
} else {
|
||||
$params = $name;
|
||||
$name = $key;
|
||||
}
|
||||
$definition["type"] = [types::get($nullable, $name, $params, $definition)];
|
||||
}
|
||||
}
|
||||
|
||||
return $definition;
|
||||
}
|
||||
|
||||
|
@ -71,57 +71,65 @@ class ScalarWrapper extends Wrapper {
|
||||
|
||||
/** analyser la valeur et résoudre son type */
|
||||
function _analyze(AnalyzerContext $context): int {
|
||||
$schema = $this->schema;
|
||||
$input = $this->input;
|
||||
$destKey = $this->destKey;
|
||||
$result = $this->result;
|
||||
/** @var ScalarSchema $schema */
|
||||
$schema = $context->schema;
|
||||
$input = $context->input;
|
||||
$destKey = $context->destKey;
|
||||
/** @var ScalarResult $result */
|
||||
$result = $context->result;
|
||||
|
||||
if (!$input->isPresent($destKey)) return $result->setMissing($schema);
|
||||
|
||||
$haveType = false;
|
||||
$types = [];
|
||||
$type = $firstType = null;
|
||||
$haveValue = false;
|
||||
$value = null;
|
||||
# d'abord chercher un type pour lequel c'est une valeur normalisée
|
||||
$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)) {
|
||||
if (!$haveValue) {
|
||||
$value = $input->get($destKey);
|
||||
$haveValue = true;
|
||||
$schemaTypes = $schema->type;
|
||||
if (count($schemaTypes) == 1 && $schemaTypes[0] instanceof IType) {
|
||||
$type = $schemaTypes[0];
|
||||
} else {
|
||||
# type union
|
||||
$haveType = false;
|
||||
$types = [];
|
||||
$type = $firstType = null;
|
||||
$value = null;
|
||||
# d'abord chercher un type pour lequel c'est une valeur normalisée
|
||||
$index = 0;
|
||||
$haveValue = false;
|
||||
foreach ($schemaTypes as $key => $name) {
|
||||
if ($key === $index) {
|
||||
$index++;
|
||||
$params = null;
|
||||
} else {
|
||||
$params = $name;
|
||||
$name = $key;
|
||||
}
|
||||
if ($type->isValid($value, $normalized) && $normalized) {
|
||||
$haveType = true;
|
||||
$this->type = $type;
|
||||
break;
|
||||
$type = types::get($schema->nullable, $name, $params, $this->schema->getDefinition());
|
||||
if ($firstType === null) $firstType = $type;
|
||||
$types[] = $type;
|
||||
if ($type->isAvailable($input, $destKey)) {
|
||||
if (!$haveValue) {
|
||||
$value = $input->get($destKey);
|
||||
$haveValue = true;
|
||||
}
|
||||
if ($type->isValid($value, $normalized) && $normalized) {
|
||||
$haveType = true;
|
||||
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;
|
||||
if (!$haveType) {
|
||||
foreach ($types as $type) {
|
||||
if ($type->isAvailable($input, $destKey) && $type->isValid($value)) {
|
||||
$haveType = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
# sinon prendre le premier type
|
||||
if (!$haveType) {
|
||||
$type = $firstType;
|
||||
}
|
||||
}
|
||||
$context->type = $this->type = $type;
|
||||
|
||||
# sinon prendre le premier type
|
||||
if (!$haveType) $type = $this->type = $firstType;
|
||||
$context->type = $type;
|
||||
if (!$type->isAvailable($input, $destKey)) return $result->setUnavailable($schema);
|
||||
|
||||
$value = $input->get($destKey);
|
||||
|
@ -25,16 +25,16 @@ class types {
|
||||
return self::$registry;
|
||||
}
|
||||
|
||||
static function get(string $name, ?array $params=null, ?array $definition=null): IType {
|
||||
return self::registry()->get($name, $params, $definition);
|
||||
static function get(bool $nullable, string $name, ?array $params=null, ?array $definition=null): IType {
|
||||
return self::registry()->get($nullable, $name, $params, $definition);
|
||||
}
|
||||
|
||||
static function rawstring(): trawstring { return self::get("rawstring"); }
|
||||
static function string(): tstring { return self::get("string"); }
|
||||
static function text(): ttext { return self::get("text"); }
|
||||
static function bool(): tbool { return self::get("bool"); }
|
||||
static function int(): tint { return self::get("int"); }
|
||||
static function float(): tfloat { return self::get("float"); }
|
||||
static function array(): tarray { return self::get("array"); }
|
||||
static function callable(): tcallable { return self::get("callable"); }
|
||||
static function rawstring(bool $nullable=true): trawstring { return self::get($nullable, "rawstring"); }
|
||||
static function string(bool $nullable=true): tstring { return self::get($nullable, "string"); }
|
||||
static function text(bool $nullable=true): ttext { return self::get($nullable, "text"); }
|
||||
static function bool(bool $nullable=true): tbool { return self::get($nullable, "bool"); }
|
||||
static function int(bool $nullable=true): tint { return self::get($nullable, "int"); }
|
||||
static function float(bool $nullable=true): tfloat { return self::get($nullable, "float"); }
|
||||
static function array(bool $nullable=true): tarray { return self::get($nullable, "array"); }
|
||||
static function callable(bool $nullable=true): tcallable { return self::get($nullable, "callable"); }
|
||||
}
|
||||
|
@ -10,6 +10,54 @@ use nur\sery\wip\schema\Schema;
|
||||
* Interface IType: un type de données
|
||||
*/
|
||||
interface IType {
|
||||
/**
|
||||
* @return string la classe des objets gérés par ce format: le type attendu
|
||||
* par {@link format()} et le type retourné par {@link verifix()}
|
||||
*
|
||||
* Les valeurs "mixed", "bool", "float", "int", "string" et "array" peuvent
|
||||
* aussi être retournées, bien qu'elles ne soient pas à proprement parler des
|
||||
* classes.
|
||||
*
|
||||
* La valeur "mixed" signifie qu'il peut s'agir de n'importe quelle classe
|
||||
* et/ou que la valeur ne peut pas être déterminée à l'avance.
|
||||
*/
|
||||
function getClass(): string;
|
||||
|
||||
/**
|
||||
* comme {@link getClass()} mais peut être utilisé directement comme type dans
|
||||
* une déclaration PHP. notamment, si le type est nullable et que
|
||||
* $allowNullable==true, il y a "?" devant le nom.
|
||||
*
|
||||
* Par exemple:
|
||||
* - pour un type chaine nullable, {@link getClass()} retournerait "string"
|
||||
* alors que cette méthode retournerait "?string".
|
||||
* - pour un type mixed, {@link getClass()} retournerait "mixed" alors que
|
||||
* cette méthode retournerait null
|
||||
*/
|
||||
function getPhpType(bool $allowNullable=true): ?string;
|
||||
|
||||
/**
|
||||
* indiquer si c'est le type d'une valeur qui ne peut prendre que 2 états: une
|
||||
* "vraie" et une "fausse"
|
||||
*/
|
||||
function is2States(): bool;
|
||||
|
||||
/**
|
||||
* Si {@link is2States()} est vrai, retourner les deux valeurs [faux, vrai]
|
||||
*/
|
||||
function get2States(): array;
|
||||
|
||||
/**
|
||||
* indiquer si c'est le type d'une valeur qui ne peut prendre que 3 états: une
|
||||
* "vraie", une "fausse", et une "indéterminée"
|
||||
*/
|
||||
function is3States(): bool;
|
||||
|
||||
/**
|
||||
* Si {@link is3States()} est vrai, retourner les 3 valeurs [faux, vrai, undef]
|
||||
*/
|
||||
function get3States(): array;
|
||||
|
||||
/** la donnée $input($destKey) est-elle disponible? */
|
||||
function isAvailable(Input $input, $destKey): bool;
|
||||
|
||||
@ -54,4 +102,29 @@ interface IType {
|
||||
* garantie d'être du bon type
|
||||
*/
|
||||
function format($value, $format=null): string;
|
||||
|
||||
#############################################################################
|
||||
|
||||
/** @return string le nom d'un getter pour une valeur de ce type */
|
||||
function getGetterName(string $name): string;
|
||||
|
||||
/** @return string le nom d'un setter pour une valeur de ce type */
|
||||
function getSetterName(string $name): string;
|
||||
|
||||
/** @return string le nom d'un deleter pour une valeur de ce type */
|
||||
function getDeleterName(string $name): string;
|
||||
|
||||
/**
|
||||
* @return string le nom d'une constante de classe pour une valeur de ce type
|
||||
*/
|
||||
function getClassConstName(string $name): string;
|
||||
|
||||
/**
|
||||
* @return string le nom d'une propriété d'une classe pour une valeur de ce
|
||||
* type
|
||||
*/
|
||||
function getObjectPropertyName(string $name): string;
|
||||
|
||||
/** @return string le nom d'une clé d'un tableau pour une valeur de ce type */
|
||||
function getArrayKeyName(string $name): string;
|
||||
}
|
||||
|
@ -28,14 +28,15 @@ class Registry {
|
||||
/** @var IType[] */
|
||||
protected $types;
|
||||
|
||||
function get(string $name, ?array $params=null, ?array $definition=null): IType {
|
||||
function get(bool $nullable, string $name, ?array $params=null, ?array $definition=null): IType {
|
||||
$class = self::TYPES[$name];
|
||||
$params = cl::merge($class::get_params_from_definition($definition), $params);
|
||||
if ($params !== null) {
|
||||
return func::with([$class, false, $params])->invoke();
|
||||
return func::with([$class, false, $nullable, $params])->invoke();
|
||||
}
|
||||
if ($nullable) $name = "?$name";
|
||||
$type = cl::get($this->types, $name);
|
||||
if ($type === null) $type = $this->types[$name] = new $class();
|
||||
if ($type === null) $type = $this->types[$name] = new $class($nullable);
|
||||
return $type;
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,44 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
use nulib\StateException;
|
||||
use nur\prop;
|
||||
use nur\sery\wip\schema\input\Input;
|
||||
use nur\str;
|
||||
|
||||
abstract class _tsimple implements IType {
|
||||
static function get_params_from_definition(?array $definition): ?array {
|
||||
return null;
|
||||
}
|
||||
|
||||
function __construct(?array $params=null) {
|
||||
function __construct(bool $nullable, ?array $params=null) {
|
||||
$this->nullable = $nullable;
|
||||
$this->params = $params;
|
||||
}
|
||||
|
||||
protected bool $nullable;
|
||||
|
||||
protected ?array $params;
|
||||
|
||||
function getPhpType(bool $allowNullable=true): ?string {
|
||||
$phpType = $this->getClass();
|
||||
if ($phpType === "mixed") return null;
|
||||
if ($this->nullable && $allowNullable) $phpType = "?$phpType";
|
||||
return $phpType;
|
||||
}
|
||||
|
||||
function get2States(): array {
|
||||
throw StateException::not_implemented();
|
||||
}
|
||||
|
||||
function is3States(): bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
function get3States(): array {
|
||||
throw StateException::not_implemented();
|
||||
}
|
||||
|
||||
function isAvailable(Input $input, $destKey): bool {
|
||||
return $input->isAvailable($destKey) && $input->get($destKey) !== false;
|
||||
}
|
||||
@ -25,4 +50,34 @@ abstract class _tsimple implements IType {
|
||||
function extract(string $value): string {
|
||||
return $value;
|
||||
}
|
||||
|
||||
function is2States(): bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
#############################################################################
|
||||
|
||||
function getGetterName(string $name): string {
|
||||
return prop::get_getter_name($name);
|
||||
}
|
||||
|
||||
function getSetterName(string $name): string {
|
||||
return prop::get_setter_name($name);
|
||||
}
|
||||
|
||||
function getDeleterName(string $name): string {
|
||||
return prop::get_deletter_name($name);
|
||||
}
|
||||
|
||||
function getClassConstName(string $name): string {
|
||||
return strtoupper($name);
|
||||
}
|
||||
|
||||
function getObjectPropertyName(string $name): string {
|
||||
return str::us2camel($name);
|
||||
}
|
||||
|
||||
function getArrayKeyName(string $name): string {
|
||||
return $name;
|
||||
}
|
||||
}
|
||||
|
10
src/schema/types/_tunion.php
Normal file
10
src/schema/types/_tunion.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
abstract class _tunion extends _tsimple {
|
||||
function getPhpType(bool $allowNullable=true): ?string {
|
||||
# assumer mixed pour le moment
|
||||
#XXX à terme, lister les types de l'union
|
||||
return null;
|
||||
}
|
||||
}
|
@ -29,6 +29,10 @@ class tarray extends _tstring {
|
||||
if ($array !== null) self::ensure_array($array);
|
||||
}
|
||||
|
||||
function getClass(): string {
|
||||
return "array";
|
||||
}
|
||||
|
||||
function isValid($value, ?bool &$normalized=null): bool {
|
||||
$normalized = is_array($value);
|
||||
return is_scalar($value) || is_array($value);
|
||||
|
@ -3,6 +3,7 @@ namespace nur\sery\wip\schema\types;
|
||||
|
||||
use nulib\cl;
|
||||
use nulib\ValueException;
|
||||
use nur\prop;
|
||||
use nur\sery\wip\schema\_scalar\ScalarResult;
|
||||
use nur\sery\wip\schema\_scalar\ScalarSchema;
|
||||
use nur\sery\wip\schema\input\Input;
|
||||
@ -51,6 +52,26 @@ class tbool extends _tformatable {
|
||||
if ($bool !== null) self::ensure_bool($bool);
|
||||
}
|
||||
|
||||
function getClass(): string {
|
||||
return "bool";
|
||||
}
|
||||
|
||||
function is2States(): bool {
|
||||
return !$this->nullable;
|
||||
}
|
||||
|
||||
function get2States(): array {
|
||||
return [false, true];
|
||||
}
|
||||
|
||||
function is3States(): bool {
|
||||
return $this->nullable;
|
||||
}
|
||||
|
||||
function get3States(): array {
|
||||
return [false, true, null];
|
||||
}
|
||||
|
||||
function isAvailable(Input $input, $destKey): bool {
|
||||
return $input->isAvailable($destKey);
|
||||
}
|
||||
@ -124,4 +145,8 @@ class tbool extends _tformatable {
|
||||
}
|
||||
return $value? $format[0]: $format[1];
|
||||
}
|
||||
|
||||
function getGetterName(string $name): string {
|
||||
return prop::get_getter_name($name, !$this->nullable);
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,10 @@ class tcallable extends _tsimple {
|
||||
if ($callable !== null) self::ensure_callable($callable);
|
||||
}
|
||||
|
||||
function getClass(): string {
|
||||
return func::class;
|
||||
}
|
||||
|
||||
function isValid($value, ?bool &$normalized=null): bool {
|
||||
$normalized = is_callable($value);
|
||||
return func::check($value);
|
||||
|
@ -7,7 +7,7 @@ use nur\sery\wip\schema\_scalar\ScalarSchema;
|
||||
use nur\sery\wip\schema\Result;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
|
||||
abstract class tcontent extends _tsimple {
|
||||
abstract class tcontent extends _tunion {
|
||||
static function ensure_content(&$content): void {
|
||||
if ($content === null || $content === false) $content = [];
|
||||
elseif (!is_string($content) && !is_array($content)) $content = strval($content);
|
||||
@ -17,6 +17,10 @@ abstract class tcontent extends _tsimple {
|
||||
if ($content !== null) self::ensure_content($content);
|
||||
}
|
||||
|
||||
function getClass(): string {
|
||||
return "string|array";
|
||||
}
|
||||
|
||||
function isValid($value, ?bool &$normalized=null): bool {
|
||||
$normalized = is_string($value) || is_array($value);
|
||||
return is_scalar($value) || is_array($value);
|
||||
|
@ -16,6 +16,10 @@ class tfloat extends _tformatable {
|
||||
if ($float !== null) self::ensure_float($float);
|
||||
}
|
||||
|
||||
function getClass(): string {
|
||||
return "float";
|
||||
}
|
||||
|
||||
function isValid($value, ?bool &$normalized=null): bool {
|
||||
$normalized = is_float($value);
|
||||
return is_scalar($value);
|
||||
|
@ -17,7 +17,11 @@ class tint extends _tformatable {
|
||||
}
|
||||
|
||||
//const INT_PATTERN = '/^[-+]?[0-9]+(?:\.[0-9]*)?$/';
|
||||
|
||||
|
||||
function getClass(): string {
|
||||
return "int";
|
||||
}
|
||||
|
||||
function isValid($value, ?bool &$normalized=null): bool {
|
||||
$normalized = is_int($value);
|
||||
return is_scalar($value);
|
||||
|
@ -6,7 +6,7 @@ use nur\sery\wip\schema\_scalar\ScalarSchema;
|
||||
use nur\sery\wip\schema\Result;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
|
||||
class tkey extends _tsimple {
|
||||
class tkey extends _tunion {
|
||||
static function ensure_key(&$key): void {
|
||||
if ($key === null) $key = "";
|
||||
elseif ($key === false) $key = 0;
|
||||
@ -17,6 +17,10 @@ class tkey extends _tsimple {
|
||||
if ($key !== null) self::ensure_key($key);
|
||||
}
|
||||
|
||||
function getClass(): string {
|
||||
return "string|int";
|
||||
}
|
||||
|
||||
function isValid($value, ?bool &$normalized=null): bool {
|
||||
$normalized = is_string($value) || is_int($value);
|
||||
return is_scalar($value);
|
||||
|
@ -6,7 +6,7 @@ use nur\sery\wip\schema\_scalar\ScalarSchema;
|
||||
use nur\sery\wip\schema\Result;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
|
||||
class tpkey extends _tsimple {
|
||||
class tpkey extends _tunion {
|
||||
static function ensure_pkey(&$pkey): void {
|
||||
if ($pkey === null) $pkey = "";
|
||||
elseif ($pkey === false) $pkey = 0;
|
||||
@ -22,6 +22,10 @@ class tpkey extends _tsimple {
|
||||
if ($pkey !== null) self::ensure_pkey($pkey);
|
||||
}
|
||||
|
||||
function getClass(): string {
|
||||
return "string|int|array";
|
||||
}
|
||||
|
||||
function isValid($value, ?bool &$normalized=null): bool {
|
||||
$normalized = is_string($value) || is_int($value) || is_array($value);
|
||||
return is_scalar($value) || is_array($value);
|
||||
|
@ -18,6 +18,10 @@ class trawstring extends _tstring {
|
||||
if ($string !== null) self::ensure_string($string);
|
||||
}
|
||||
|
||||
function getClass(): string {
|
||||
return "string";
|
||||
}
|
||||
|
||||
function isNull($value): bool {
|
||||
return $value === null;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user