supprimer schema qui n'est pas encore prêt
This commit is contained in:
parent
350622997c
commit
fa8fd6e7c3
|
@ -42,10 +42,11 @@ class RunFile {
|
||||||
"serial" => 0,
|
"serial" => 0,
|
||||||
"date_start" => $dateStart,
|
"date_start" => $dateStart,
|
||||||
"date_stop" => null,
|
"date_stop" => null,
|
||||||
|
"exitcode" => null,
|
||||||
"action" => null,
|
"action" => null,
|
||||||
"action_date_start" => null,
|
"action_date_start" => null,
|
||||||
"action_max_step" => null,
|
|
||||||
"action_current_step" => null,
|
"action_current_step" => null,
|
||||||
|
"action_max_step" => null,
|
||||||
"action_date_step" => null,
|
"action_date_step" => null,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -119,6 +120,14 @@ class RunFile {
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** après l'arrêt de l'application, mettre à jour le code de retour */
|
||||||
|
function stopped(int $exitcode): void {
|
||||||
|
[$file, $data] = $this->willWrite();
|
||||||
|
$file->serialize(self::merge($data, [
|
||||||
|
"exitcode" => $exitcode,
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
function getLockFile(?string $name=null, ?string $title=null): LockFile {
|
function getLockFile(?string $name=null, ?string $title=null): LockFile {
|
||||||
$ext = self::LOCK_EXT;
|
$ext = self::LOCK_EXT;
|
||||||
if ($name !== null) $ext = ".$name$ext";
|
if ($name !== null) $ext = ".$name$ext";
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema;
|
|
||||||
|
|
||||||
class OldSchema {
|
|
||||||
/**
|
|
||||||
* @var bool true si toutes les clés du schéma doivent exister, avec leur
|
|
||||||
* valeur par défaut le cas échéant
|
|
||||||
*/
|
|
||||||
protected $ppEnsureKeys;
|
|
||||||
|
|
||||||
/** @var bool true si les clés doivent être dans l'ordre du schéma */
|
|
||||||
protected $ppOrderKeys;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var bool true si les valeurs doivent être automatiquement vérifiées et
|
|
||||||
* corrigées
|
|
||||||
*/
|
|
||||||
protected $ppVerifix;
|
|
||||||
|
|
||||||
function ensureSchema(&$value, $key=null, ?array $params=null): void {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,197 +0,0 @@
|
||||||
# nulib\schema
|
|
||||||
|
|
||||||
objet: s'assurer que des données soit dans un type particulier, en les
|
|
||||||
convertissant si nécessaire. la source de ces données peut-être diverse:
|
|
||||||
formulaire web, résultat d'une requête SQL, flux CSV, etc.
|
|
||||||
|
|
||||||
les données dont on peut modéliser le schéma sont de 3 types:
|
|
||||||
* scalaire
|
|
||||||
* tableau associatif
|
|
||||||
* liste (tableau séquentiel ou associatif d'éléments du même type)
|
|
||||||
|
|
||||||
chaque type de données a une syntaxe spécifique pour la définition du schéma.
|
|
||||||
|
|
||||||
## Nature de schéma
|
|
||||||
|
|
||||||
Un schéma se présente sous la forme d'un tableau associatif avec des clés qui
|
|
||||||
dépendent de la nature du schéma. La nature du schéma est indiquée avec la clé
|
|
||||||
`""` (chaine vide), e.g
|
|
||||||
~~~php
|
|
||||||
const SCHEMA = [
|
|
||||||
"" => NATURE,
|
|
||||||
];
|
|
||||||
~~~
|
|
||||||
|
|
||||||
La nature indique le type de données représenté par le schéma.
|
|
||||||
* nature scalaire: modélise une donnée scalaire
|
|
||||||
~~~php
|
|
||||||
const SCALAR_SCHEMA = [
|
|
||||||
$type, [$default, $title, ...]
|
|
||||||
"" => "scalar",
|
|
||||||
];
|
|
||||||
~~~
|
|
||||||
Si le type est "array" ou "?array", on peut préciser le schéma de la donnée
|
|
||||||
~~~php
|
|
||||||
const SCALAR_SCHEMA = [
|
|
||||||
"?array", [$default, $title, ...]
|
|
||||||
"" => "scalar",
|
|
||||||
"schema" => NAKED_SCHEMA,
|
|
||||||
];
|
|
||||||
~~~
|
|
||||||
* nature tableau associatif: modélise un tableau associatif (le tableau peut
|
|
||||||
avoir des clés numériques ou chaines --> seules les clés décrites par le
|
|
||||||
schéma sont validées)
|
|
||||||
~~~php
|
|
||||||
const ASSOC_SCHEMA = [
|
|
||||||
KEY => VALUE_SCHEMA,
|
|
||||||
...
|
|
||||||
"" => "assoc",
|
|
||||||
];
|
|
||||||
~~~
|
|
||||||
la nature "tableau associatif" est du sucre syntaxique pour une valeur
|
|
||||||
scalaire de type "?array" dont on précise le schéma
|
|
||||||
~~~php
|
|
||||||
// la valeur ci-dessus est strictement équivalent à
|
|
||||||
const ASSOC_SCHEMA = [
|
|
||||||
"?array",
|
|
||||||
"" => "scalar",
|
|
||||||
"schema" => [
|
|
||||||
KEY => VALUE_SCHEMA,
|
|
||||||
...
|
|
||||||
],
|
|
||||||
];
|
|
||||||
~~~
|
|
||||||
|
|
||||||
* nature liste: modélise une liste de valeurs du même type (le tableau peut
|
|
||||||
avoir des clés numériques ou chaines --> on ne modélise ni le type ni la
|
|
||||||
valeur des clés)
|
|
||||||
~~~php
|
|
||||||
const LIST_SCHEMA = [
|
|
||||||
"?array", [$default, $title, ...]
|
|
||||||
"" => "list",
|
|
||||||
"schema" => ITEM_SCHEMA,
|
|
||||||
];
|
|
||||||
~~~
|
|
||||||
|
|
||||||
## Schéma d'une valeur scalaire
|
|
||||||
|
|
||||||
Dans sa forme normalisée, une valeur scalaire est généralement modélisée de
|
|
||||||
cette manière:
|
|
||||||
~~~php
|
|
||||||
const SCALAR_SCHEMA = [
|
|
||||||
"type" => "types autorisés de la valeur",
|
|
||||||
"default" => "valeur par défaut si la valeur n'existe pas",
|
|
||||||
"title" => "libellé de la valeur, utilisable par exemple dans un formulaire",
|
|
||||||
"required" => "la valeur est-elle requise? si oui, elle doit exister",
|
|
||||||
"nullable" => "si la valeur existe, peut-elle être nulle?",
|
|
||||||
"desc" => "description de la valeur",
|
|
||||||
"checker_func" => "une fonction qui vérifie une valeur et la classifie",
|
|
||||||
"parser_func" => "une fonction qui analyse une chaine pour produire la valeur",
|
|
||||||
"messages" => "messages à afficher en cas d'erreur d'analyse",
|
|
||||||
"formatter_func" => "une fonction qui formatte la valeur pour affichage",
|
|
||||||
"format" => "format à utiliser pour l'affichage",
|
|
||||||
"" => "scalar",
|
|
||||||
"schema" => "schéma de la valeur si le type est array ou ?array, null sinon",
|
|
||||||
];
|
|
||||||
~~~
|
|
||||||
|
|
||||||
L'ordre des clés du schéma ci-dessus indique la clé associé à une valeur si elle
|
|
||||||
est fournie dans un tableau séquentiel. Par exemple, les deux schéma suivants
|
|
||||||
sont équivalents:
|
|
||||||
~~~php
|
|
||||||
const SCALAR_SCHEMA1 = [
|
|
||||||
"string", null, "une valeur chaine",
|
|
||||||
];
|
|
||||||
const SCALAR_SCHEMA2 = [
|
|
||||||
"type" => "string",
|
|
||||||
"default" => null,
|
|
||||||
"title" => "une valeur chaine",
|
|
||||||
"" => "scalar",
|
|
||||||
];
|
|
||||||
~~~
|
|
||||||
|
|
||||||
Si la nature du schéma n'est pas spécifiée, on considère que c'est un schéma de
|
|
||||||
nature scalaire si:
|
|
||||||
* c'est une chaine, qui représente alors le type, e.g `"string"`
|
|
||||||
* c'est un tableau avec un unique élément à l'index 0 de type chaine, qui est
|
|
||||||
aussi le type, e.g `["string"]`
|
|
||||||
* c'est un tableau avec un élément à l'index 0, ainsi que d'autres éléments,
|
|
||||||
e.g `["string", null, "required" => true]`
|
|
||||||
|
|
||||||
message indique les messages à afficher en cas d'erreur d'analyse. les clés sont
|
|
||||||
normalisées et correspondent à différents états de la valeur tels qu'analysés
|
|
||||||
par `checker_func`
|
|
||||||
~~~php
|
|
||||||
const MESSAGE_SCHEMA = [
|
|
||||||
"missing" => "message si la valeur n'existe pas dans la source et qu'elle est requise",
|
|
||||||
"unavailable" => "message si la valeur vaut false dans la source et qu'elle est requise",
|
|
||||||
"null" => "message si la valeur est nulle et qu'elle n'est pas nullable",
|
|
||||||
"empty" => "message si la valeur est une chaine vide et que ce n'est pas autorisé",
|
|
||||||
"invalid" => "message si la valeur est invalide",
|
|
||||||
];
|
|
||||||
~~~
|
|
||||||
|
|
||||||
## Schéma d'un tableau associatif
|
|
||||||
|
|
||||||
Dans sa forme *non normalisée*, un tableau associatif est généralement modélisé
|
|
||||||
de cette manière:
|
|
||||||
~~~php
|
|
||||||
const ASSOC_SCHEMA = [
|
|
||||||
KEY => VALUE_SCHEMA,
|
|
||||||
...
|
|
||||||
"" => "assoc",
|
|
||||||
];
|
|
||||||
~~~
|
|
||||||
où chaque occurrence de `KEY => VALUE_SCHEMA` définit le schéma de la valeur
|
|
||||||
dont la clé est `KEY`
|
|
||||||
|
|
||||||
Si la nature du schéma n'est pas spécifiée, on considère que c'est un schéma de
|
|
||||||
nature associative si:
|
|
||||||
* c'est un tableau uniquement associatif avec aucun élément séquentiel, e.g
|
|
||||||
`["name" => "string", "age" => "int"]`
|
|
||||||
|
|
||||||
VALUE_SCHEMA peut-être n'importe quel schéma valide, qui sera analysé
|
|
||||||
récursivement, avec cependant l'ajout de quelques clés supplémentaires:
|
|
||||||
* description de la valeur dans le contexte du tableau
|
|
||||||
~~~php
|
|
||||||
VALUE_SCHEMA = [
|
|
||||||
...
|
|
||||||
"name" => "identifiant de la valeur",
|
|
||||||
"pkey" => "chemin de clé de la valeur dans le tableau associatif",
|
|
||||||
];
|
|
||||||
~~~
|
|
||||||
* s'il s'agit d'une valeur scalaire simple autre que array
|
|
||||||
~~~php
|
|
||||||
VALUE_SCHEMA = [
|
|
||||||
...
|
|
||||||
"header" => "nom de l'en-tête s'il faut présenter cette donnée dans un tableau",
|
|
||||||
"composite" => "ce champ fait-il partie d'une valeur composite?",
|
|
||||||
];
|
|
||||||
~~~
|
|
||||||
|
|
||||||
## Schéma d'une liste (tableau séquentiel ou associatif d'éléments du même type)
|
|
||||||
|
|
||||||
Dans sa forme *non normalisée*, une liste est généralement modélisée de cette
|
|
||||||
manière:
|
|
||||||
~~~php
|
|
||||||
const LIST_SCHEMA = [ITEM_SCHEMA];
|
|
||||||
~~~
|
|
||||||
où ITEM_SCHEMA est le schéma des éléments de la liste
|
|
||||||
|
|
||||||
Pour information, la forme normalisée est plutôt de la forme
|
|
||||||
~~~php
|
|
||||||
const LIST_SCHEMA = [
|
|
||||||
"?array",
|
|
||||||
"" => "list",
|
|
||||||
"schema" => ITEM_SCHEMA,
|
|
||||||
];
|
|
||||||
~~~
|
|
||||||
le type "?array" ou "array" indique si la liste est nullable ou non. la valeur
|
|
||||||
par défaut est "?array"
|
|
||||||
|
|
||||||
Si la nature du schéma n'est pas spécifiée, on considère que c'est un schéma de
|
|
||||||
nature liste si:
|
|
||||||
* c'est un tableau avec un unique élément de type tableau à l'index 0, e.g
|
|
||||||
`[["string", null, "required" => true]]`
|
|
||||||
|
|
||||||
-*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary
|
|
|
@ -1,30 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema;
|
|
||||||
|
|
||||||
use nulib\schema\_assoc\AssocResult;
|
|
||||||
use nulib\schema\_list\ListResult;
|
|
||||||
use nulib\schema\_scalar\ScalarResult;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class Result: résultat de l'analyse ou de la normalisation d'une valeur
|
|
||||||
*/
|
|
||||||
abstract class Result {
|
|
||||||
function __construct() {
|
|
||||||
$this->reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
function isAssoc(?AssocResult &$assoc=null): bool { return false; }
|
|
||||||
function isList(?ListResult &$list=null): bool { return false; }
|
|
||||||
function isScalar(?ScalarResult &$scalar=null): bool { return false; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtenir la liste des clés valides pour les valeurs accessibles via cet
|
|
||||||
* objet
|
|
||||||
*/
|
|
||||||
abstract function getKeys(): array;
|
|
||||||
|
|
||||||
/** obtenir un objet pour gérer la valeur spécifiée */
|
|
||||||
abstract function getResult($key=null): Result;
|
|
||||||
|
|
||||||
abstract function reset(): void;
|
|
||||||
}
|
|
|
@ -1,94 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema;
|
|
||||||
|
|
||||||
use ArrayAccess;
|
|
||||||
use nulib\AccessException;
|
|
||||||
use nulib\cl;
|
|
||||||
use nulib\schema\_assoc\AssocSchema;
|
|
||||||
use nulib\schema\_list\ListSchema;
|
|
||||||
use nulib\schema\_scalar\ScalarSchema;
|
|
||||||
|
|
||||||
abstract class Schema implements ArrayAccess {
|
|
||||||
/**
|
|
||||||
* créer si besoin une nouvelle instance de {@link Schema} à partir d'une
|
|
||||||
* définition de schéma
|
|
||||||
*
|
|
||||||
* - si $schema est une instance de schéma, la retourner
|
|
||||||
* - si $schema est un array, c'est une définition, et elle est remplacée par
|
|
||||||
* l'instance de Schema nouvelle créée
|
|
||||||
* - sinon, prendre $definition comme définition
|
|
||||||
*/
|
|
||||||
static function ns(&$schema, $definition=null, $definitionKey=null): self {
|
|
||||||
if (is_array($schema)) {
|
|
||||||
$definition = $schema;
|
|
||||||
$schema = null;
|
|
||||||
}
|
|
||||||
if ($schema === null) {
|
|
||||||
if (AssocSchema::isa_definition($definition)) {
|
|
||||||
$schema = new AssocSchema($definition, $definitionKey);
|
|
||||||
} elseif (ListSchema::isa_definition($definition)) {
|
|
||||||
$schema = new ListSchema($definition, $definitionKey);
|
|
||||||
} elseif (ScalarSchema::isa_definition($definition)) {
|
|
||||||
$schema = new ScalarSchema($definition, $definitionKey);
|
|
||||||
} else {
|
|
||||||
throw SchemaException::invalid_schema();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $schema;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Créer si besoin une nouvelle instance de {@link Value} qui référence la
|
|
||||||
* variable $dest (si $destKey===null) ou $dest[$destKey] si $destKey n'est
|
|
||||||
* pas null
|
|
||||||
*/
|
|
||||||
static function nv(?Value &$destv=null, &$dest=null, $destKey=null, &$schema=null, $definition=null): Value {
|
|
||||||
if ($definition === null) {
|
|
||||||
# bien que techniquement, $definition peut être null (il s'agit alors du
|
|
||||||
# schéma d'un scalaire quelconque), on ne l'autorise pas ici
|
|
||||||
throw SchemaException::invalid_schema("definition is required");
|
|
||||||
}
|
|
||||||
return self::ns($schema, $definition)->newValue($destv, $dest, $destKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array définition du schéma, à redéfinir le cas échéant dans une classe
|
|
||||||
* dérivée
|
|
||||||
*/
|
|
||||||
const SCHEMA = null;
|
|
||||||
|
|
||||||
/** @var array */
|
|
||||||
protected $definition;
|
|
||||||
|
|
||||||
/** retourner true si le schéma est de nature tableau associatif */
|
|
||||||
function isAssoc(?AssocSchema &$assoc=null): bool { return false; }
|
|
||||||
/** retourner true si le schéma est de nature liste */
|
|
||||||
function isList(?ListSchema &$list=null): bool { return false; }
|
|
||||||
/** retourner true si le schéma est de nature scalaire */
|
|
||||||
function isScalar(?ScalarSchema &$scalar=null): bool { return false; }
|
|
||||||
|
|
||||||
abstract function newValue(?Value &$destv=null, &$dest=null, $destKey=null): Value;
|
|
||||||
|
|
||||||
#############################################################################
|
|
||||||
# key & properties
|
|
||||||
|
|
||||||
function offsetExists($offset): bool {
|
|
||||||
return array_key_exists($offset, $this->definition);
|
|
||||||
}
|
|
||||||
function offsetGet($offset) {
|
|
||||||
if (!array_key_exists($offset, $this->definition)) return null;
|
|
||||||
else return $this->definition[$offset];
|
|
||||||
}
|
|
||||||
function offsetSet($offset, $value): void {
|
|
||||||
throw AccessException::read_only(null, $offset);
|
|
||||||
}
|
|
||||||
function offsetUnset($offset): void {
|
|
||||||
throw AccessException::read_only(null, $offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
const _PROPERTY_PKEYS = [];
|
|
||||||
function __get($name) {
|
|
||||||
$pkey = cl::get(static::_PROPERTY_PKEYS, $name, $name);
|
|
||||||
return cl::pget($this->definition, $pkey);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema;
|
|
||||||
|
|
||||||
use Exception;
|
|
||||||
|
|
||||||
class SchemaException extends Exception {
|
|
||||||
static final function invalid_schema(?string $message=null): self {
|
|
||||||
$invalid_schema = "invalid schema";
|
|
||||||
if ($message !== null) $invalid_schema .= ": $message";
|
|
||||||
return new static($invalid_schema);
|
|
||||||
}
|
|
||||||
|
|
||||||
static final function invalid_kind(string $kind, $value, ?string $message=null): self {
|
|
||||||
$invalid_kind = var_export($value, true).": invalid $kind";
|
|
||||||
if ($message !== null) $invalid_kind .= ": $message";
|
|
||||||
return new static($invalid_kind);
|
|
||||||
}
|
|
||||||
|
|
||||||
static final function invalid_type($value, ?string $message=null): self {
|
|
||||||
return self::invalid_kind("type", $value, $message);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,82 +0,0 @@
|
||||||
# nulib\schema
|
|
||||||
|
|
||||||
* implémenter support `analyzer_func`, `extractor_func`, `parser_func`,
|
|
||||||
`normalizer_func`, `formatter_func`
|
|
||||||
* 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, [
|
|
||||||
"a" => "?string",
|
|
||||||
"b" => "?int",
|
|
||||||
])->newValue();
|
|
||||||
$dest = ["x_a" => 5, "x_b" => "10"],
|
|
||||||
$value->reset($dest, null, [
|
|
||||||
"key_prefix" => "x_",
|
|
||||||
]);
|
|
||||||
# $dest vaut ["x_a" => "5", "x_b" => 10];
|
|
||||||
~~~
|
|
||||||
définir si le préfixe doit être spécifié sur le schéma ou sur la valeur...
|
|
||||||
actuellement, le code ne permet pas de définir de tels paramètres...
|
|
||||||
|
|
||||||
alternative: c'est lors de la *définition* du schéma que le préfixe est ajouté
|
|
||||||
e.g
|
|
||||||
~~~php
|
|
||||||
$value = Schema::ns($schema, [
|
|
||||||
"a" => "?string",
|
|
||||||
"b" => "?int",
|
|
||||||
], [
|
|
||||||
"key_prefix" => "x_",
|
|
||||||
])->newValue();
|
|
||||||
$dest = ["x_a" => 5, "x_b" => "10"],
|
|
||||||
$value->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
|
|
||||||
~~~php
|
|
||||||
const SCHEMA = ["type", default, "required" => true];
|
|
||||||
# le type est instancié comme suit:
|
|
||||||
$type = new ttype();
|
|
||||||
|
|
||||||
const SCHEMA = [[["type", ...]], default, "required" => true];
|
|
||||||
# le type est instancié comme suit:
|
|
||||||
# le tableau peut être une liste ou associatif, c'est au type de décider ce
|
|
||||||
# qu'il en fait
|
|
||||||
$type = new ttype(["type", ...], SCHEMA);
|
|
||||||
~~~
|
|
||||||
* ajouter à IType les méthodes getName() pour le nom officiel du type,
|
|
||||||
getAliases() pour les alias supportés, et getClass() pour la définition de la
|
|
||||||
classe dans les méthodes et propriétés
|
|
||||||
getName() et getAliases() sont juste pour information, ils ne sont pas utilisés
|
|
||||||
lors de la résolution du type effectif.
|
|
||||||
* si cela a du sens, dans AssocSchema, n'instancier les schémas de chaque clé qu'à la demande.
|
|
||||||
l'idée est de ne pas perdre du temps à instancier un schéma qui ne serait pas utilisé
|
|
||||||
|
|
||||||
on pourrait avoir d'une manière générale quelque chose comme:
|
|
||||||
~~~
|
|
||||||
Schema::ensure(&$schema, ?array $def=null, $defKey=null): Schema;
|
|
||||||
~~~
|
|
||||||
* si $schema est une instance de Schema, la retourner
|
|
||||||
* si c'est un array, c'est une définition et il faut la remplacer par l'instance de Schema correspondant
|
|
||||||
* sinon, prendre $def comme définition
|
|
||||||
$key est la clé si $schema est dans un autre schema
|
|
||||||
* actuellement, pour un schéma associatif, si on normalise un tableau séquentiel,
|
|
||||||
chaque valeur correspond à la clé de même rang, eg. pour un schéma
|
|
||||||
~~~php
|
|
||||||
const SCHEMA = ["first" => DEF, "second" => DEF];
|
|
||||||
const ARRAY = ["first", "second"];
|
|
||||||
~~~
|
|
||||||
la valeur normalisée de `ARRAY` est `["first" => "first", "second" => "second"]`
|
|
||||||
|
|
||||||
cependant, dans certaines circonstances (notamment pour des paramètres), on
|
|
||||||
devrait pouvoir considérer une valeur indexée comme un flag, i.e la valeur
|
|
||||||
normalisée de ARRAY serait `["first" => true, "second" => true]`
|
|
||||||
|
|
||||||
la définition de ces "circonstances" est encore à faire: soit un paramètre
|
|
||||||
lors de la définition du schéma, soit un truc magique du genre "toutes les
|
|
||||||
valeurs séquentielles sont des clés du schéma"
|
|
||||||
|
|
||||||
-*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary
|
|
|
@ -1,85 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema;
|
|
||||||
|
|
||||||
use ArrayAccess;
|
|
||||||
use IteratorAggregate;
|
|
||||||
use nulib\schema\_assoc\AssocValue;
|
|
||||||
use nulib\schema\_list\ListValue;
|
|
||||||
use nulib\schema\_scalar\ScalarValue;
|
|
||||||
use nulib\schema\types\IType;
|
|
||||||
|
|
||||||
abstract class Value implements ArrayAccess, IteratorAggregate {
|
|
||||||
function isAssoc(?AssocValue &$assoc=null): bool { return false; }
|
|
||||||
function isList(?ListValue &$list=null): bool { return false; }
|
|
||||||
function isScalar(?ScalarValue &$scalar=null): bool { return false; }
|
|
||||||
|
|
||||||
/** spécifier la valeur destination gérée par cet objet */
|
|
||||||
abstract function reset(&$dest, $destKey=null, ?bool $verifix=null): self;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtenir la liste des clés valides pour les valeurs accessibles via cet
|
|
||||||
* objet
|
|
||||||
*/
|
|
||||||
abstract function getKeys(): array;
|
|
||||||
|
|
||||||
/** obtenir un objet pour gérer la valeur spécifiée */
|
|
||||||
abstract function getValue($key=null): Value;
|
|
||||||
|
|
||||||
function getIterator() {
|
|
||||||
foreach ($this->getKeys() as $key) {
|
|
||||||
yield $key => $this->getValue($key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* obtenir le résultat de l'appel d'une des fonctions {@link set()} ou
|
|
||||||
* {@link unset()}
|
|
||||||
*/
|
|
||||||
abstract function getResult(): Result;
|
|
||||||
|
|
||||||
/** retourner true si la valeur existe */
|
|
||||||
abstract function isPresent(): bool;
|
|
||||||
|
|
||||||
/** retourner le type associé à la valeur */
|
|
||||||
abstract function getType(): IType;
|
|
||||||
|
|
||||||
/** retourner true si la valeur est disponible */
|
|
||||||
abstract function isAvailable(): bool;
|
|
||||||
|
|
||||||
/** retourner true si la valeur est valide */
|
|
||||||
abstract function isValid(): bool;
|
|
||||||
|
|
||||||
/** retourner true si la valeur est dans sa forme normalisée */
|
|
||||||
abstract function isNormalized(): bool;
|
|
||||||
|
|
||||||
/** obtenir la valeur */
|
|
||||||
abstract function get($default=null);
|
|
||||||
|
|
||||||
/** remplacer la valeur */
|
|
||||||
abstract function set($value): self;
|
|
||||||
|
|
||||||
/** supprimer la valeur */
|
|
||||||
abstract function unset(): self;
|
|
||||||
|
|
||||||
/** formatter la valeur pour affichage */
|
|
||||||
abstract function format($format=null): string;
|
|
||||||
|
|
||||||
#############################################################################
|
|
||||||
# key & properties
|
|
||||||
|
|
||||||
function offsetExists($offset): bool {
|
|
||||||
return in_array($offset, $this->getKeys());
|
|
||||||
}
|
|
||||||
|
|
||||||
function offsetGet($offset) {
|
|
||||||
return $this->getValue($offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
function offsetSet($offset, $value): void {
|
|
||||||
$this->getValue($offset)->set($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
function offsetUnset($offset): void {
|
|
||||||
$this->getValue($offset)->unset();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\_assoc;
|
|
||||||
|
|
||||||
use nulib\schema\Result;
|
|
||||||
|
|
||||||
class AssocResult extends Result {
|
|
||||||
function isAssoc(?AssocResult &$assoc=null): bool { $assoc = $this; return true;}
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\_assoc;
|
|
||||||
|
|
||||||
use nulib\cl;
|
|
||||||
use nulib\ref\schema\ref_schema;
|
|
||||||
use nulib\schema\Schema;
|
|
||||||
use nulib\schema\Value;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class AssocSchema
|
|
||||||
*/
|
|
||||||
class AssocSchema extends Schema {
|
|
||||||
/** @var array meta-schema d'un schéma de nature tableau associatif */
|
|
||||||
const METASCHEMA = ref_schema::ASSOC_METASCHEMA;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* indiquer si $definition est une définition de schéma de nature tableau
|
|
||||||
* associatif que {@link normalize()} pourrait normaliser
|
|
||||||
*/
|
|
||||||
static function isa_definition($definition): bool {
|
|
||||||
if (!is_array($definition)) return false;
|
|
||||||
# nature explicitement spécifiée
|
|
||||||
if (array_key_exists("", $definition)) {
|
|
||||||
$nature = $definition[""];
|
|
||||||
if ($nature === "assoc") return true;
|
|
||||||
if (is_array($nature)
|
|
||||||
&& array_key_exists(0, $nature)
|
|
||||||
&& $nature[0] === "assoc") {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
# un tableau associatif
|
|
||||||
return !cl::have_num_keys($definition);
|
|
||||||
}
|
|
||||||
|
|
||||||
static function normalize($definition, $definitionKey=null): array {
|
|
||||||
}
|
|
||||||
|
|
||||||
function __construct($definition=null, $definitionKey=null, bool $normalize=true) {
|
|
||||||
if ($definition === null) $definition = static::SCHEMA;
|
|
||||||
if ($normalize) $definition = self::normalize($definition, $definitionKey);
|
|
||||||
$this->definition = $definition;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isAssoc(?AssocSchema &$assoc=null): bool {
|
|
||||||
$assoc = $this;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function newValue(?Value &$destv=null, &$dest=null, $destKey=null): AssocValue {
|
|
||||||
if ($destv instanceof AssocValue) return $destv->reset($dest, $destKey);
|
|
||||||
else return ($destv = new AssocValue($this, $dest, $destKey));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\_assoc;
|
|
||||||
|
|
||||||
use nulib\schema\Result;
|
|
||||||
use nulib\schema\Value;
|
|
||||||
|
|
||||||
class AssocValue extends Value {
|
|
||||||
function isAssoc(?AssocValue &$assoc=null): bool { $assoc = $this; return true; }
|
|
||||||
|
|
||||||
function ensureKeys(): bool {
|
|
||||||
}
|
|
||||||
function orderKeys(): bool {
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param Result[] $results */
|
|
||||||
function verifix(bool $throw=true, ?array &$results=null): bool {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\_list;
|
|
||||||
|
|
||||||
use nulib\schema\Result;
|
|
||||||
|
|
||||||
class ListResult extends Result {
|
|
||||||
function isList(?ListResult &$list=null): bool { $list = $this; return true;}
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\_list;
|
|
||||||
|
|
||||||
use nulib\ref\schema\ref_schema;
|
|
||||||
use nulib\schema\Schema;
|
|
||||||
use nulib\schema\Value;
|
|
||||||
|
|
||||||
class ListSchema extends Schema {
|
|
||||||
/** @var array meta-schema d'un schéma de nature liste */
|
|
||||||
const METASCHEMA = ref_schema::LIST_METASCHEMA;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* indiquer si $definition est une définition de schéma de nature liste que
|
|
||||||
* {@link normalize()} pourrait normaliser
|
|
||||||
*/
|
|
||||||
static function isa_definition($definition): bool {
|
|
||||||
if (!is_array($definition)) return false;
|
|
||||||
# nature explicitement spécifiée
|
|
||||||
if (array_key_exists("", $definition)) {
|
|
||||||
$nature = $definition[""];
|
|
||||||
if ($nature === "list") return true;
|
|
||||||
if (is_array($nature)
|
|
||||||
&& array_key_exists(0, $nature)
|
|
||||||
&& $nature[0] === "list") {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
# un unique élément tableau à l'index 0
|
|
||||||
$count = count($definition);
|
|
||||||
$haveIndex0 = array_key_exists(0, $definition);
|
|
||||||
return $count == 1 && $haveIndex0 && is_array($definition[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static function normalize($definition, $definitionKey=null): array {
|
|
||||||
}
|
|
||||||
|
|
||||||
function __construct($definition=null, $definitionKey=null, bool $normalize=true) {
|
|
||||||
if ($definition === null) $definition = static::SCHEMA;
|
|
||||||
if ($normalize) $definition = self::normalize($definition, $definitionKey);
|
|
||||||
$this->definition = $definition;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isList(?ListSchema &$list=null): bool {
|
|
||||||
$list = $this;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function newValue(?Value &$destv=null, &$dest=null, $destKey=null): ListValue {
|
|
||||||
if ($destv instanceof ListValue) return $destv->reset($dest, $destKey);
|
|
||||||
else return ($destv = new ListValue($this, $dest, $destKey));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\_list;
|
|
||||||
|
|
||||||
use nulib\schema\Result;
|
|
||||||
use nulib\schema\Value;
|
|
||||||
|
|
||||||
class ListValue extends Value {
|
|
||||||
function isList(?ListValue &$list=null): bool { $list = $this; return true; }
|
|
||||||
|
|
||||||
function ensureKeys(): bool {
|
|
||||||
}
|
|
||||||
|
|
||||||
function orderKeys(): bool {
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param Result[] $results */
|
|
||||||
function verifix(bool $throw=true, ?array &$results=null): bool {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,165 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\_scalar;
|
|
||||||
|
|
||||||
use nulib\cl;
|
|
||||||
use nulib\ref\schema\ref_analyze;
|
|
||||||
use nulib\ref\schema\ref_schema;
|
|
||||||
use nulib\schema\Result;
|
|
||||||
use nulib\ValueException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 $available si la valeur existe, est-elle disponible?
|
|
||||||
* @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 $message message si la valeur n'est pas valide
|
|
||||||
*/
|
|
||||||
class ScalarResult extends Result {
|
|
||||||
const KEYS = ["resultAvailable", "present", "available", "null", "valid", "normalized", "orig", "message"];
|
|
||||||
|
|
||||||
function isScalar(?ScalarResult &$scalar=null): bool { $scalar = $this; return true; }
|
|
||||||
|
|
||||||
function getKeys(): array {
|
|
||||||
return [null];
|
|
||||||
}
|
|
||||||
|
|
||||||
function getResult($key=null): Result {
|
|
||||||
if ($key === null) return $this;
|
|
||||||
else throw ValueException::invalid_key($key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var array */
|
|
||||||
protected $result;
|
|
||||||
|
|
||||||
function reset(): void {
|
|
||||||
$this->result = array_merge(
|
|
||||||
array_fill_keys(static::KEYS, null), [
|
|
||||||
"resultAvailable" => false,
|
|
||||||
"present" => false,
|
|
||||||
"available" => false,
|
|
||||||
"null" => false,
|
|
||||||
"valid" => false,
|
|
||||||
"normalized" => false,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function __get(string $name) {
|
|
||||||
return $this->result[$name];
|
|
||||||
}
|
|
||||||
|
|
||||||
function __set(string $name, $value): void {
|
|
||||||
$this->result[$name] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static function replace_key(string &$message, ?string $key): void {
|
|
||||||
if ($key) {
|
|
||||||
$message = str_replace("{key}", $key, $message);
|
|
||||||
} else {
|
|
||||||
$message = str_replace("{key}: ", "", $message);
|
|
||||||
$message = str_replace("cette valeur", "la valeur", $message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static function replace_orig(string &$message, $orig): void {
|
|
||||||
$message = str_replace("{orig}", strval($orig), $message);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getMessage(string $key, ScalarSchema $schema): string {
|
|
||||||
$message = cl::get($schema->messages, $key);
|
|
||||||
if ($message !== null) return $message;
|
|
||||||
return cl::get(ref_schema::MESSAGES, $key);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setMissing(ScalarSchema $schema): int {
|
|
||||||
$this->resultAvailable = true;
|
|
||||||
$this->present = false;
|
|
||||||
$this->available = false;
|
|
||||||
if (!$schema->required) {
|
|
||||||
$this->null = false;
|
|
||||||
$this->valid = true;
|
|
||||||
$this->normalized = true;
|
|
||||||
return ref_analyze::NORMALIZED;
|
|
||||||
} else {
|
|
||||||
$message = $this->getMessage("missing", $schema);
|
|
||||||
self::replace_key($message, $schema->name);
|
|
||||||
$this->message = $message;
|
|
||||||
return ref_analyze::MISSING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setUnavailable(ScalarSchema $schema): int {
|
|
||||||
$this->resultAvailable = true;
|
|
||||||
$this->present = true;
|
|
||||||
$this->available = false;
|
|
||||||
if (!$schema->required) {
|
|
||||||
$this->null = false;
|
|
||||||
$this->valid = true;
|
|
||||||
$this->normalized = true;
|
|
||||||
return ref_analyze::NORMALIZED;
|
|
||||||
} else {
|
|
||||||
$message = $this->getMessage("unavailable", $schema);
|
|
||||||
self::replace_key($message, $schema->name);
|
|
||||||
$this->message = $message;
|
|
||||||
return ref_analyze::UNAVAILABLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setNull(ScalarSchema $schema): int {
|
|
||||||
$this->resultAvailable = true;
|
|
||||||
$this->present = true;
|
|
||||||
$this->available = true;
|
|
||||||
$this->null = true;
|
|
||||||
if ($schema->nullable) {
|
|
||||||
$this->valid = true;
|
|
||||||
$this->normalized = true;
|
|
||||||
return ref_analyze::NORMALIZED;
|
|
||||||
} else {
|
|
||||||
$message = $this->getMessage("null", $schema);
|
|
||||||
self::replace_key($message, $schema->name);
|
|
||||||
$this->message = $message;
|
|
||||||
return ref_analyze::NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setInvalid($value, ScalarSchema $schema): int {
|
|
||||||
$this->resultAvailable = true;
|
|
||||||
$this->present = true;
|
|
||||||
$this->available = true;
|
|
||||||
$this->null = false;
|
|
||||||
$this->valid = false;
|
|
||||||
$this->orig = $value;
|
|
||||||
$message = $this->getMessage("invalid", $schema);
|
|
||||||
self::replace_key($message, $schema->name);
|
|
||||||
self::replace_orig($message, $schema->orig);
|
|
||||||
$this->message = $message;
|
|
||||||
return ref_analyze::INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setValid(): int {
|
|
||||||
$this->resultAvailable = true;
|
|
||||||
$this->present = true;
|
|
||||||
$this->available = true;
|
|
||||||
$this->null = false;
|
|
||||||
$this->valid = true;
|
|
||||||
return ref_analyze::VALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setNormalized(): int {
|
|
||||||
$this->resultAvailable = true;
|
|
||||||
$this->present = true;
|
|
||||||
$this->available = true;
|
|
||||||
$this->null = false;
|
|
||||||
$this->valid = true;
|
|
||||||
$this->normalized = true;
|
|
||||||
return ref_analyze::NORMALIZED;
|
|
||||||
}
|
|
||||||
|
|
||||||
function throw(bool $throw): void {
|
|
||||||
if ($throw) throw new ValueException($this->message);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,193 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\_scalar;
|
|
||||||
|
|
||||||
use nulib\cl;
|
|
||||||
use nulib\ref\schema\ref_schema;
|
|
||||||
use nulib\ref\schema\ref_types;
|
|
||||||
use nulib\schema\Schema;
|
|
||||||
use nulib\schema\SchemaException;
|
|
||||||
use nulib\schema\types\tarray;
|
|
||||||
use nulib\schema\types\tbool;
|
|
||||||
use nulib\schema\types\tcallable;
|
|
||||||
use nulib\schema\types\tcontent;
|
|
||||||
use nulib\schema\types\tpkey;
|
|
||||||
use nulib\schema\types\tstring;
|
|
||||||
use nulib\schema\Value;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class ScalarSchema
|
|
||||||
*
|
|
||||||
* @property-read array $type
|
|
||||||
* @property-read mixed $default
|
|
||||||
* @property-read string|null $title
|
|
||||||
* @property-read bool $required
|
|
||||||
* @property-read bool $nullable
|
|
||||||
* @property-read string|array|null $desc
|
|
||||||
* @property-read callable|null $analyzerFunc
|
|
||||||
* @property-read callable|null $extractorFunc
|
|
||||||
* @property-read callable|null $parserFunc
|
|
||||||
* @property-read callable|null $normalizerFunc
|
|
||||||
* @property-read array|null $messages
|
|
||||||
* @property-read callable|null $formatterFunc
|
|
||||||
* @property-read mixed $format
|
|
||||||
* @property-read array $nature
|
|
||||||
* @property-read string|int|null $name
|
|
||||||
* @property-read string|array|null $pkey
|
|
||||||
* @property-read string|null $header
|
|
||||||
* @property-read bool|null $composite
|
|
||||||
*/
|
|
||||||
class ScalarSchema extends Schema {
|
|
||||||
/** @var array meta-schema d'un schéma de nature scalaire */
|
|
||||||
const METASCHEMA = ref_schema::SCALAR_METASCHEMA;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* indiquer si $definition est une définition de schéma scalaire que
|
|
||||||
* {@link normalize()} pourrait normaliser
|
|
||||||
*/
|
|
||||||
static function isa_definition($definition): bool {
|
|
||||||
# chaine ou null
|
|
||||||
if ($definition === null) return true;
|
|
||||||
if (is_string($definition)) return true;
|
|
||||||
if (!is_array($definition)) return false;
|
|
||||||
# nature explicitement spécifiée
|
|
||||||
if (array_key_exists("", $definition)) {
|
|
||||||
$nature = $definition[""];
|
|
||||||
if ($nature === "scalar") return true;
|
|
||||||
if (is_array($nature)
|
|
||||||
&& array_key_exists(0, $nature)
|
|
||||||
&& $nature[0] === "scalar") {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
# un unique élément chaine à l'index 0
|
|
||||||
$count = count($definition);
|
|
||||||
$haveIndex0 = array_key_exists(0, $definition);
|
|
||||||
if ($count == 1 && $haveIndex0
|
|
||||||
&& ($definition[0] === null || is_string($definition[0]))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
# un élément à l'index 0, et d'autres éléments
|
|
||||||
return $haveIndex0 && $count > 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static function normalize($definition, $definitionKey=null): array {
|
|
||||||
if (!is_array($definition)) $definition = [$definition];
|
|
||||||
# s'assurer que toutes les clés existent avec leur valeur par défaut
|
|
||||||
$index = 0;
|
|
||||||
foreach (array_keys(self::METASCHEMA) as $key) {
|
|
||||||
if (!array_key_exists($key, $definition)) {
|
|
||||||
if (array_key_exists($index, $definition)) {
|
|
||||||
$definition[$key] = $definition[$index];
|
|
||||||
unset($definition[$index]);
|
|
||||||
$index++;
|
|
||||||
} else {
|
|
||||||
$definition[$key] = self::METASCHEMA[$key][1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
# réordonner les clés numériques
|
|
||||||
if (cl::have_num_keys($definition)) {
|
|
||||||
$keys = array_keys($definition);
|
|
||||||
$index = 0;
|
|
||||||
foreach ($keys as $key) {
|
|
||||||
if (!is_int($key)) continue;
|
|
||||||
$definition[$index] = $definition[$key];
|
|
||||||
unset($definition[$key]);
|
|
||||||
$index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
# type
|
|
||||||
$types = [];
|
|
||||||
$deftype = $definition["type"];
|
|
||||||
$nullable = $definition["nullable"];
|
|
||||||
if ($deftype === null) {
|
|
||||||
$types[] = null;
|
|
||||||
$nullable = true;
|
|
||||||
} else {
|
|
||||||
if (!is_array($deftype)) {
|
|
||||||
if (!is_string($deftype)) throw SchemaException::invalid_type($deftype);
|
|
||||||
$deftype = explode("|", $deftype);
|
|
||||||
}
|
|
||||||
foreach ($deftype as $type) {
|
|
||||||
if ($type === null || $type === "null") {
|
|
||||||
$nullable = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!is_string($type)) throw SchemaException::invalid_type($type);
|
|
||||||
if (substr($type, 0, 1) == "?") {
|
|
||||||
$type = substr($type, 1);
|
|
||||||
$nullable = true;
|
|
||||||
}
|
|
||||||
if ($type === "") throw SchemaException::invalid_type($type);
|
|
||||||
$type = cl::get(ref_types::ALIASES, $type, $type);
|
|
||||||
$types = array_merge($types, explode("|", $type));
|
|
||||||
}
|
|
||||||
if (!$types) throw SchemaException::invalid_schema("scalar: type is required");
|
|
||||||
$types = array_keys(array_fill_keys($types, true));
|
|
||||||
}
|
|
||||||
$definition["type"] = $types;
|
|
||||||
$definition["nullable"] = $nullable;
|
|
||||||
# nature
|
|
||||||
$nature = $definition[""];
|
|
||||||
tarray::ensure_array($nature);
|
|
||||||
if (!array_key_exists(0, $nature) || $nature[0] !== "scalar") {
|
|
||||||
throw SchemaException::invalid_schema("expected scalar nature");
|
|
||||||
}
|
|
||||||
$definition[""] = $nature;
|
|
||||||
# name, pkey, header
|
|
||||||
$name = $definition["name"];
|
|
||||||
$pkey = $definition["pkey"];
|
|
||||||
$header = $definition["header"];
|
|
||||||
if ($name === null) $name = $definitionKey;
|
|
||||||
tstring::ensure_nstring($name);
|
|
||||||
tpkey::ensure_npkey($pkey);
|
|
||||||
tstring::ensure_nstring($header);
|
|
||||||
if ($pkey === null) $pkey = $name;
|
|
||||||
if ($header === null) $header = $name;
|
|
||||||
$definition["name"] = $name;
|
|
||||||
$definition["pkey"] = $pkey;
|
|
||||||
$definition["header"] = $header;
|
|
||||||
# autres éléments
|
|
||||||
tstring::ensure_nstring($definition["title"]);
|
|
||||||
tbool::ensure_bool($definition["required"]);
|
|
||||||
tbool::ensure_bool($definition["nullable"]);
|
|
||||||
tcontent::ensure_ncontent($definition["desc"]);
|
|
||||||
tcallable::ensure_ncallable($definition["analyzer_func"]);
|
|
||||||
tcallable::ensure_ncallable($definition["extractor_func"]);
|
|
||||||
tcallable::ensure_ncallable($definition["parser_func"]);
|
|
||||||
tcallable::ensure_ncallable($definition["normalizer_func"]);
|
|
||||||
tarray::ensure_narray($definition["messages"]);
|
|
||||||
tcallable::ensure_ncallable($definition["formatter_func"]);
|
|
||||||
tbool::ensure_nbool($definition["composite"]);
|
|
||||||
return $definition;
|
|
||||||
}
|
|
||||||
|
|
||||||
function __construct($definition=null, $definitionKey=null, bool $normalize=true) {
|
|
||||||
if ($definition === null) $definition = static::SCHEMA;
|
|
||||||
if ($normalize) $definition = self::normalize($definition, $definitionKey);
|
|
||||||
$this->definition = $definition;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isScalar(?ScalarSchema &$scalar=null): bool {
|
|
||||||
$scalar = $this;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function newValue(?Value &$destv=null, &$dest=null, $destKey=null): ScalarValue {
|
|
||||||
if ($destv instanceof ScalarValue) return $destv->reset($dest, $destKey);
|
|
||||||
else return ($destv = new ScalarValue($this, $dest, $destKey));
|
|
||||||
}
|
|
||||||
|
|
||||||
#############################################################################
|
|
||||||
# key & properties
|
|
||||||
|
|
||||||
const _PROPERTY_PKEYS = [
|
|
||||||
"analyzerFunc" => "analyzer_func",
|
|
||||||
"extractorFunc" => "extractor_func",
|
|
||||||
"parserFunc" => "parser_func",
|
|
||||||
"normalizerFunc" => "normalizer_func",
|
|
||||||
"formatterFunc" => "formatter_func",
|
|
||||||
"nature" => ["", 0],
|
|
||||||
];
|
|
||||||
}
|
|
|
@ -1,198 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\_scalar;
|
|
||||||
|
|
||||||
use nulib\ref\schema\ref_analyze;
|
|
||||||
use nulib\schema\input\Input;
|
|
||||||
use nulib\schema\types;
|
|
||||||
use nulib\schema\types\IType;
|
|
||||||
use nulib\schema\Value;
|
|
||||||
use nulib\ValueException;
|
|
||||||
|
|
||||||
class ScalarValue extends Value {
|
|
||||||
function __construct(ScalarSchema $schema, &$dest=null, $destKey=null, bool $defaultVerifix=true, ?bool $defaultThrow=null) {
|
|
||||||
if ($dest !== null && $defaultThrow = 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;
|
|
||||||
}
|
|
||||||
$this->schema = $schema;
|
|
||||||
$this->defaultVerifix = $defaultVerifix;
|
|
||||||
$this->defaultThrow = $defaultThrow !== null? $defaultThrow: false;
|
|
||||||
$this->result = new ScalarResult();
|
|
||||||
$this->reset($dest, $destKey);
|
|
||||||
$this->defaultThrow = $defaultThrow !== null? $defaultThrow: true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isScalar(?ScalarValue &$scalar=null): bool { $scalar = $this; return true; }
|
|
||||||
|
|
||||||
/** @var ScalarSchema schéma de cette valeur */
|
|
||||||
protected $schema;
|
|
||||||
|
|
||||||
/** @var Input source et destination de la valeur */
|
|
||||||
protected $input;
|
|
||||||
|
|
||||||
/** @var string|int|null clé de la valeur dans le tableau destination */
|
|
||||||
protected $destKey;
|
|
||||||
|
|
||||||
/** @var bool */
|
|
||||||
protected $defaultVerifix;
|
|
||||||
|
|
||||||
/** @var bool */
|
|
||||||
protected $defaultThrow;
|
|
||||||
|
|
||||||
/** @var IType type de la valeur après analyse */
|
|
||||||
protected $type;
|
|
||||||
|
|
||||||
/** @var ?ScalarResult résultat de l'analyse de la valeur */
|
|
||||||
protected $result;
|
|
||||||
|
|
||||||
function reset(&$dest, $destKey=null, ?bool $verifix=null): Value {
|
|
||||||
if ($dest instanceof Input) $input = $dest;
|
|
||||||
else $input = new Input($dest);
|
|
||||||
$this->input = $input;
|
|
||||||
$this->destKey = $destKey;
|
|
||||||
$this->type = null;
|
|
||||||
$this->_analyze();
|
|
||||||
if ($verifix == null) $verifix = $this->defaultVerifix;
|
|
||||||
if ($verifix) $this->verifix();
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getKeys(): array {
|
|
||||||
return [null];
|
|
||||||
}
|
|
||||||
|
|
||||||
function getValue($key=null): ScalarValue {
|
|
||||||
if ($key === null) return $this;
|
|
||||||
throw ValueException::invalid_key($key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** analyser la valeur et résoudre son type */
|
|
||||||
function _analyze(): 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;
|
|
||||||
$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) {
|
|
||||||
$type = types::get($name);
|
|
||||||
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;
|
|
||||||
$this->type = $type;
|
|
||||||
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 (!$type->isAvailable($input, $destKey)) return $result->setUnavailable($schema);
|
|
||||||
$value = $input->get($destKey);
|
|
||||||
if ($type->isNull($value)) return $result->setNull($schema);
|
|
||||||
if ($type->isValid($value, $normalized)) {
|
|
||||||
if ($normalized) return $result->setNormalized();
|
|
||||||
else return $result->setValid();
|
|
||||||
}
|
|
||||||
if (is_string($value)) return ref_analyze::STRING;
|
|
||||||
else return $result->setInvalid($value, $schema);
|
|
||||||
}
|
|
||||||
|
|
||||||
function verifix(?bool $throw=null): bool {
|
|
||||||
if ($throw === null) $throw = $this->defaultThrow;
|
|
||||||
$destKey = $this->destKey;
|
|
||||||
$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;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getResult(): ScalarResult {
|
|
||||||
return $this->result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isPresent(): bool {
|
|
||||||
return $this->result->present;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getType(): IType {
|
|
||||||
return $this->type;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isAvailable(): bool {
|
|
||||||
return $this->result->available;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isValid(): bool {
|
|
||||||
return $this->result->valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isNormalized(): bool {
|
|
||||||
return $this->result->normalized;
|
|
||||||
}
|
|
||||||
|
|
||||||
function get($default=null) {
|
|
||||||
if ($this->result->available) return $this->input->get($this->destKey);
|
|
||||||
else return $default;
|
|
||||||
}
|
|
||||||
|
|
||||||
function set($value, ?bool $verifix=null): ScalarValue {
|
|
||||||
$this->input->set($value, $this->destKey);
|
|
||||||
$this->_analyze();
|
|
||||||
if ($verifix === null) $verifix = $this->defaultVerifix;
|
|
||||||
if ($verifix) $this->verifix();
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
function unset(?bool $verifix=null): ScalarValue {
|
|
||||||
$this->input->unset($this->destKey);
|
|
||||||
$this->_analyze();
|
|
||||||
if ($verifix === null) $verifix = $this->defaultVerifix;
|
|
||||||
if ($verifix) $this->verifix();
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
function format($format=null): string {
|
|
||||||
return $this->type->format($this->input->get($this->destKey), $format);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\input;
|
|
||||||
|
|
||||||
#XXX implémenter le renommage de paramètres et faire des méthodes pour
|
|
||||||
# construire des querystring et paramètres de formulaires
|
|
||||||
/**
|
|
||||||
* Class FormInput: accès à des paramètres de formulaire (POST ou GET, dans cet
|
|
||||||
* ordre)
|
|
||||||
*
|
|
||||||
* cette implémentation lit depuis les paramètres de formulaire et écrit dans
|
|
||||||
* une référence
|
|
||||||
*/
|
|
||||||
class FormInput extends Input {
|
|
||||||
const ALLOW_EMPTY = false;
|
|
||||||
|
|
||||||
function isPresent($key=null): bool {
|
|
||||||
if ($key === null) return false;
|
|
||||||
return array_key_exists($key, $_POST) || array_key_exists($key, $_GET);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isAvailable($key=null): bool {
|
|
||||||
if ($key === null) return false;
|
|
||||||
if (array_key_exists($key, $_POST)) {
|
|
||||||
return $this->allowEmpty || $_POST[$key] !== "";
|
|
||||||
} elseif (array_key_exists($key, $_GET)) {
|
|
||||||
return $this->allowEmpty || $_GET[$key] !== "";
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function get($key=null) {
|
|
||||||
if ($key === null) return null;
|
|
||||||
if (array_key_exists($key, $_POST)) {
|
|
||||||
$value = $_POST[$key];
|
|
||||||
if ($value === "" && !$this->allowEmpty) return null;
|
|
||||||
return $value;
|
|
||||||
} elseif (array_key_exists($key, $_GET)) {
|
|
||||||
$value = $_GET[$key];
|
|
||||||
if ($value === "" && !$this->allowEmpty) return null;
|
|
||||||
return $value;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\input;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class GetInput: accès à des paramètres de formulaire de type GET uniquement
|
|
||||||
*
|
|
||||||
* cette implémentation lit depuis les paramètres de formulaire et écrit dans
|
|
||||||
* une référence
|
|
||||||
*/
|
|
||||||
class GetInput extends FormInput {
|
|
||||||
function isPresent($key=null): bool {
|
|
||||||
if ($key === null) return false;
|
|
||||||
return array_key_exists($key, $_GET);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isAvailable($key=null): bool {
|
|
||||||
if ($key === null) return false;
|
|
||||||
if (array_key_exists($key, $_GET)) {
|
|
||||||
return $this->allowEmpty || $_GET[$key] !== "";
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function get($key=null) {
|
|
||||||
if ($key === null) return null;
|
|
||||||
if (array_key_exists($key, $_GET)) {
|
|
||||||
$value = $_GET[$key];
|
|
||||||
if ($value === "" && !$this->allowEmpty) return null;
|
|
||||||
return $value;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\input;
|
|
||||||
|
|
||||||
use nulib\cl;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class Input: accès à une valeur
|
|
||||||
*
|
|
||||||
* cette implémentation lit depuis et écrit dans une référence
|
|
||||||
*/
|
|
||||||
class Input {
|
|
||||||
const ALLOW_EMPTY = true;
|
|
||||||
|
|
||||||
function __construct(&$dest=null, ?array $params=null) {
|
|
||||||
$this->dest =& $dest;
|
|
||||||
$allowEmpty = cl::get($params, "allow_empty");
|
|
||||||
if ($allowEmpty === null) $allowEmpty = static::ALLOW_EMPTY;
|
|
||||||
$this->allowEmpty = $allowEmpty;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected $dest;
|
|
||||||
|
|
||||||
/** tester si la valeur existe sans tenir compte de $allowEmpty */
|
|
||||||
function isPresent($key=null): bool {
|
|
||||||
if ($key === null) return true;
|
|
||||||
$dest = $this->dest;
|
|
||||||
return $dest !== null && array_key_exists($key, $dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var bool comment considérer une chaine vide: "" si allowEmpty, null sinon
|
|
||||||
*/
|
|
||||||
protected $allowEmpty;
|
|
||||||
|
|
||||||
/** tester si la valeur est disponible en tenant compte de $allowEmpty */
|
|
||||||
function isAvailable($key=null): bool {
|
|
||||||
if ($key === null) return true;
|
|
||||||
$dest = $this->dest;
|
|
||||||
if ($dest === null || !array_key_exists($key, $dest)) return false;
|
|
||||||
return $this->allowEmpty || $dest[$key] !== "";
|
|
||||||
}
|
|
||||||
|
|
||||||
function get($key=null) {
|
|
||||||
$dest = $this->dest;
|
|
||||||
if ($key === null) return $dest;
|
|
||||||
if ($dest === null || !array_key_exists($key, $dest)) return null;
|
|
||||||
$value = $dest[$key];
|
|
||||||
if ($value === "" && !$this->allowEmpty) return null;
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
function set($value, $key=null): void {
|
|
||||||
if ($key === null) $this->dest = $value;
|
|
||||||
else $this->dest[$key] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
function unset($key=null): void {
|
|
||||||
if ($key === null) $this->dest = null;
|
|
||||||
else unset($this->dest[$key]);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\input;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class PostInput: accès à des paramètres de formulaire de type POST uniquement
|
|
||||||
*
|
|
||||||
* cette implémentation lit depuis les paramètres de formulaire et écrit dans
|
|
||||||
* une référence
|
|
||||||
*/
|
|
||||||
class PostInput extends FormInput {
|
|
||||||
function isPresent($key=null): bool {
|
|
||||||
if ($key === null) return false;
|
|
||||||
return array_key_exists($key, $_POST);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isAvailable($key=null): bool {
|
|
||||||
if ($key === null) return false;
|
|
||||||
if (array_key_exists($key, $_POST)) {
|
|
||||||
return $this->allowEmpty || $_POST[$key] !== "";
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function get($key=null) {
|
|
||||||
if ($key === null) return null;
|
|
||||||
if (array_key_exists($key, $_POST)) {
|
|
||||||
$value = $_POST[$key];
|
|
||||||
if ($value === "" && !$this->allowEmpty) return null;
|
|
||||||
return $value;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema;
|
|
||||||
|
|
||||||
use nulib\schema\types\IType;
|
|
||||||
use nulib\schema\types\Registry;
|
|
||||||
use nulib\schema\types\tarray;
|
|
||||||
use nulib\schema\types\tbool;
|
|
||||||
use nulib\schema\types\tcallable;
|
|
||||||
use nulib\schema\types\tfloat;
|
|
||||||
use nulib\schema\types\tint;
|
|
||||||
use nulib\schema\types\tstring;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class types: classe outil pour gérer le registre de types
|
|
||||||
*/
|
|
||||||
class types {
|
|
||||||
/** @var Registry */
|
|
||||||
private static $registry;
|
|
||||||
|
|
||||||
static function registry(): Registry {
|
|
||||||
if (self::$registry === null) {
|
|
||||||
self::$registry = new Registry();
|
|
||||||
}
|
|
||||||
return self::$registry;
|
|
||||||
}
|
|
||||||
|
|
||||||
static function get(string $name): IType {
|
|
||||||
return self::registry()->get($name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static function string(): tstring { return self::get("string"); }
|
|
||||||
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"); }
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\types;
|
|
||||||
|
|
||||||
use nulib\schema\input\Input;
|
|
||||||
use nulib\schema\Result;
|
|
||||||
use nulib\schema\Schema;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface IType: un type de données
|
|
||||||
*/
|
|
||||||
interface IType {
|
|
||||||
/** la donnée $input($destKey) est-elle disponible? */
|
|
||||||
function isAvailable(Input $input, $destKey): bool;
|
|
||||||
|
|
||||||
/** la valeur $value est-elle nulle? */
|
|
||||||
function isNull($value): bool;
|
|
||||||
|
|
||||||
/** la valeur $value est-elle valide et normalisée le cas échéant? */
|
|
||||||
function isValid($value, ?bool &$normalized=null): bool;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* analyser, corriger éventuellement et normaliser la valeur
|
|
||||||
*
|
|
||||||
* si la valeur était déjà normalisée, ou si une erreur s'est produite,
|
|
||||||
* retourner false.
|
|
||||||
*/
|
|
||||||
function verifix(&$value, Result &$result, Schema $schema): bool;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* formatter la valeur pour affichage. $value est garanti d'être du bon type
|
|
||||||
*/
|
|
||||||
function format($value, $format=null): string;
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\types;
|
|
||||||
|
|
||||||
use nulib\cl;
|
|
||||||
|
|
||||||
class Registry {
|
|
||||||
const TYPES = [
|
|
||||||
"string" => tstring::class,
|
|
||||||
"bool" => tbool::class, "boolean" => tbool::class,
|
|
||||||
"int" => tint::class, "integer" => tint::class,
|
|
||||||
"float" => tfloat::class, "flt" => tfloat::class,
|
|
||||||
"double" => tfloat::class, "dbl" => tfloat::class,
|
|
||||||
"array" => tarray::class,
|
|
||||||
"callable" => tcallable::class,
|
|
||||||
# types spéciaux
|
|
||||||
"key" => tkey::class,
|
|
||||||
"pkey" => tpkey::class,
|
|
||||||
"content" => tcontent::class,
|
|
||||||
];
|
|
||||||
|
|
||||||
function __construct() {
|
|
||||||
$this->types = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var IType[] */
|
|
||||||
protected $types;
|
|
||||||
|
|
||||||
function get(string $name): IType {
|
|
||||||
$type = cl::get($this->types, $name);
|
|
||||||
if ($type === null) {
|
|
||||||
$class = self::TYPES[$name];
|
|
||||||
$type = $this->types[$name] = new $class();
|
|
||||||
}
|
|
||||||
return $type;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\types;
|
|
||||||
|
|
||||||
use nulib\schema\input\Input;
|
|
||||||
|
|
||||||
abstract class _tsimple implements IType {
|
|
||||||
function isAvailable(Input $input, $destKey): bool {
|
|
||||||
return $input->isAvailable($destKey) && $input->get($destKey) !== false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isNull($value): bool {
|
|
||||||
return $value === null || (is_string($value) && trim($value) === "");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\types;
|
|
||||||
|
|
||||||
use nulib\cl;
|
|
||||||
use nulib\schema\Result;
|
|
||||||
use nulib\schema\Schema;
|
|
||||||
|
|
||||||
class tarray extends _tsimple {
|
|
||||||
static function ensure_array(&$array): void {
|
|
||||||
if (!is_array($array)) $array = cl::with($array);
|
|
||||||
}
|
|
||||||
|
|
||||||
static function ensure_narray(&$array): void {
|
|
||||||
if ($array !== null) self::ensure_array($array);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isValid($value, ?bool &$normalized=null): bool {
|
|
||||||
$normalized = is_array($value);
|
|
||||||
return is_scalar($value) || is_array($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
function verifix(&$value, Result &$result, Schema $schema): bool {
|
|
||||||
}
|
|
||||||
|
|
||||||
function format($value, $format=null): string {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,123 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\types;
|
|
||||||
|
|
||||||
use nulib\cl;
|
|
||||||
use nulib\schema\_scalar\ScalarResult;
|
|
||||||
use nulib\schema\_scalar\ScalarSchema;
|
|
||||||
use nulib\schema\input\Input;
|
|
||||||
use nulib\schema\Result;
|
|
||||||
use nulib\schema\Schema;
|
|
||||||
use nulib\ValueException;
|
|
||||||
|
|
||||||
class tbool extends _tsimple {
|
|
||||||
/** liste de valeurs chaines à considérer comme 'OUI' */
|
|
||||||
const YES_VALUES = [
|
|
||||||
# IMPORTANT: ordonner par taille décroissante pour compatibilité avec parse()
|
|
||||||
"true", "vrai", "yes", "oui",
|
|
||||||
"t", "v", "y", "o", "1",
|
|
||||||
];
|
|
||||||
|
|
||||||
/** liste de valeurs chaines à considérer comme 'NON' */
|
|
||||||
const NO_VALUES = [
|
|
||||||
# IMPORTANT: ordonner par taille décroissante pour compatibilité avec parse()
|
|
||||||
"false", "faux", "non", "no",
|
|
||||||
"f", "n", "0",
|
|
||||||
];
|
|
||||||
|
|
||||||
/** Vérifier si $value est 'OUI' */
|
|
||||||
static final function is_yes(?string $value): bool {
|
|
||||||
if ($value === null) return false;
|
|
||||||
$value = strtolower(trim($value));
|
|
||||||
if (in_array($value, self::YES_VALUES, true)) return true;
|
|
||||||
// n'importe quelle valeur numérique
|
|
||||||
if (is_numeric($value)) return $value != 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Vérifier si $value est 'NON' */
|
|
||||||
static final function is_no(?string $value): bool {
|
|
||||||
if ($value === null) return true;
|
|
||||||
$value = strtolower(trim($value));
|
|
||||||
return in_array($value, self::NO_VALUES, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static function ensure_bool(&$bool): void {
|
|
||||||
if (is_string($bool)) {
|
|
||||||
if (self::is_yes($bool)) $bool = true;
|
|
||||||
elseif (self::is_no($bool)) $bool = false;
|
|
||||||
}
|
|
||||||
if (!is_bool($bool)) $bool = boolval($bool);
|
|
||||||
}
|
|
||||||
|
|
||||||
static function ensure_nbool(&$bool): void {
|
|
||||||
if ($bool !== null) self::ensure_bool($bool);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isAvailable(Input $input, $destKey): bool {
|
|
||||||
return $input->isAvailable($destKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isValid($value, ?bool &$normalized=null): bool {
|
|
||||||
$normalized = is_bool($value);
|
|
||||||
if (is_string($value)) {
|
|
||||||
$value = trim($value);
|
|
||||||
$valid = self::is_yes($value) || self::is_no($value);
|
|
||||||
} else {
|
|
||||||
$valid = is_scalar($value);
|
|
||||||
}
|
|
||||||
return $valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ScalarResult $result
|
|
||||||
* @var ScalarSchema $schema
|
|
||||||
*/
|
|
||||||
function verifix(&$value, Result &$result, Schema $schema): bool {
|
|
||||||
if (is_bool($value)) {
|
|
||||||
$result->setNormalized();
|
|
||||||
return false;
|
|
||||||
} elseif (is_string($value)) {
|
|
||||||
$bool = trim($value);
|
|
||||||
if (self::is_yes($bool)) $value = true;
|
|
||||||
elseif (self::is_no($bool)) $value = false;
|
|
||||||
else return $result->setInvalid($value, $schema);
|
|
||||||
} elseif (is_scalar($value)) {
|
|
||||||
$value = boolval($value);
|
|
||||||
} else {
|
|
||||||
return $result->setInvalid($value, $schema);
|
|
||||||
}
|
|
||||||
$result->setValid();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const OUINON_FORMAT = ["Oui", "Non", false];
|
|
||||||
const OUINONNULL_FORMAT = ["Oui", "Non", ""];
|
|
||||||
const ON_FORMAT = ["O", "N", false];
|
|
||||||
const ONN_FORMAT = ["O", "N", ""];
|
|
||||||
const XN_FORMAT = ["X", "", false];
|
|
||||||
const OZ_FORMAT = ["1", "", false];
|
|
||||||
const FORMATS = [
|
|
||||||
"ouinon" => self::OUINON_FORMAT,
|
|
||||||
"ouinonnull" => self::OUINONNULL_FORMAT,
|
|
||||||
"on" => self::ON_FORMAT,
|
|
||||||
"onn" => self::ONN_FORMAT,
|
|
||||||
"xn" => self::XN_FORMAT,
|
|
||||||
"oz" => self::OZ_FORMAT,
|
|
||||||
];
|
|
||||||
|
|
||||||
const DEFAULT_FORMAT = self::OUINON_FORMAT;
|
|
||||||
|
|
||||||
function format($value, $format=null): string {
|
|
||||||
if ($format === null) $format = static::DEFAULT_FORMAT;
|
|
||||||
if (is_string($format)) {
|
|
||||||
$oformat = $format;
|
|
||||||
$format = cl::get(self::FORMATS, strtolower($oformat));
|
|
||||||
if ($format === null) throw ValueException::invalid_kind($oformat, "format");
|
|
||||||
}
|
|
||||||
if ($value === null) {
|
|
||||||
$null = $format[2];
|
|
||||||
if ($null !== false) return $null;
|
|
||||||
}
|
|
||||||
return $value? $format[0]: $format[1];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\types;
|
|
||||||
|
|
||||||
use nulib\php\func;
|
|
||||||
use nulib\schema\Result;
|
|
||||||
use nulib\schema\Schema;
|
|
||||||
use nulib\ValueException;
|
|
||||||
use stdClass;
|
|
||||||
|
|
||||||
class tcallable extends _tsimple {
|
|
||||||
static function ensure_callable(&$callable): void {
|
|
||||||
if (!is_callable($callable)) throw ValueException::invalid_type($callable, "callable");
|
|
||||||
}
|
|
||||||
|
|
||||||
static function ensure_ncallable(&$callable): void {
|
|
||||||
if ($callable !== null) self::ensure_callable($callable);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isValid($value, ?bool &$normalized=null): bool {
|
|
||||||
$normalized = is_callable($value);
|
|
||||||
return func::check_func($value, stdClass::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
function verifix(&$value, Result &$result, Schema $schema): bool {
|
|
||||||
}
|
|
||||||
|
|
||||||
function format($value, $format=null): string {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\types;
|
|
||||||
|
|
||||||
use nulib\schema\Result;
|
|
||||||
use nulib\schema\Schema;
|
|
||||||
|
|
||||||
abstract class tcontent extends _tsimple {
|
|
||||||
static function ensure_content(&$content): void {
|
|
||||||
if (!is_string($content) && !is_array($content)) $content = strval($content);
|
|
||||||
}
|
|
||||||
|
|
||||||
static function ensure_ncontent(&$content): void {
|
|
||||||
if ($content !== null) self::ensure_content($content);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isValid($value, ?bool &$normalized=null): bool {
|
|
||||||
$normalized = is_string($value) || is_array($value);
|
|
||||||
return is_scalar($value) || is_array($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
function verifix(&$value, Result &$result, Schema $schema): bool {
|
|
||||||
}
|
|
||||||
|
|
||||||
function format($value, $format=null): string {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\types;
|
|
||||||
|
|
||||||
use nulib\schema\_scalar\ScalarResult;
|
|
||||||
use nulib\schema\_scalar\ScalarSchema;
|
|
||||||
use nulib\schema\Result;
|
|
||||||
use nulib\schema\Schema;
|
|
||||||
|
|
||||||
class tfloat extends _tsimple {
|
|
||||||
static function ensure_float(&$float): void {
|
|
||||||
if (!is_float($float)) $float = floatval($float);
|
|
||||||
}
|
|
||||||
|
|
||||||
static function ensure_nfloat(&$float): void {
|
|
||||||
if ($float !== null) self::ensure_float($float);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isValid($value, ?bool &$normalized=null): bool {
|
|
||||||
$normalized = is_float($value);
|
|
||||||
if (is_string($value)) $valid = is_numeric(trim($value));
|
|
||||||
else $valid = is_scalar($value);
|
|
||||||
return $valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ScalarResult $result
|
|
||||||
* @var ScalarSchema $schema
|
|
||||||
*/
|
|
||||||
function verifix(&$value, Result &$result, Schema $schema): bool {
|
|
||||||
if (is_float($value)) {
|
|
||||||
$result->setNormalized();
|
|
||||||
return false;
|
|
||||||
} elseif (is_string($value)) {
|
|
||||||
$float = trim($value);
|
|
||||||
if (is_numeric($float)) $value = floatval($float);
|
|
||||||
else return $result->setInvalid($value, $schema);
|
|
||||||
} elseif (is_scalar($value)) {
|
|
||||||
$value = floatval($value);
|
|
||||||
} else {
|
|
||||||
return $result->setInvalid($value, $schema);
|
|
||||||
}
|
|
||||||
$result->setValid();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function format($value, $format=null): string {
|
|
||||||
if ($format !== null) return sprintf($format, $value);
|
|
||||||
else return strval($value);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\types;
|
|
||||||
|
|
||||||
use nulib\schema\_scalar\ScalarResult;
|
|
||||||
use nulib\schema\_scalar\ScalarSchema;
|
|
||||||
use nulib\schema\Result;
|
|
||||||
use nulib\schema\Schema;
|
|
||||||
|
|
||||||
class tint extends _tsimple {
|
|
||||||
static function ensure_int(&$int): void {
|
|
||||||
if (!is_int($int)) $int = intval($int);
|
|
||||||
}
|
|
||||||
|
|
||||||
static function ensure_nint(&$int): void {
|
|
||||||
if ($int !== null) self::ensure_int($int);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
return $valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ScalarResult $result
|
|
||||||
* @var ScalarSchema $schema
|
|
||||||
*/
|
|
||||||
function verifix(&$value, Result &$result, Schema $schema): bool {
|
|
||||||
if (is_int($value)) {
|
|
||||||
$result->setNormalized();
|
|
||||||
return false;
|
|
||||||
} elseif (is_string($value)) {
|
|
||||||
$int = trim($value);
|
|
||||||
if (is_numeric($int)) $value = intval($int);
|
|
||||||
else return $result->setInvalid($value, $schema);
|
|
||||||
} elseif (is_scalar($value)) {
|
|
||||||
$value = intval($value);
|
|
||||||
} else {
|
|
||||||
return $result->setInvalid($value, $schema);
|
|
||||||
}
|
|
||||||
$result->setValid();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function format($value, $format=null): string {
|
|
||||||
if ($format !== null) return sprintf($format, $value);
|
|
||||||
else return strval($value);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\types;
|
|
||||||
|
|
||||||
use nulib\schema\Result;
|
|
||||||
use nulib\schema\Schema;
|
|
||||||
|
|
||||||
class tkey extends _tsimple {
|
|
||||||
static function ensure_key(&$key): void {
|
|
||||||
if (!is_string($key) && !is_int($key)) $key = strval($key);
|
|
||||||
}
|
|
||||||
|
|
||||||
static function ensure_nkey(&$key): void {
|
|
||||||
if ($key !== null) self::ensure_key($key);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isValid($value, ?bool &$normalized=null): bool {
|
|
||||||
$normalized = is_string($value) || is_int($value);
|
|
||||||
return is_scalar($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
function verifix(&$value, Result &$result, Schema $schema): bool {
|
|
||||||
}
|
|
||||||
|
|
||||||
function format($value, $format=null): string {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\types;
|
|
||||||
|
|
||||||
use nulib\schema\Result;
|
|
||||||
use nulib\schema\Schema;
|
|
||||||
|
|
||||||
class tpkey extends _tsimple {
|
|
||||||
static function ensure_pkey(&$pkey): void {
|
|
||||||
if (!is_string($pkey) && !is_int($pkey) && !is_array($pkey)) $pkey = strval($pkey);
|
|
||||||
if (is_array($pkey)) {
|
|
||||||
foreach ($pkey as &$key) {
|
|
||||||
tkey::ensure_key($key);
|
|
||||||
};
|
|
||||||
unset($key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static function ensure_npkey(&$pkey): void {
|
|
||||||
if ($pkey !== null) self::ensure_pkey($pkey);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isValid($value, ?bool &$normalized=null): bool {
|
|
||||||
$normalized = is_string($value) || is_int($value) || is_array($value);
|
|
||||||
return is_scalar($value) || is_array($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
function verifix(&$value, Result &$result, Schema $schema): bool {
|
|
||||||
}
|
|
||||||
|
|
||||||
function format($value, $format=null): string {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace nulib\schema\types;
|
|
||||||
|
|
||||||
use nulib\schema\_scalar\ScalarResult;
|
|
||||||
use nulib\schema\_scalar\ScalarSchema;
|
|
||||||
use nulib\schema\Result;
|
|
||||||
use nulib\schema\Schema;
|
|
||||||
|
|
||||||
class tstring extends _tsimple {
|
|
||||||
static function ensure_string(&$string): void {
|
|
||||||
if (!is_string($string)) $string = strval($string);
|
|
||||||
}
|
|
||||||
|
|
||||||
static function ensure_nstring(&$string): void {
|
|
||||||
if ($string !== null) self::ensure_string($string);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isNull($value): bool {
|
|
||||||
return $value === null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isValid($value, ?bool &$normalized=null): bool {
|
|
||||||
$normalized = is_string($value);
|
|
||||||
return is_scalar($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ScalarResult $result
|
|
||||||
* @var ScalarSchema $schema
|
|
||||||
*/
|
|
||||||
function verifix(&$value, Result &$result, Schema $schema): bool {
|
|
||||||
if (is_string($value)) {
|
|
||||||
$result->setNormalized();
|
|
||||||
return false;
|
|
||||||
} elseif (is_scalar($value)) {
|
|
||||||
$value = strval($value);
|
|
||||||
$result->setValid();
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
$result->setInvalid($value, $schema);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function format($value, $format=null): string {
|
|
||||||
return strval($value);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue