supprimer schema qui n'est pas encore prêt

This commit is contained in:
Jephté Clain 2024-05-23 08:16:02 +04:00
parent 350622997c
commit fa8fd6e7c3
34 changed files with 10 additions and 1960 deletions

View File

@ -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";

View File

@ -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 {
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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();
}
}

View File

@ -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;}
}

View File

@ -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));
}
}

View File

@ -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 {
}
}

View File

@ -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;}
}

View File

@ -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));
}
}

View File

@ -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 {
}
}

View File

@ -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);
}
}

View File

@ -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],
];
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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]);
}
}

View File

@ -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;
}
}
}

View File

@ -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"); }
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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) === "");
}
}

View File

@ -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 {
}
}

View File

@ -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];
}
}

View File

@ -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 {
}
}

View File

@ -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 {
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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 {
}
}

View File

@ -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 {
}
}

View File

@ -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);
}
}