<pman>Intégration de la branche dev74
This commit is contained in:
commit
62b8b76ae5
7
.idea/inspectionProfiles/Project_Default.xml
generated
7
.idea/inspectionProfiles/Project_Default.xml
generated
@ -2,5 +2,12 @@
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="GrazieInspection" enabled="false" level="GRAMMAR_ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="LanguageDetectionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||
<option name="processCode" value="true" />
|
||||
<option name="processLiterals" value="true" />
|
||||
<option name="processComments" value="true" />
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
15
.idea/php.xml
generated
15
.idea/php.xml
generated
@ -10,6 +10,11 @@
|
||||
<option name="highlightLevel" value="WARNING" />
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PhpCodeSniffer">
|
||||
<phpcs_settings>
|
||||
<phpcs_by_interpreter asDefaultInterpreter="true" interpreter_id="846389f7-9fb5-4173-a868-1dc6b8fbb3fa" timeout="30000" />
|
||||
</phpcs_settings>
|
||||
</component>
|
||||
<component name="PhpIncludePathManager">
|
||||
<include_path>
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/code-unit-reverse-lookup" />
|
||||
@ -64,6 +69,11 @@
|
||||
</include_path>
|
||||
</component>
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="7.4" />
|
||||
<component name="PhpStan">
|
||||
<PhpStan_settings>
|
||||
<phpstan_by_interpreter asDefaultInterpreter="true" interpreter_id="846389f7-9fb5-4173-a868-1dc6b8fbb3fa" timeout="60000" />
|
||||
</PhpStan_settings>
|
||||
</component>
|
||||
<component name="PhpStanOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
@ -72,6 +82,11 @@
|
||||
<PhpUnitSettings custom_loader_path="$PROJECT_DIR$/vendor/autoload.php" />
|
||||
</phpunit_settings>
|
||||
</component>
|
||||
<component name="Psalm">
|
||||
<Psalm_settings>
|
||||
<psalm_fixer_by_interpreter asDefaultInterpreter="true" interpreter_id="846389f7-9fb5-4173-a868-1dc6b8fbb3fa" timeout="60000" />
|
||||
</Psalm_settings>
|
||||
</component>
|
||||
<component name="PsalmOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
|
@ -12,12 +12,16 @@ DIST=
|
||||
NOAUTO=
|
||||
|
||||
AFTER_CREATE_RELEASE='
|
||||
set -x
|
||||
pman --composer-select-profile dist
|
||||
composer u
|
||||
composer u || exit 1
|
||||
git commit -am "<pman>deps de dist"
|
||||
true
|
||||
'
|
||||
AFTER_MERGE_RELEASE='
|
||||
set -x
|
||||
pman --composer-select-profile dev
|
||||
composer u
|
||||
composer u || exit 1
|
||||
git commit -am "<pman>deps de dev"
|
||||
true
|
||||
'
|
||||
|
11
CHANGES.md
11
CHANGES.md
@ -1,3 +1,14 @@
|
||||
## Release 0.4.0p74 du 14/03/2025-15:44
|
||||
|
||||
* `4b84f11` début assocSchema
|
||||
* `7227cd7` maj TODO
|
||||
* `089e487` renommer dest en value; tenir compte de la valeur par défaut
|
||||
* `fc523bf` instancier type le plus vite possible
|
||||
* `f8eec57` renommer Value en Wrapper
|
||||
* `1aa266b` tstring et trawstring
|
||||
* `1a5ca79` support des colonnes
|
||||
* `9438aaf` ajout config .pman.yml
|
||||
|
||||
## Release 0.3.0p82 du 01/03/2025-13:49
|
||||
|
||||
## Release 0.3.0p74 du 01/03/2025-13:44
|
||||
|
@ -1 +1 @@
|
||||
0.3.0
|
||||
0.4.0
|
||||
|
6
composer.lock
generated
6
composer.lock
generated
@ -589,7 +589,7 @@
|
||||
"dist": {
|
||||
"type": "path",
|
||||
"url": "../nulib",
|
||||
"reference": "939f7726ab139071e8a3ef5c83fc147fba859d9d"
|
||||
"reference": "927915093af5196099ae26645c07e90ddf1b2330"
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
@ -637,7 +637,7 @@
|
||||
"dist": {
|
||||
"type": "path",
|
||||
"url": "../nulib-phpss",
|
||||
"reference": "a78623f5ae6891144b9581709847328b93342e1d"
|
||||
"reference": "9e4f41e38deef10993d859202988567db9d4fada"
|
||||
},
|
||||
"require": {
|
||||
"nulib/php": "^7.4-dev",
|
||||
@ -681,7 +681,7 @@
|
||||
"dist": {
|
||||
"type": "path",
|
||||
"url": "../nulib-spout",
|
||||
"reference": "f9c420058015d02e913f0d65c41242ec7b8a0cee"
|
||||
"reference": "65c74a1db6dda718aa20970ede3dfa4b4d32c791"
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\php\access;
|
||||
|
||||
use nur\sery\cl;
|
||||
use nulib\cl;
|
||||
|
||||
/**
|
||||
* Class AbstractAccess: implémentation par défaut pour des instances standard
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\php\access;
|
||||
|
||||
use nur\sery\cl;
|
||||
use nulib\cl;
|
||||
|
||||
/**
|
||||
* Class FormAccess: accès à une valeur de $_POST puis $_GET, dans cet ordre
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\php\access;
|
||||
|
||||
use nur\sery\cl;
|
||||
use nulib\cl;
|
||||
|
||||
/**
|
||||
* Class GetAccess: accès à une valeur de $_GET
|
||||
|
@ -5,10 +5,10 @@ namespace nur\sery\wip\php\access;
|
||||
* Interface IAccess: abstraction d'un accès complet à une valeur
|
||||
*/
|
||||
interface IAccess extends IGetter, ISetter, IDeleter {
|
||||
/** incrémenter la valeur */
|
||||
/** incrémenter la valeur et la retourner */
|
||||
function inc(): int;
|
||||
|
||||
/** décrémenter la valeur */
|
||||
/** décrémenter la valeur et la retourner */
|
||||
function dec(bool $allowNegative=false): int;
|
||||
|
||||
/**
|
||||
|
@ -2,14 +2,14 @@
|
||||
namespace nur\sery\wip\php\access;
|
||||
|
||||
use ArrayAccess;
|
||||
use nur\sery\cl;
|
||||
use nulib\cl;
|
||||
|
||||
/**
|
||||
* Class KeyAccess: accès à une valeur d'une clé dans un tableau
|
||||
*/
|
||||
class KeyAccess extends AbstractAccess {
|
||||
function __construct(&$dest, $key, ?array $params=null) {
|
||||
$this->dest =& $dest;
|
||||
function __construct(&$array, $key, ?array $params=null) {
|
||||
$this->array =& $array;
|
||||
$this->key = $key;
|
||||
$this->allowNull = $params["allow_null"] ?? true;
|
||||
$this->allowFalse = $params["allow_false"] ?? false;
|
||||
@ -17,10 +17,10 @@ class KeyAccess extends AbstractAccess {
|
||||
}
|
||||
|
||||
/** @var array|ArrayAccess */
|
||||
protected $dest;
|
||||
protected $array;
|
||||
|
||||
function reset(&$dest): self {
|
||||
$this->dest =& $dest;
|
||||
function reset(&$array): self {
|
||||
$this->array =& $array;
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -36,12 +36,12 @@ class KeyAccess extends AbstractAccess {
|
||||
function exists(): bool {
|
||||
$key = $this->key;
|
||||
if ($key === null) return false;
|
||||
return cl::has($this->dest, $key);
|
||||
return cl::has($this->array, $key);
|
||||
}
|
||||
|
||||
function available(): bool {
|
||||
if (!$this->exists()) return false;
|
||||
$value = cl::get($this->dest, $this->key);
|
||||
$value = cl::get($this->array, $this->key);
|
||||
if ($value === null) return $this->allowNull;
|
||||
if ($value === false) return $this->allowFalse;
|
||||
if ($value === "") return $this->allowEmpty;
|
||||
@ -50,7 +50,7 @@ class KeyAccess extends AbstractAccess {
|
||||
|
||||
function get($default=null) {
|
||||
if ($this->key === null) return $default;
|
||||
$value = cl::get($this->dest, $this->key, $default);
|
||||
$value = cl::get($this->array, $this->key, $default);
|
||||
if ($value === null && !$this->allowNull) return $default;
|
||||
if ($value === false && !$this->allowFalse) return $default;
|
||||
if ($value === "" && !$this->allowEmpty) return $default;
|
||||
@ -59,11 +59,11 @@ class KeyAccess extends AbstractAccess {
|
||||
|
||||
function set($value): void {
|
||||
if ($this->key === null) return;
|
||||
cl::set($this->dest, $this->key, $value);
|
||||
cl::set($this->array, $this->key, $value);
|
||||
}
|
||||
|
||||
function del(): void {
|
||||
if ($this->key === null) return;
|
||||
cl::del($this->dest, $this->key);
|
||||
cl::del($this->array, $this->key);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\php\access;
|
||||
|
||||
use nur\sery\cl;
|
||||
use nulib\cl;
|
||||
|
||||
/**
|
||||
* Class PostAccess: accès à une valeur de $_POST
|
||||
|
@ -5,18 +5,18 @@ namespace nur\sery\wip\php\access;
|
||||
* Class ValueAccess: accès à une valeur unitaire
|
||||
*/
|
||||
class ValueAccess extends AbstractAccess {
|
||||
function __construct(&$dest, ?array $params=null) {
|
||||
$this->dest =& $dest;
|
||||
function __construct(&$value, ?array $params=null) {
|
||||
$this->value =& $value;
|
||||
$this->allowNull = $params["allow_null"] ?? false;
|
||||
$this->allowFalse = $params["allow_false"] ?? true;
|
||||
$this->allowEmpty = $params["allow_empty"] ?? true;
|
||||
}
|
||||
|
||||
/** @var mixed */
|
||||
protected $dest;
|
||||
protected $value;
|
||||
|
||||
function reset(&$dest): self {
|
||||
$this->dest =& $dest;
|
||||
function reset(&$value): self {
|
||||
$this->value =& $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -27,19 +27,19 @@ class ValueAccess extends AbstractAccess {
|
||||
protected bool $allowEmpty;
|
||||
|
||||
function exists(): bool {
|
||||
return $this->allowNull || $this->dest !== null;
|
||||
return $this->allowNull || $this->value !== null;
|
||||
}
|
||||
|
||||
function available(): bool {
|
||||
if (!$this->exists()) return false;
|
||||
$value = $this->dest;
|
||||
$value = $this->value;
|
||||
if ($value === false) return $this->allowFalse;
|
||||
if ($value === "") return $this->allowEmpty;
|
||||
return true;
|
||||
}
|
||||
|
||||
function get($default=null) {
|
||||
$value = $this->dest;
|
||||
$value = $this->value;
|
||||
if ($value === null && !$this->allowNull) return $default;
|
||||
if ($value === false && !$this->allowFalse) return $default;
|
||||
if ($value === "" && !$this->allowEmpty) return $default;
|
||||
@ -47,10 +47,10 @@ class ValueAccess extends AbstractAccess {
|
||||
}
|
||||
|
||||
function set($value): void {
|
||||
$this->dest = $value;
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
function del(): void {
|
||||
$this->dest = null;
|
||||
$this->value = null;
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
namespace nur\sery\wip\php\coll;
|
||||
|
||||
use Iterator;
|
||||
use IteratorAggregate;
|
||||
use nulib\cl;
|
||||
use nulib\php\func;
|
||||
use nur\sery\wip\php\iter;
|
||||
@ -33,7 +34,7 @@ class Cursor implements Iterator {
|
||||
* alors retourner le tableau
|
||||
* ["a" => $row["a"], "b" => $row["x"], "c" => "y", "d" => null]
|
||||
*/
|
||||
private static function map_row(array $row, ?array $map): array {
|
||||
protected static function map_row(array $row, ?array $map): array {
|
||||
if ($map === null) return $row;
|
||||
$index = 0;
|
||||
$mapped = [];
|
||||
@ -48,7 +49,7 @@ class Cursor implements Iterator {
|
||||
$mapped[$key] = $func->invoke([$value, $key, $row]);
|
||||
} else {
|
||||
if ($value === null) $mapped[$key] = null;
|
||||
else $mapped[$key] = cl::get($row, $key);
|
||||
else $mapped[$key] = cl::get($row, $value);
|
||||
}
|
||||
}
|
||||
return $mapped;
|
||||
@ -67,7 +68,7 @@ class Cursor implements Iterator {
|
||||
* - une valeur associative $key => $value indique que la clé correspondante
|
||||
* doit exiter avec la valeur spécifiée
|
||||
*/
|
||||
private static function filter_row(array $row, $filter): bool {
|
||||
protected static function filter_row(array $row, $filter): bool {
|
||||
if ($filter === null) return false;
|
||||
if (!is_array($filter)) $filter = [$filter];
|
||||
if (!$filter) return false;
|
||||
@ -79,12 +80,12 @@ class Cursor implements Iterator {
|
||||
if (!array_key_exists($value, $row)) return false;
|
||||
} elseif (is_bool($value)) {
|
||||
if ($value) {
|
||||
if (!array_key_exists($value, $row)) return false;
|
||||
if (!array_key_exists($key, $row)) return false;
|
||||
} else {
|
||||
if (array_key_exists($value, $row)) return false;
|
||||
if (array_key_exists($key, $row)) return false;
|
||||
}
|
||||
} else {
|
||||
if (!array_key_exists($value, $row)) return false;
|
||||
if (!array_key_exists($key, $row)) return false;
|
||||
if ($row[$key] !== $value) return false;
|
||||
}
|
||||
}
|
||||
@ -114,6 +115,11 @@ class Cursor implements Iterator {
|
||||
$this->rowsGenerator = $rowsGenerator;
|
||||
$this->rowsFunc = $rowsFunc;
|
||||
|
||||
$this->cols = $params["cols"] ?? null;
|
||||
$colsFunc = $params["cols_func"] ?? null;
|
||||
if ($colsFunc !== null) $colsFunc = func::with($colsFunc);
|
||||
$this->colsFunc = $colsFunc;
|
||||
|
||||
$map = $params["map"] ?? null;
|
||||
$mapFunc = $params["map_func"] ?? null;
|
||||
if ($mapFunc !== null) {
|
||||
@ -140,16 +146,16 @@ class Cursor implements Iterator {
|
||||
/** un générateur de lignes */
|
||||
private ?Traversable $rowsGenerator;
|
||||
|
||||
/** une fonction de signature <code>function(Cursor):?iterable</code> */
|
||||
/** une fonction de signature <code>function(Cursor): ?iterable</code> */
|
||||
private ?func $rowsFunc;
|
||||
|
||||
/** une fonction de signature <code>function(Cursor):?array</code> */
|
||||
/** une fonction de signature <code>function(Cursor): ?array</code> */
|
||||
private ?func $colsFunc;
|
||||
|
||||
/** une fonction de signature <code>function(Cursor):?array</code> */
|
||||
/** une fonction de signature <code>function(Cursor): ?array</code> */
|
||||
private ?func $mapFunc;
|
||||
|
||||
/** une fonction de signature <code>function(Cursor):bool</code> */
|
||||
/** une fonction de signature <code>function(Cursor): bool</code> */
|
||||
private ?func $filterFunc;
|
||||
|
||||
protected ?iterable $rows;
|
||||
@ -173,6 +179,10 @@ class Cursor implements Iterator {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function cols(): ?array {
|
||||
return $this->row !== null? array_keys($this->row): null;
|
||||
}
|
||||
|
||||
protected function filter(): bool {
|
||||
return false;
|
||||
}
|
||||
@ -185,20 +195,24 @@ class Cursor implements Iterator {
|
||||
# Iterator
|
||||
|
||||
function rewind() {
|
||||
$this->cols = null;
|
||||
$this->index = 0;
|
||||
$this->origIndex = 0;
|
||||
$this->key = null;
|
||||
$this->raw = null;
|
||||
$this->row = null;
|
||||
if ($this->rowsGenerator !== null) {
|
||||
$this->rows = $this->rowsGenerator;
|
||||
$this->rows->rewind();
|
||||
$rows = $this->rowsGenerator;
|
||||
if ($rows instanceof IteratorAggregate) $rows = $rows->getIterator();
|
||||
$rows->rewind();
|
||||
$this->rows = $rows;
|
||||
} else {
|
||||
$this->rows = $this->rowsFunc->invoke();
|
||||
}
|
||||
}
|
||||
|
||||
function valid() {
|
||||
function valid(): bool {
|
||||
$cols = $this->colsFunc;
|
||||
$filter = $this->filterFunc;
|
||||
$map = $this->mapFunc;
|
||||
while ($valid = iter::valid($this->rows)) {
|
||||
@ -210,6 +224,10 @@ class Cursor implements Iterator {
|
||||
if (!$filtered) {
|
||||
if ($map === null) $this->row = $this->map();
|
||||
else $this->row = $map->invoke([$this]);
|
||||
if ($this->cols === null) {
|
||||
if ($cols === null) $this->cols = $this->cols();
|
||||
else $this->cols = $cols->invoke([$this]);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
iter::next($this->rows);
|
||||
@ -219,6 +237,7 @@ class Cursor implements Iterator {
|
||||
if (!$valid) {
|
||||
iter::close($this->rows);
|
||||
$this->rows = null;
|
||||
$this->cols = null;
|
||||
$this->index = -1;
|
||||
$this->origIndex = -1;
|
||||
$this->key = null;
|
||||
@ -228,7 +247,7 @@ class Cursor implements Iterator {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
function current() {
|
||||
function current(): ?array {
|
||||
return $this->row;
|
||||
}
|
||||
|
||||
|
30
src/schema/AnalyzerContext.php
Normal file
30
src/schema/AnalyzerContext.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema;
|
||||
|
||||
use nur\sery\wip\schema\input\Input;
|
||||
use nur\sery\wip\schema\types\IType;
|
||||
|
||||
class AnalyzerContext {
|
||||
function __construct(Schema $schema, Wrapper $wrapper, Input $input, $valueKey, Result $result) {
|
||||
$this->schema = $schema;
|
||||
$this->wrapper = $wrapper;
|
||||
$this->input = $input;
|
||||
$this->result = $result;
|
||||
$this->type = null;
|
||||
$this->origValue = null;
|
||||
$this->value = null;
|
||||
$this->valueKey = $valueKey;
|
||||
}
|
||||
|
||||
public Schema $schema;
|
||||
public Wrapper $wrapper;
|
||||
public Input $input;
|
||||
public Result $result;
|
||||
public ?IType $type;
|
||||
/** @var mixed */
|
||||
public $origValue;
|
||||
/** @var mixed */
|
||||
public $value;
|
||||
/** @var int|string|null */
|
||||
public $valueKey;
|
||||
}
|
@ -1,70 +1,60 @@
|
||||
# nur\sery\schema
|
||||
# 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 classes de ce package permettent de 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)
|
||||
les données dont on peut modéliser le schéma sont de 3 types: scalaire, tableau
|
||||
associatif ou liste. la nature du schéma (la valeur de la clé `"""`) indique le
|
||||
type de donnée modélisée
|
||||
* donnée scalaire
|
||||
|
||||
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
|
||||
forme courante:
|
||||
~~~php
|
||||
const SCALAR_SCHEMA = [
|
||||
$type, [$default, $title, ...]
|
||||
];
|
||||
~~~
|
||||
forme normalisée:
|
||||
~~~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)
|
||||
* tableau associatif
|
||||
le tableau modélisé peut avoir des clés numériques ou chaines --> seules les
|
||||
clés décrites par le schéma sont validées
|
||||
|
||||
forme courante:
|
||||
~~~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
|
||||
forme normalisée:
|
||||
~~~php
|
||||
// la valeur ci-dessus est strictement équivalent à
|
||||
const ASSOC_SCHEMA = [
|
||||
"?array",
|
||||
"" => "scalar",
|
||||
"?array", [$default, $title, ...]
|
||||
"" => "assoc",
|
||||
"schema" => [
|
||||
KEY => VALUE_SCHEMA,
|
||||
...
|
||||
],
|
||||
];
|
||||
~~~
|
||||
* liste (tableau d'éléments du même type)
|
||||
le tableau modélisé peut avoir des clés numériques ou chaines --> on ne
|
||||
modélise ni le type ni la valeur des clés
|
||||
|
||||
* 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)
|
||||
forme courante:
|
||||
~~~php
|
||||
const LIST_SCHEMA = [[
|
||||
ITEM_SCHEMA,
|
||||
]];
|
||||
~~~
|
||||
forme normalisée:
|
||||
~~~php
|
||||
const LIST_SCHEMA = [
|
||||
"?array", [$default, $title, ...]
|
||||
@ -85,7 +75,8 @@ const SCALAR_SCHEMA = [
|
||||
"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",
|
||||
"analyzer_func" => "XXX",
|
||||
"extractor_func" => "XXX",
|
||||
"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",
|
||||
@ -118,9 +109,9 @@ nature scalaire si:
|
||||
* 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`
|
||||
`messages` 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 `analyzer_func`
|
||||
~~~php
|
||||
const MESSAGE_SCHEMA = [
|
||||
"missing" => "message si la valeur n'existe pas dans la source et qu'elle est requise",
|
||||
@ -133,23 +124,27 @@ const MESSAGE_SCHEMA = [
|
||||
|
||||
## 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:
|
||||
Dans la forme courante, 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"]`
|
||||
|
||||
La forme normalisée est
|
||||
~~~php
|
||||
const ASSOC_SCHEMA = [
|
||||
"?array",
|
||||
"" => "assoc",
|
||||
"schema" => [
|
||||
KEY => VALUE_SCHEMA,
|
||||
...
|
||||
],
|
||||
];
|
||||
~~~
|
||||
le type "?array" ou "array" indique si la liste est nullable ou non. la valeur
|
||||
par défaut est "?array"
|
||||
|
||||
chaque occurrence de `KEY => VALUE_SCHEMA` définit le schéma de la valeur dont
|
||||
la clé est `KEY`
|
||||
|
||||
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
|
||||
@ -171,14 +166,11 @@ récursivement, avec cependant l'ajout de quelques clés supplémentaires:
|
||||
|
||||
## 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
|
||||
Dans la forme courante, 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]]`
|
||||
|
||||
Pour information, la forme normalisée est plutôt de la forme
|
||||
La forme normalisée est
|
||||
~~~php
|
||||
const LIST_SCHEMA = [
|
||||
"?array",
|
||||
@ -189,9 +181,4 @@ const LIST_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,21 +1,42 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema;
|
||||
|
||||
use IteratorAggregate;
|
||||
use nur\sery\wip\schema\_assoc\AssocResult;
|
||||
use nur\sery\wip\schema\_list\ListResult;
|
||||
use nur\sery\wip\schema\_scalar\ScalarResult;
|
||||
|
||||
/**
|
||||
* Class Result: 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 $messageKey clé de message si la valeur n'est pas valide
|
||||
* @property string|null $message message si la valeur n'est pas valide
|
||||
* @property string|null $origValue valeur originale avant extraction et analyse
|
||||
* @property mixed|null $normalizedValue la valeur normalisée si elle est
|
||||
* disponible, null sinon. ce champ est utilisé comme optimisation si la valeur
|
||||
* normalisée a déjà été calculée
|
||||
*/
|
||||
abstract class Result {
|
||||
abstract class Result implements IteratorAggregate {
|
||||
const KEYS = [
|
||||
"resultAvailable",
|
||||
"present", "available", "null", "valid", "normalized",
|
||||
"messageKey", "message",
|
||||
"origValue", "normalizedValue",
|
||||
];
|
||||
|
||||
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; }
|
||||
function isAssoc(?AssocResult &$result=null): bool { return false; }
|
||||
function isList(?ListResult &$result=null): bool { return false; }
|
||||
function isScalar(?ScalarResult &$result=null): bool { return false; }
|
||||
|
||||
/**
|
||||
* Obtenir la liste des clés valides pour les valeurs accessibles via cet
|
||||
@ -23,8 +44,21 @@ abstract class Result {
|
||||
*/
|
||||
abstract function getKeys(): array;
|
||||
|
||||
/** obtenir un objet pour gérer la valeur spécifiée */
|
||||
abstract function getResult($key=null): Result;
|
||||
/**
|
||||
* sélectionner le résultat associé à la clé spécifiée
|
||||
*
|
||||
* @param string|int|null $key
|
||||
* @return Result $this
|
||||
*/
|
||||
abstract function select($key): Result;
|
||||
|
||||
function getIterator() {
|
||||
foreach ($this->getKeys() as $key) {
|
||||
yield $key => $this->select($key);
|
||||
}
|
||||
$this->select(null);
|
||||
}
|
||||
|
||||
/** réinitialiser tous les objets résultats accessibles via cet objet */
|
||||
abstract function reset(): void;
|
||||
}
|
||||
|
@ -2,15 +2,24 @@
|
||||
namespace nur\sery\wip\schema;
|
||||
|
||||
use ArrayAccess;
|
||||
use nur\sery\AccessException;
|
||||
use nur\sery\cl;
|
||||
use nulib\AccessException;
|
||||
use nulib\cl;
|
||||
use nulib\ref\schema\ref_schema;
|
||||
use nulib\ref\schema\ref_types;
|
||||
use nur\sery\wip\schema\_assoc\AssocSchema;
|
||||
use nur\sery\wip\schema\_list\ListSchema;
|
||||
use nur\sery\wip\schema\_scalar\ScalarSchema;
|
||||
use nur\sery\wip\schema\types\IType;
|
||||
use nur\sery\wip\schema\types\tarray;
|
||||
use nur\sery\wip\schema\types\tbool;
|
||||
use nur\sery\wip\schema\types\tcallable;
|
||||
use nur\sery\wip\schema\types\tcontent;
|
||||
use nur\sery\wip\schema\types\tpkey;
|
||||
use nur\sery\wip\schema\types\trawstring;
|
||||
|
||||
abstract class Schema implements ArrayAccess {
|
||||
/**
|
||||
* créer si besoin une nouvelle instance de {@link Schema} à partir d'une
|
||||
* créer le cas échéant une nouvelle instance de {@link Schema} à partir d'une
|
||||
* définition de schéma
|
||||
*
|
||||
* - si $schema est une instance de schéma, la retourner
|
||||
@ -18,18 +27,18 @@ abstract class Schema implements ArrayAccess {
|
||||
* l'instance de Schema nouvelle créée
|
||||
* - sinon, prendre $definition comme définition
|
||||
*/
|
||||
static function ns(&$schema, $definition=null, $definitionKey=null): self {
|
||||
static function ns(&$schema, $definition=null, $definitionKey=null, bool $normalize=true): self {
|
||||
if (is_array($schema)) {
|
||||
$definition = $schema;
|
||||
$schema = null;
|
||||
}
|
||||
if ($schema === null) {
|
||||
if (AssocSchema::isa_definition($definition)) {
|
||||
$schema = new AssocSchema($definition, $definitionKey);
|
||||
$schema = new AssocSchema($definition, $definitionKey, $normalize);
|
||||
} elseif (ListSchema::isa_definition($definition)) {
|
||||
$schema = new ListSchema($definition, $definitionKey);
|
||||
$schema = new ListSchema($definition, $definitionKey, $normalize);
|
||||
} elseif (ScalarSchema::isa_definition($definition)) {
|
||||
$schema = new ScalarSchema($definition, $definitionKey);
|
||||
$schema = new ScalarSchema($definition, $definitionKey, $normalize);
|
||||
} else {
|
||||
throw SchemaException::invalid_schema();
|
||||
}
|
||||
@ -38,17 +47,189 @@ abstract class Schema implements ArrayAccess {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Créer une nouvelle instance de {@link Wrapper} qui référence la
|
||||
* variable $value (si $valueKey===null) ou $value[$valueKey] si $valueKey
|
||||
* n'est pas null
|
||||
*/
|
||||
static function nv(?Value &$destv=null, &$dest=null, $destKey=null, &$schema=null, $definition=null): Value {
|
||||
static function nw(&$value=null, $valueKey=null, &$schema=null, $definition=null, ?Wrapper &$wrapper=null): Wrapper {
|
||||
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);
|
||||
return self::ns($schema, $definition)->getWrapper($value, $valueKey, $wrapper);
|
||||
}
|
||||
|
||||
protected static function have_nature(array $definition, ?string &$nature=null): bool {
|
||||
$definitionNature = $definition[""] ?? null;
|
||||
if (is_string($definitionNature)) {
|
||||
$nature = $definitionNature;
|
||||
return true;
|
||||
}
|
||||
if (is_array($definitionNature)
|
||||
&& array_key_exists(0, $definitionNature)
|
||||
&& is_string($definitionNature[0])) {
|
||||
$nature = $definitionNature;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static function _normalize(&$definition, $definitionKey=null): void {
|
||||
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(ref_schema::SCALAR_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] = ref_schema::SCALAR_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;
|
||||
if ($key !== $index) {
|
||||
$definition[$index] = $definition[$key];
|
||||
unset($definition[$key]);
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
}
|
||||
# type
|
||||
$types = [];
|
||||
$deftype = $definition["type"];
|
||||
$nullable = $definition["nullable"] ?? false;
|
||||
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 = trim($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);
|
||||
$definition[""] = $nature;
|
||||
# name, pkey, header
|
||||
$name = $definition["name"];
|
||||
$pkey = $definition["pkey"];
|
||||
$header = $definition["header"];
|
||||
if ($name === null) $name = $definitionKey;
|
||||
trawstring::ensure_nstring($name);
|
||||
tpkey::ensure_npkey($pkey);
|
||||
trawstring::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
|
||||
tarray::ensure_narray($definition["schema"]);
|
||||
trawstring::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"]);
|
||||
|
||||
switch ($nature[0] ?? null) {
|
||||
case "assoc":
|
||||
foreach ($definition["schema"] as $key => &$keydef) {
|
||||
self::_normalize($keydef, $key);
|
||||
}; unset($keydef);
|
||||
break;
|
||||
case "list":
|
||||
self::_normalize($definition["schema"]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected static function _ensure_nature(array $definition, string $expectedNature, ?string $expectedType=null): void {
|
||||
$nature = $definition[""];
|
||||
if (!array_key_exists(0, $nature) || $nature[0] !== $expectedNature) {
|
||||
throw SchemaException::invalid_schema("$nature: invalid nature. expected $expectedNature");
|
||||
}
|
||||
if ($expectedType !== null) {
|
||||
$types = $definition["type"];
|
||||
if (count($types) !== 1 || $types[0] !== $expectedType) {
|
||||
throw new SchemaException("{$types[O]}: invalide type. expected $expectedType");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static function _ensure_type(array &$definition): void {
|
||||
$types = $definition["type"];
|
||||
$nullable = $definition["nullable"];
|
||||
# s'il n'y a qu'une seul type, l'instancier tout de suite
|
||||
if (is_array($types) && count($types) == 1 && $types[0] !== null) {
|
||||
foreach ($types as $key => $name) {
|
||||
if ($key === 0) {
|
||||
$args = null;
|
||||
} else {
|
||||
$args = $name;
|
||||
$name = $key;
|
||||
}
|
||||
$definition["type"] = types::get($nullable, $name, $args, $definition);
|
||||
}
|
||||
}
|
||||
switch ($definition[""][0]) {
|
||||
case "assoc":
|
||||
foreach ($definition["schema"] as &$keydef) {
|
||||
self::_ensure_type($keydef);
|
||||
}; unset($keydef);
|
||||
break;
|
||||
case "list":
|
||||
self::_ensure_type($definition["schema"]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected static function _ensure_schema_instances(array &$definition): void {
|
||||
switch ($definition[""][0]) {
|
||||
case "assoc":
|
||||
foreach ($definition["schema"] as &$keydef) {
|
||||
self::_ensure_schema_instances($keydef);
|
||||
Schema::ns($keydef, null, null, false);
|
||||
}; unset($keydef);
|
||||
break;
|
||||
case "list":
|
||||
Schema::ns($definition["schema"], null, null, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,17 +238,22 @@ abstract class Schema implements ArrayAccess {
|
||||
*/
|
||||
const SCHEMA = null;
|
||||
|
||||
/** @var array */
|
||||
protected $definition;
|
||||
protected array $_definition;
|
||||
|
||||
protected array $definition;
|
||||
|
||||
function getDefinition(): array {
|
||||
return $this->_definition;
|
||||
}
|
||||
|
||||
/** retourner true si le schéma est de nature tableau associatif */
|
||||
function isAssoc(?AssocSchema &$assoc=null): bool { return false; }
|
||||
function isAssoc(?AssocSchema &$schema=null): bool { return false; }
|
||||
/** retourner true si le schéma est de nature liste */
|
||||
function isList(?ListSchema &$list=null): bool { return false; }
|
||||
function isList(?ListSchema &$schema=null): bool { return false; }
|
||||
/** retourner true si le schéma est de nature scalaire */
|
||||
function isScalar(?ScalarSchema &$scalar=null): bool { return false; }
|
||||
function isScalar(?ScalarSchema &$schema=null): bool { return false; }
|
||||
|
||||
abstract function newValue(?Value &$destv=null, &$dest=null, $destKey=null): Value;
|
||||
abstract function getWrapper(&$value=null, $valueKey=null, ?Wrapper &$wrapper=null): Wrapper;
|
||||
|
||||
#############################################################################
|
||||
# key & properties
|
||||
|
@ -1,19 +1,36 @@
|
||||
# nur\sery\schema
|
||||
# nulib\schema
|
||||
|
||||
* tdate et tdatetime. qu'en est-il des autres classes (delay, etc.)
|
||||
* possibilité de spécifier le format de la date à analyser
|
||||
* ScalarSchema::from_property()
|
||||
* possibilité de spécifier un type via sa classe, e.g
|
||||
~~~php
|
||||
Schema::ns($schema, [
|
||||
MyType::class, null, "une valeur de type MyType"
|
||||
]);
|
||||
~~~
|
||||
MyType doit implémenter IType
|
||||
* type générique construit à partir d'un nom de classe, e.g
|
||||
~~~php
|
||||
Schema::ns($schema, [
|
||||
MyClass::class, null, "une valeur de type MyClass"
|
||||
]);
|
||||
~~~
|
||||
MyClass ne doit pas implémenter IType, et le type correspondant est créé avec
|
||||
`new tgeneric(MyClass::class)`
|
||||
|
||||
* 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, [
|
||||
$wrapper = Schema::ns($schema, [
|
||||
"a" => "?string",
|
||||
"b" => "?int",
|
||||
])->newValue();
|
||||
$dest = ["x_a" => 5, "x_b" => "10"],
|
||||
$value->reset($dest, null, [
|
||||
])->newWrapper();
|
||||
$value = ["x_a" => 5, "x_b" => "10"],
|
||||
$wrapper->reset($value, null, [
|
||||
"key_prefix" => "x_",
|
||||
]);
|
||||
# $dest vaut ["x_a" => "5", "x_b" => 10];
|
||||
# $value 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...
|
||||
@ -21,48 +38,16 @@
|
||||
alternative: c'est lors de la *définition* du schéma que le préfixe est ajouté
|
||||
e.g
|
||||
~~~php
|
||||
$value = Schema::ns($schema, [
|
||||
$wrapper = 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];
|
||||
])->newWrapper();
|
||||
$value = ["x_a" => 5, "x_b" => "10"],
|
||||
$wrapper->reset($value);
|
||||
# $value 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
|
||||
|
@ -3,18 +3,18 @@ namespace nur\sery\wip\schema;
|
||||
|
||||
use ArrayAccess;
|
||||
use IteratorAggregate;
|
||||
use nur\sery\wip\schema\_assoc\AssocValue;
|
||||
use nur\sery\wip\schema\_list\ListValue;
|
||||
use nur\sery\wip\schema\_scalar\ScalarValue;
|
||||
use nur\sery\wip\schema\_assoc\AssocWrapper;
|
||||
use nur\sery\wip\schema\_list\ListWrapper;
|
||||
use nur\sery\wip\schema\_scalar\ScalarWrapper;
|
||||
use nur\sery\wip\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; }
|
||||
abstract class Wrapper implements ArrayAccess, IteratorAggregate {
|
||||
function isAssoc(?AssocWrapper &$wrapper=null): bool { return false; }
|
||||
function isList(?ListWrapper &$wrapper=null): bool { return false; }
|
||||
function isScalar(?ScalarWrapper &$wrapper=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;
|
||||
abstract function reset(&$value, $valueKey=null, ?bool $verifix=null): self;
|
||||
|
||||
/**
|
||||
* Obtenir la liste des clés valides pour les valeurs accessibles via cet
|
||||
@ -22,13 +22,19 @@ abstract class Value implements ArrayAccess, IteratorAggregate {
|
||||
*/
|
||||
abstract function getKeys(): array;
|
||||
|
||||
/** obtenir un objet pour gérer la valeur spécifiée */
|
||||
abstract function getValue($key=null): Value;
|
||||
/**
|
||||
* sélectionner le wrapper associé à la clé spécifiée
|
||||
*
|
||||
* @param string|int|null $key
|
||||
* @return Wrapper $this
|
||||
*/
|
||||
abstract function select($key): Wrapper;
|
||||
|
||||
function getIterator() {
|
||||
foreach ($this->getKeys() as $key) {
|
||||
yield $key => $this->getValue($key);
|
||||
yield $key => $this->select($key);
|
||||
}
|
||||
$this->select(null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -72,14 +78,14 @@ abstract class Value implements ArrayAccess, IteratorAggregate {
|
||||
}
|
||||
|
||||
function offsetGet($offset) {
|
||||
return $this->getValue($offset);
|
||||
return $this->select($offset);
|
||||
}
|
||||
|
||||
function offsetSet($offset, $value): void {
|
||||
$this->getValue($offset)->set($value);
|
||||
$this->select($offset)->set($value);
|
||||
}
|
||||
|
||||
function offsetUnset($offset): void {
|
||||
$this->getValue($offset)->unset();
|
||||
$this->select($offset)->unset();
|
||||
}
|
||||
}
|
@ -1,8 +1,53 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\_assoc;
|
||||
|
||||
use nulib\ValueException;
|
||||
use nur\sery\wip\schema\Result;
|
||||
|
||||
class AssocResult extends Result {
|
||||
function isAssoc(?AssocResult &$assoc=null): bool { $assoc = $this; return true;}
|
||||
function __construct(Result $arrayResult, array &$keyResults) {
|
||||
$this->arrayResult = $arrayResult;
|
||||
$this->keyResults =& $keyResults;
|
||||
$this->result =& $this->arrayResult;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
function isAssoc(?AssocResult &$result=null): bool { $result = $this; return true;}
|
||||
|
||||
protected Result $arrayResult;
|
||||
|
||||
/** @var Result[] */
|
||||
protected array $keyResults;
|
||||
|
||||
function getKeys(): array {
|
||||
return array_keys($this->keyResults);
|
||||
}
|
||||
|
||||
protected Result $result;
|
||||
|
||||
function select($key): Result {
|
||||
if ($key === null) {
|
||||
$this->result =& $this->arrayResult;
|
||||
} elseif (array_key_exists($key, $this->keyResults)) {
|
||||
$this->result =& $this->keyResults[$key];
|
||||
} else {
|
||||
throw ValueException::invalid_key($key);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
function reset(): void {
|
||||
$this->arrayResult->reset();
|
||||
foreach ($this->keyResults as $result) {
|
||||
$result->reset();
|
||||
}
|
||||
}
|
||||
|
||||
function __get(string $name) {
|
||||
return $this->result[$name];
|
||||
}
|
||||
|
||||
function __set(string $name, $value): void {
|
||||
$this->result[$name] = $value;
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\_assoc;
|
||||
|
||||
use nur\sery\cl;
|
||||
use nur\sery\ref\schema\ref_schema;
|
||||
use nulib\cl;
|
||||
use nulib\ref\schema\ref_schema;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
use nur\sery\wip\schema\Value;
|
||||
use nur\sery\wip\schema\Wrapper;
|
||||
|
||||
/**
|
||||
* Class AssocSchema
|
||||
@ -20,36 +20,49 @@ class AssocSchema extends Schema {
|
||||
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;
|
||||
if (self::have_nature($definition, $nature)) {
|
||||
return $nature === "assoc";
|
||||
}
|
||||
# un tableau associatif
|
||||
# tableau associatif
|
||||
return !cl::have_num_keys($definition);
|
||||
}
|
||||
|
||||
static function normalize($definition, $definitionKey=null): array {
|
||||
if (!is_array($definition)) $definition = [$definition];
|
||||
if (!self::have_nature($definition)) {
|
||||
$definition = [
|
||||
"?array",
|
||||
"" => "assoc",
|
||||
"schema" => $definition,
|
||||
];
|
||||
}
|
||||
self::_normalize($definition, $definitionKey);
|
||||
self::_ensure_nature($definition, "assoc", "array");
|
||||
return $definition;
|
||||
}
|
||||
|
||||
function __construct($definition=null, $definitionKey=null, bool $normalize=true) {
|
||||
if ($definition === null) $definition = static::SCHEMA;
|
||||
if ($normalize) $definition = self::normalize($definition, $definitionKey);
|
||||
if ($normalize) {
|
||||
$definition = self::normalize($definition, $definitionKey);
|
||||
$this->_definition = $definition;
|
||||
self::_ensure_type($definition);
|
||||
self::_ensure_schema_instances($definition);
|
||||
}
|
||||
$this->definition = $definition;
|
||||
}
|
||||
|
||||
function isAssoc(?AssocSchema &$assoc=null): bool {
|
||||
$assoc = $this;
|
||||
function isAssoc(?AssocSchema &$schema=null): bool {
|
||||
$schema = $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));
|
||||
protected function newWrapper(): AssocWrapper {
|
||||
return new AssocWrapper($this);
|
||||
}
|
||||
|
||||
function getWrapper(&$array=null, $arrayKey=null, ?Wrapper &$wrapper=null): AssocWrapper {
|
||||
if (!($wrapper instanceof AssocWrapper)) $wrapper = $this->newWrapper();
|
||||
return $wrapper->reset($array, $arrayKey);
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +0,0 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\_assoc;
|
||||
|
||||
use nur\sery\wip\schema\Result;
|
||||
use nur\sery\wip\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 {
|
||||
}
|
||||
}
|
140
src/schema/_assoc/AssocWrapper.php
Normal file
140
src/schema/_assoc/AssocWrapper.php
Normal file
@ -0,0 +1,140 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\_assoc;
|
||||
|
||||
use nulib\ValueException;
|
||||
use nur\sery\wip\schema\_scalar\ScalarResult;
|
||||
use nur\sery\wip\schema\_scalar\ScalarWrapper;
|
||||
use nur\sery\wip\schema\input\Input;
|
||||
use nur\sery\wip\schema\Result;
|
||||
use nur\sery\wip\schema\types\IType;
|
||||
use nur\sery\wip\schema\Wrapper;
|
||||
|
||||
class AssocWrapper extends Wrapper {
|
||||
function __construct(AssocSchema $schema, &$array=null, $arrayKey=null, ?array $params=null) {
|
||||
$verifix = $params["verifix"] ?? true;
|
||||
$throw = $params["throw"] ?? null;
|
||||
if ($array !== null && $throw === null) {
|
||||
# Si $value est null, ne pas lancer d'exception, parce qu'on considère que
|
||||
# c'est une initialisation sans conséquences
|
||||
$throw = true;
|
||||
}
|
||||
$this->schema = $schema;
|
||||
$this->verifix = $verifix;
|
||||
$this->throw = $throw ?? false;
|
||||
$this->result = new AssocResult();
|
||||
$this->reset($array, $arrayKey);
|
||||
$this->throw = $throw ?? true;
|
||||
}
|
||||
|
||||
function isAssoc(?AssocWrapper &$wrapper=null): bool { $wrapper = $this; return true; }
|
||||
|
||||
protected bool $verifix;
|
||||
|
||||
protected bool $throw;
|
||||
|
||||
/** schéma de ce tableau */
|
||||
protected AssocSchema $schema;
|
||||
|
||||
/** source et destination de la valeur */
|
||||
protected Input $input;
|
||||
|
||||
/** @var string|int|null clé du tableau dans le tableau destination */
|
||||
protected $arrayKey;
|
||||
|
||||
protected IType $arrayType;
|
||||
|
||||
protected ScalarResult $arrayResult;
|
||||
|
||||
/** @var IType[] */
|
||||
protected array $keyTypes;
|
||||
|
||||
/** @var Result[] */
|
||||
protected array $keyResults;
|
||||
|
||||
protected AssocResult $result;
|
||||
|
||||
protected ?array $keys;
|
||||
|
||||
protected ?array $wrappers;
|
||||
|
||||
protected function newInput(&$value): Input {
|
||||
return new Input($value);
|
||||
}
|
||||
|
||||
function reset(&$array, $arrayKey=null, ?bool $verifix=null): Wrapper {
|
||||
if ($array instanceof Input) $input = $array;
|
||||
else $input = $this->newInput($array);
|
||||
$this->input = $input;
|
||||
$this->arrayKey = $arrayKey;
|
||||
$this->analyze();
|
||||
if ($verifix ?? $this->verifix) $this->verifix();
|
||||
return $this;
|
||||
}
|
||||
|
||||
function getKeys(): array {
|
||||
return $this->keys;
|
||||
}
|
||||
|
||||
function select($key=null): ScalarWrapper {
|
||||
$wrapper = $this->wrappers[$key] ?? null;
|
||||
if ($key !== null) return $wrapper;
|
||||
throw ValueException::invalid_key($key);
|
||||
}
|
||||
|
||||
/** @param Result[] $results */
|
||||
function verifix(?bool $throw=null, ?array &$results=null): bool {
|
||||
}
|
||||
|
||||
|
||||
function getResult(): AssocResult {
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
function isPresent(): bool {
|
||||
return $this->result->present;
|
||||
}
|
||||
|
||||
function getType(): IType {
|
||||
return $this->arrayType;
|
||||
}
|
||||
|
||||
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->arrayKey);
|
||||
else return $default;
|
||||
}
|
||||
|
||||
function set($value, ?bool $verifix=null): AssocWrapper {
|
||||
$this->input->set($value, $this->arrayKey);
|
||||
$this->analyze();
|
||||
if ($verifix ?? $this->verifix) $this->verifix();
|
||||
return $this;
|
||||
}
|
||||
|
||||
function unset(?bool $verifix=null): AssocWrapper {
|
||||
$this->input->unset($this->arrayKey);
|
||||
$this->analyze();
|
||||
if ($verifix ?? $this->verifix) $this->verifix();
|
||||
return $this;
|
||||
}
|
||||
|
||||
function format($format = null): string {
|
||||
// TODO: Implement format() method.
|
||||
}
|
||||
|
||||
function ensureKeys(): bool {
|
||||
}
|
||||
function orderKeys(): bool {
|
||||
}
|
||||
}
|
@ -1,8 +1,53 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\_list;
|
||||
|
||||
use nulib\ValueException;
|
||||
use nur\sery\wip\schema\Result;
|
||||
|
||||
class ListResult extends Result {
|
||||
function isList(?ListResult &$list=null): bool { $list = $this; return true;}
|
||||
function __construct(Result $arrayResult, array &$keyResults) {
|
||||
$this->arrayResult = $arrayResult;
|
||||
$this->keyResults =& $keyResults;
|
||||
$this->result =& $this->arrayResult;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
function isList(?ListResult &$result=null): bool { $result = $this; return true;}
|
||||
|
||||
protected Result $arrayResult;
|
||||
|
||||
/** @var Result[] */
|
||||
protected array $keyResults;
|
||||
|
||||
function getKeys(): array {
|
||||
return array_keys($this->keyResults);
|
||||
}
|
||||
|
||||
protected Result $result;
|
||||
|
||||
function select($key): Result {
|
||||
if ($key === null) {
|
||||
$this->result =& $this->arrayResult;
|
||||
} elseif (array_key_exists($key, $this->keyResults)) {
|
||||
$this->result =& $this->keyResults[$key];
|
||||
} else {
|
||||
throw ValueException::invalid_key($key);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
function reset(): void {
|
||||
$this->arrayResult->reset();
|
||||
foreach ($this->keyResults as $result) {
|
||||
$result->reset();
|
||||
}
|
||||
}
|
||||
|
||||
function __get(string $name) {
|
||||
return $this->result[$name];
|
||||
}
|
||||
|
||||
function __set(string $name, $value): void {
|
||||
$this->result[$name] = $value;
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\_list;
|
||||
|
||||
use nur\sery\ref\schema\ref_schema;
|
||||
use nulib\ref\schema\ref_schema;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
use nur\sery\wip\schema\Value;
|
||||
use nur\sery\wip\schema\Wrapper;
|
||||
|
||||
class ListSchema extends Schema {
|
||||
/** @var array meta-schema d'un schéma de nature liste */
|
||||
@ -16,15 +16,8 @@ class ListSchema extends Schema {
|
||||
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;
|
||||
if (self::have_nature($definition, $nature)) {
|
||||
return $nature === "list";
|
||||
}
|
||||
# un unique élément tableau à l'index 0
|
||||
$count = count($definition);
|
||||
@ -33,21 +26,41 @@ class ListSchema extends Schema {
|
||||
}
|
||||
|
||||
static function normalize($definition, $definitionKey=null): array {
|
||||
if (!is_array($definition)) $definition = [$definition];
|
||||
if (!self::have_nature($definition)) {
|
||||
$definition = [
|
||||
"?array",
|
||||
"" => "list",
|
||||
"schema" => $definition[0],
|
||||
];
|
||||
}
|
||||
self::_normalize($definition, $definitionKey);
|
||||
self::_ensure_nature($definition, "list", "array");
|
||||
return $definition;
|
||||
}
|
||||
|
||||
function __construct($definition=null, $definitionKey=null, bool $normalize=true) {
|
||||
if ($definition === null) $definition = static::SCHEMA;
|
||||
if ($normalize) $definition = self::normalize($definition, $definitionKey);
|
||||
if ($normalize) {
|
||||
$definition = self::normalize($definition, $definitionKey);
|
||||
$this->_definition = $definition;
|
||||
self::_ensure_type($definition);
|
||||
self::_ensure_schema_instances($definition);
|
||||
}
|
||||
$this->definition = $definition;
|
||||
}
|
||||
|
||||
function isList(?ListSchema &$list=null): bool {
|
||||
$list = $this;
|
||||
function isList(?ListSchema &$schema=null): bool {
|
||||
$schema = $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));
|
||||
protected function newWrapper(): ListWrapper {
|
||||
return new ListWrapper($this);
|
||||
}
|
||||
|
||||
function getWrapper(&$value=null, $valueKey=null, ?Wrapper &$wrapper=null): ListWrapper {
|
||||
if (!($wrapper instanceof ListWrapper)) $wrapper = $this->newWrapper();
|
||||
return $wrapper->reset($value, $valueKey);
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,10 @@
|
||||
namespace nur\sery\wip\schema\_list;
|
||||
|
||||
use nur\sery\wip\schema\Result;
|
||||
use nur\sery\wip\schema\Value;
|
||||
use nur\sery\wip\schema\Wrapper;
|
||||
|
||||
class ListValue extends Value {
|
||||
function isList(?ListValue &$list=null): bool { $list = $this; return true; }
|
||||
abstract/*XXX*/ class ListWrapper extends Wrapper {
|
||||
function isList(?ListWrapper &$wrapper=null): bool { $wrapper = $this; return true; }
|
||||
|
||||
function ensureKeys(): bool {
|
||||
}
|
@ -1,36 +1,27 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\_scalar;
|
||||
|
||||
use nur\sery\cl;
|
||||
use nur\sery\ref\schema\ref_analyze;
|
||||
use nur\sery\ref\schema\ref_schema;
|
||||
use nur\sery\ValueException;
|
||||
use Exception;
|
||||
use nulib\cl;
|
||||
use nulib\ref\schema\ref_analyze;
|
||||
use nulib\ref\schema\ref_schema;
|
||||
use nulib\ValueException;
|
||||
use nur\sery\wip\schema\Result;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* 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 isScalar(?ScalarResult &$result=null): bool { $result = $this; return true; }
|
||||
|
||||
function getKeys(): array {
|
||||
return [null];
|
||||
}
|
||||
|
||||
function getResult($key=null): Result {
|
||||
if ($key === null) return $this;
|
||||
else throw ValueException::invalid_key($key);
|
||||
function select($key): Result {
|
||||
if ($key !== null) throw ValueException::invalid_key($key);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** @var array */
|
||||
@ -65,8 +56,8 @@ class ScalarResult extends Result {
|
||||
}
|
||||
}
|
||||
|
||||
protected static function replace_orig(string &$message, $orig): void {
|
||||
$message = str_replace("{orig}", strval($orig), $message);
|
||||
protected static function replace_orig(string &$message, $origValue): void {
|
||||
$message = str_replace("{orig}", strval($origValue), $message);
|
||||
}
|
||||
|
||||
protected function getMessage(string $key, ScalarSchema $schema): string {
|
||||
@ -85,7 +76,8 @@ class ScalarResult extends Result {
|
||||
$this->normalized = true;
|
||||
return ref_analyze::NORMALIZED;
|
||||
} else {
|
||||
$message = $this->getMessage("missing", $schema);
|
||||
$messageKey = $this->messageKey = "missing";
|
||||
$message = $this->getMessage($messageKey, $schema);
|
||||
self::replace_key($message, $schema->name);
|
||||
$this->message = $message;
|
||||
return ref_analyze::MISSING;
|
||||
@ -102,7 +94,8 @@ class ScalarResult extends Result {
|
||||
$this->normalized = true;
|
||||
return ref_analyze::NORMALIZED;
|
||||
} else {
|
||||
$message = $this->getMessage("unavailable", $schema);
|
||||
$messageKey = $this->messageKey = "unavailable";
|
||||
$message = $this->getMessage($messageKey, $schema);
|
||||
self::replace_key($message, $schema->name);
|
||||
$this->message = $message;
|
||||
return ref_analyze::UNAVAILABLE;
|
||||
@ -119,33 +112,40 @@ class ScalarResult extends Result {
|
||||
$this->normalized = true;
|
||||
return ref_analyze::NORMALIZED;
|
||||
} else {
|
||||
$message = $this->getMessage("null", $schema);
|
||||
$messageKey = $this->messageKey = "null";
|
||||
$message = $this->getMessage($messageKey, $schema);
|
||||
self::replace_key($message, $schema->name);
|
||||
$this->message = $message;
|
||||
return ref_analyze::NULL;
|
||||
}
|
||||
}
|
||||
|
||||
function setInvalid($value, ScalarSchema $schema): int {
|
||||
function setInvalid($value, ScalarSchema $schema, ?Throwable $t=null): int {
|
||||
$this->resultAvailable = true;
|
||||
$this->present = true;
|
||||
$this->available = true;
|
||||
$this->null = false;
|
||||
$this->valid = false;
|
||||
$this->orig = $value;
|
||||
$message = $this->getMessage("invalid", $schema);
|
||||
$this->origValue = $value;
|
||||
$messageKey = $this->messageKey = "invalid";
|
||||
$message = $this->getMessage($messageKey, $schema);
|
||||
self::replace_key($message, $schema->name);
|
||||
self::replace_orig($message, $schema->orig);
|
||||
if ($t !== null) {
|
||||
$tmessage = ValueException::get_message($t);
|
||||
if ($tmessage) $message .= ": $tmessage";
|
||||
}
|
||||
$this->message = $message;
|
||||
return ref_analyze::INVALID;
|
||||
}
|
||||
|
||||
function setValid(): int {
|
||||
function setValid($normalizedValue=null): int {
|
||||
$this->resultAvailable = true;
|
||||
$this->present = true;
|
||||
$this->available = true;
|
||||
$this->null = false;
|
||||
$this->valid = true;
|
||||
$this->normalizedValue = $normalizedValue;
|
||||
return ref_analyze::VALID;
|
||||
}
|
||||
|
||||
|
@ -1,23 +1,15 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\_scalar;
|
||||
|
||||
use nur\sery\cl;
|
||||
use nur\sery\ref\schema\ref_schema;
|
||||
use nur\sery\ref\schema\ref_types;
|
||||
use nulib\ref\schema\ref_schema;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
use nur\sery\wip\schema\SchemaException;
|
||||
use nur\sery\wip\schema\types\tarray;
|
||||
use nur\sery\wip\schema\types\tbool;
|
||||
use nur\sery\wip\schema\types\tcallable;
|
||||
use nur\sery\wip\schema\types\tcontent;
|
||||
use nur\sery\wip\schema\types\tpkey;
|
||||
use nur\sery\wip\schema\types\tstring;
|
||||
use nur\sery\wip\schema\Value;
|
||||
use nur\sery\wip\schema\types\IType;
|
||||
use nur\sery\wip\schema\Wrapper;
|
||||
|
||||
/**
|
||||
* Class ScalarSchema
|
||||
*
|
||||
* @property-read array $type
|
||||
* @property-read array|IType $type
|
||||
* @property-read mixed $default
|
||||
* @property-read string|null $title
|
||||
* @property-read bool $required
|
||||
@ -31,6 +23,7 @@ use nur\sery\wip\schema\Value;
|
||||
* @property-read callable|null $formatterFunc
|
||||
* @property-read mixed $format
|
||||
* @property-read array $nature
|
||||
* @property-read array|null $schema
|
||||
* @property-read string|int|null $name
|
||||
* @property-read string|array|null $pkey
|
||||
* @property-read string|null $header
|
||||
@ -72,111 +65,34 @@ class ScalarSchema extends Schema {
|
||||
}
|
||||
|
||||
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"]);
|
||||
self::_normalize($definition, $definitionKey);
|
||||
self::_ensure_nature($definition, "scalar");
|
||||
return $definition;
|
||||
}
|
||||
|
||||
function __construct($definition=null, $definitionKey=null, bool $normalize=true) {
|
||||
if ($definition === null) $definition = static::SCHEMA;
|
||||
if ($normalize) $definition = self::normalize($definition, $definitionKey);
|
||||
if ($normalize) {
|
||||
$definition = self::normalize($definition, $definitionKey);
|
||||
$this->_definition = $definition;
|
||||
self::_ensure_type($definition);
|
||||
self::_ensure_schema_instances($definition);
|
||||
}
|
||||
$this->definition = $definition;
|
||||
}
|
||||
|
||||
function isScalar(?ScalarSchema &$scalar=null): bool {
|
||||
$scalar = $this;
|
||||
function isScalar(?ScalarSchema &$schema=null): bool {
|
||||
$schema = $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));
|
||||
protected function newWrapper(): ScalarWrapper {
|
||||
return new ScalarWrapper($this);
|
||||
}
|
||||
|
||||
function getWrapper(&$value=null, $valueKey=null, ?Wrapper &$wrapper=null): ScalarWrapper {
|
||||
if (!($wrapper instanceof ScalarWrapper)) $wrapper = $this->newWrapper();
|
||||
return $wrapper->reset($value, $valueKey);
|
||||
}
|
||||
|
||||
#############################################################################
|
||||
|
@ -1,198 +0,0 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\_scalar;
|
||||
|
||||
use nur\sery\ref\schema\ref_analyze;
|
||||
use nur\sery\ValueException;
|
||||
use nur\sery\wip\schema\input\Input;
|
||||
use nur\sery\wip\schema\types;
|
||||
use nur\sery\wip\schema\types\IType;
|
||||
use nur\sery\wip\schema\Value;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
317
src/schema/_scalar/ScalarWrapper.php
Normal file
317
src/schema/_scalar/ScalarWrapper.php
Normal file
@ -0,0 +1,317 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\_scalar;
|
||||
|
||||
use nulib\php\func;
|
||||
use nulib\ref\schema\ref_analyze;
|
||||
use nulib\ValueException;
|
||||
use nur\sery\wip\schema\AnalyzerContext;
|
||||
use nur\sery\wip\schema\input\Input;
|
||||
use nur\sery\wip\schema\types;
|
||||
use nur\sery\wip\schema\types\IType;
|
||||
use nur\sery\wip\schema\Wrapper;
|
||||
|
||||
class ScalarWrapper extends Wrapper {
|
||||
function __construct(ScalarSchema $schema, &$value=null, $valueKey=null, ?array $params=null) {
|
||||
$verifix = $params["verifix"] ?? true;
|
||||
$throw = $params["throw"] ?? null;
|
||||
if ($value !== null && $throw === null) {
|
||||
# Si $value est null, ne pas lancer d'exception, parce qu'on considère que
|
||||
# c'est une initialisation sans conséquences
|
||||
$throw = true;
|
||||
}
|
||||
$this->verifix = $verifix;
|
||||
$this->throw = $throw ?? false;
|
||||
$this->schema = $schema;
|
||||
$this->result = new ScalarResult();
|
||||
$this->reset($value, $valueKey);
|
||||
$this->throw = $throw ?? true;
|
||||
}
|
||||
|
||||
function isScalar(?ScalarWrapper &$wrapper=null): bool { $wrapper = $this; return true; }
|
||||
|
||||
protected bool $verifix;
|
||||
|
||||
protected bool $throw;
|
||||
|
||||
/** schéma de cette valeur */
|
||||
protected ScalarSchema $schema;
|
||||
|
||||
/** source et destination de la valeur */
|
||||
protected Input $input;
|
||||
|
||||
/** @var string|int|null clé de la valeur dans le tableau destination */
|
||||
protected $valueKey;
|
||||
|
||||
/** type de la valeur après analyse */
|
||||
protected ?IType $type;
|
||||
|
||||
/** résultat de l'analyse de la valeur */
|
||||
protected ScalarResult $result;
|
||||
|
||||
protected function newInput(&$value): Input {
|
||||
return new Input($value);
|
||||
}
|
||||
|
||||
function reset(&$value, $valueKey=null, ?bool $verifix=null): Wrapper {
|
||||
if ($value instanceof Input) $input = $value;
|
||||
else $input = $this->newInput($value);
|
||||
$this->input = $input;
|
||||
$this->valueKey = $valueKey;
|
||||
$this->type = null;
|
||||
$this->analyze();
|
||||
if ($verifix ?? $this->verifix) $this->verifix();
|
||||
return $this;
|
||||
}
|
||||
|
||||
function getKeys(): array {
|
||||
return [null];
|
||||
}
|
||||
|
||||
/** @param string|int|null $key */
|
||||
function select($key): ScalarWrapper {
|
||||
if ($key !== null) throw ValueException::invalid_key($key);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** analyser la valeur et résoudre son type */
|
||||
protected function analyze0(AnalyzerContext $context): int {
|
||||
/** @var ScalarSchema $schema */
|
||||
$schema = $context->schema;
|
||||
$input = $context->input;
|
||||
$valueKey = $context->valueKey;
|
||||
/** @var ScalarResult $result */
|
||||
$result = $context->result;
|
||||
|
||||
$default = $schema->default;
|
||||
if (!$input->isPresent($valueKey)) {
|
||||
if ($default !== null) {
|
||||
$input->set($default, $valueKey);
|
||||
return $result->setNormalized();
|
||||
} else {
|
||||
return $result->setMissing($schema);
|
||||
}
|
||||
}
|
||||
|
||||
$schemaTypes = $schema->type;
|
||||
if ($schemaTypes instanceof IType) {
|
||||
$type = $schemaTypes;
|
||||
} else {
|
||||
# type union
|
||||
$haveType = false;
|
||||
$types = [];
|
||||
$type = $firstType = null;
|
||||
$value = null;
|
||||
# d'abord chercher un type pour lequel c'est une valeur normalisée
|
||||
$index = 0;
|
||||
$haveValue = false;
|
||||
foreach ($schemaTypes as $key => $name) {
|
||||
if ($key === $index) {
|
||||
$index++;
|
||||
$args = null;
|
||||
} else {
|
||||
$args = $name;
|
||||
$name = $key;
|
||||
}
|
||||
$type = types::get($schema->nullable, $name, $args, $this->schema->getDefinition());
|
||||
if ($firstType === null) $firstType = $type;
|
||||
$types[] = $type;
|
||||
if ($type->isAvailable($input, $valueKey)) {
|
||||
if (!$haveValue) {
|
||||
$value = $input->get($valueKey);
|
||||
$haveValue = true;
|
||||
}
|
||||
if ($type->isValid($value, $normalized) && $normalized) {
|
||||
$haveType = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
# ensuite chercher un type pour lequel la valeur est valide
|
||||
if (!$haveType) {
|
||||
foreach ($types as $type) {
|
||||
if ($type->isAvailable($input, $valueKey) && $type->isValid($value)) {
|
||||
$haveType = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
# sinon prendre le premier type
|
||||
if (!$haveType) {
|
||||
$type = $firstType;
|
||||
}
|
||||
}
|
||||
$context->type = $this->type = $type;
|
||||
|
||||
if (!$type->isAvailable($input, $valueKey)) {
|
||||
if ($default !== null) {
|
||||
$input->set($default, $valueKey);
|
||||
return $result->setNormalized();
|
||||
} else {
|
||||
return $result->setUnavailable($schema);
|
||||
}
|
||||
}
|
||||
|
||||
$value = $input->get($valueKey);
|
||||
$context->origValue = $context->value = $value;
|
||||
if ($type->isNull($value)) {
|
||||
return $result->setNull($schema);
|
||||
} elseif (is_string($value)) {
|
||||
return ref_analyze::STRING;
|
||||
} elseif ($type->isValid($value, $normalized)) {
|
||||
if ($normalized) return $result->setNormalized();
|
||||
else return $result->setValid();
|
||||
} else {
|
||||
return $result->setInvalid($value, $schema);
|
||||
}
|
||||
}
|
||||
|
||||
protected function analyze(): int {
|
||||
$schema = $this->schema;
|
||||
$input = $this->input;
|
||||
$valueKey = $this->valueKey;
|
||||
$result = $this->result;
|
||||
$result->reset();
|
||||
$context = new AnalyzerContext($schema, $this, $input, $valueKey, $result);
|
||||
|
||||
/** @var func $analyzerFunc */
|
||||
$analyzerFunc = $schema->analyzerFunc;
|
||||
if ($analyzerFunc !== null) $what = $analyzerFunc->invoke([$context]);
|
||||
else $what = $this->analyze0($context);
|
||||
if ($what !== ref_analyze::STRING) return $what;
|
||||
|
||||
$value = $context->value;
|
||||
try {
|
||||
/** @var func $extractorFunc */
|
||||
$extractorFunc = $schema->extractorFunc;
|
||||
if ($extractorFunc !== null) $extracted = $extractorFunc->invoke([$value, $context]);
|
||||
else $extracted = $context->type->extract($value);
|
||||
$context->value = $extracted;
|
||||
} catch (ValueException $e) {
|
||||
return $result->setInvalid($context->origValue, $schema, $e);
|
||||
}
|
||||
if ($context->type->isNull($extracted)) return $result->setNull($schema);
|
||||
|
||||
try {
|
||||
/** @var func $parserFunc */
|
||||
$parserFunc = $schema->parserFunc;
|
||||
if ($parserFunc !== null) $parsed = $parserFunc->invoke([$extracted, $context]);
|
||||
else $parsed = $context->type->parse($extracted);
|
||||
$context->value = $parsed;
|
||||
} catch (ValueException $e) {
|
||||
return $result->setInvalid($context->origValue, $schema, $e);
|
||||
}
|
||||
|
||||
$normalized = $parsed === $context->origValue;
|
||||
if ($normalized) {
|
||||
$input->set($parsed, $valueKey);
|
||||
return $result->setNormalized();
|
||||
} else {
|
||||
$input->set($extracted, $valueKey);
|
||||
return $result->setValid($parsed);
|
||||
}
|
||||
}
|
||||
|
||||
function verifix(?bool $throw=null): bool {
|
||||
$result = $this->result;
|
||||
$valueKey = $this->valueKey;
|
||||
$verifix = false;
|
||||
$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, $valueKey);
|
||||
} elseif ($result->valid && !$result->normalized) {
|
||||
$normalizedValue = $result->normalizedValue;
|
||||
if ($normalizedValue !== null) {
|
||||
# la valeur normalisée est disponible
|
||||
$this->input->set($normalizedValue);
|
||||
$result->normalizedValue = null;
|
||||
$modified = true;
|
||||
} else {
|
||||
# normaliser la valeur
|
||||
$verifix = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$verifix = true;
|
||||
}
|
||||
|
||||
if ($verifix) {
|
||||
$value = $this->input->get($valueKey);
|
||||
$schema = $this->schema;
|
||||
/** @var func $normalizerFunc */
|
||||
$normalizerFunc = $schema->normalizerFunc;
|
||||
if ($normalizerFunc !== null) {
|
||||
$context = new AnalyzerContext($schema, $this, $this->input, $valueKey, $result);
|
||||
$orig = $value;
|
||||
$value = $normalizerFunc->invoke([$orig, $context]);
|
||||
$modified = $value !== $orig;
|
||||
} else {
|
||||
$modified = $this->type->verifix($value, $result, $this->schema);
|
||||
}
|
||||
if ($result->valid) $this->input->set($value, $valueKey);
|
||||
}
|
||||
if (!$result->valid) $result->throw($throw ?? $this->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->valueKey);
|
||||
else return $default;
|
||||
}
|
||||
|
||||
function set($value, ?bool $verifix=null): ScalarWrapper {
|
||||
$this->input->set($value, $this->valueKey);
|
||||
$this->analyze();
|
||||
if ($verifix ?? $this->verifix) $this->verifix();
|
||||
return $this;
|
||||
}
|
||||
|
||||
function unset(?bool $verifix=null): ScalarWrapper {
|
||||
$this->input->unset($this->valueKey);
|
||||
$this->analyze();
|
||||
if ($verifix ?? $this->verifix) $this->verifix();
|
||||
return $this;
|
||||
}
|
||||
|
||||
function format($format=null): string {
|
||||
$value = $this->input->get($this->valueKey);
|
||||
/** @var func $formatterFunc */
|
||||
$formatterFunc = $this->schema->formatterFunc;
|
||||
if ($formatterFunc !== null) {
|
||||
# la fonction formatter n'a pas forcément accès au format de la définition
|
||||
# le lui fournir ici
|
||||
$format ??= $this->schema->format;
|
||||
return $formatterFunc->invoke([$value, $format]);
|
||||
} else {
|
||||
# on assume que le type a été initialisé avec le format de la définition
|
||||
# le cas échéant
|
||||
return $this->type->format($value, $format);
|
||||
}
|
||||
}
|
||||
}
|
@ -25,7 +25,7 @@ class FormInput extends Input {
|
||||
}
|
||||
|
||||
protected function access($key): IAccess {
|
||||
return $this->keyAccess[$key] ??= new ShadowAccess($this->formAccess($key), new KeyAccess($this->dest, $key, [
|
||||
return $this->keyAccess[$key] ??= new ShadowAccess($this->formAccess($key), new KeyAccess($this->value, $key, [
|
||||
"allow_empty" => $this->allowEmpty,
|
||||
]));
|
||||
}
|
||||
|
@ -13,13 +13,13 @@ use nur\sery\wip\php\access\ValueAccess;
|
||||
class Input {
|
||||
const ALLOW_EMPTY = true;
|
||||
|
||||
function __construct(&$dest=null, ?array $params=null) {
|
||||
$this->dest =& $dest;
|
||||
function __construct(&$value=null, ?array $params=null) {
|
||||
$this->value =& $value;
|
||||
$this->allowEmpty = $params["allow_empty"] ?? static::ALLOW_EMPTY;
|
||||
}
|
||||
|
||||
/** @var mixed */
|
||||
protected $dest;
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* @var bool comment considérer une chaine vide: "" si allowEmpty, null sinon
|
||||
@ -31,12 +31,12 @@ class Input {
|
||||
|
||||
protected function access($key): IAccess {
|
||||
if ($key === null) {
|
||||
return $this->valueAccess ??= new ValueAccess($this->dest, [
|
||||
return $this->valueAccess ??= new ValueAccess($this->value, [
|
||||
"allow_null" => true,
|
||||
"allow_empty" => $this->allowEmpty,
|
||||
]);
|
||||
} else {
|
||||
return $this->keyAccess[$key] ??= new KeyAccess($this->dest, $key, [
|
||||
return $this->keyAccess[$key] ??= new KeyAccess($this->value, $key, [
|
||||
"allow_empty" => $this->allowEmpty,
|
||||
]);
|
||||
}
|
||||
|
@ -6,9 +6,16 @@ use nur\sery\wip\schema\types\Registry;
|
||||
use nur\sery\wip\schema\types\tarray;
|
||||
use nur\sery\wip\schema\types\tbool;
|
||||
use nur\sery\wip\schema\types\tcallable;
|
||||
use nur\sery\wip\schema\types\tcontent;
|
||||
use nur\sery\wip\schema\types\tfloat;
|
||||
use nur\sery\wip\schema\types\tint;
|
||||
use nur\sery\wip\schema\types\tkey;
|
||||
use nur\sery\wip\schema\types\tmixed;
|
||||
use nur\sery\wip\schema\types\tpkey;
|
||||
use nur\sery\wip\schema\types\traw;
|
||||
use nur\sery\wip\schema\types\trawstring;
|
||||
use nur\sery\wip\schema\types\tstring;
|
||||
use nur\sery\wip\schema\types\ttext;
|
||||
|
||||
/**
|
||||
* Class types: classe outil pour gérer le registre de types
|
||||
@ -24,14 +31,21 @@ class types {
|
||||
return self::$registry;
|
||||
}
|
||||
|
||||
static function get(string $name): IType {
|
||||
return self::registry()->get($name);
|
||||
static function get(bool $nullable, ?string $name, ?array $args=null, ?array $definition=null): IType {
|
||||
return self::registry()->get($nullable, $name, $args, $definition);
|
||||
}
|
||||
|
||||
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"); }
|
||||
static function rawstring(bool $nullable=true): trawstring { return self::get($nullable, "rawstring"); }
|
||||
static function string(bool $nullable=true): tstring { return self::get($nullable, "string"); }
|
||||
static function text(bool $nullable=true): ttext { return self::get($nullable, "text"); }
|
||||
static function bool(bool $nullable=true): tbool { return self::get($nullable, "bool"); }
|
||||
static function int(bool $nullable=true): tint { return self::get($nullable, "int"); }
|
||||
static function float(bool $nullable=true): tfloat { return self::get($nullable, "float"); }
|
||||
static function array(bool $nullable=true): tarray { return self::get($nullable, "array"); }
|
||||
static function callable(bool $nullable=true): tcallable { return self::get($nullable, "callable"); }
|
||||
static function raw(bool $nullable=true): traw { return self::get($nullable, "raw"); }
|
||||
static function mixed(bool $nullable=true): tmixed { return self::get($nullable, "mixed"); }
|
||||
static function key(bool $nullable=true): tkey { return self::get($nullable, "key"); }
|
||||
static function pkey(bool $nullable=true): tpkey { return self::get($nullable, "pkey"); }
|
||||
static function content(bool $nullable=true): tcontent { return self::get($nullable, "content"); }
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
use nulib\ValueException;
|
||||
use nur\sery\wip\schema\input\Input;
|
||||
use nur\sery\wip\schema\Result;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
@ -9,25 +10,130 @@ use nur\sery\wip\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;
|
||||
/**
|
||||
* obtenir, pour information, le nom officiel de ce type, utilisable dans une
|
||||
* définition de schéma
|
||||
*/
|
||||
function getName(): string;
|
||||
|
||||
/** obtenir la liste des aliases valides pour ce type */
|
||||
function getAliases(): array;
|
||||
|
||||
/**
|
||||
* @return string la classe des objets gérés par ce format: le type attendu
|
||||
* par {@link format()} et le type retourné par {@link verifix()}
|
||||
*
|
||||
* Les valeurs "mixed", "bool", "float", "int", "string" et "array" peuvent
|
||||
* aussi être retournées, bien qu'elles ne soient pas à proprement parler des
|
||||
* classes.
|
||||
*
|
||||
* La valeur "mixed" signifie qu'il peut s'agir de n'importe quelle classe
|
||||
* et/ou que la valeur ne peut pas être déterminée à l'avance.
|
||||
*/
|
||||
function getClass(): string;
|
||||
|
||||
/**
|
||||
* comme {@link getClass()} mais peut être utilisé directement comme type dans
|
||||
* une déclaration PHP. notamment, si le type est nullable et que
|
||||
* $allowNullable==true, il y a "?" devant le nom.
|
||||
*
|
||||
* Par exemple:
|
||||
* - pour un type chaine nullable, {@link getClass()} retournerait "string"
|
||||
* alors que cette méthode retournerait "?string".
|
||||
* - pour un type mixed, {@link getClass()} retournerait "mixed" alors que
|
||||
* cette méthode retournerait null
|
||||
*/
|
||||
function getPhpType(bool $allowNullable=true): ?string;
|
||||
|
||||
/**
|
||||
* indiquer si c'est le type d'une valeur qui ne peut prendre que 2 états: une
|
||||
* "vraie" et une "fausse"
|
||||
*/
|
||||
function is2States(): bool;
|
||||
|
||||
/**
|
||||
* Si {@link is2States()} est vrai, retourner les deux valeurs [faux, vrai]
|
||||
*/
|
||||
function get2States(): array;
|
||||
|
||||
/**
|
||||
* indiquer si c'est le type d'une valeur qui ne peut prendre que 3 états: une
|
||||
* "vraie", une "fausse", et une "indéterminée"
|
||||
*/
|
||||
function is3States(): bool;
|
||||
|
||||
/**
|
||||
* Si {@link is3States()} est vrai, retourner les 3 valeurs [faux, vrai, undef]
|
||||
*/
|
||||
function get3States(): array;
|
||||
|
||||
/** la donnée $input($valueKey) est-elle disponible? */
|
||||
function isAvailable(Input $input, $valueKey): bool;
|
||||
|
||||
/** la valeur $value est-elle nulle? */
|
||||
function isNull($value): bool;
|
||||
|
||||
/** la valeur $value est-elle valide et normalisée le cas échéant? */
|
||||
/**
|
||||
* la valeur $value est-elle valide et normalisée le cas échéant?
|
||||
*
|
||||
* NB: si $value est un string. elle doit avoir déjà été traitée au préalable
|
||||
* par extract() et parse()
|
||||
*/
|
||||
function isValid($value, ?bool &$normalized=null): bool;
|
||||
|
||||
/**
|
||||
* extraire de la chaine la valeur à analyser
|
||||
*
|
||||
* @throws ValueException en cas d'erreur d'analyse
|
||||
*/
|
||||
function extract(string $value): string;
|
||||
|
||||
/**
|
||||
* analyser la chaine et retourner la valeur "convertie"
|
||||
*
|
||||
* @throws ValueException en cas d'erreur d'analyse
|
||||
*/
|
||||
function parse(string $value);
|
||||
|
||||
/**
|
||||
* analyser, corriger éventuellement et normaliser la valeur
|
||||
*
|
||||
* NB: si $value est un string. elle doit avoir déjà été traitée au préalable
|
||||
* par extract() et parse()
|
||||
*
|
||||
* 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;
|
||||
function verifix(&$value, Result $result, Schema $schema): bool;
|
||||
|
||||
/**
|
||||
* formatter la valeur pour affichage. $value est garanti d'être du bon type
|
||||
* formatter la valeur pour affichage. si $value n'est pas null, elle est
|
||||
* garantie d'être du bon type
|
||||
*/
|
||||
function format($value, $format=null): string;
|
||||
|
||||
#############################################################################
|
||||
|
||||
/** @return string le nom d'un getter pour une valeur de ce type */
|
||||
function getGetterName(string $name): string;
|
||||
|
||||
/** @return string le nom d'un setter pour une valeur de ce type */
|
||||
function getSetterName(string $name): string;
|
||||
|
||||
/** @return string le nom d'un deleter pour une valeur de ce type */
|
||||
function getDeleterName(string $name): string;
|
||||
|
||||
/**
|
||||
* @return string le nom d'une constante de classe pour une valeur de ce type
|
||||
*/
|
||||
function getClassConstName(string $name): string;
|
||||
|
||||
/**
|
||||
* @return string le nom d'une propriété d'une classe pour une valeur de ce
|
||||
* type
|
||||
*/
|
||||
function getObjectPropertyName(string $name): string;
|
||||
|
||||
/** @return string le nom d'une clé d'un tableau pour une valeur de ce type */
|
||||
function getArrayKeyName(string $name): string;
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
use nur\sery\cl;
|
||||
use nulib\cl;
|
||||
use nulib\php\func;
|
||||
|
||||
class Registry {
|
||||
const TYPES = [
|
||||
"rawstring" => trawstring::class,
|
||||
"string" => tstring::class,
|
||||
"text" => ttext::class,
|
||||
"bool" => tbool::class, "boolean" => tbool::class,
|
||||
"int" => tint::class, "integer" => tint::class,
|
||||
"float" => tfloat::class, "flt" => tfloat::class,
|
||||
@ -13,6 +16,8 @@ class Registry {
|
||||
"array" => tarray::class,
|
||||
"callable" => tcallable::class,
|
||||
# types spéciaux
|
||||
"raw" => tmixed::class,
|
||||
"mixed" => tmixed::class,
|
||||
"key" => tkey::class,
|
||||
"pkey" => tpkey::class,
|
||||
"content" => tcontent::class,
|
||||
@ -25,12 +30,25 @@ class Registry {
|
||||
/** @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();
|
||||
function get(bool $nullable, ?string $name, ?array $args=null, ?array $definition=null): IType {
|
||||
$name ??= "raw";
|
||||
$class = self::TYPES[$name];
|
||||
if (cl::is_list($args)) {
|
||||
$key = array_key_last($args);
|
||||
$params = $args[$key];
|
||||
unset($args[$key]);
|
||||
} else {
|
||||
$params = $args;
|
||||
$args = null;
|
||||
}
|
||||
$params = cl::merge($class::get_params_from_definition($definition), $params);
|
||||
if ($args || $params !== null) {
|
||||
$args ??= [];
|
||||
return func::with([$class, false, ...$args, $nullable, $params])->invoke();
|
||||
}
|
||||
if ($nullable) $name = "?$name";
|
||||
$type = cl::get($this->types, $name);
|
||||
if ($type === null) $type = $this->types[$name] = new $class($nullable);
|
||||
return $type;
|
||||
}
|
||||
}
|
||||
|
19
src/schema/types/_tformatable.php
Normal file
19
src/schema/types/_tformatable.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
abstract class _tformatable extends _tsimple {
|
||||
const FORMAT = null;
|
||||
|
||||
static function get_params_from_definition(?array $definition): ?array {
|
||||
$params = null;
|
||||
$format = $definition["format"] ?? null;
|
||||
if ($format !== null) $params["format"] = $format;
|
||||
return $params;
|
||||
}
|
||||
|
||||
function format($value, $format=null): string {
|
||||
$format ??= $this->params["format"] ?? static::FORMAT;
|
||||
if ($format !== null) return sprintf($format, $value);
|
||||
else return strval($value);
|
||||
}
|
||||
}
|
@ -1,14 +1,99 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
use nulib\StateException;
|
||||
use nur\prop;
|
||||
use nur\sery\wip\schema\input\Input;
|
||||
use nur\str;
|
||||
|
||||
abstract class _tsimple implements IType {
|
||||
function isAvailable(Input $input, $destKey): bool {
|
||||
return $input->isAvailable($destKey) && $input->get($destKey) !== false;
|
||||
const NAME = null;
|
||||
|
||||
const ALIASES = [];
|
||||
|
||||
static function get_params_from_definition(?array $definition): ?array {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* $nullable et $params doivent toujours être les derniers arguments du
|
||||
* constructeur
|
||||
*/
|
||||
function __construct(bool $nullable, ?array $params=null) {
|
||||
$this->nullable = $nullable;
|
||||
$this->params = $params;
|
||||
}
|
||||
|
||||
protected bool $nullable;
|
||||
|
||||
protected ?array $params;
|
||||
|
||||
function getName(): string {
|
||||
return static::NAME;
|
||||
}
|
||||
|
||||
function getAliases(): array {
|
||||
return static::ALIASES;
|
||||
}
|
||||
|
||||
function getPhpType(bool $allowNullable=true): ?string {
|
||||
$phpType = $this->getClass();
|
||||
if ($phpType === "mixed") return null;
|
||||
if ($this->nullable && $allowNullable) $phpType = "?$phpType";
|
||||
return $phpType;
|
||||
}
|
||||
|
||||
function is2States(): bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
function get2States(): array {
|
||||
throw StateException::not_implemented();
|
||||
}
|
||||
|
||||
function is3States(): bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
function get3States(): array {
|
||||
throw StateException::not_implemented();
|
||||
}
|
||||
|
||||
function isAvailable(Input $input, $valueKey): bool {
|
||||
return $input->isAvailable($valueKey) && $input->get($valueKey) !== false;
|
||||
}
|
||||
|
||||
function isNull($value): bool {
|
||||
return $value === null || (is_string($value) && trim($value) === "");
|
||||
return $value === null || $value === "";
|
||||
}
|
||||
|
||||
function extract(string $value): string {
|
||||
return $value;
|
||||
}
|
||||
|
||||
#############################################################################
|
||||
|
||||
function getGetterName(string $name): string {
|
||||
return prop::get_getter_name($name);
|
||||
}
|
||||
|
||||
function getSetterName(string $name): string {
|
||||
return prop::get_setter_name($name);
|
||||
}
|
||||
|
||||
function getDeleterName(string $name): string {
|
||||
return prop::get_deletter_name($name);
|
||||
}
|
||||
|
||||
function getClassConstName(string $name): string {
|
||||
return strtoupper($name);
|
||||
}
|
||||
|
||||
function getObjectPropertyName(string $name): string {
|
||||
return str::us2camel($name);
|
||||
}
|
||||
|
||||
function getArrayKeyName(string $name): string {
|
||||
return $name;
|
||||
}
|
||||
}
|
||||
|
26
src/schema/types/_tstring.php
Normal file
26
src/schema/types/_tstring.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
use nulib\str;
|
||||
|
||||
abstract class _tstring extends _tsimple {
|
||||
/** @var bool faut-il trimmer la valeur */
|
||||
const TRIM = false;
|
||||
/** @var bool faut-il normaliser les caractères fin de ligne */
|
||||
const NORM_NL = false;
|
||||
|
||||
static function get_params_from_definition(?array $definition): ?array {
|
||||
$params = null;
|
||||
$trim = $definition["trim"] ?? null;
|
||||
if ($trim !== null) $params["trim"] = $trim;
|
||||
$normNl = $definition["norm_nl"] ?? null;
|
||||
if ($normNl !== null) $params["norm_nl"] = $normNl;
|
||||
return $params;
|
||||
}
|
||||
|
||||
function extract(string $value): string {
|
||||
if ($this->params["trim"] ?? static::TRIM) $value = trim($value);
|
||||
if ($this->params["norm_nl"] ?? static::NORM_NL) $value = str::norm_nl($value);
|
||||
return $value;
|
||||
}
|
||||
}
|
10
src/schema/types/_tunion.php
Normal file
10
src/schema/types/_tunion.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
abstract class _tunion extends _tsimple {
|
||||
function getPhpType(bool $allowNullable=true): ?string {
|
||||
# assumer mixed pour le moment
|
||||
#XXX à terme, lister les types de l'union
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,11 +1,28 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
use nur\sery\cl;
|
||||
use nulib\cl;
|
||||
use nulib\ValueException;
|
||||
use nur\sery\wip\schema\_scalar\ScalarResult;
|
||||
use nur\sery\wip\schema\_scalar\ScalarSchema;
|
||||
use nur\sery\wip\schema\Result;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
|
||||
class tarray extends _tsimple {
|
||||
class tarray extends _tstring {
|
||||
const NAME = "array";
|
||||
|
||||
const SPLIT_PATTERN = '/\s+/';
|
||||
const FORMAT = " ";
|
||||
|
||||
public static function get_params_from_definition(?array $definition): ?array {
|
||||
$params = parent::get_params_from_definition($definition);
|
||||
$splitPattern = $definition["split_pattern"] ?? null;
|
||||
if ($splitPattern !== null) $params["split_pattern"] = $splitPattern;
|
||||
$format = $definition["format"] ?? null;
|
||||
if ($format !== null) $params["format"] = $format;
|
||||
return $params;
|
||||
}
|
||||
|
||||
static function ensure_array(&$array): void {
|
||||
if (!is_array($array)) $array = cl::with($array);
|
||||
}
|
||||
@ -14,14 +31,47 @@ class tarray extends _tsimple {
|
||||
if ($array !== null) self::ensure_array($array);
|
||||
}
|
||||
|
||||
function getClass(): string {
|
||||
return "array";
|
||||
}
|
||||
|
||||
function isValid($value, ?bool &$normalized=null): bool {
|
||||
$normalized = is_array($value);
|
||||
return is_scalar($value) || is_array($value);
|
||||
}
|
||||
|
||||
function verifix(&$value, Result &$result, Schema $schema): bool {
|
||||
function parse(string $value) {
|
||||
$pattern = $this->params["split_pattern"] ?? static::SPLIT_PATTERN;
|
||||
return preg_split($pattern, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @var ScalarResult $result
|
||||
* @var ScalarSchema $schema
|
||||
*/
|
||||
function verifix(&$value, Result $result, Schema $schema): bool {
|
||||
if (is_array($value)) {
|
||||
$result->setNormalized();
|
||||
return false;
|
||||
} elseif (is_string($value)) {
|
||||
try {
|
||||
$value = $this->parse($value);
|
||||
$result->setValid();
|
||||
return true;
|
||||
} catch (ValueException $e) {
|
||||
}
|
||||
} elseif (is_scalar($value)) {
|
||||
$value = cl::with($value);
|
||||
$result->setValid();
|
||||
return true;
|
||||
}
|
||||
$result->setInvalid($value, $schema);
|
||||
return false;
|
||||
}
|
||||
|
||||
function format($value, $format=null): string {
|
||||
if ($value === null) return "";
|
||||
$format ??= $this->params["format"] ?? static::FORMAT;
|
||||
return implode($format, $value);
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,28 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
use nur\sery\cl;
|
||||
use nur\sery\ValueException;
|
||||
use nulib\cl;
|
||||
use nulib\ValueException;
|
||||
use nur\prop;
|
||||
use nur\sery\wip\schema\_scalar\ScalarResult;
|
||||
use nur\sery\wip\schema\_scalar\ScalarSchema;
|
||||
use nur\sery\wip\schema\input\Input;
|
||||
use nur\sery\wip\schema\Result;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
|
||||
class tbool extends _tsimple {
|
||||
class tbool extends _tformatable {
|
||||
const NAME = "bool";
|
||||
|
||||
const ALIASES = ["boolean"];
|
||||
|
||||
/** 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",
|
||||
];
|
||||
@ -53,41 +56,67 @@ class tbool extends _tsimple {
|
||||
if ($bool !== null) self::ensure_bool($bool);
|
||||
}
|
||||
|
||||
function isAvailable(Input $input, $destKey): bool {
|
||||
return $input->isAvailable($destKey);
|
||||
function getClass(): string {
|
||||
return "bool";
|
||||
}
|
||||
|
||||
function is2States(): bool {
|
||||
return !$this->nullable;
|
||||
}
|
||||
|
||||
function get2States(): array {
|
||||
return [false, true];
|
||||
}
|
||||
|
||||
function is3States(): bool {
|
||||
return $this->nullable;
|
||||
}
|
||||
|
||||
function get3States(): array {
|
||||
return [false, true, null];
|
||||
}
|
||||
|
||||
function isAvailable(Input $input, $valueKey): bool {
|
||||
return $input->isAvailable($valueKey);
|
||||
}
|
||||
|
||||
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;
|
||||
return is_scalar($value);
|
||||
}
|
||||
|
||||
function extract(string $value): string {
|
||||
return trim($value);
|
||||
}
|
||||
|
||||
function parse(string $value) {
|
||||
if (self::is_yes($value)) return true;
|
||||
elseif (self::is_no($value)) return false;
|
||||
throw new ValueException("une valeur booléenne est attendue");
|
||||
}
|
||||
|
||||
/**
|
||||
* @var ScalarResult $result
|
||||
* @var ScalarSchema $schema
|
||||
*/
|
||||
function verifix(&$value, Result &$result, Schema $schema): bool {
|
||||
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);
|
||||
try {
|
||||
$value = $this->parse($value);
|
||||
$result->setValid();
|
||||
return true;
|
||||
} catch (ValueException $e) {
|
||||
}
|
||||
} elseif (is_scalar($value)) {
|
||||
$value = boolval($value);
|
||||
} else {
|
||||
return $result->setInvalid($value, $schema);
|
||||
$result->setValid();
|
||||
return true;
|
||||
}
|
||||
$result->setValid();
|
||||
return true;
|
||||
$result->setInvalid($value, $schema);
|
||||
return false;
|
||||
}
|
||||
|
||||
const OUINON_FORMAT = ["Oui", "Non", false];
|
||||
@ -105,10 +134,10 @@ class tbool extends _tsimple {
|
||||
"oz" => self::OZ_FORMAT,
|
||||
];
|
||||
|
||||
const DEFAULT_FORMAT = self::OUINON_FORMAT;
|
||||
const FORMAT = self::OUINON_FORMAT;
|
||||
|
||||
function format($value, $format=null): string {
|
||||
if ($format === null) $format = static::DEFAULT_FORMAT;
|
||||
$format ??= $this->params["format"] ?? static::FORMAT;
|
||||
if (is_string($format)) {
|
||||
$oformat = $format;
|
||||
$format = cl::get(self::FORMATS, strtolower($oformat));
|
||||
@ -120,4 +149,8 @@ class tbool extends _tsimple {
|
||||
}
|
||||
return $value? $format[0]: $format[1];
|
||||
}
|
||||
|
||||
function getGetterName(string $name): string {
|
||||
return prop::get_getter_name($name, !$this->nullable);
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,66 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
use nur\sery\php\nur_func;
|
||||
use nur\sery\ValueException;
|
||||
use Exception;
|
||||
use nulib\php\func;
|
||||
use nulib\ValueException;
|
||||
use nur\sery\wip\schema\_scalar\ScalarResult;
|
||||
use nur\sery\wip\schema\_scalar\ScalarSchema;
|
||||
use nur\sery\wip\schema\Result;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
use stdClass;
|
||||
|
||||
class tcallable extends _tsimple {
|
||||
const NAME = "callable";
|
||||
|
||||
const ALIASES = ["func", "function"];
|
||||
|
||||
static function ensure_callable(&$callable): void {
|
||||
if (!is_callable($callable)) throw ValueException::invalid_type($callable, "callable");
|
||||
$callable = func::ensure($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 nur_func::check_func($value, stdClass::class);
|
||||
function getClass(): string {
|
||||
return func::class;
|
||||
}
|
||||
|
||||
function verifix(&$value, Result &$result, Schema $schema): bool {
|
||||
function isValid($value, ?bool &$normalized=null): bool {
|
||||
$normalized = is_callable($value);
|
||||
return func::check($value);
|
||||
}
|
||||
|
||||
function parse(string $value) {
|
||||
try {
|
||||
return func::ensure($value);
|
||||
} catch (Exception $e) {
|
||||
throw new ValueException(null, null, 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @var ScalarResult $result
|
||||
* @var ScalarSchema $schema
|
||||
*/
|
||||
function verifix(&$value, Result $result, Schema $schema): bool {
|
||||
if ($value instanceof func) {
|
||||
$result->setNormalized();
|
||||
return false;
|
||||
} elseif (is_callable($value)) {
|
||||
$value = func::with($value);
|
||||
$result->setNormalized();
|
||||
return true;
|
||||
} elseif (is_string($value)) {
|
||||
try {
|
||||
$value = $this->parse($value);
|
||||
$result->setValid();
|
||||
return true;
|
||||
} catch (ValueException $e) {
|
||||
}
|
||||
}
|
||||
$result->setInvalid($value, $schema);
|
||||
return false;
|
||||
}
|
||||
|
||||
function format($value, $format=null): string {
|
||||
|
@ -1,26 +1,56 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
use nulib\php\content\c;
|
||||
use nur\sery\wip\schema\_scalar\ScalarResult;
|
||||
use nur\sery\wip\schema\_scalar\ScalarSchema;
|
||||
use nur\sery\wip\schema\Result;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
|
||||
abstract class tcontent extends _tsimple {
|
||||
abstract class tcontent extends _tunion {
|
||||
const NAME = "content";
|
||||
|
||||
static function ensure_content(&$content): void {
|
||||
if (!is_string($content) && !is_array($content)) $content = strval($content);
|
||||
if ($content === null || $content === false) $content = [];
|
||||
elseif (!is_string($content) && !is_array($content)) $content = strval($content);
|
||||
}
|
||||
|
||||
static function ensure_ncontent(&$content): void {
|
||||
if ($content !== null) self::ensure_content($content);
|
||||
}
|
||||
|
||||
function getClass(): string {
|
||||
return "string|array";
|
||||
}
|
||||
|
||||
function isValid($value, ?bool &$normalized=null): bool {
|
||||
$normalized = is_string($value) || is_array($value);
|
||||
return is_scalar($value) || is_array($value);
|
||||
}
|
||||
|
||||
function verifix(&$value, Result &$result, Schema $schema): bool {
|
||||
function parse(string $value) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var ScalarResult $result
|
||||
* @var ScalarSchema $schema
|
||||
*/
|
||||
function verifix(&$value, Result $result, Schema $schema): bool {
|
||||
if (is_string($value) || is_array($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 c::to_string($value);
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,17 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
use nulib\ValueException;
|
||||
use nur\sery\wip\schema\_scalar\ScalarResult;
|
||||
use nur\sery\wip\schema\_scalar\ScalarSchema;
|
||||
use nur\sery\wip\schema\Result;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
|
||||
class tfloat extends _tsimple {
|
||||
class tfloat extends _tformatable {
|
||||
const NAME = "float";
|
||||
|
||||
const ALIASES = ["flt", "double", "dbl"];
|
||||
|
||||
static function ensure_float(&$float): void {
|
||||
if (!is_float($float)) $float = floatval($float);
|
||||
}
|
||||
@ -15,36 +20,46 @@ class tfloat extends _tsimple {
|
||||
if ($float !== null) self::ensure_float($float);
|
||||
}
|
||||
|
||||
function getClass(): string {
|
||||
return "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;
|
||||
return is_scalar($value);
|
||||
}
|
||||
|
||||
function extract(string $value): string {
|
||||
return trim($value);
|
||||
}
|
||||
|
||||
function parse(string $value) {
|
||||
$value = str_replace(",", ".", trim($value));
|
||||
if (is_numeric($value)) return floatval($value);
|
||||
throw new ValueException("une valeur numérique flottante est attendue");
|
||||
}
|
||||
|
||||
/**
|
||||
* @var ScalarResult $result
|
||||
* @var ScalarSchema $schema
|
||||
*/
|
||||
function verifix(&$value, Result &$result, Schema $schema): bool {
|
||||
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);
|
||||
try {
|
||||
$value = $this->parse($value);
|
||||
$result->setValid();
|
||||
return true;
|
||||
} catch (ValueException $e) {
|
||||
}
|
||||
} elseif (is_scalar($value)) {
|
||||
$value = floatval($value);
|
||||
} else {
|
||||
return $result->setInvalid($value, $schema);
|
||||
$result->setValid();
|
||||
return true;
|
||||
}
|
||||
$result->setValid();
|
||||
return true;
|
||||
}
|
||||
|
||||
function format($value, $format=null): string {
|
||||
if ($format !== null) return sprintf($format, $value);
|
||||
else return strval($value);
|
||||
$result->setInvalid($value, $schema);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,17 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
use nulib\ValueException;
|
||||
use nur\sery\wip\schema\_scalar\ScalarResult;
|
||||
use nur\sery\wip\schema\_scalar\ScalarSchema;
|
||||
use nur\sery\wip\schema\Result;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
|
||||
class tint extends _tsimple {
|
||||
class tint extends _tformatable {
|
||||
const NAME = "int";
|
||||
|
||||
const ALIASES = ["integer"];
|
||||
|
||||
static function ensure_int(&$int): void {
|
||||
if (!is_int($int)) $int = intval($int);
|
||||
}
|
||||
@ -15,38 +20,48 @@ class tint extends _tsimple {
|
||||
if ($int !== null) self::ensure_int($int);
|
||||
}
|
||||
|
||||
const INT_PATTERN = '/^[-+]?[0-9]+(?:\.[0-9]*)?$/';
|
||||
//const INT_PATTERN = '/^[-+]?[0-9]+(?:\.[0-9]*)?$/';
|
||||
|
||||
function getClass(): string {
|
||||
return "int";
|
||||
}
|
||||
|
||||
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;
|
||||
return is_scalar($value);
|
||||
}
|
||||
|
||||
function extract(string $value): string {
|
||||
return trim($value);
|
||||
}
|
||||
|
||||
function parse(string $value) {
|
||||
$value = str_replace(",", ".", trim($value));
|
||||
if (is_numeric($value)) return intval($value);
|
||||
throw new ValueException("une valeur numérique entière est attendue");
|
||||
}
|
||||
|
||||
/**
|
||||
* @var ScalarResult $result
|
||||
* @var ScalarSchema $schema
|
||||
*/
|
||||
function verifix(&$value, Result &$result, Schema $schema): bool {
|
||||
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);
|
||||
try {
|
||||
$value = $this->parse($value);
|
||||
$result->setValid();
|
||||
return true;
|
||||
} catch (ValueException $e) {
|
||||
}
|
||||
} elseif (is_scalar($value)) {
|
||||
$value = intval($value);
|
||||
} else {
|
||||
return $result->setInvalid($value, $schema);
|
||||
$result->setValid();
|
||||
return true;
|
||||
}
|
||||
$result->setValid();
|
||||
return true;
|
||||
}
|
||||
|
||||
function format($value, $format=null): string {
|
||||
if ($format !== null) return sprintf($format, $value);
|
||||
else return strval($value);
|
||||
$result->setInvalid($value, $schema);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1,26 +1,56 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
use nur\sery\wip\schema\_scalar\ScalarResult;
|
||||
use nur\sery\wip\schema\_scalar\ScalarSchema;
|
||||
use nur\sery\wip\schema\Result;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
|
||||
class tkey extends _tsimple {
|
||||
class tkey extends _tunion {
|
||||
const NAME = "key";
|
||||
|
||||
static function ensure_key(&$key): void {
|
||||
if (!is_string($key) && !is_int($key)) $key = strval($key);
|
||||
if ($key === null) $key = "";
|
||||
elseif ($key === false) $key = 0;
|
||||
elseif (!is_string($key) && !is_int($key)) $key = strval($key);
|
||||
}
|
||||
|
||||
static function ensure_nkey(&$key): void {
|
||||
if ($key !== null) self::ensure_key($key);
|
||||
}
|
||||
|
||||
function getClass(): string {
|
||||
return "string|int";
|
||||
}
|
||||
|
||||
function isValid($value, ?bool &$normalized=null): bool {
|
||||
$normalized = is_string($value) || is_int($value);
|
||||
return is_scalar($value);
|
||||
}
|
||||
|
||||
function verifix(&$value, Result &$result, Schema $schema): bool {
|
||||
function parse(string $value) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var ScalarResult $result
|
||||
* @var ScalarSchema $schema
|
||||
*/
|
||||
function verifix(&$value, Result $result, Schema $schema): bool {
|
||||
if (is_string($value) || is_int($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);
|
||||
}
|
||||
}
|
||||
|
46
src/schema/types/tmixed.php
Normal file
46
src/schema/types/tmixed.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
use nur\sery\wip\schema\_scalar\ScalarResult;
|
||||
use nur\sery\wip\schema\_scalar\ScalarSchema;
|
||||
use nur\sery\wip\schema\input\Input;
|
||||
use nur\sery\wip\schema\Result;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
|
||||
class tmixed extends _tsimple {
|
||||
const NAME = "mixed";
|
||||
|
||||
function getClass(): string {
|
||||
return "mixed";
|
||||
}
|
||||
|
||||
function isAvailable(Input $input, $valueKey): bool {
|
||||
return $input->isAvailable($valueKey);
|
||||
}
|
||||
|
||||
public function isNull($value): bool {
|
||||
return $value === null;
|
||||
}
|
||||
|
||||
function isValid($value, ?bool &$normalized=null): bool {
|
||||
$normalized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
function parse(string $value) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var ScalarResult $result
|
||||
* @var ScalarSchema $schema
|
||||
*/
|
||||
function verifix(&$value, Result $result, Schema $schema): bool {
|
||||
$result->setNormalized();
|
||||
return false;
|
||||
}
|
||||
|
||||
function format($value, $format=null): string {
|
||||
return var_export($value, true);
|
||||
}
|
||||
}
|
@ -1,17 +1,22 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
use nur\sery\wip\schema\_scalar\ScalarResult;
|
||||
use nur\sery\wip\schema\_scalar\ScalarSchema;
|
||||
use nur\sery\wip\schema\Result;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
|
||||
class tpkey extends _tsimple {
|
||||
class tpkey extends _tunion {
|
||||
const NAME = "pkey";
|
||||
|
||||
static function ensure_pkey(&$pkey): void {
|
||||
if (!is_string($pkey) && !is_int($pkey) && !is_array($pkey)) $pkey = strval($pkey);
|
||||
if ($pkey === null) $pkey = "";
|
||||
elseif ($pkey === false) $pkey = 0;
|
||||
elseif (!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);
|
||||
}; unset($key);
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,14 +24,39 @@ class tpkey extends _tsimple {
|
||||
if ($pkey !== null) self::ensure_pkey($pkey);
|
||||
}
|
||||
|
||||
function getClass(): string {
|
||||
return "string|int|array";
|
||||
}
|
||||
|
||||
function isValid($value, ?bool &$normalized=null): bool {
|
||||
$normalized = is_string($value) || is_int($value) || is_array($value);
|
||||
return is_scalar($value) || is_array($value);
|
||||
}
|
||||
|
||||
function verifix(&$value, Result &$result, Schema $schema): bool {
|
||||
function parse(string $value) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var ScalarResult $result
|
||||
* @var ScalarSchema $schema
|
||||
*/
|
||||
function verifix(&$value, Result $result, Schema $schema): bool {
|
||||
if (is_string($value) || is_int($value) || is_array($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 {
|
||||
if (is_array($value)) return implode(".", $value);
|
||||
else return strval($value);
|
||||
}
|
||||
}
|
||||
|
16
src/schema/types/traw.php
Normal file
16
src/schema/types/traw.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
use nur\sery\wip\schema\input\Input;
|
||||
|
||||
class traw extends tmixed {
|
||||
const NAME = "raw";
|
||||
|
||||
function isAvailable(Input $input, $valueKey): bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isNull($value): bool {
|
||||
return false;
|
||||
}
|
||||
}
|
64
src/schema/types/trawstring.php
Normal file
64
src/schema/types/trawstring.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
use nulib\str;
|
||||
use nur\sery\wip\schema\_scalar\ScalarResult;
|
||||
use nur\sery\wip\schema\_scalar\ScalarSchema;
|
||||
use nur\sery\wip\schema\Result;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
|
||||
class trawstring extends _tstring {
|
||||
const NAME = "rawstring";
|
||||
|
||||
static function ensure_string(&$string): void {
|
||||
if (!is_string($string)) $string = strval($string);
|
||||
if (static::TRIM) $string = trim($string);
|
||||
if (static::NORM_NL) $string = str::norm_nl($string);
|
||||
}
|
||||
|
||||
static function ensure_nstring(&$string): void {
|
||||
if ($string !== null) self::ensure_string($string);
|
||||
}
|
||||
|
||||
function getClass(): string {
|
||||
return "string";
|
||||
}
|
||||
|
||||
function isNull($value): bool {
|
||||
return $value === null;
|
||||
}
|
||||
|
||||
function isValid($value, ?bool &$normalized=null): bool {
|
||||
if (is_string($value)) {
|
||||
$normalized = true;
|
||||
return true;
|
||||
}
|
||||
return is_scalar($value);
|
||||
}
|
||||
|
||||
function parse(string $value) {
|
||||
return $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);
|
||||
}
|
||||
}
|
@ -1,48 +1,8 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
use nur\sery\wip\schema\_scalar\ScalarResult;
|
||||
use nur\sery\wip\schema\_scalar\ScalarSchema;
|
||||
use nur\sery\wip\schema\Result;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
class tstring extends trawstring {
|
||||
const NAME = "string";
|
||||
|
||||
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);
|
||||
}
|
||||
const TRIM = true;
|
||||
}
|
||||
|
9
src/schema/types/ttext.php
Normal file
9
src/schema/types/ttext.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
class ttext extends trawstring {
|
||||
const NAME = "text";
|
||||
|
||||
const TRIM = true;
|
||||
const NORM_NL = true;
|
||||
}
|
@ -1,9 +1,10 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\web\content;
|
||||
|
||||
use nur\sery\A;
|
||||
use nur\sery\php\content\c;
|
||||
use nur\sery\php\content\IContent;
|
||||
|
||||
use nulib\A;
|
||||
use nulib\php\content\c;
|
||||
use nulib\php\content\IContent;
|
||||
|
||||
class Tag implements IContent {
|
||||
function __construct(string $tag, $content=null) {
|
||||
|
@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace nur\sery\app;
|
||||
|
||||
use nulib\tests\TestCase;
|
||||
use nur\sery\app\args;
|
||||
|
||||
class argsTest extends TestCase {
|
||||
function testFrom_array() {
|
||||
self::assertSame([], args::from_array(null));
|
||||
self::assertSame([], args::from_array([]));
|
||||
self::assertSame([], args::from_array([false]));
|
||||
self::assertSame(["x"], args::from_array(["x", false]));
|
||||
|
||||
self::assertSame(["--opt"], args::from_array(["--opt"]));
|
||||
self::assertSame(["--opt", "value"], args::from_array(["--opt", "value"]));
|
||||
|
||||
self::assertSame([], args::from_array(["opt" => false]));
|
||||
self::assertSame(["--opt"], args::from_array(["opt" => true]));
|
||||
self::assertSame(["--opt", "value"], args::from_array(["opt" => "value"]));
|
||||
self::assertSame(["--opt", "42"], args::from_array(["opt" => 42]));
|
||||
self::assertSame(["--opt", "1", "2", "3", "--"], args::from_array(["opt" => [1, 2, 3]]));
|
||||
|
||||
self::assertSame(["x", "1", "2", "3", "y"], args::from_array(["x", [1, 2, 3], "y"]));
|
||||
}
|
||||
}
|
@ -1,132 +0,0 @@
|
||||
<?php
|
||||
namespace nur\sery {
|
||||
use nulib\tests\TestCase;
|
||||
use nur\sery\impl\config;
|
||||
use nur\sery\impl\myapp;
|
||||
use nur\sery\impl\MyApplication1;
|
||||
use nur\sery\impl\MyApplication2;
|
||||
|
||||
class appTest extends TestCase {
|
||||
function testWith() {
|
||||
$projdir = config::get_projdir();
|
||||
$cwd = getcwd();
|
||||
|
||||
myapp::reset();
|
||||
$app1 = myapp::with(MyApplication1::class);
|
||||
self::assertSame([
|
||||
"projdir" => $projdir,
|
||||
"vendor" => [
|
||||
"bindir" => "$projdir/vendor/bin",
|
||||
"autoload" => "$projdir/vendor/autoload.php",
|
||||
],
|
||||
"appcode" => "nur-sery",
|
||||
"cwd" => $cwd,
|
||||
"datadir" => "$projdir/devel",
|
||||
"etcdir" => "$projdir/devel/etc",
|
||||
"vardir" => "$projdir/devel/var",
|
||||
"logdir" => "$projdir/devel/log",
|
||||
"profile" => "devel",
|
||||
"appgroup" => null,
|
||||
"name" => "my-application1",
|
||||
"title" => null,
|
||||
], $app1->getParams());
|
||||
|
||||
$app2 = myapp::with(MyApplication2::class, $app1);
|
||||
self::assertSame([
|
||||
"projdir" => $projdir,
|
||||
"vendor" => [
|
||||
"bindir" => "$projdir/vendor/bin",
|
||||
"autoload" => "$projdir/vendor/autoload.php",
|
||||
],
|
||||
"appcode" => "nur-sery",
|
||||
"cwd" => $cwd,
|
||||
"datadir" => "$projdir/devel",
|
||||
"etcdir" => "$projdir/devel/etc",
|
||||
"vardir" => "$projdir/devel/var",
|
||||
"logdir" => "$projdir/devel/log",
|
||||
"profile" => "devel",
|
||||
"appgroup" => null,
|
||||
"name" => "my-application2",
|
||||
"title" => null,
|
||||
], $app2->getParams());
|
||||
}
|
||||
|
||||
function testInit() {
|
||||
$projdir = config::get_projdir();
|
||||
$cwd = getcwd();
|
||||
|
||||
myapp::reset();
|
||||
myapp::init(MyApplication1::class);
|
||||
self::assertSame([
|
||||
"projdir" => $projdir,
|
||||
"vendor" => [
|
||||
"bindir" => "$projdir/vendor/bin",
|
||||
"autoload" => "$projdir/vendor/autoload.php",
|
||||
],
|
||||
"appcode" => "nur-sery",
|
||||
"cwd" => $cwd,
|
||||
"datadir" => "$projdir/devel",
|
||||
"etcdir" => "$projdir/devel/etc",
|
||||
"vardir" => "$projdir/devel/var",
|
||||
"logdir" => "$projdir/devel/log",
|
||||
"profile" => "devel",
|
||||
"appgroup" => null,
|
||||
"name" => "my-application1",
|
||||
"title" => null,
|
||||
], myapp::get()->getParams());
|
||||
|
||||
myapp::init(MyApplication2::class);
|
||||
self::assertSame([
|
||||
"projdir" => $projdir,
|
||||
"vendor" => [
|
||||
"bindir" => "$projdir/vendor/bin",
|
||||
"autoload" => "$projdir/vendor/autoload.php",
|
||||
],
|
||||
"appcode" => "nur-sery",
|
||||
"cwd" => $cwd,
|
||||
"datadir" => "$projdir/devel",
|
||||
"etcdir" => "$projdir/devel/etc",
|
||||
"vardir" => "$projdir/devel/var",
|
||||
"logdir" => "$projdir/devel/log",
|
||||
"profile" => "devel",
|
||||
"appgroup" => null,
|
||||
"name" => "my-application2",
|
||||
"title" => null,
|
||||
], myapp::get()->getParams());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace nur\sery\impl {
|
||||
|
||||
use nur\sery\app\cli\Application;
|
||||
use nur\sery\os\path;
|
||||
use nur\sery\app;
|
||||
|
||||
class config {
|
||||
const PROJDIR = __DIR__.'/..';
|
||||
|
||||
static function get_projdir(): string {
|
||||
return path::abspath(self::PROJDIR);
|
||||
}
|
||||
}
|
||||
|
||||
class myapp extends app {
|
||||
static function reset(): void {
|
||||
self::$app = null;
|
||||
}
|
||||
}
|
||||
|
||||
class MyApplication1 extends Application {
|
||||
const PROJDIR = config::PROJDIR;
|
||||
|
||||
function main() {
|
||||
}
|
||||
}
|
||||
class MyApplication2 extends Application {
|
||||
const PROJDIR = null;
|
||||
|
||||
function main() {
|
||||
}
|
||||
}
|
||||
}
|
1
tests/db/sqlite/.gitignore
vendored
1
tests/db/sqlite/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/capacitor.db*
|
@ -1,344 +0,0 @@
|
||||
<?php
|
||||
namespace nur\sery\db\sqlite;
|
||||
|
||||
use nulib\tests\TestCase;
|
||||
use nur\sery\cl;
|
||||
use nur\sery\db\Capacitor;
|
||||
use nur\sery\db\CapacitorChannel;
|
||||
|
||||
class SqliteStorageTest extends TestCase {
|
||||
function _testChargeStrings(SqliteStorage $storage, ?string $channel) {
|
||||
$storage->reset($channel);
|
||||
$storage->charge($channel, "first");
|
||||
$storage->charge($channel, "second");
|
||||
$storage->charge($channel, "third");
|
||||
$items = cl::all($storage->discharge($channel, false));
|
||||
self::assertSame(["first", "second", "third"], $items);
|
||||
}
|
||||
|
||||
function _testChargeArrays(SqliteStorage $storage, ?string $channel) {
|
||||
$storage->reset($channel);
|
||||
$storage->charge($channel, ["id" => 10, "name" => "first"]);
|
||||
$storage->charge($channel, ["name" => "second", "id" => 20]);
|
||||
$storage->charge($channel, ["name" => "third", "id" => "30"]);
|
||||
}
|
||||
|
||||
function testChargeStrings() {
|
||||
$storage = new SqliteStorage(__DIR__.'/capacitor.db');
|
||||
$this->_testChargeStrings($storage, null);
|
||||
$storage->close();
|
||||
}
|
||||
|
||||
function testChargeArrays() {
|
||||
$storage = new SqliteStorage(__DIR__.'/capacitor.db');
|
||||
$storage->addChannel(new class extends CapacitorChannel {
|
||||
const NAME = "arrays";
|
||||
const COLUMN_DEFINITIONS = ["id" => "integer"];
|
||||
|
||||
function getItemValues($item): ?array {
|
||||
return ["id" => $item["id"] ?? null];
|
||||
}
|
||||
});
|
||||
|
||||
$this->_testChargeStrings($storage, "strings");
|
||||
$this->_testChargeArrays($storage, "arrays");
|
||||
$storage->close();
|
||||
}
|
||||
|
||||
function testEach() {
|
||||
$storage = new SqliteStorage(__DIR__.'/capacitor.db');
|
||||
$capacitor = new Capacitor($storage, new class extends CapacitorChannel {
|
||||
const NAME = "each";
|
||||
const COLUMN_DEFINITIONS = [
|
||||
"age" => "integer",
|
||||
"done" => "integer default 0",
|
||||
];
|
||||
|
||||
function getItemValues($item): ?array {
|
||||
return [
|
||||
"age" => $item["age"],
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
$capacitor->reset();
|
||||
$capacitor->charge(["name" => "first", "age" => 5]);
|
||||
$capacitor->charge(["name" => "second", "age" => 10]);
|
||||
$capacitor->charge(["name" => "third", "age" => 15]);
|
||||
$capacitor->charge(["name" => "fourth", "age" => 20]);
|
||||
|
||||
$setDone = function ($item, $row, $suffix=null) {
|
||||
$updates = ["done" => 1];
|
||||
if ($suffix !== null) {
|
||||
$item["name"] .= $suffix;
|
||||
$updates["item"] = $item;
|
||||
}
|
||||
return $updates;
|
||||
};
|
||||
$capacitor->each(["age" => [">", 10]], $setDone, ["++"]);
|
||||
$capacitor->each(["done" => 0], $setDone, null);
|
||||
|
||||
Txx(cl::all($capacitor->discharge(false)));
|
||||
$capacitor->close();
|
||||
self::assertTrue(true);
|
||||
}
|
||||
|
||||
function testPrimayKey() {
|
||||
$storage = new SqliteStorage(__DIR__.'/capacitor.db');
|
||||
$capacitor = new Capacitor($storage, new class extends CapacitorChannel {
|
||||
const NAME = "pk";
|
||||
const COLUMN_DEFINITIONS = [
|
||||
"id_" => "varchar primary key",
|
||||
"done" => "integer default 0",
|
||||
];
|
||||
|
||||
function getItemValues($item): ?array {
|
||||
return [
|
||||
"id_" => $item["numero"],
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
$capacitor->charge(["numero" => "a", "name" => "first", "age" => 5]);
|
||||
$capacitor->charge(["numero" => "b", "name" => "second", "age" => 10]);
|
||||
$capacitor->charge(["numero" => "c", "name" => "third", "age" => 15]);
|
||||
$capacitor->charge(["numero" => "d", "name" => "fourth", "age" => 20]);
|
||||
sleep(2);
|
||||
$capacitor->charge(["numero" => "b", "name" => "second", "age" => 100]);
|
||||
$capacitor->charge(["numero" => "d", "name" => "fourth", "age" => 200]);
|
||||
|
||||
$capacitor->close();
|
||||
self::assertTrue(true);
|
||||
}
|
||||
|
||||
function testSum() {
|
||||
$storage = new SqliteStorage(__DIR__.'/capacitor.db');
|
||||
$capacitor = new Capacitor($storage, new class extends CapacitorChannel {
|
||||
const NAME = "sum";
|
||||
const COLUMN_DEFINITIONS = [
|
||||
"a__" => "varchar",
|
||||
"b__" => "varchar",
|
||||
"b__sum_" => self::SUM_DEFINITION,
|
||||
];
|
||||
|
||||
function getItemValues($item): ?array {
|
||||
return [
|
||||
"a" => $item["a"],
|
||||
"b" => $item["b"],
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
$capacitor->reset();
|
||||
$capacitor->charge(["a" => null, "b" => null]);
|
||||
$capacitor->charge(["a" => "first", "b" => "second"]);
|
||||
|
||||
Txx("=== all");
|
||||
/** @var Sqlite $sqlite */
|
||||
$sqlite = $capacitor->getStorage()->db();
|
||||
Txx(cl::all($sqlite->all([
|
||||
"select",
|
||||
"from" => $capacitor->getChannel()->getTableName(),
|
||||
])));
|
||||
Txx("=== each");
|
||||
$capacitor->each(null, function ($item, $values) {
|
||||
Txx($values);
|
||||
});
|
||||
|
||||
$capacitor->close();
|
||||
self::assertTrue(true);
|
||||
}
|
||||
|
||||
function testEachValues() {
|
||||
# tester que values contient bien toutes les valeurs de la ligne
|
||||
$storage = new SqliteStorage(__DIR__.'/capacitor.db');
|
||||
$capacitor = new Capacitor($storage, new class extends CapacitorChannel {
|
||||
const NAME = "each_values";
|
||||
const COLUMN_DEFINITIONS = [
|
||||
"name" => "varchar primary key",
|
||||
"age" => "integer",
|
||||
"done" => "integer default 0",
|
||||
"notes" => "text",
|
||||
];
|
||||
|
||||
function getItemValues($item): ?array {
|
||||
return [
|
||||
"name" => $item["name"],
|
||||
"age" => $item["age"],
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
$capacitor->reset();
|
||||
$capacitor->charge(["name" => "first", "age" => 5], function($item, ?array $values, ?array $pvalues) {
|
||||
self::assertSame("first", $item["name"]);
|
||||
self::assertSame(5, $item["age"]);
|
||||
self::assertnotnull($values);
|
||||
self::assertSame(["name", "age", "item", "item__sum_", "created_", "modified_"], array_keys($values));
|
||||
self::assertSame([
|
||||
"name" => "first",
|
||||
"age" => 5,
|
||||
"item" => $item,
|
||||
], cl::select($values, ["name", "age", "item"]));
|
||||
self::assertNull($pvalues);
|
||||
});
|
||||
$capacitor->charge(["name" => "first", "age" => 10], function($item, ?array $values, ?array $pvalues) {
|
||||
self::assertSame("first", $item["name"]);
|
||||
self::assertSame(10, $item["age"]);
|
||||
self::assertnotnull($values);
|
||||
self::assertSame(["name", "age", "done", "notes", "item", "item__sum_", "created_", "modified_"], array_keys($values));
|
||||
self::assertSame([
|
||||
"name" => "first",
|
||||
"age" => 10,
|
||||
"done" => 0,
|
||||
"notes" => null,
|
||||
"item" => $item,
|
||||
], cl::select($values, ["name", "age", "done", "notes", "item"]));
|
||||
self::assertNotNull($pvalues);
|
||||
self::assertSame([
|
||||
"name" => "first",
|
||||
"age" => 5,
|
||||
"done" => 0,
|
||||
"notes" => null,
|
||||
"item" => ["name" => "first", "age" => 5],
|
||||
], cl::select($pvalues, ["name", "age", "done", "notes", "item"]));
|
||||
});
|
||||
|
||||
$capacitor->each(null, function($item, ?array $values) {
|
||||
self::assertSame("first", $item["name"]);
|
||||
self::assertSame(10, $item["age"]);
|
||||
self::assertnotnull($values);
|
||||
self::assertSame(["name", "age", "done", "notes", "item", "item__sum_", "created_", "modified_"], array_keys($values));
|
||||
self::assertSame([
|
||||
"name" => "first",
|
||||
"age" => 10,
|
||||
"done" => 0,
|
||||
"notes" => null,
|
||||
"item" => $item,
|
||||
], cl::select($values, ["name", "age", "done", "notes", "item"]));
|
||||
return [
|
||||
"done" => 1,
|
||||
"notes" => "modified",
|
||||
];
|
||||
});
|
||||
$capacitor->charge(["name" => "first", "age" => 10], function($item, ?array $values, ?array $pvalues) {
|
||||
self::assertSame("first", $item["name"]);
|
||||
self::assertSame(10, $item["age"]);
|
||||
self::assertnotnull($values);
|
||||
self::assertSame(["name", "age", "done", "notes", "item", "item__sum_", "created_", "modified_"], array_keys($values));
|
||||
self::assertSame([
|
||||
"name" => "first",
|
||||
"age" => 10,
|
||||
"done" => 1,
|
||||
"notes" => "modified",
|
||||
"item" => $item,
|
||||
], cl::select($values, ["name", "age", "done", "notes", "item"]));
|
||||
self::assertNotNull($pvalues);
|
||||
self::assertSame([
|
||||
"name" => "first",
|
||||
"age" => 10,
|
||||
"done" => 1,
|
||||
"notes" => "modified",
|
||||
"item" => $item,
|
||||
], cl::select($pvalues, ["name", "age", "done", "notes", "item"]));
|
||||
});
|
||||
|
||||
$capacitor->charge(["name" => "first", "age" => 20], function($item, ?array $values, ?array $pvalues) {
|
||||
self::assertSame("first", $item["name"]);
|
||||
self::assertSame(20, $item["age"]);
|
||||
self::assertnotnull($values);
|
||||
self::assertSame(["name", "age", "done", "notes", "item", "item__sum_", "created_", "modified_"], array_keys($values));
|
||||
self::assertSame([
|
||||
"name" => "first",
|
||||
"age" => 20,
|
||||
"done" => 1,
|
||||
"notes" => "modified",
|
||||
"item" => $item,
|
||||
], cl::select($values, ["name", "age", "done", "notes", "item"]));
|
||||
self::assertNotNull($pvalues);
|
||||
self::assertSame([
|
||||
"name" => "first",
|
||||
"age" => 10,
|
||||
"done" => 1,
|
||||
"notes" => "modified",
|
||||
"item" => ["name" => "first", "age" => 10],
|
||||
], cl::select($pvalues, ["name", "age", "done", "notes", "item"]));
|
||||
});
|
||||
}
|
||||
|
||||
function testSetItemNull() {
|
||||
# tester le forçage de $îtem à null pour économiser la place
|
||||
$storage = new SqliteStorage(__DIR__.'/capacitor.db');
|
||||
$capacitor = new Capacitor($storage, new class extends CapacitorChannel {
|
||||
const NAME = "set_item_null";
|
||||
const COLUMN_DEFINITIONS = [
|
||||
"name" => "varchar primary key",
|
||||
"age" => "integer",
|
||||
"done" => "integer default 0",
|
||||
"notes" => "text",
|
||||
];
|
||||
|
||||
function getItemValues($item): ?array {
|
||||
return [
|
||||
"name" => $item["name"],
|
||||
"age" => $item["age"],
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
$capacitor->reset();
|
||||
$nbModified = $capacitor->charge(["name" => "first", "age" => 5], function ($item, ?array $values, ?array $pvalues) {
|
||||
self::assertSame([
|
||||
"name" => "first", "age" => 5,
|
||||
"item" => $item,
|
||||
], cl::select($values, ["name", "age", "item"]));
|
||||
return ["item" => null];
|
||||
});
|
||||
self::assertSame(1, $nbModified);
|
||||
sleep(1);
|
||||
# nb: on met des sleep() pour que la date de modification soit systématiquement différente
|
||||
|
||||
$nbModified = $capacitor->charge(["name" => "first", "age" => 10], function ($item, ?array $values, ?array $pvalues) {
|
||||
self::assertSame([
|
||||
"name" => "first", "age" => 10,
|
||||
"item" => $item, "item__sum_" => "9181336dfca20c86313d6065d89aa2ad5070b0fc",
|
||||
], cl::select($values, ["name", "age", "item", "item__sum_"]));
|
||||
self::assertSame([
|
||||
"name" => "first", "age" => 5,
|
||||
"item" => null, "item__sum_" => null,
|
||||
], cl::select($pvalues, ["name", "age", "item", "item__sum_"]));
|
||||
return ["item" => null];
|
||||
});
|
||||
self::assertSame(1, $nbModified);
|
||||
sleep(1);
|
||||
|
||||
# pas de modification ici
|
||||
$nbModified = $capacitor->charge(["name" => "first", "age" => 10], function ($item, ?array $values, ?array $pvalues) {
|
||||
self::assertSame([
|
||||
"name" => "first", "age" => 10,
|
||||
"item" => $item, "item__sum_" => "9181336dfca20c86313d6065d89aa2ad5070b0fc",
|
||||
], cl::select($values, ["name", "age", "item", "item__sum_"]));
|
||||
self::assertSame([
|
||||
"name" => "first", "age" => 10,
|
||||
"item" => null, "item__sum_" => null,
|
||||
], cl::select($pvalues, ["name", "age", "item", "item__sum_"]));
|
||||
return ["item" => null];
|
||||
});
|
||||
self::assertSame(0, $nbModified);
|
||||
sleep(1);
|
||||
|
||||
$nbModified = $capacitor->charge(["name" => "first", "age" => 20], function ($item, ?array $values, ?array $pvalues) {
|
||||
self::assertSame([
|
||||
"name" => "first", "age" => 20,
|
||||
"item" => $item, "item__sum_" => "001b91982b4e0883b75428c0eb28573a5dc5f7a5",
|
||||
], cl::select($values, ["name", "age", "item", "item__sum_"]));
|
||||
self::assertSame([
|
||||
"name" => "first", "age" => 10,
|
||||
"item" => null, "item__sum_" => null,
|
||||
], cl::select($pvalues, ["name", "age", "item", "item__sum_"]));
|
||||
return ["item" => null];
|
||||
});
|
||||
self::assertSame(1, $nbModified);
|
||||
sleep(1);
|
||||
}
|
||||
}
|
@ -1,146 +0,0 @@
|
||||
<?php
|
||||
namespace nur\sery\db\sqlite;
|
||||
|
||||
use Exception;
|
||||
use nulib\tests\TestCase;
|
||||
|
||||
class SqliteTest extends TestCase {
|
||||
const CREATE_PERSON = "create table person(nom varchar, prenom varchar, age integer)";
|
||||
const INSERT_JEPHTE = "insert into person(nom, prenom, age) values ('clain', 'jephte', 50)";
|
||||
const INSERT_JEAN = "insert into person(nom, prenom, age) values ('payet', 'jean', 32)";
|
||||
|
||||
function testMigration() {
|
||||
$sqlite = new Sqlite(":memory:", [
|
||||
"migrate" => [
|
||||
self::CREATE_PERSON,
|
||||
self::INSERT_JEPHTE,
|
||||
],
|
||||
]);
|
||||
self::assertSame("clain", $sqlite->get("select nom, age from person"));
|
||||
self::assertSame([
|
||||
"nom" => "clain",
|
||||
"age" => 50,
|
||||
], $sqlite->get("select nom, age from person", null, true));
|
||||
|
||||
$sqlite->exec(self::INSERT_JEAN);
|
||||
self::assertSame("payet", $sqlite->get("select nom, age from person where nom = 'payet'"));
|
||||
self::assertSame([
|
||||
"nom" => "payet",
|
||||
"age" => 32,
|
||||
], $sqlite->get("select nom, age from person where nom = 'payet'", null, true));
|
||||
|
||||
self::assertSame([
|
||||
["key" => "0", "value" => self::CREATE_PERSON, "done" => 1],
|
||||
["key" => "1", "value" => self::INSERT_JEPHTE, "done" => 1],
|
||||
], iterator_to_array($sqlite->all("select key, value, done from _migration")));
|
||||
}
|
||||
|
||||
function testException() {
|
||||
$sqlite = new Sqlite(":memory:");
|
||||
self::assertException(Exception::class, [$sqlite, "exec"], "prout");
|
||||
self::assertException(SqliteException::class, [$sqlite, "exec"], ["prout"]);
|
||||
}
|
||||
|
||||
protected function assertInserted(Sqlite $sqlite, array $row, array $query): void {
|
||||
$sqlite->exec($query);
|
||||
self::assertSame($row, $sqlite->one("select * from mapping where i = :i", [
|
||||
"i" => $query["values"]["i"],
|
||||
]));
|
||||
}
|
||||
function testInsert() {
|
||||
$sqlite = new Sqlite(":memory:", [
|
||||
"migrate" => "create table mapping (i integer, s varchar)",
|
||||
]);
|
||||
$sqlite->exec(["insert into mapping", "values" => ["i" => 1, "s" => "un"]]);
|
||||
$sqlite->exec(["insert mapping", "values" => ["i" => 2, "s" => "deux"]]);
|
||||
$sqlite->exec(["insert into", "into" => "mapping", "values" => ["i" => 3, "s" => "trois"]]);
|
||||
$sqlite->exec(["insert", "into" => "mapping", "values" => ["i" => 4, "s" => "quatre"]]);
|
||||
$sqlite->exec(["insert into mapping(i)", "values" => ["i" => 5, "s" => "cinq"]]);
|
||||
$sqlite->exec(["insert into (i)", "into" => "mapping", "values" => ["i" => 6, "s" => "six"]]);
|
||||
$sqlite->exec(["insert into mapping(i) values ()", "values" => ["i" => 7, "s" => "sept"]]);
|
||||
$sqlite->exec(["insert into mapping(i) values (8)", "values" => ["i" => 42, "s" => "whatever"]]);
|
||||
$sqlite->exec(["insert into mapping(i, s) values (9, 'neuf')", "values" => ["i" => 43, "s" => "garbage"]]);
|
||||
$sqlite->exec(["insert into mapping", "cols" => ["i"], "values" => ["i" => 10, "s" => "dix"]]);
|
||||
|
||||
self::assertSame([
|
||||
["i" => 1, "s" => "un"],
|
||||
["i" => 2, "s" => "deux"],
|
||||
["i" => 3, "s" => "trois"],
|
||||
["i" => 4, "s" => "quatre"],
|
||||
["i" => 5, "s" => null/*"cinq"*/],
|
||||
["i" => 6, "s" => null/*"six"*/],
|
||||
["i" => 7, "s" => null/*"sept"*/],
|
||||
["i" => 8, "s" => null/*"huit"*/],
|
||||
["i" => 9, "s" => "neuf"],
|
||||
["i" => 10, "s" => null/*"dix"*/],
|
||||
], iterator_to_array($sqlite->all("select * from mapping")));
|
||||
}
|
||||
|
||||
function testSelect() {
|
||||
$sqlite = new Sqlite(":memory:", [
|
||||
"migrate" => "create table user (name varchar, amount integer)",
|
||||
]);
|
||||
$sqlite->exec(["insert into user", "values" => ["name" => "jclain1", "amount" => 1]]);
|
||||
$sqlite->exec(["insert into user", "values" => ["name" => "jclain2", "amount" => 2]]);
|
||||
$sqlite->exec(["insert into user", "values" => ["name" => "jclain5", "amount" => 5]]);
|
||||
$sqlite->exec(["insert into user", "values" => ["name" => "fclain7", "amount" => 7]]);
|
||||
$sqlite->exec(["insert into user", "values" => ["name" => "fclain9", "amount" => 9]]);
|
||||
$sqlite->exec(["insert into user", "values" => ["name" => "fclain10", "amount" => 10]]);
|
||||
self::assertSame([
|
||||
"name" => "jclain1",
|
||||
"amount" => 1,
|
||||
], $sqlite->one("select * from user where name = 'jclain1'"));
|
||||
self::assertSame([
|
||||
"name" => "jclain1",
|
||||
"amount" => 1,
|
||||
], $sqlite->one(["select * from user where name = 'jclain1'"]));
|
||||
self::assertSame([
|
||||
"name" => "jclain1",
|
||||
"amount" => 1,
|
||||
], $sqlite->one(["select from user where name = 'jclain1'"]));
|
||||
self::assertSame([
|
||||
"name" => "jclain1",
|
||||
"amount" => 1,
|
||||
], $sqlite->one(["select from user where", "where" => ["name = 'jclain1'"]]));
|
||||
self::assertSame([
|
||||
"name" => "jclain1",
|
||||
"amount" => 1,
|
||||
], $sqlite->one(["select from user", "where" => ["name = 'jclain1'"]]));
|
||||
self::assertSame([
|
||||
"name" => "jclain1",
|
||||
"amount" => 1,
|
||||
], $sqlite->one(["select", "from" => "user", "where" => ["name = 'jclain1'"]]));
|
||||
self::assertSame([
|
||||
"name" => "jclain1",
|
||||
"amount" => 1,
|
||||
], $sqlite->one(["select", "from" => "user", "where" => ["name" => "jclain1"]]));
|
||||
self::assertSame([
|
||||
"name" => "jclain1",
|
||||
], $sqlite->one(["select name", "from" => "user", "where" => ["name" => "jclain1"]]));
|
||||
self::assertSame([
|
||||
"name" => "jclain1",
|
||||
], $sqlite->one(["select", "cols" => "name", "from" => "user", "where" => ["name" => "jclain1"]]));
|
||||
self::assertSame([
|
||||
"name" => "jclain1",
|
||||
], $sqlite->one(["select", "cols" => ["name"], "from" => "user", "where" => ["name" => "jclain1"]]));
|
||||
self::assertSame([
|
||||
"plouf" => "jclain1",
|
||||
], $sqlite->one(["select", "cols" => ["plouf" => "name"], "from" => "user", "where" => ["name" => "jclain1"]]));
|
||||
}
|
||||
|
||||
function testSelectGroupBy() {
|
||||
$sqlite = new Sqlite(":memory:", [
|
||||
"migrate" => "create table user (name varchar, amount integer)",
|
||||
]);
|
||||
$sqlite->exec(["insert into user", "values" => ["name" => "jclain1", "amount" => 1]]);
|
||||
$sqlite->exec(["insert into user", "values" => ["name" => "jclain2", "amount" => 1]]);
|
||||
$sqlite->exec(["insert into user", "values" => ["name" => "jclain5", "amount" => 2]]);
|
||||
$sqlite->exec(["insert into user", "values" => ["name" => "fclain7", "amount" => 2]]);
|
||||
$sqlite->exec(["insert into user", "values" => ["name" => "fclain9", "amount" => 2]]);
|
||||
$sqlite->exec(["insert into user", "values" => ["name" => "fclain10", "amount" => 3]]);
|
||||
|
||||
self::assertSame([
|
||||
["count" => 2],
|
||||
], iterator_to_array($sqlite->all(["select count(name) as count from user", "group by" => ["amount"], "having" => ["count(name) = 2"]])));
|
||||
}
|
||||
}
|
@ -1,125 +0,0 @@
|
||||
<?php
|
||||
namespace nur\sery\db\sqlite;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class _queryTest extends TestCase {
|
||||
function testParseConds(): void {
|
||||
$sql = $params = null;
|
||||
_query_base::parse_conds(null, $sql, $params);
|
||||
self::assertNull($sql);
|
||||
self::assertNull($params);
|
||||
|
||||
$sql = $params = null;
|
||||
_query_base::parse_conds([], $sql, $params);
|
||||
self::assertNull($sql);
|
||||
self::assertNull($params);
|
||||
|
||||
$sql = $params = null;
|
||||
_query_base::parse_conds(["col" => null], $sql, $params);
|
||||
self::assertSame(["col is null"], $sql);
|
||||
self::assertNull($params);
|
||||
|
||||
$sql = $params = null;
|
||||
_query_base::parse_conds(["col = 'value'"], $sql, $params);
|
||||
self::assertSame(["col = 'value'"], $sql);
|
||||
self::assertNull($params);
|
||||
|
||||
$sql = $params = null;
|
||||
_query_base::parse_conds([["col = 'value'"]], $sql, $params);
|
||||
self::assertSame(["col = 'value'"], $sql);
|
||||
self::assertNull($params);
|
||||
|
||||
$sql = $params = null;
|
||||
_query_base::parse_conds(["int" => 42, "string" => "value"], $sql, $params);
|
||||
self::assertSame(["(int = :int and string = :string)"], $sql);
|
||||
self::assertSame(["int" => 42, "string" => "value"], $params);
|
||||
|
||||
$sql = $params = null;
|
||||
_query_base::parse_conds(["or", "int" => 42, "string" => "value"], $sql, $params);
|
||||
self::assertSame(["(int = :int or string = :string)"], $sql);
|
||||
self::assertSame(["int" => 42, "string" => "value"], $params);
|
||||
|
||||
$sql = $params = null;
|
||||
_query_base::parse_conds([["int" => 42, "string" => "value"], ["int" => 24, "string" => "eulav"]], $sql, $params);
|
||||
self::assertSame(["((int = :int and string = :string) and (int = :int2 and string = :string2))"], $sql);
|
||||
self::assertSame(["int" => 42, "string" => "value", "int2" => 24, "string2" => "eulav"], $params);
|
||||
|
||||
$sql = $params = null;
|
||||
_query_base::parse_conds(["int" => ["is null"], "string" => ["<>", "value"]], $sql, $params);
|
||||
self::assertSame(["(int is null and string <> :string)"], $sql);
|
||||
self::assertSame(["string" => "value"], $params);
|
||||
|
||||
$sql = $params = null;
|
||||
_query_base::parse_conds(["col" => ["between", "lower", "upper"]], $sql, $params);
|
||||
self::assertSame(["col between :col and :col2"], $sql);
|
||||
self::assertSame(["col" => "lower", "col2" => "upper"], $params);
|
||||
|
||||
$sql = $params = null;
|
||||
_query_base::parse_conds(["col" => ["in", "one"]], $sql, $params);
|
||||
self::assertSame(["col in (:col)"], $sql);
|
||||
self::assertSame(["col" => "one"], $params);
|
||||
|
||||
$sql = $params = null;
|
||||
_query_base::parse_conds(["col" => ["in", ["one", "two"]]], $sql, $params);
|
||||
self::assertSame(["col in (:col, :col2)"], $sql);
|
||||
self::assertSame(["col" => "one", "col2" => "two"], $params);
|
||||
|
||||
$sql = $params = null;
|
||||
_query_base::parse_conds(["col" => ["=", ["one", "two"]]], $sql, $params);
|
||||
self::assertSame(["col = :col and col = :col2"], $sql);
|
||||
self::assertSame(["col" => "one", "col2" => "two"], $params);
|
||||
|
||||
$sql = $params = null;
|
||||
_query_base::parse_conds(["or", "col" => ["=", ["one", "two"]]], $sql, $params);
|
||||
self::assertSame(["col = :col or col = :col2"], $sql);
|
||||
self::assertSame(["col" => "one", "col2" => "two"], $params);
|
||||
|
||||
$sql = $params = null;
|
||||
_query_base::parse_conds(["col" => ["<>", ["one", "two"]]], $sql, $params);
|
||||
self::assertSame(["col <> :col and col <> :col2"], $sql);
|
||||
self::assertSame(["col" => "one", "col2" => "two"], $params);
|
||||
|
||||
$sql = $params = null;
|
||||
_query_base::parse_conds(["or", "col" => ["<>", ["one", "two"]]], $sql, $params);
|
||||
self::assertSame(["col <> :col or col <> :col2"], $sql);
|
||||
self::assertSame(["col" => "one", "col2" => "two"], $params);
|
||||
}
|
||||
|
||||
function testParseValues(): void {
|
||||
$sql = $params = null;
|
||||
_query_base::parse_set_values(null, $sql, $params);
|
||||
self::assertNull($sql);
|
||||
self::assertNull($params);
|
||||
|
||||
$sql = $params = null;
|
||||
_query_base::parse_set_values([], $sql, $params);
|
||||
self::assertNull($sql);
|
||||
self::assertNull($params);
|
||||
|
||||
$sql = $params = null;
|
||||
_query_base::parse_set_values(["col = 'value'"], $sql, $params);
|
||||
self::assertSame(["col = 'value'"], $sql);
|
||||
self::assertNull($params);
|
||||
|
||||
$sql = $params = null;
|
||||
_query_base::parse_set_values([["col = 'value'"]], $sql, $params);
|
||||
self::assertSame(["col = 'value'"], $sql);
|
||||
self::assertNull($params);
|
||||
|
||||
$sql = $params = null;
|
||||
_query_base::parse_set_values(["int" => 42, "string" => "value"], $sql, $params);
|
||||
self::assertSame(["int = :int", "string = :string"], $sql);
|
||||
self::assertSame(["int" => 42, "string" => "value"], $params);
|
||||
|
||||
$sql = $params = null;
|
||||
_query_base::parse_set_values(["int" => 42, "string" => "value"], $sql, $params);
|
||||
self::assertSame(["int = :int", "string = :string"], $sql);
|
||||
self::assertSame(["int" => 42, "string" => "value"], $params);
|
||||
|
||||
$sql = $params = null;
|
||||
_query_base::parse_set_values([["int" => 42, "string" => "value"], ["int" => 24, "string" => "eulav"]], $sql, $params);
|
||||
self::assertSame(["int = :int", "string = :string", "int = :int2", "string = :string2"], $sql);
|
||||
self::assertSame(["int" => 42, "string" => "value", "int2" => 24, "string2" => "eulav"], $params);
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
<?php
|
||||
namespace nur\sery\file\base;
|
||||
|
||||
use nur\sery\file\FileReader;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class FileReaderTest extends TestCase {
|
||||
function testIgnoreBom() {
|
||||
# la lecture avec et sans BOM doit être identique
|
||||
## sans BOM
|
||||
$reader = new FileReader(__DIR__ . '/impl/sans_bom.txt');
|
||||
self::assertSame("0123456789", $reader->fread(10));
|
||||
self::assertSame(10, $reader->ftell());
|
||||
$reader->seek(30);
|
||||
self::assertSame("abcdefghij", $reader->fread(10));
|
||||
self::assertSame(40, $reader->ftell());
|
||||
$reader->seek(10);
|
||||
self::assertSame("ABCDEFGHIJ", $reader->fread(10));
|
||||
self::assertSame(20, $reader->ftell());
|
||||
$reader->seek(40);
|
||||
self::assertSame("0123456789\n", $reader->getContents());
|
||||
$reader->close();
|
||||
## avec BOM
|
||||
$reader = new FileReader(__DIR__ . '/impl/avec_bom.txt');
|
||||
self::assertSame("0123456789", $reader->fread(10));
|
||||
self::assertSame(10, $reader->ftell());
|
||||
$reader->seek(30);
|
||||
self::assertSame("abcdefghij", $reader->fread(10));
|
||||
self::assertSame(40, $reader->ftell());
|
||||
$reader->seek(10);
|
||||
self::assertSame("ABCDEFGHIJ", $reader->fread(10));
|
||||
self::assertSame(20, $reader->ftell());
|
||||
$reader->seek(40);
|
||||
self::assertSame("0123456789\n", $reader->getContents());
|
||||
$reader->close();
|
||||
}
|
||||
|
||||
function testCsvAutoParams() {
|
||||
$reader = new FileReader(__DIR__ . '/impl/msexcel.csv');
|
||||
self::assertSame(["nom", "prenom", "age"], $reader->fgetcsv());
|
||||
self::assertSame(["clain", "jephte", "50"], $reader->fgetcsv());
|
||||
self::assertNull($reader->fgetcsv());
|
||||
$reader->close();
|
||||
|
||||
$reader = new FileReader(__DIR__ . '/impl/ooffice.csv');
|
||||
self::assertSame(["nom", "prenom", "age"], $reader->fgetcsv());
|
||||
self::assertSame(["clain", "jephte", "50"], $reader->fgetcsv());
|
||||
self::assertNull($reader->fgetcsv());
|
||||
$reader->close();
|
||||
|
||||
$reader = new FileReader(__DIR__ . '/impl/weird.tsv');
|
||||
self::assertSame(["nom", "prenom", "age"], $reader->fgetcsv());
|
||||
self::assertSame(["clain", "jephte", "50"], $reader->fgetcsv());
|
||||
self::assertNull($reader->fgetcsv());
|
||||
$reader->close();
|
||||
|
||||
$reader = new FileReader(__DIR__ . '/impl/avec_bom.csv');
|
||||
self::assertSame(["nom", "prenom", "age"], $reader->fgetcsv());
|
||||
self::assertSame(["clain", "jephte", "50"], $reader->fgetcsv());
|
||||
self::assertNull($reader->fgetcsv());
|
||||
$reader->close();
|
||||
}
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
nom,prenom,age
|
||||
clain,jephte,50
|
|
@ -1 +0,0 @@
|
||||
0123456789ABCDEFGHIJ0123456789abcdefghij0123456789
|
@ -1,2 +0,0 @@
|
||||
nom;prenom;age
|
||||
clain;jephte;50
|
|
@ -1,2 +0,0 @@
|
||||
nom,prenom,age
|
||||
clain,jephte,50
|
|
@ -1 +0,0 @@
|
||||
0123456789ABCDEFGHIJ0123456789abcdefghij0123456789
|
@ -1,2 +0,0 @@
|
||||
nom prenom age
|
||||
clain jephte 50
|
|
File diff suppressed because it is too large
Load Diff
@ -1,292 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace {
|
||||
function func36(): int { return 36; }
|
||||
|
||||
function func_m1($a): array { return [$a]; }
|
||||
function func_o1($b=9): array { return [$b]; }
|
||||
function func_v(...$c): array { return [...$c]; }
|
||||
function func_m1o1($a, $b=9): array { return [$a, $b]; }
|
||||
function func_m1v($a, ...$c): array { return [$a, ...$c]; }
|
||||
function func_m1o1v($a, $b=9, ...$c): array { return [$a, $b, ...$c]; }
|
||||
function func_o1v($b=9, ...$c): array { return [$b, ...$c]; }
|
||||
}
|
||||
|
||||
namespace nur\sery\php {
|
||||
|
||||
use nulib\tests\TestCase;
|
||||
|
||||
class nur_funcTest extends TestCase {
|
||||
function testIs_static() {
|
||||
self::assertFalse(nur_func::is_static(null));
|
||||
self::assertFalse(nur_func::is_static(""));
|
||||
self::assertFalse(nur_func::is_static("::"));
|
||||
self::assertFalse(nur_func::is_static("xxx::"));
|
||||
self::assertFalse(nur_func::is_static([]));
|
||||
self::assertFalse(nur_func::is_static([""]));
|
||||
self::assertFalse(nur_func::is_static([null, ""]));
|
||||
self::assertFalse(nur_func::is_static(["xxx", ""]));
|
||||
|
||||
self::assertTrue(nur_func::is_static("::xxx"));
|
||||
self::assertTrue(nur_func::is_static(["xxx"]));
|
||||
self::assertTrue(nur_func::is_static([null, "yyy"]));
|
||||
self::assertTrue(nur_func::is_static(["xxx", "yyy"]));
|
||||
self::assertTrue(nur_func::is_static([null, "yyy", "aaa"]));
|
||||
self::assertTrue(nur_func::is_static(["xxx", "yyy", "aaa"]));
|
||||
}
|
||||
|
||||
function testFix_static() {
|
||||
$class = "class";
|
||||
$func = "::xxx";
|
||||
nur_func::fix_static($func, $class);
|
||||
self::assertSame("class::xxx", $func);
|
||||
$func = ["xxx"];
|
||||
nur_func::fix_static($func, $class);
|
||||
self::assertSame(["class", "xxx"], $func);
|
||||
$func = [null, "yyy"];
|
||||
nur_func::fix_static($func, $class);
|
||||
self::assertSame(["class", "yyy"], $func);
|
||||
$func = ["xxx", "yyy"];
|
||||
nur_func::fix_static($func, $class);
|
||||
self::assertSame(["xxx", "yyy"], $func);
|
||||
$func = [null, "yyy", "aaa"];
|
||||
nur_func::fix_static($func, $class);
|
||||
self::assertSame(["class", "yyy", "aaa"], $func);
|
||||
$func = ["xxx", "yyy", "aaa"];
|
||||
nur_func::fix_static($func, $class);
|
||||
self::assertSame(["xxx", "yyy", "aaa"], $func);
|
||||
}
|
||||
|
||||
function testIs_method() {
|
||||
self::assertFalse(nur_func::is_method(null));
|
||||
self::assertFalse(nur_func::is_method(""));
|
||||
self::assertFalse(nur_func::is_method("->"));
|
||||
self::assertFalse(nur_func::is_method([]));
|
||||
self::assertFalse(nur_func::is_method([""]));
|
||||
self::assertFalse(nur_func::is_method([null, "->"]));
|
||||
self::assertFalse(nur_func::is_method(["xxx", "->"]));
|
||||
|
||||
self::assertTrue(nur_func::is_method("->xxx"));
|
||||
self::assertTrue(nur_func::is_method(["->xxx"]));
|
||||
self::assertTrue(nur_func::is_method([null, "->yyy"]));
|
||||
self::assertTrue(nur_func::is_method(["xxx", "->yyy"]));
|
||||
self::assertTrue(nur_func::is_method([null, "->yyy", "aaa"]));
|
||||
self::assertTrue(nur_func::is_method(["xxx", "->yyy", "aaa"]));
|
||||
}
|
||||
|
||||
function testFix_method() {
|
||||
$object = new \stdClass();
|
||||
$func= "->xxx";
|
||||
nur_func::fix_method($func, $object);
|
||||
self::assertSame([$object, "xxx"], $func);
|
||||
$func= ["->xxx"];
|
||||
nur_func::fix_method($func, $object);
|
||||
self::assertSame([$object, "xxx"], $func);
|
||||
$func= [null, "->yyy"];
|
||||
nur_func::fix_method($func, $object);
|
||||
self::assertSame([$object, "yyy"], $func);
|
||||
$func= ["xxx", "->yyy"];
|
||||
nur_func::fix_method($func, $object);
|
||||
self::assertSame([$object, "yyy"], $func);
|
||||
$func= [null, "->yyy", "aaa"];
|
||||
nur_func::fix_method($func, $object);
|
||||
self::assertSame([$object, "yyy", "aaa"], $func);
|
||||
$func= ["xxx", "->yyy", "aaa"];
|
||||
nur_func::fix_method($func, $object);
|
||||
self::assertSame([$object, "yyy", "aaa"], $func);
|
||||
}
|
||||
|
||||
function testCall() {
|
||||
self::assertSame(36, nur_func::call("func36"));
|
||||
self::assertSame(12, nur_func::call(TC::class."::method"));
|
||||
self::assertSame(12, nur_func::call([TC::class, "method"]));
|
||||
$closure = function() {
|
||||
return 21;
|
||||
};
|
||||
self::assertSame(21, nur_func::call($closure));
|
||||
}
|
||||
|
||||
function test_prepare_fill() {
|
||||
# vérifier que les arguments sont bien remplis, en fonction du fait qu'ils
|
||||
# soient obligatoires, facultatifs ou variadiques
|
||||
|
||||
# m1
|
||||
self::assertSame([null], nur_func::call("func_m1"));
|
||||
self::assertSame([null], nur_func::call("func_m1", null));
|
||||
self::assertSame([null], nur_func::call("func_m1", null, null));
|
||||
self::assertSame([null], nur_func::call("func_m1", null, null, null));
|
||||
self::assertSame([null], nur_func::call("func_m1", null, null, null, null));
|
||||
self::assertSame([1], nur_func::call("func_m1", 1));
|
||||
self::assertSame([1], nur_func::call("func_m1", 1, 2));
|
||||
self::assertSame([1], nur_func::call("func_m1", 1, 2, 3));
|
||||
self::assertSame([1], nur_func::call("func_m1", 1, 2, 3, 4));
|
||||
|
||||
# o1
|
||||
self::assertSame([9], nur_func::call("func_o1"));
|
||||
self::assertSame([null], nur_func::call("func_o1", null));
|
||||
self::assertSame([null], nur_func::call("func_o1", null, null));
|
||||
self::assertSame([null], nur_func::call("func_o1", null, null, null));
|
||||
self::assertSame([null], nur_func::call("func_o1", null, null, null, null));
|
||||
self::assertSame([1], nur_func::call("func_o1", 1));
|
||||
self::assertSame([1], nur_func::call("func_o1", 1, 2));
|
||||
self::assertSame([1], nur_func::call("func_o1", 1, 2, 3));
|
||||
self::assertSame([1], nur_func::call("func_o1", 1, 2, 3, 4));
|
||||
|
||||
# v
|
||||
self::assertSame([], nur_func::call("func_v"));
|
||||
self::assertSame([null], nur_func::call("func_v", null));
|
||||
self::assertSame([null, null], nur_func::call("func_v", null, null));
|
||||
self::assertSame([null, null, null], nur_func::call("func_v", null, null, null));
|
||||
self::assertSame([null, null, null, null], nur_func::call("func_v", null, null, null, null));
|
||||
self::assertSame([1], nur_func::call("func_v", 1));
|
||||
self::assertSame([1, 2], nur_func::call("func_v", 1, 2));
|
||||
self::assertSame([1, 2, 3], nur_func::call("func_v", 1, 2, 3));
|
||||
self::assertSame([1, 2, 3, 4], nur_func::call("func_v", 1, 2, 3, 4));
|
||||
|
||||
# m1o1
|
||||
self::assertSame([null, 9], nur_func::call("func_m1o1"));
|
||||
self::assertSame([null, 9], nur_func::call("func_m1o1", null));
|
||||
self::assertSame([null, null], nur_func::call("func_m1o1", null, null));
|
||||
self::assertSame([null, null], nur_func::call("func_m1o1", null, null, null));
|
||||
self::assertSame([null, null], nur_func::call("func_m1o1", null, null, null, null));
|
||||
self::assertSame([1, 9], nur_func::call("func_m1o1", 1));
|
||||
self::assertSame([1, 2], nur_func::call("func_m1o1", 1, 2));
|
||||
self::assertSame([1, 2], nur_func::call("func_m1o1", 1, 2, 3));
|
||||
self::assertSame([1, 2], nur_func::call("func_m1o1", 1, 2, 3, 4));
|
||||
|
||||
# m1v
|
||||
self::assertSame([null], nur_func::call("func_m1v"));
|
||||
self::assertSame([null], nur_func::call("func_m1v", null));
|
||||
self::assertSame([null, null], nur_func::call("func_m1v", null, null));
|
||||
self::assertSame([null, null, null], nur_func::call("func_m1v", null, null, null));
|
||||
self::assertSame([null, null, null, null], nur_func::call("func_m1v", null, null, null, null));
|
||||
self::assertSame([1], nur_func::call("func_m1v", 1));
|
||||
self::assertSame([1, 2], nur_func::call("func_m1v", 1, 2));
|
||||
self::assertSame([1, 2, 3], nur_func::call("func_m1v", 1, 2, 3));
|
||||
self::assertSame([1, 2, 3, 4], nur_func::call("func_m1v", 1, 2, 3, 4));
|
||||
|
||||
# m1o1v
|
||||
self::assertSame([null, 9], nur_func::call("func_m1o1v"));
|
||||
self::assertSame([null, 9], nur_func::call("func_m1o1v", null));
|
||||
self::assertSame([null, null], nur_func::call("func_m1o1v", null, null));
|
||||
self::assertSame([null, null, null], nur_func::call("func_m1o1v", null, null, null));
|
||||
self::assertSame([null, null, null, null], nur_func::call("func_m1o1v", null, null, null, null));
|
||||
self::assertSame([1, 9], nur_func::call("func_m1o1v", 1));
|
||||
self::assertSame([1, 2], nur_func::call("func_m1o1v", 1, 2));
|
||||
self::assertSame([1, 2, 3], nur_func::call("func_m1o1v", 1, 2, 3));
|
||||
self::assertSame([1, 2, 3, 4], nur_func::call("func_m1o1v", 1, 2, 3, 4));
|
||||
|
||||
# o1v
|
||||
self::assertSame([9], nur_func::call("func_o1v"));
|
||||
self::assertSame([null], nur_func::call("func_o1v", null));
|
||||
self::assertSame([null, null], nur_func::call("func_o1v", null, null));
|
||||
self::assertSame([null, null, null], nur_func::call("func_o1v", null, null, null));
|
||||
self::assertSame([null, null, null, null], nur_func::call("func_o1v", null, null, null, null));
|
||||
self::assertSame([1], nur_func::call("func_o1v", 1));
|
||||
self::assertSame([1, 2], nur_func::call("func_o1v", 1, 2));
|
||||
self::assertSame([1, 2, 3], nur_func::call("func_o1v", 1, 2, 3));
|
||||
self::assertSame([1, 2, 3, 4], nur_func::call("func_o1v", 1, 2, 3, 4));
|
||||
}
|
||||
|
||||
function testCall_all() {
|
||||
$c1 = new C1();
|
||||
$c2 = new C2();
|
||||
$c3 = new C3();
|
||||
|
||||
self::assertSameValues([11, 12], nur_func::call_all(C1::class));
|
||||
self::assertSameValues([11, 12, 21, 22], nur_func::call_all($c1));
|
||||
self::assertSameValues([13, 11, 12], nur_func::call_all(C2::class));
|
||||
self::assertSameValues([13, 23, 11, 12, 21, 22], nur_func::call_all($c2));
|
||||
self::assertSameValues([111, 13, 12], nur_func::call_all(C3::class));
|
||||
self::assertSameValues([111, 121, 13, 23, 12, 22], nur_func::call_all($c3));
|
||||
|
||||
$options = "conf";
|
||||
self::assertSameValues([11], nur_func::call_all(C1::class, $options));
|
||||
self::assertSameValues([11, 21], nur_func::call_all($c1, $options));
|
||||
self::assertSameValues([11], nur_func::call_all(C2::class, $options));
|
||||
self::assertSameValues([11, 21], nur_func::call_all($c2, $options));
|
||||
self::assertSameValues([111], nur_func::call_all(C3::class, $options));
|
||||
self::assertSameValues([111, 121], nur_func::call_all($c3, $options));
|
||||
|
||||
$options = ["prefix" => "conf"];
|
||||
self::assertSameValues([11], nur_func::call_all(C1::class, $options));
|
||||
self::assertSameValues([11, 21], nur_func::call_all($c1, $options));
|
||||
self::assertSameValues([11], nur_func::call_all(C2::class, $options));
|
||||
self::assertSameValues([11, 21], nur_func::call_all($c2, $options));
|
||||
self::assertSameValues([111], nur_func::call_all(C3::class, $options));
|
||||
self::assertSameValues([111, 121], nur_func::call_all($c3, $options));
|
||||
|
||||
self::assertSameValues([11, 12], nur_func::call_all($c1, ["include" => "x"]));
|
||||
self::assertSameValues([11, 21], nur_func::call_all($c1, ["include" => "y"]));
|
||||
self::assertSameValues([11, 12, 21], nur_func::call_all($c1, ["include" => ["x", "y"]]));
|
||||
|
||||
self::assertSameValues([21, 22], nur_func::call_all($c1, ["exclude" => "x"]));
|
||||
self::assertSameValues([12, 22], nur_func::call_all($c1, ["exclude" => "y"]));
|
||||
self::assertSameValues([22], nur_func::call_all($c1, ["exclude" => ["x", "y"]]));
|
||||
|
||||
self::assertSameValues([12], nur_func::call_all($c1, ["include" => "x", "exclude" => "y"]));
|
||||
}
|
||||
|
||||
function testCons() {
|
||||
$obj1 = nur_func::cons(WoCons::class, 1, 2, 3);
|
||||
self::assertInstanceOf(WoCons::class, $obj1);
|
||||
|
||||
$obj2 = nur_func::cons(WithEmptyCons::class, 1, 2, 3);
|
||||
self::assertInstanceOf(WithEmptyCons::class, $obj2);
|
||||
|
||||
$obj3 = nur_func::cons(WithCons::class, 1, 2, 3);
|
||||
self::assertInstanceOf(WithCons::class, $obj3);
|
||||
self::assertSame(1, $obj3->first);
|
||||
}
|
||||
}
|
||||
|
||||
class WoCons {
|
||||
}
|
||||
class WithEmptyCons {
|
||||
function __construct() {
|
||||
}
|
||||
}
|
||||
class WithCons {
|
||||
public $first;
|
||||
function __construct($first) {
|
||||
$this->first = $first;
|
||||
}
|
||||
}
|
||||
|
||||
class TC {
|
||||
static function method() {
|
||||
return 12;
|
||||
}
|
||||
}
|
||||
|
||||
class C1 {
|
||||
static function confps1_xy() {
|
||||
return 11;
|
||||
}
|
||||
static function ps2_x() {
|
||||
return 12;
|
||||
}
|
||||
function confp1_y() {
|
||||
return 21;
|
||||
}
|
||||
function p2() {
|
||||
return 22;
|
||||
}
|
||||
}
|
||||
class C2 extends C1 {
|
||||
static function ps3() {
|
||||
return 13;
|
||||
}
|
||||
function p3() {
|
||||
return 23;
|
||||
}
|
||||
}
|
||||
class C3 extends C2 {
|
||||
static function confps1_xy() {
|
||||
return 111;
|
||||
}
|
||||
function confp1_y() {
|
||||
return 121;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
<?php
|
||||
namespace nur\sery\php\time;
|
||||
|
||||
use DateTimeZone;
|
||||
use nulib\tests\TestCase;
|
||||
|
||||
class DateTest extends TestCase {
|
||||
protected static function dt(string $datetime): Date {
|
||||
return new Date($datetime, new DateTimeZone("Indian/Reunion"));
|
||||
}
|
||||
|
||||
function testDate() {
|
||||
$date = self::dt("2024-04-05 09:15:23");
|
||||
|
||||
self::assertSame("05/04/2024", $date->format());
|
||||
self::assertSame("05/04/2024", strval($date));
|
||||
self::assertSame(2024, $date->year);
|
||||
self::assertSame(4, $date->month);
|
||||
self::assertSame(5, $date->day);
|
||||
self::assertSame(0, $date->hour);
|
||||
self::assertSame(0, $date->minute);
|
||||
self::assertSame(0, $date->second);
|
||||
self::assertSame(5, $date->wday);
|
||||
self::assertSame(14, $date->wnum);
|
||||
self::assertSame("+04:00", $date->timezone);
|
||||
self::assertSame("05/04/2024 00:00:00", $date->datetime);
|
||||
self::assertSame("05/04/2024", $date->date);
|
||||
}
|
||||
|
||||
function testClone() {
|
||||
$date = self::dt("now");
|
||||
$clone = Date::clone($date);
|
||||
self::assertInstanceOf(DateTime::class, $clone);
|
||||
}
|
||||
|
||||
function testConstruct() {
|
||||
$y = date("Y");
|
||||
self::assertSame("05/04/$y", strval(new Date("5/4")));
|
||||
self::assertSame("05/04/2024", strval(new Date("5/4/24")));
|
||||
self::assertSame("05/04/2024", strval(new Date("5/4/2024")));
|
||||
self::assertSame("05/04/2024", strval(new Date("05/04/2024")));
|
||||
self::assertSame("05/04/2024", strval(new Date("20240405")));
|
||||
self::assertSame("05/04/2024", strval(new Date("240405")));
|
||||
self::assertSame("05/04/2024", strval(new Date("20240405T091523")));
|
||||
self::assertSame("05/04/2024", strval(new Date("20240405T091523Z")));
|
||||
self::assertSame("05/04/2024", strval(new Date("5/4/2024 9:15:23")));
|
||||
self::assertSame("05/04/2024", strval(new Date("5/4/2024 9.15.23")));
|
||||
self::assertSame("05/04/2024", strval(new Date("5/4/2024 9:15")));
|
||||
self::assertSame("05/04/2024", strval(new Date("5/4/2024 9.15")));
|
||||
self::assertSame("05/04/2024", strval(new Date("5/4/2024 9h15")));
|
||||
self::assertSame("05/04/2024", strval(new Date("5/4/2024 09:15:23")));
|
||||
self::assertSame("05/04/2024", strval(new Date("5/4/2024 09:15")));
|
||||
self::assertSame("05/04/2024", strval(new Date("5/4/2024 09h15")));
|
||||
}
|
||||
|
||||
function testCompare() {
|
||||
$a = new Date("10/02/2024");
|
||||
$b = new Date("15/02/2024");
|
||||
$c = new Date("20/02/2024");
|
||||
$a2 = new Date("10/02/2024");
|
||||
$b2 = new Date("15/02/2024");
|
||||
$c2 = new Date("20/02/2024");
|
||||
|
||||
self::assertTrue($a == $a2);
|
||||
self::assertFalse($a === $a2);
|
||||
self::assertTrue($b == $b2);
|
||||
self::assertTrue($c == $c2);
|
||||
|
||||
self::assertFalse($a < $a);
|
||||
self::assertTrue($a < $b);
|
||||
self::assertTrue($a < $c);
|
||||
|
||||
self::assertTrue($a <= $a);
|
||||
self::assertTrue($a <= $b);
|
||||
self::assertTrue($a <= $c);
|
||||
|
||||
self::assertFalse($c > $c);
|
||||
self::assertTrue($c > $b);
|
||||
self::assertTrue($c > $a);
|
||||
|
||||
self::assertTrue($c >= $c);
|
||||
self::assertTrue($c >= $b);
|
||||
self::assertTrue($c >= $a);
|
||||
}
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
<?php
|
||||
namespace nur\sery\php\time;
|
||||
|
||||
use DateTimeZone;
|
||||
use nulib\tests\TestCase;
|
||||
|
||||
class DateTimeTest extends TestCase {
|
||||
protected static function dt(string $datetime): DateTime {
|
||||
return new DateTime($datetime, new DateTimeZone("Indian/Reunion"));
|
||||
}
|
||||
|
||||
function testDateTime() {
|
||||
$date = self::dt("2024-04-05 09:15:23");
|
||||
|
||||
self::assertEquals("05/04/2024 09:15:23", $date->format());
|
||||
self::assertEquals("05/04/2024 09:15:23", strval($date));
|
||||
self::assertSame(2024, $date->year);
|
||||
self::assertSame(4, $date->month);
|
||||
self::assertSame(5, $date->day);
|
||||
self::assertSame(9, $date->hour);
|
||||
self::assertSame(15, $date->minute);
|
||||
self::assertSame(23, $date->second);
|
||||
self::assertSame(5, $date->wday);
|
||||
self::assertSame(14, $date->wnum);
|
||||
self::assertEquals("+04:00", $date->timezone);
|
||||
self::assertSame("05/04/2024 09:15:23", $date->datetime);
|
||||
self::assertSame("05/04/2024", $date->date);
|
||||
self::assertSame("20240405", $date->Ymd);
|
||||
self::assertSame("20240405T091523", $date->YmdHMS);
|
||||
self::assertSame("20240405T091523+04:00", $date->YmdHMSZ);
|
||||
}
|
||||
|
||||
function testDateTimeZ() {
|
||||
$date = new DateTime("20240405T091523Z");
|
||||
self::assertSame("20240405T091523", $date->YmdHMS);
|
||||
self::assertSame("20240405T091523Z", $date->YmdHMSZ);
|
||||
}
|
||||
|
||||
function testClone() {
|
||||
$date = self::dt("now");
|
||||
$clone = DateTime::clone($date);
|
||||
self::assertInstanceOf(DateTime::class, $clone);
|
||||
}
|
||||
|
||||
function testConstruct() {
|
||||
$y = date("Y");
|
||||
self::assertSame("05/04/$y 00:00:00", strval(new DateTime("5/4")));
|
||||
self::assertSame("05/04/2024 00:00:00", strval(new DateTime("5/4/24")));
|
||||
self::assertSame("05/04/2024 00:00:00", strval(new DateTime("5/4/2024")));
|
||||
self::assertSame("05/04/2024 00:00:00", strval(new DateTime("05/04/2024")));
|
||||
self::assertSame("05/04/2024 00:00:00", strval(new DateTime("20240405")));
|
||||
self::assertSame("05/04/2024 00:00:00", strval(new DateTime("240405")));
|
||||
self::assertSame("05/04/2024 09:15:23", strval(new DateTime("20240405T091523")));
|
||||
self::assertSame("05/04/2024 09:15:23", strval(new DateTime("20240405T091523Z")));
|
||||
self::assertSame("05/04/2024 09:15:23", strval(new DateTime("5/4/2024 9:15:23")));
|
||||
self::assertSame("05/04/2024 09:15:23", strval(new DateTime("5/4/2024 9.15.23")));
|
||||
self::assertSame("05/04/2024 09:15:00", strval(new DateTime("5/4/2024 9:15")));
|
||||
self::assertSame("05/04/2024 09:15:00", strval(new DateTime("5/4/2024 9.15")));
|
||||
self::assertSame("05/04/2024 09:15:00", strval(new DateTime("5/4/2024 9h15")));
|
||||
self::assertSame("05/04/2024 09:15:23", strval(new DateTime("5/4/2024 09:15:23")));
|
||||
self::assertSame("05/04/2024 09:15:00", strval(new DateTime("5/4/2024 09:15")));
|
||||
self::assertSame("05/04/2024 09:15:00", strval(new DateTime("5/4/2024 09h15")));
|
||||
}
|
||||
|
||||
function testCompare() {
|
||||
$a = new DateTime("10/02/2024");
|
||||
$a2 = new DateTime("10/02/2024 8:30");
|
||||
$a3 = new DateTime("10/02/2024 15:45");
|
||||
$b = new DateTime("15/02/2024");
|
||||
$b2 = new DateTime("15/02/2024 8:30");
|
||||
$b3 = new DateTime("15/02/2024 15:45");
|
||||
$x = new DateTime("10/02/2024");
|
||||
$x2 = new DateTime("10/02/2024 8:30");
|
||||
$x3 = new DateTime("10/02/2024 15:45");
|
||||
|
||||
self::assertTrue($a == $x);
|
||||
self::assertFalse($a === $x);
|
||||
self::assertTrue($a2 == $x2);
|
||||
self::assertTrue($a3 == $x3);
|
||||
|
||||
self::assertFalse($a < $a);
|
||||
self::assertTrue($a < $a2);
|
||||
self::assertTrue($a < $a3);
|
||||
self::assertTrue($a < $b);
|
||||
self::assertTrue($a < $b2);
|
||||
self::assertTrue($a < $b3);
|
||||
|
||||
self::assertTrue($a <= $a);
|
||||
self::assertTrue($a <= $a2);
|
||||
self::assertTrue($a <= $a3);
|
||||
self::assertTrue($a <= $b);
|
||||
self::assertTrue($a <= $b2);
|
||||
self::assertTrue($a <= $b3);
|
||||
|
||||
self::assertTrue($b > $a);
|
||||
self::assertTrue($b > $a2);
|
||||
self::assertTrue($b > $a3);
|
||||
self::assertFalse($b > $b);
|
||||
self::assertFalse($b > $b2);
|
||||
self::assertFalse($b > $b3);
|
||||
|
||||
self::assertTrue($b >= $a);
|
||||
self::assertTrue($b >= $a2);
|
||||
self::assertTrue($b >= $a3);
|
||||
self::assertTrue($b >= $b);
|
||||
self::assertFalse($b >= $b2);
|
||||
self::assertFalse($b >= $b3);
|
||||
}
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
<?php
|
||||
namespace nur\sery\php\time;
|
||||
|
||||
use DateTimeZone;
|
||||
use nulib\tests\TestCase;
|
||||
|
||||
class DelayTest extends TestCase {
|
||||
protected static function dt(string $datetime): DateTime {
|
||||
return new DateTime($datetime, new DateTimeZone("Indian/Reunion"));
|
||||
}
|
||||
|
||||
function testDelay() {
|
||||
$from = self::dt("2024-04-05 09:15:23");
|
||||
|
||||
$delay = new Delay(10, $from);
|
||||
self::assertEquals(self::dt("2024-04-05 09:15:33"), $delay->getDest());
|
||||
|
||||
$delay = new Delay("10", $from);
|
||||
self::assertEquals(self::dt("2024-04-05 09:15:33"), $delay->getDest());
|
||||
|
||||
$delay = new Delay("10s", $from);
|
||||
self::assertEquals(self::dt("2024-04-05 09:15:33"), $delay->getDest());
|
||||
|
||||
$delay = new Delay("s", $from);
|
||||
self::assertEquals(self::dt("2024-04-05 09:15:24"), $delay->getDest());
|
||||
|
||||
$delay = new Delay("5m", $from);
|
||||
self::assertEquals(self::dt("2024-04-05 09:20:00"), $delay->getDest());
|
||||
|
||||
$delay = new Delay("5m0", $from);
|
||||
self::assertEquals(self::dt("2024-04-05 09:20:00"), $delay->getDest());
|
||||
|
||||
$delay = new Delay("5m2", $from);
|
||||
self::assertEquals(self::dt("2024-04-05 09:20:02"), $delay->getDest());
|
||||
|
||||
$delay = new Delay("m", $from);
|
||||
self::assertEquals(self::dt("2024-04-05 09:16:00"), $delay->getDest());
|
||||
|
||||
$delay = new Delay("5h", $from);
|
||||
self::assertEquals(self::dt("2024-04-05 14:00:00"), $delay->getDest());
|
||||
|
||||
$delay = new Delay("5h0", $from);
|
||||
self::assertEquals(self::dt("2024-04-05 14:00:00"), $delay->getDest());
|
||||
|
||||
$delay = new Delay("5h2", $from);
|
||||
self::assertEquals(self::dt("2024-04-05 14:02:00"), $delay->getDest());
|
||||
|
||||
$delay = new Delay("h", $from);
|
||||
self::assertEquals(self::dt("2024-04-05 10:00:00"), $delay->getDest());
|
||||
|
||||
$delay = new Delay("5d", $from);
|
||||
self::assertEquals(self::dt("2024-04-10 05:00:00"), $delay->getDest());
|
||||
|
||||
$delay = new Delay("5d2", $from);
|
||||
self::assertEquals(self::dt("2024-04-10 02:00:00"), $delay->getDest());
|
||||
|
||||
$delay = new Delay("5d0", $from);
|
||||
self::assertEquals(self::dt("2024-04-10 00:00:00"), $delay->getDest());
|
||||
|
||||
$delay = new Delay("d", $from);
|
||||
self::assertEquals(self::dt("2024-04-06 05:00:00"), $delay->getDest());
|
||||
|
||||
$delay = new Delay("2w", $from);
|
||||
self::assertEquals(self::dt("2024-04-21 05:00:00"), $delay->getDest());
|
||||
|
||||
$delay = new Delay("2w2", $from);
|
||||
self::assertEquals(self::dt("2024-04-21 02:00:00"), $delay->getDest());
|
||||
|
||||
$delay = new Delay("2w0", $from);
|
||||
self::assertEquals(self::dt("2024-04-21 00:00:00"), $delay->getDest());
|
||||
|
||||
$delay = new Delay("w", $from);
|
||||
self::assertEquals(self::dt("2024-04-07 05:00:00"), $delay->getDest());
|
||||
}
|
||||
|
||||
function testElapsed() {
|
||||
$delay = new Delay(5);
|
||||
sleep(2);
|
||||
self::assertFalse($delay->isElapsed());
|
||||
sleep(5);
|
||||
self::assertTrue($delay->isElapsed());
|
||||
}
|
||||
}
|
@ -1,111 +0,0 @@
|
||||
<?php
|
||||
namespace nur\sery\schema\types;
|
||||
|
||||
use Exception;
|
||||
use nulib\tests\TestCase;
|
||||
use nur\sery\schema\_scalar\ScalarValue;
|
||||
use nur\sery\schema\Schema;
|
||||
|
||||
class boolTest extends TestCase {
|
||||
function commonTests($destv, &$dest, callable $destvSetter): void {
|
||||
$destv->set(true);
|
||||
self::assertSame(true, $destv->get());
|
||||
self::assertSame(true, $dest);
|
||||
self::assertSame("Oui", $destv->format());
|
||||
self::assertSame("Oui", $destv->format("OuiNonNull"));
|
||||
self::assertSame("O", $destv->format("ON"));
|
||||
self::assertSame("O", $destv->format("ONN"));
|
||||
|
||||
$destv->set(false);
|
||||
self::assertSame(false, $destv->get());
|
||||
self::assertSame(false, $dest);
|
||||
self::assertSame("Non", $destv->format());
|
||||
self::assertSame("Non", $destv->format("OuiNonNull"));
|
||||
self::assertSame("N", $destv->format("ON"));
|
||||
self::assertSame("N", $destv->format("ONN"));
|
||||
|
||||
$destv->set("yes");
|
||||
self::assertSame(true, $destv->get());
|
||||
|
||||
$destv->set(" yes ");
|
||||
self::assertSame(true, $destv->get());
|
||||
|
||||
$destv->set("12");
|
||||
self::assertSame(true, $destv->get());
|
||||
|
||||
$destv->set(12);
|
||||
self::assertSame(true, $destv->get());
|
||||
|
||||
$destv->set("no");
|
||||
self::assertSame(false, $destv->get());
|
||||
|
||||
$destv->set(" no ");
|
||||
self::assertSame(false, $destv->get());
|
||||
|
||||
$destv->set("0");
|
||||
self::assertSame(false, $destv->get());
|
||||
|
||||
$destv->set(0);
|
||||
self::assertSame(false, $destv->get());
|
||||
|
||||
$destv->set(12.34);
|
||||
self::assertSame(true, $destv->get());
|
||||
|
||||
self::assertException(Exception::class, $destvSetter("a"));
|
||||
self::assertException(Exception::class, $destvSetter([]));
|
||||
self::assertException(Exception::class, $destvSetter(["a"]));
|
||||
|
||||
}
|
||||
|
||||
function testBool() {
|
||||
/** @var ScalarValue $destv */
|
||||
Schema::nv($destv, $dest, null, $schema, "bool");
|
||||
$destvSetter = function($value) use($destv) {
|
||||
return function() use($destv, $value) {
|
||||
$destv->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
self::assertException(Exception::class, $destvSetter(null));
|
||||
self::assertException(Exception::class, $destvSetter(""));
|
||||
self::assertException(Exception::class, $destvSetter(" "));
|
||||
|
||||
$this->commonTests($destv, $dest, $destvSetter);
|
||||
}
|
||||
|
||||
function testNbool() {
|
||||
/** @var ScalarValue $destv */
|
||||
Schema::nv($destv, $dest, null, $schema, "?bool");
|
||||
$destvSetter = function($value) use($destv) {
|
||||
return function() use($destv, $value) {
|
||||
$destv->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
$destv->set(null);
|
||||
self::assertNull($destv->get());
|
||||
self::assertNull($dest);
|
||||
self::assertSame("Non", $destv->format());
|
||||
self::assertSame("", $destv->format("OuiNonNull"));
|
||||
self::assertSame("N", $destv->format("ON"));
|
||||
self::assertSame("", $destv->format("ONN"));
|
||||
|
||||
$destv->set("");
|
||||
self::assertNull($destv->get());
|
||||
self::assertNull($dest);
|
||||
self::assertSame("Non", $destv->format());
|
||||
self::assertSame("", $destv->format("OuiNonNull"));
|
||||
self::assertSame("N", $destv->format("ON"));
|
||||
self::assertSame("", $destv->format("ONN"));
|
||||
|
||||
$destv->set(" ");
|
||||
self::assertNull($destv->get());
|
||||
self::assertNull($dest);
|
||||
self::assertSame("Non", $destv->format());
|
||||
self::assertSame("", $destv->format("OuiNonNull"));
|
||||
self::assertSame("N", $destv->format("ON"));
|
||||
self::assertSame("", $destv->format("ONN"));
|
||||
|
||||
$this->commonTests($destv, $dest, $destvSetter);
|
||||
}
|
||||
}
|
@ -1,139 +0,0 @@
|
||||
<?php
|
||||
namespace nur\sery\schema\types;
|
||||
|
||||
use Exception;
|
||||
use nulib\tests\TestCase;
|
||||
use nur\sery\schema\_scalar\ScalarValue;
|
||||
use nur\sery\schema\Schema;
|
||||
|
||||
class floatTest extends TestCase {
|
||||
function commonTests($destv, &$dest, callable $destvSetter): void {
|
||||
$destv->set(12);
|
||||
self::assertSame(12.0, $destv->get());
|
||||
self::assertSame(12.0, $dest);
|
||||
self::assertSame("12", $destv->format());
|
||||
self::assertSame("0012", $destv->format("%04u"));
|
||||
|
||||
$destv->set("12");
|
||||
self::assertSame(12.0, $destv->get());
|
||||
|
||||
$destv->set(" 12 ");
|
||||
self::assertSame(12.0, $destv->get());
|
||||
|
||||
$destv->set(12.34);
|
||||
self::assertSame(12.34, $destv->get());
|
||||
|
||||
$destv->set(true);
|
||||
self::assertSame(1.0, $destv->get());
|
||||
|
||||
self::assertException(Exception::class, $destvSetter("a"));
|
||||
self::assertException(Exception::class, $destvSetter([]));
|
||||
self::assertException(Exception::class, $destvSetter(["a"]));
|
||||
}
|
||||
|
||||
function testFloat() {
|
||||
/** @var ScalarValue $destv */
|
||||
Schema::nv($destv, $dest, null, $schema, "float");
|
||||
$destvSetter = function($value) use($destv) {
|
||||
return function() use($destv, $value) {
|
||||
$destv->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
self::assertException(Exception::class, $destvSetter(null));
|
||||
self::assertException(Exception::class, $destvSetter(""));
|
||||
self::assertException(Exception::class, $destvSetter(" "));
|
||||
|
||||
// valeur non requise donc retourne null
|
||||
$destv->set(false);
|
||||
self::assertNull($destv->get());
|
||||
|
||||
$this->commonTests($destv, $dest, $destvSetter);
|
||||
}
|
||||
|
||||
function testRequiredFloat() {
|
||||
/** @var ScalarValue $destv */
|
||||
Schema::nv($destv, $dest, null, $schema, [
|
||||
"float", null,
|
||||
"required" => true,
|
||||
]);
|
||||
$destvSetter = function($value) use($destv) {
|
||||
return function() use($destv, $value) {
|
||||
$destv->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
self::assertException(Exception::class, $destvSetter(null));
|
||||
self::assertException(Exception::class, $destvSetter(""));
|
||||
self::assertException(Exception::class, $destvSetter(" "));
|
||||
|
||||
// valeur requise donc lance une exception
|
||||
self::assertException(Exception::class, $destvSetter(false));
|
||||
|
||||
$this->commonTests($destv, $dest, $destvSetter);
|
||||
}
|
||||
|
||||
function testNfloat() {
|
||||
/** @var ScalarValue $destv */
|
||||
Schema::nv($destv, $dest, null, $schema, "?float");
|
||||
$destvSetter = function($value) use($destv) {
|
||||
return function() use($destv, $value) {
|
||||
$destv->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
$destv->set(null);
|
||||
self::assertNull($destv->get());
|
||||
self::assertNull($dest);
|
||||
self::assertSame("", $destv->format());
|
||||
|
||||
$destv->set("");
|
||||
self::assertNull($destv->get());
|
||||
self::assertNull($dest);
|
||||
self::assertSame("", $destv->format());
|
||||
|
||||
$destv->set(" ");
|
||||
self::assertNull($destv->get());
|
||||
self::assertNull($dest);
|
||||
self::assertSame("", $destv->format());
|
||||
|
||||
// valeur non requise donc retourne null
|
||||
$destv->set(false);
|
||||
self::assertNull($destv->get());
|
||||
|
||||
$this->commonTests($destv, $dest, $destvSetter);
|
||||
}
|
||||
|
||||
function testRequiredNfloat() {
|
||||
/** @var ScalarValue $destv */
|
||||
Schema::nv($destv, $dest, null, $schema, [
|
||||
"?float", null,
|
||||
"required" => true,
|
||||
]);
|
||||
$destvSetter = function($value) use($destv) {
|
||||
return function() use($destv, $value) {
|
||||
$destv->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
$destv->set(null);
|
||||
self::assertNull($destv->get());
|
||||
self::assertNull($dest);
|
||||
self::assertSame("", $destv->format());
|
||||
|
||||
$destv->set("");
|
||||
self::assertNull($destv->get());
|
||||
self::assertNull($dest);
|
||||
self::assertSame("", $destv->format());
|
||||
|
||||
$destv->set(" ");
|
||||
self::assertNull($destv->get());
|
||||
self::assertNull($dest);
|
||||
self::assertSame("", $destv->format());
|
||||
|
||||
// valeur requise donc lance une exception
|
||||
self::assertException(Exception::class, $destvSetter(false));
|
||||
|
||||
$this->commonTests($destv, $dest, $destvSetter);
|
||||
}
|
||||
}
|
@ -1,139 +0,0 @@
|
||||
<?php
|
||||
namespace nur\sery\schema\types;
|
||||
|
||||
use Exception;
|
||||
use nulib\tests\TestCase;
|
||||
use nur\sery\schema\_scalar\ScalarValue;
|
||||
use nur\sery\schema\Schema;
|
||||
|
||||
class intTest extends TestCase {
|
||||
function commonTests($destv, &$dest, callable $destvSetter): void {
|
||||
$destv->set(12);
|
||||
self::assertSame(12, $destv->get());
|
||||
self::assertSame(12, $dest);
|
||||
self::assertSame("12", $destv->format());
|
||||
self::assertSame("0012", $destv->format("%04u"));
|
||||
|
||||
$destv->set("12");
|
||||
self::assertSame(12, $destv->get());
|
||||
|
||||
$destv->set(" 12 ");
|
||||
self::assertSame(12, $destv->get());
|
||||
|
||||
$destv->set(12.34);
|
||||
self::assertSame(12, $destv->get());
|
||||
|
||||
$destv->set(true);
|
||||
self::assertSame(1, $destv->get());
|
||||
|
||||
self::assertException(Exception::class, $destvSetter("a"));
|
||||
self::assertException(Exception::class, $destvSetter([]));
|
||||
self::assertException(Exception::class, $destvSetter(["a"]));
|
||||
}
|
||||
|
||||
function testInt() {
|
||||
/** @var ScalarValue $destv */
|
||||
Schema::nv($destv, $dest, null, $schema, "int");
|
||||
$destvSetter = function($value) use($destv) {
|
||||
return function() use($destv, $value) {
|
||||
$destv->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
self::assertException(Exception::class, $destvSetter(null));
|
||||
self::assertException(Exception::class, $destvSetter(""));
|
||||
self::assertException(Exception::class, $destvSetter(" "));
|
||||
|
||||
// valeur non requise donc retourne null
|
||||
$destv->set(false);
|
||||
self::assertNull($destv->get());
|
||||
|
||||
$this->commonTests($destv, $dest, $destvSetter);
|
||||
}
|
||||
|
||||
function testRequiredInt() {
|
||||
/** @var ScalarValue $destv */
|
||||
Schema::nv($destv, $dest, null, $schema, [
|
||||
"int", null,
|
||||
"required" => true,
|
||||
]);
|
||||
$destvSetter = function($value) use($destv) {
|
||||
return function() use($destv, $value) {
|
||||
$destv->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
self::assertException(Exception::class, $destvSetter(null));
|
||||
self::assertException(Exception::class, $destvSetter(""));
|
||||
self::assertException(Exception::class, $destvSetter(" "));
|
||||
|
||||
// valeur requise donc lance une exception
|
||||
self::assertException(Exception::class, $destvSetter(false));
|
||||
|
||||
$this->commonTests($destv, $dest, $destvSetter);
|
||||
}
|
||||
|
||||
function testNint() {
|
||||
/** @var ScalarValue $destv */
|
||||
Schema::nv($destv, $dest, null, $schema, "?int");
|
||||
$destvSetter = function($value) use($destv) {
|
||||
return function() use($destv, $value) {
|
||||
$destv->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
$destv->set(null);
|
||||
self::assertNull($destv->get());
|
||||
self::assertNull($dest);
|
||||
self::assertSame("", $destv->format());
|
||||
|
||||
$destv->set("");
|
||||
self::assertNull($destv->get());
|
||||
self::assertNull($dest);
|
||||
self::assertSame("", $destv->format());
|
||||
|
||||
$destv->set(" ");
|
||||
self::assertNull($destv->get());
|
||||
self::assertNull($dest);
|
||||
self::assertSame("", $destv->format());
|
||||
|
||||
// valeur non requise donc retourne null
|
||||
$destv->set(false);
|
||||
self::assertNull($destv->get());
|
||||
|
||||
$this->commonTests($destv, $dest, $destvSetter);
|
||||
}
|
||||
|
||||
function testRequiredNint() {
|
||||
/** @var ScalarValue $destv */
|
||||
Schema::nv($destv, $dest, null, $schema, [
|
||||
"?int", null,
|
||||
"required" => true,
|
||||
]);
|
||||
$destvSetter = function($value) use($destv) {
|
||||
return function() use($destv, $value) {
|
||||
$destv->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
$destv->set(null);
|
||||
self::assertNull($destv->get());
|
||||
self::assertNull($dest);
|
||||
self::assertSame("", $destv->format());
|
||||
|
||||
$destv->set("");
|
||||
self::assertNull($destv->get());
|
||||
self::assertNull($dest);
|
||||
self::assertSame("", $destv->format());
|
||||
|
||||
$destv->set(" ");
|
||||
self::assertNull($destv->get());
|
||||
self::assertNull($dest);
|
||||
self::assertSame("", $destv->format());
|
||||
|
||||
// valeur requise donc lance une exception
|
||||
self::assertException(Exception::class, $destvSetter(false));
|
||||
|
||||
$this->commonTests($destv, $dest, $destvSetter);
|
||||
}
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
<?php
|
||||
namespace nur\sery\schema\types;
|
||||
|
||||
use Exception;
|
||||
use nulib\tests\TestCase;
|
||||
use nur\sery\wip\schema\_scalar\ScalarValue;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
|
||||
class strTest extends TestCase {
|
||||
function commonTests($destv, &$dest, callable $destvSetter): void {
|
||||
$destv->set("");
|
||||
self::assertSame("", $destv->get());
|
||||
self::assertSame("", $dest);
|
||||
|
||||
$destv->set(" ");
|
||||
self::assertSame(" ", $destv->get());
|
||||
self::assertSame(" ", $dest);
|
||||
|
||||
$destv->set("a");
|
||||
self::assertSame("a", $destv->get());
|
||||
self::assertSame("a", $dest);
|
||||
|
||||
$destv->set("12");
|
||||
self::assertSame("12", $destv->get());
|
||||
|
||||
$destv->set(" 12 ");
|
||||
self::assertSame(" 12 ", $destv->get());
|
||||
|
||||
$destv->set(12);
|
||||
self::assertSame("12", $destv->get());
|
||||
|
||||
$destv->set(12.34);
|
||||
self::assertSame("12.34", $destv->get());
|
||||
|
||||
$destv->set(true);
|
||||
self::assertSame("1", $destv->get());
|
||||
|
||||
self::assertException(Exception::class, $destvSetter([]));
|
||||
self::assertException(Exception::class, $destvSetter(["a"]));
|
||||
}
|
||||
|
||||
function testStr() {
|
||||
/** @var ScalarValue $destv */
|
||||
Schema::nv($destv, $dest, null, $schema, "string");
|
||||
$destvSetter = function($value) use($destv) {
|
||||
return function() use($destv, $value) {
|
||||
$destv->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
self::assertException(Exception::class, $destvSetter(null));
|
||||
|
||||
// valeur non requise donc retourne null
|
||||
$destv->set(false);
|
||||
self::assertNull($destv->get());
|
||||
|
||||
$this->commonTests($destv, $dest, $destvSetter);
|
||||
}
|
||||
|
||||
function testRequiredStr() {
|
||||
/** @var ScalarValue $destv */
|
||||
Schema::nv($destv, $dest, null, $schema, [
|
||||
"string", null,
|
||||
"required" => true,
|
||||
]);
|
||||
$destvSetter = function($value) use($destv) {
|
||||
return function() use($destv, $value) {
|
||||
$destv->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
self::assertException(Exception::class, $destvSetter(null));
|
||||
|
||||
// valeur requise donc lance une exception
|
||||
self::assertException(Exception::class, $destvSetter(false));
|
||||
|
||||
$this->commonTests($destv, $dest, $destvSetter);
|
||||
}
|
||||
|
||||
function testNstr() {
|
||||
/** @var ScalarValue $destv */
|
||||
Schema::nv($destv, $dest, null, $schema, "?string");
|
||||
$destvSetter = function($value) use($destv) {
|
||||
return function() use($destv, $value) {
|
||||
$destv->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
$destv->set(null);
|
||||
self::assertNull($destv->get());
|
||||
self::assertNull($dest);
|
||||
self::assertSame("", $destv->format());
|
||||
|
||||
// valeur non requise donc retourne null
|
||||
$destv->set(false);
|
||||
self::assertNull($destv->get());
|
||||
|
||||
$this->commonTests($destv, $dest, $destvSetter);
|
||||
}
|
||||
|
||||
function testRequiredNstr() {
|
||||
/** @var ScalarValue $destv */
|
||||
Schema::nv($destv, $dest, null, $schema, [
|
||||
"?string", null,
|
||||
"required" => true,
|
||||
]);
|
||||
$destvSetter = function($value) use($destv) {
|
||||
return function() use($destv, $value) {
|
||||
$destv->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
$destv->set(null);
|
||||
self::assertNull($destv->get());
|
||||
self::assertNull($dest);
|
||||
self::assertSame("", $destv->format());
|
||||
|
||||
// valeur requise donc lance une exception
|
||||
self::assertException(Exception::class, $destvSetter(false));
|
||||
|
||||
$this->commonTests($destv, $dest, $destvSetter);
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
<?php
|
||||
namespace nur\sery\schema\types;
|
||||
|
||||
use nulib\tests\TestCase;
|
||||
use nur\sery\schema\_scalar\ScalarValue;
|
||||
use nur\sery\schema\Schema;
|
||||
|
||||
class unionTest extends TestCase {
|
||||
function testUnionTypes() {
|
||||
## l'ordre des types doit être respecté
|
||||
|
||||
# string puis int
|
||||
/** @var ScalarValue $siv */
|
||||
Schema::nv($siv, $si, null, $sis, "string|int");
|
||||
|
||||
$siv->set("12");
|
||||
self::assertSame("12", $si);
|
||||
$siv->set(12);
|
||||
self::assertSame(12, $si);
|
||||
|
||||
# int puis string
|
||||
Schema::nv($isv, $is, null, $iss, "int|string");
|
||||
|
||||
$isv->set("12");
|
||||
self::assertSame("12", $is);
|
||||
$isv->set(12);
|
||||
self::assertSame(12, $is);
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace nur\sery;
|
||||
|
||||
use nulib\tests\TestCase;
|
||||
|
||||
class strTest extends TestCase {
|
||||
function testCamel2us() {
|
||||
self::assertSame("a", str::camel2us("a"));
|
||||
self::assertSame("aa", str::camel2us("aa"));
|
||||
self::assertSame("aaa", str::camel2us("aaa"));
|
||||
self::assertSame("a", str::camel2us("A"));
|
||||
self::assertSame("aa", str::camel2us("Aa"));
|
||||
self::assertSame("aa", str::camel2us("AA"));
|
||||
self::assertSame("aaa", str::camel2us("Aaa"));
|
||||
self::assertSame("aaa", str::camel2us("AAA"));
|
||||
self::assertSame("a_aa", str::camel2us("AAa"));
|
||||
self::assertSame("a_b", str::camel2us("aB"));
|
||||
self::assertSame("aa_bb", str::camel2us("aaBb"));
|
||||
self::assertSame("aaa_bbb", str::camel2us("aaaBbb"));
|
||||
self::assertSame("aa_bb", str::camel2us("AaBb"));
|
||||
self::assertSame("aaa_bbb", str::camel2us("AaaBbb"));
|
||||
|
||||
self::assertSame("_aaa", str::camel2us("_aaa"));
|
||||
self::assertSame("__aaa_bbb", str::camel2us("__aaaBbb"));
|
||||
self::assertSame("___aaa_bbb", str::camel2us("___AaaBbb"));
|
||||
}
|
||||
}
|
@ -1,200 +0,0 @@
|
||||
<?php
|
||||
namespace nur\sery\web;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class uploadsTest extends TestCase {
|
||||
const _FILES = [
|
||||
# name="simple"
|
||||
'simple' => [
|
||||
'name' => '',
|
||||
'type' => '',
|
||||
'tmp_name' => '',
|
||||
'error' => 4,
|
||||
'size' => 0,
|
||||
],
|
||||
# name=multiple[], name=multiple[]
|
||||
'multiple' => [
|
||||
'name' => [
|
||||
0 => '',
|
||||
1 => '',
|
||||
],
|
||||
'type' => [
|
||||
0 => '',
|
||||
1 => '',
|
||||
],
|
||||
'tmp_name' => [
|
||||
0 => '',
|
||||
1 => '',
|
||||
],
|
||||
'error' => [
|
||||
0 => 4,
|
||||
1 => 4,
|
||||
],
|
||||
'size' => [
|
||||
0 => 0,
|
||||
1 => 0,
|
||||
],
|
||||
],
|
||||
# name=onelevel[a], name=onelevel[b]
|
||||
'onelevel' => [
|
||||
'name' => [
|
||||
'a' => '',
|
||||
'b' => '',
|
||||
],
|
||||
'type' => [
|
||||
'a' => '',
|
||||
'b' => '',
|
||||
],
|
||||
'tmp_name' => [
|
||||
'a' => '',
|
||||
'b' => '',
|
||||
],
|
||||
'error' => [
|
||||
'a' => 4,
|
||||
'b' => 4,
|
||||
],
|
||||
'size' => [
|
||||
'a' => 0,
|
||||
'b' => 0,
|
||||
],
|
||||
],
|
||||
# name=multiplelevel[a][], name=multiplelevel[a][], name=multiplelevel[b][], name=multiplelevel[b][]
|
||||
'multiplelevel' => [
|
||||
'name' => [
|
||||
'a' => [
|
||||
0 => '',
|
||||
1 => '',
|
||||
],
|
||||
'b' => [
|
||||
0 => '',
|
||||
1 => '',
|
||||
],
|
||||
],
|
||||
'type' => [
|
||||
'a' => [
|
||||
0 => '',
|
||||
1 => '',
|
||||
],
|
||||
'b' => [
|
||||
0 => '',
|
||||
1 => '',
|
||||
],
|
||||
],
|
||||
'tmp_name' => [
|
||||
'a' => [
|
||||
0 => '',
|
||||
1 => '',
|
||||
],
|
||||
'b' => [
|
||||
0 => '',
|
||||
1 => '',
|
||||
],
|
||||
],
|
||||
'error' => [
|
||||
'a' => [
|
||||
0 => 4,
|
||||
1 => 4,
|
||||
],
|
||||
'b' => [
|
||||
0 => 4,
|
||||
1 => 4,
|
||||
],
|
||||
],
|
||||
'size' => [
|
||||
'a' => [
|
||||
0 => 0,
|
||||
1 => 0,
|
||||
],
|
||||
'b' => [
|
||||
0 => 0,
|
||||
1 => 0,
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
const PARSED = [
|
||||
# name="simple"
|
||||
'simple' => [
|
||||
'name' => '',
|
||||
'type' => '',
|
||||
'tmp_name' => '',
|
||||
'error' => 4,
|
||||
'size' => 0,
|
||||
],
|
||||
# name=multiple[], name=multiple[]
|
||||
'multiple' => [
|
||||
0 => [
|
||||
'name' => '',
|
||||
'type' => '',
|
||||
'tmp_name' => '',
|
||||
'error' => 4,
|
||||
'size' => 0,
|
||||
],
|
||||
1 => [
|
||||
'name' => '',
|
||||
'type' => '',
|
||||
'tmp_name' => '',
|
||||
'error' => 4,
|
||||
'size' => 0,
|
||||
],
|
||||
],
|
||||
# name=onelevel[a], name=onelevel[b]
|
||||
'onelevel' => [
|
||||
'a' => [
|
||||
'name' => '',
|
||||
'type' => '',
|
||||
'tmp_name' => '',
|
||||
'error' => 4,
|
||||
'size' => 0,
|
||||
],
|
||||
'b' => [
|
||||
'name' => '',
|
||||
'type' => '',
|
||||
'tmp_name' => '',
|
||||
'error' => 4,
|
||||
'size' => 0,
|
||||
],
|
||||
],
|
||||
# name=multiplelevel[a][], name=multiplelevel[a][], name=multiplelevel[b][], name=multiplelevel[b][]
|
||||
'multiplelevel' => [
|
||||
'a' => [
|
||||
0 => [
|
||||
'name' => '',
|
||||
'type' => '',
|
||||
'tmp_name' => '',
|
||||
'error' => 4,
|
||||
'size' => 0,
|
||||
],
|
||||
1 => [
|
||||
'name' => '',
|
||||
'type' => '',
|
||||
'tmp_name' => '',
|
||||
'error' => 4,
|
||||
'size' => 0,
|
||||
],
|
||||
],
|
||||
'b' => [
|
||||
0 => [
|
||||
'name' => '',
|
||||
'type' => '',
|
||||
'tmp_name' => '',
|
||||
'error' => 4,
|
||||
'size' => 0,
|
||||
],
|
||||
1 => [
|
||||
'name' => '',
|
||||
'type' => '',
|
||||
'tmp_name' => '',
|
||||
'error' => 4,
|
||||
'size' => 0,
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
function test_files() {
|
||||
self::assertSame(self::PARSED, uploads::_files(self::_FILES));
|
||||
}
|
||||
}
|
@ -1,8 +1,7 @@
|
||||
<?php
|
||||
namespace nur\sery\php\access;
|
||||
namespace nur\sery\wip\php\access;
|
||||
|
||||
use nulib\tests\TestCase;
|
||||
use nur\sery\wip\php\access\KeyAccess;
|
||||
use stdClass;
|
||||
|
||||
class KeyAccessTest extends TestCase {
|
@ -1,8 +1,7 @@
|
||||
<?php
|
||||
namespace nur\sery\php\access;
|
||||
namespace nur\sery\wip\php\access;
|
||||
|
||||
use nulib\tests\TestCase;
|
||||
use nur\sery\wip\php\access\ValueAccess;
|
||||
use stdClass;
|
||||
|
||||
class ValueAccessTest extends TestCase {
|
@ -13,6 +13,43 @@ class CursorTest extends TestCase {
|
||||
msg::set_messenger(new StdMessenger());
|
||||
}
|
||||
|
||||
function test_map_row() {
|
||||
$cursor = new class extends Cursor {
|
||||
function mapRow(array $row, ?array $map): array {
|
||||
return self::map_row($row, $map);
|
||||
}
|
||||
};
|
||||
$row = ["a" => 1, "b" => 2, "c" => 3, "x" => 99];
|
||||
$map = ["a", "b" => "x", "c" => function() { return "y"; }, "d" => null];
|
||||
self::assertSame([
|
||||
"a" => $row["a"],
|
||||
"b" => $row["x"],
|
||||
"c" => "y",
|
||||
"d" => null
|
||||
], $cursor->mapRow($row, $map));
|
||||
}
|
||||
|
||||
function test_filter_row() {
|
||||
$cursor = new class extends Cursor {
|
||||
function filterRow(array $row, $filter): bool {
|
||||
return self::filter_row($row, $filter);
|
||||
}
|
||||
};
|
||||
$row = ["a" => 1, "b" => 2, "c" => 3, "x" => 99];
|
||||
self::assertTrue($cursor->filterRow($row, "a"));
|
||||
self::assertTrue($cursor->filterRow($row, ["a"]));
|
||||
self::assertTrue($cursor->filterRow($row, ["a" => true]));
|
||||
self::assertFalse($cursor->filterRow($row, ["a" => false]));
|
||||
self::assertTrue($cursor->filterRow($row, ["a" => 1]));
|
||||
self::assertFalse($cursor->filterRow($row, ["a" => 2]));
|
||||
|
||||
self::assertFalse($cursor->filterRow($row, "z"));
|
||||
self::assertFalse($cursor->filterRow($row, ["z"]));
|
||||
self::assertFalse($cursor->filterRow($row, ["z" => true]));
|
||||
self::assertTrue($cursor->filterRow($row, ["z" => false]));
|
||||
self::assertFalse($cursor->filterRow($row, ["z" => 1]));
|
||||
}
|
||||
|
||||
const SCALARS = [0, 1, 2, 3, 4];
|
||||
|
||||
function generator() {
|
||||
@ -41,6 +78,15 @@ class CursorTest extends TestCase {
|
||||
return cl::all($c);
|
||||
});
|
||||
|
||||
$c = new Cursor(null, [
|
||||
"rows" => $this->generator(),
|
||||
]);
|
||||
self::assertSame([[0], [1], [2], [3], [4]], cl::all($c));
|
||||
self::assertException(Exception::class, function() use ($c) {
|
||||
// pas possible de rewind un générateur
|
||||
return cl::all($c);
|
||||
});
|
||||
|
||||
$c = new Cursor(null, [
|
||||
"rows_func" => function() {
|
||||
return self::SCALARS;
|
||||
|
@ -1,7 +1,8 @@
|
||||
<?php
|
||||
namespace nur\sery\php\content;
|
||||
namespace nur\sery\wip\php\content;
|
||||
|
||||
use nur\sery\php\content\impl\html;
|
||||
use nulib\php\content\c;
|
||||
use nur\sery\wip\php\content\impl\html;
|
||||
use nur\sery\wip\web\content\v;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
namespace nur\sery\php\content\impl;
|
||||
namespace nur\sery\wip\php\content\impl;
|
||||
|
||||
use nur\sery\php\content\IContent;
|
||||
use nulib\php\content\IContent;
|
||||
|
||||
class AContent implements IContent {
|
||||
function getContent(): iterable {
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
namespace nur\sery\php\content\impl;
|
||||
namespace nur\sery\wip\php\content\impl;
|
||||
|
||||
use nur\sery\php\content\IPrintable;
|
||||
use nulib\php\content\IPrintable;
|
||||
|
||||
class APrintable implements IPrintable {
|
||||
function print(): void {
|
@ -1,8 +1,8 @@
|
||||
<?php
|
||||
namespace nur\sery\php\content\impl;
|
||||
namespace nur\sery\wip\php\content\impl;
|
||||
|
||||
use nur\sery\php\content\c;
|
||||
use nur\sery\php\content\IContent;
|
||||
use nulib\php\content\c;
|
||||
use nulib\php\content\IContent;
|
||||
|
||||
class ATag implements IContent {
|
||||
function __construct(string $tag, $content=null) {
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
namespace nur\sery\php\content\impl;
|
||||
namespace nur\sery\wip\php\content\impl;
|
||||
|
||||
class html {
|
||||
const H1 = [self::class, "h1"];
|
95
tests/wip/schema/_assoc/AssocSchemaTest.php
Normal file
95
tests/wip/schema/_assoc/AssocSchemaTest.php
Normal file
@ -0,0 +1,95 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\_assoc;
|
||||
|
||||
use nulib\ext\yaml;
|
||||
use nulib\tests\TestCase;
|
||||
use nur\sery\wip\schema\_scalar\ScalarSchemaTest;
|
||||
|
||||
class AssocSchemaTest extends TestCase {
|
||||
const NULL_SCHEMA = [
|
||||
"" => ["assoc"],
|
||||
"schema" => null,
|
||||
"type" => [null],
|
||||
"default" => null,
|
||||
"title" => null,
|
||||
"required" => false,
|
||||
"nullable" => true,
|
||||
"desc" => null,
|
||||
"analyzer_func" => null,
|
||||
"extractor_func" => null,
|
||||
"parser_func" => null,
|
||||
"normalizer_func" => null,
|
||||
"messages" => null,
|
||||
"formatter_func" => null,
|
||||
"format" => null,
|
||||
"name" => null,
|
||||
"pkey" => null,
|
||||
"header" => null,
|
||||
"composite" => null,
|
||||
];
|
||||
|
||||
static function schema(array $definition, array $keyDefinitions): array {
|
||||
$definition = array_merge(self::NULL_SCHEMA, $definition, ["schema" => []]);
|
||||
foreach ($keyDefinitions as $key => $keydef) {
|
||||
$definition["schema"][$key] = array_merge(ScalarSchemaTest::NULL_SCHEMA, $keydef);
|
||||
}; unset($subdef);
|
||||
return $definition;
|
||||
}
|
||||
|
||||
function testNormalize() {
|
||||
self::assertSame(self::schema([
|
||||
"type" => ["array"], "nullable" => true,
|
||||
], [
|
||||
"a" => [
|
||||
"type" => ["string"], "nullable" => false,
|
||||
"name" => "a", "pkey" => "a", "header" => "a",
|
||||
],
|
||||
]), AssocSchema::normalize(["a" => "string"]));
|
||||
|
||||
self::assertSame(self::schema([
|
||||
"type" => ["array"], "nullable" => true,
|
||||
], [
|
||||
"a" => [
|
||||
"type" => ["string"], "nullable" => false,
|
||||
"name" => "a", "pkey" => "a", "header" => "a",
|
||||
],
|
||||
"b" => [
|
||||
"type" => ["int"], "nullable" => false,
|
||||
"name" => "b", "pkey" => "b", "header" => "b",
|
||||
],
|
||||
"c" => [
|
||||
"type" => ["bool"], "nullable" => false,
|
||||
"name" => "c", "pkey" => "c", "header" => "c",
|
||||
],
|
||||
]), AssocSchema::normalize([
|
||||
"a" => "string",
|
||||
"b" => "int",
|
||||
"c" => "bool",
|
||||
]));
|
||||
}
|
||||
|
||||
function testConstructor() {
|
||||
$schema = new AssocSchema([
|
||||
"a" => "string",
|
||||
"b" => "int",
|
||||
"c" => "bool",
|
||||
]);
|
||||
self::assertSame(self::schema([
|
||||
"type" => ["array"], "nullable" => true,
|
||||
], [
|
||||
"a" => [
|
||||
"type" => ["string"], "nullable" => false,
|
||||
"name" => "a", "pkey" => "a", "header" => "a",
|
||||
],
|
||||
"b" => [
|
||||
"type" => ["int"], "nullable" => false,
|
||||
"name" => "b", "pkey" => "b", "header" => "b",
|
||||
],
|
||||
"c" => [
|
||||
"type" => ["bool"], "nullable" => false,
|
||||
"name" => "c", "pkey" => "c", "header" => "c",
|
||||
],
|
||||
]), $schema->getDefinition());
|
||||
yaml::dump($schema->getDefinition());
|
||||
}
|
||||
}
|
@ -1,8 +1,7 @@
|
||||
<?php
|
||||
namespace nur\sery\schema\_scalar;
|
||||
namespace nur\sery\wip\schema\_scalar;
|
||||
|
||||
use nulib\tests\TestCase;
|
||||
use nur\sery\wip\schema\_scalar\ScalarSchema;
|
||||
use nur\sery\wip\schema\SchemaException;
|
||||
|
||||
class ScalarSchemaTest extends TestCase {
|
||||
@ -21,6 +20,7 @@ class ScalarSchemaTest extends TestCase {
|
||||
"formatter_func" => null,
|
||||
"format" => null,
|
||||
"" => ["scalar"],
|
||||
"schema" => null,
|
||||
"name" => null,
|
||||
"pkey" => null,
|
||||
"header" => null,
|
294
tests/wip/schema/_scalar/ScalarWrapperTest.php
Normal file
294
tests/wip/schema/_scalar/ScalarWrapperTest.php
Normal file
@ -0,0 +1,294 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\_scalar;
|
||||
|
||||
use nulib\tests\TestCase;
|
||||
use nulib\ValueException;
|
||||
use nur\sery\wip\schema\input\Input;
|
||||
use stdClass;
|
||||
|
||||
class ScalarWrapperTest extends TestCase {
|
||||
function checkValue(ScalarWrapper $wrapper, $value, bool $present, bool $available, bool $valid, bool $normalized): void {
|
||||
self::assertSame($value, $wrapper->get(), "value");
|
||||
self::assertSame($present, $wrapper->isPresent(), "present");
|
||||
self::assertSame($available, $wrapper->isAvailable(), "available");
|
||||
self::assertSame($valid, $wrapper->isValid(), "valid");
|
||||
self::assertSame($normalized, $wrapper->isNormalized(), "normalized");
|
||||
}
|
||||
|
||||
function checkVerifix(ScalarSchema $schema, $orig, bool $verifix, $value, bool $present, bool $available, bool $valid, bool $normalized, ?array $inputParams=null): void {
|
||||
$wrapper = $schema->getWrapper();
|
||||
if ($inputParams !== null) $input = new Input($orig, $inputParams);
|
||||
else $input = $orig;
|
||||
$wrapper->reset($input, null, $verifix);
|
||||
$this->checkValue($wrapper, $value, $present, $available, $valid, $normalized);
|
||||
}
|
||||
|
||||
function checkException(ScalarSchema $schema, $orig, bool $verifix, string $exceptionClass, ?array $inputParams=null) {
|
||||
$wrapper = $schema->getWrapper();
|
||||
if ($inputParams !== null) $orig = new Input($orig, $inputParams);
|
||||
self::assertException($exceptionClass, function() use ($wrapper, &$orig, $verifix) {
|
||||
$wrapper->reset($orig, null, $verifix);
|
||||
});
|
||||
}
|
||||
|
||||
function testRaw() {
|
||||
$schema = new ScalarSchema();
|
||||
|
||||
$this->checkVerifix($schema, false, false, false, true, true, true, true);
|
||||
$this->checkVerifix($schema, false, true, false, true, true, true, true);
|
||||
|
||||
$this->checkVerifix($schema, null, false, null, true, true, true, true);
|
||||
$this->checkVerifix($schema, null, true, null, true, true, true, true);
|
||||
|
||||
$obj = new stdClass();
|
||||
$this->checkVerifix($schema, $obj, false, $obj, true, true, true, true);
|
||||
$this->checkVerifix($schema, $obj, true, $obj, true, true, true, true);
|
||||
|
||||
$schema = new ScalarSchema("raw");
|
||||
|
||||
$this->checkVerifix($schema, false, false, false, true, true, true, true);
|
||||
$this->checkVerifix($schema, false, true, false, true, true, true, true);
|
||||
|
||||
$this->checkVerifix($schema, null, false, null, true, true, true, true);
|
||||
$this->checkVerifix($schema, null, true, null, true, true, true, true);
|
||||
|
||||
$obj = new stdClass();
|
||||
$this->checkVerifix($schema, $obj, false, $obj, true, true, true, true);
|
||||
$this->checkVerifix($schema, $obj, true, $obj, true, true, true, true);
|
||||
}
|
||||
|
||||
function testMixed() {
|
||||
$schema = new ScalarSchema("mixed");
|
||||
|
||||
$this->checkVerifix($schema, false, false, false, true, true, true, true);
|
||||
$this->checkVerifix($schema, false, true, false, true, true, true, true);
|
||||
|
||||
$this->checkVerifix($schema, null, false, null, true, true, false, false);
|
||||
$this->checkException($schema, null, true, ValueException::class);
|
||||
|
||||
$obj = new stdClass();
|
||||
$this->checkVerifix($schema, $obj, false, $obj, true, true, true, true);
|
||||
$this->checkVerifix($schema, $obj, true, $obj, true, true, true, true);
|
||||
|
||||
$schema = new ScalarSchema("?mixed");
|
||||
|
||||
$this->checkVerifix($schema, false, false, false, true, true, true, true);
|
||||
$this->checkVerifix($schema, false, true, false, true, true, true, true);
|
||||
|
||||
$this->checkVerifix($schema, null, false, null, true, true, true, true);
|
||||
$this->checkVerifix($schema, null, true, null, true, true, true, true);
|
||||
|
||||
$obj = new stdClass();
|
||||
$this->checkVerifix($schema, $obj, false, $obj, true, true, true, true);
|
||||
$this->checkVerifix($schema, $obj, true, $obj, true, true, true, true);
|
||||
}
|
||||
|
||||
function testRawstring() {
|
||||
$schema = new ScalarSchema("rawstring");
|
||||
|
||||
$this->checkVerifix($schema, false, false, null, true, false, true, true);
|
||||
$this->checkVerifix($schema, false, true, null, true, false, true, true);
|
||||
|
||||
$this->checkVerifix($schema, null, false, null, true, true, false, false);
|
||||
$this->checkException($schema, null, true, ValueException::class);
|
||||
|
||||
$this->checkVerifix($schema, "", false, "", true, true, true, true);
|
||||
$this->checkVerifix($schema, "", true, "", true, true, true, true);
|
||||
|
||||
$this->checkVerifix($schema, " ", false, " ", true, true, true, true);
|
||||
$this->checkVerifix($schema, " ", true, " ", true, true, true, true);
|
||||
|
||||
$this->checkVerifix($schema, "text", false, "text", true, true, true, true);
|
||||
$this->checkVerifix($schema, "text", true, "text", true, true, true, true);
|
||||
|
||||
$this->checkVerifix($schema, " text ", false, " text ", true, true, true, true);
|
||||
$this->checkVerifix($schema, " text ", true, " text ", true, true, true, true);
|
||||
|
||||
$this->checkVerifix($schema, true, false, true, true, true, true, false);
|
||||
$this->checkVerifix($schema, true, true, "1", true, true, true, false);
|
||||
|
||||
$this->checkVerifix($schema, 42, false, 42, true, true, true, false);
|
||||
$this->checkVerifix($schema, 42, true, "42", true, true, true, false);
|
||||
|
||||
$this->checkVerifix($schema, [], false, [], true, true, false, false);
|
||||
$this->checkException($schema, [], true, ValueException::class);
|
||||
|
||||
## Tester valeur par défaut
|
||||
$schema = new ScalarSchema(["rawstring", null]);
|
||||
|
||||
$this->checkVerifix($schema, false, false, null, true, false, true, true);
|
||||
$this->checkVerifix($schema, false, true, null, true, false, true, true);
|
||||
|
||||
$this->checkVerifix($schema, null, false, null, true, true, false, false);
|
||||
$this->checkException($schema, null, true, ValueException::class);
|
||||
|
||||
$schema = new ScalarSchema(["rawstring", "default"]);
|
||||
|
||||
$this->checkVerifix($schema, false, false, "default", true, true, true, true);
|
||||
$this->checkVerifix($schema, false, true, "default", true, true, true, true);
|
||||
|
||||
$this->checkVerifix($schema, null, false, null, true, true, false, false);
|
||||
$this->checkException($schema, null, true, ValueException::class);
|
||||
|
||||
## Tester nullable
|
||||
$schema = new ScalarSchema("?rawstring");
|
||||
|
||||
$this->checkVerifix($schema, null, false, null, true, true, true, true);
|
||||
$this->checkVerifix($schema, null, true, null, true, true, true, true);
|
||||
|
||||
## Tester required
|
||||
$schema = new ScalarSchema(["rawstring", "required" => true]);
|
||||
|
||||
$this->checkVerifix($schema, false, false, null, true, false, false, false);
|
||||
$this->checkException($schema, false, true, ValueException::class);
|
||||
|
||||
## Tester allow_empty === false
|
||||
$inputParams = ["allow_empty" => false];
|
||||
$schema = new ScalarSchema("rawstring");
|
||||
|
||||
$this->checkVerifix($schema, null, false, null, true, true, false, false, $inputParams);
|
||||
$this->checkException($schema, null, true, ValueException::class, $inputParams);
|
||||
|
||||
$this->checkVerifix($schema, "", false, null, true, false, true, true, $inputParams);
|
||||
$this->checkVerifix($schema, "", true, null, true, false, true, true, $inputParams);
|
||||
|
||||
$schema = new ScalarSchema("?rawstring");
|
||||
|
||||
$this->checkVerifix($schema, null, false, null, true, true, true, true, $inputParams);
|
||||
$this->checkVerifix($schema, null, true, null, true, true, true, true, $inputParams);
|
||||
|
||||
$this->checkVerifix($schema, "", false, null, true, false, true, true, $inputParams);
|
||||
$this->checkVerifix($schema, "", true, null, true, false, true, true, $inputParams);
|
||||
}
|
||||
|
||||
function testString() {
|
||||
$schema = new ScalarSchema("string");
|
||||
|
||||
$this->checkVerifix($schema, false, false, null, true, false, true, true);
|
||||
$this->checkVerifix($schema, false, true, null, true, false, true, true);
|
||||
|
||||
$this->checkVerifix($schema, null, false, null, true, true, false, false);
|
||||
$this->checkException($schema, null, true, ValueException::class);
|
||||
|
||||
$this->checkVerifix($schema, "", false, "", true, true, true, true);
|
||||
$this->checkVerifix($schema, "", true, "", true, true, true, true);
|
||||
|
||||
$this->checkVerifix($schema, " ", false, "", true, true, true, false);
|
||||
$this->checkVerifix($schema, " ", true, "", true, true, true, false);
|
||||
|
||||
$this->checkVerifix($schema, "text", false, "text", true, true, true, true);
|
||||
$this->checkVerifix($schema, "text", true, "text", true, true, true, true);
|
||||
|
||||
$this->checkVerifix($schema, " text ", false, "text", true, true, true, false);
|
||||
$this->checkVerifix($schema, " text ", true, "text", true, true, true, false);
|
||||
|
||||
$this->checkVerifix($schema, true, false, true, true, true, true, false);
|
||||
$this->checkVerifix($schema, true, true, "1", true, true, true, false);
|
||||
|
||||
$this->checkVerifix($schema, 42, false, 42, true, true, true, false);
|
||||
$this->checkVerifix($schema, 42, true, "42", true, true, true, false);
|
||||
|
||||
$this->checkVerifix($schema, [], false, [], true, true, false, false);
|
||||
$this->checkException($schema, [], true, ValueException::class);
|
||||
|
||||
## Tester nullable
|
||||
$schema = new ScalarSchema("?string");
|
||||
|
||||
$this->checkVerifix($schema, null, false, null, true, true, true, true);
|
||||
$this->checkVerifix($schema, null, true, null, true, true, true, true);
|
||||
|
||||
## Tester required
|
||||
$schema = new ScalarSchema(["string", "required" => true]);
|
||||
|
||||
$this->checkVerifix($schema, false, false, null, true, false, false, false);
|
||||
$this->checkException($schema, false, true, ValueException::class);
|
||||
|
||||
## Tester allow_empty === false
|
||||
$inputParams = ["allow_empty" => false];
|
||||
$schema = new ScalarSchema("string");
|
||||
|
||||
$this->checkVerifix($schema, null, false, null, true, true, false, false, $inputParams);
|
||||
$this->checkException($schema, null, true, ValueException::class, $inputParams);
|
||||
|
||||
$this->checkVerifix($schema, "", false, null, true, false, true, true, $inputParams);
|
||||
$this->checkVerifix($schema, "", true, null, true, false, true, true, $inputParams);
|
||||
|
||||
$schema = new ScalarSchema("?string");
|
||||
|
||||
$this->checkVerifix($schema, null, false, null, true, true, true, true, $inputParams);
|
||||
$this->checkVerifix($schema, null, true, null, true, true, true, true, $inputParams);
|
||||
|
||||
$this->checkVerifix($schema, "", false, null, true, false, true, true, $inputParams);
|
||||
$this->checkVerifix($schema, "", true, null, true, false, true, true, $inputParams);
|
||||
}
|
||||
|
||||
function testInt() {
|
||||
$schema = new ScalarSchema("int");
|
||||
|
||||
$this->checkVerifix($schema, false, false, null, true, false, true, true);
|
||||
$this->checkVerifix($schema, false, true, null, true, false, true, true);
|
||||
|
||||
$this->checkVerifix($schema, null, false, null, true, true, false, false);
|
||||
$this->checkException($schema, null, true, ValueException::class);
|
||||
|
||||
$this->checkVerifix($schema, 42, false, 42, true, true, true, true);
|
||||
$this->checkVerifix($schema, 42, true, 42, true, true, true, true);
|
||||
|
||||
$this->checkVerifix($schema, "42", false, "42", true, true, true, false);
|
||||
$this->checkVerifix($schema, "42", true, 42, true, true, true, false);
|
||||
|
||||
$this->checkVerifix($schema, "42.5", false, "42.5", true, true, true, false);
|
||||
$this->checkVerifix($schema, "42.5", true, 42, true, true, true, false);
|
||||
|
||||
$this->checkVerifix($schema, "42,5", false, "42,5", true, true, true, false);
|
||||
$this->checkVerifix($schema, "42,5", true, 42, true, true, true, false);
|
||||
|
||||
$this->checkVerifix($schema, " 42 ", false, "42", true, true, true, false);
|
||||
$this->checkVerifix($schema, " 42 ", true, 42, true, true, true, false);
|
||||
|
||||
$this->checkVerifix($schema, "", false, "", true, true, false, false);
|
||||
$this->checkException($schema, "", true, ValueException::class);
|
||||
|
||||
$this->checkVerifix($schema, " ", false, " ", true, true, false, false);
|
||||
$this->checkException($schema, " ", true, ValueException::class);
|
||||
|
||||
$this->checkVerifix($schema, "text", false, "text", true, true, false, false);
|
||||
$this->checkException($schema, "text", true, ValueException::class);
|
||||
|
||||
$this->checkVerifix($schema, true, false, true, true, true, true, false);
|
||||
$this->checkVerifix($schema, true, true, 1, true, true, true, false);
|
||||
|
||||
$this->checkVerifix($schema, [], false, [], true, true, false, false);
|
||||
$this->checkException($schema, [], true, ValueException::class);
|
||||
|
||||
## Tester nullable
|
||||
$schema = new ScalarSchema("?int");
|
||||
|
||||
$this->checkVerifix($schema, null, false, null, true, true, true, true);
|
||||
$this->checkVerifix($schema, null, true, null, true, true, true, true);
|
||||
|
||||
## Tester required
|
||||
$schema = new ScalarSchema(["int", "required" => true]);
|
||||
|
||||
$this->checkVerifix($schema, false, false, null, true, false, false, false);
|
||||
$this->checkException($schema, false, true, ValueException::class);
|
||||
|
||||
## Tester allow_empty === false
|
||||
$inputParams = ["allow_empty" => false];
|
||||
$schema = new ScalarSchema("int");
|
||||
|
||||
$this->checkVerifix($schema, null, false, null, true, true, false, false, $inputParams);
|
||||
$this->checkException($schema, null, true, ValueException::class, $inputParams);
|
||||
|
||||
$this->checkVerifix($schema, "", false, null, true, false, true, true, $inputParams);
|
||||
$this->checkVerifix($schema, "", true, null, true, false, true, true, $inputParams);
|
||||
|
||||
$schema = new ScalarSchema("?int");
|
||||
|
||||
$this->checkVerifix($schema, null, false, null, true, true, true, true, $inputParams);
|
||||
$this->checkVerifix($schema, null, true, null, true, true, true, true, $inputParams);
|
||||
|
||||
$this->checkVerifix($schema, "", false, null, true, false, true, true, $inputParams);
|
||||
$this->checkVerifix($schema, "", true, null, true, false, true, true, $inputParams);
|
||||
}
|
||||
}
|
111
tests/wip/schema/types/boolTest.php
Normal file
111
tests/wip/schema/types/boolTest.php
Normal file
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
use Exception;
|
||||
use nulib\tests\TestCase;
|
||||
use nur\sery\wip\schema\_scalar\ScalarWrapper;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
|
||||
class boolTest extends TestCase {
|
||||
function commonTests($wrapper, &$value, callable $wrapperSetter): void {
|
||||
$wrapper->set(true);
|
||||
self::assertSame(true, $wrapper->get());
|
||||
self::assertSame(true, $value);
|
||||
self::assertSame("Oui", $wrapper->format());
|
||||
self::assertSame("Oui", $wrapper->format("OuiNonNull"));
|
||||
self::assertSame("O", $wrapper->format("ON"));
|
||||
self::assertSame("O", $wrapper->format("ONN"));
|
||||
|
||||
$wrapper->set(false);
|
||||
self::assertSame(false, $wrapper->get());
|
||||
self::assertSame(false, $value);
|
||||
self::assertSame("Non", $wrapper->format());
|
||||
self::assertSame("Non", $wrapper->format("OuiNonNull"));
|
||||
self::assertSame("N", $wrapper->format("ON"));
|
||||
self::assertSame("N", $wrapper->format("ONN"));
|
||||
|
||||
$wrapper->set("yes");
|
||||
self::assertSame(true, $wrapper->get());
|
||||
|
||||
$wrapper->set(" yes ");
|
||||
self::assertSame(true, $wrapper->get());
|
||||
|
||||
$wrapper->set("12");
|
||||
self::assertSame(true, $wrapper->get());
|
||||
|
||||
$wrapper->set(12);
|
||||
self::assertSame(true, $wrapper->get());
|
||||
|
||||
$wrapper->set("no");
|
||||
self::assertSame(false, $wrapper->get());
|
||||
|
||||
$wrapper->set(" no ");
|
||||
self::assertSame(false, $wrapper->get());
|
||||
|
||||
$wrapper->set("0");
|
||||
self::assertSame(false, $wrapper->get());
|
||||
|
||||
$wrapper->set(0);
|
||||
self::assertSame(false, $wrapper->get());
|
||||
|
||||
$wrapper->set(12.34);
|
||||
self::assertSame(true, $wrapper->get());
|
||||
|
||||
self::assertException(Exception::class, $wrapperSetter("a"));
|
||||
self::assertException(Exception::class, $wrapperSetter([]));
|
||||
self::assertException(Exception::class, $wrapperSetter(["a"]));
|
||||
|
||||
}
|
||||
|
||||
function testBool() {
|
||||
/** @var ScalarWrapper $wrapper */
|
||||
Schema::nw($value, null, $schema, "bool", $wrapper);
|
||||
$wrapperSetter = function($value) use($wrapper) {
|
||||
return function() use($wrapper, $value) {
|
||||
$wrapper->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
self::assertException(Exception::class, $wrapperSetter(null));
|
||||
self::assertException(Exception::class, $wrapperSetter(""));
|
||||
self::assertException(Exception::class, $wrapperSetter(" "));
|
||||
|
||||
$this->commonTests($wrapper, $value, $wrapperSetter);
|
||||
}
|
||||
|
||||
function testNbool() {
|
||||
/** @var ScalarWrapper $wrapper */
|
||||
Schema::nw($value, null, $schema, "?bool", $wrapper);
|
||||
$wrapperSetter = function($value) use($wrapper) {
|
||||
return function() use($wrapper, $value) {
|
||||
$wrapper->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
$wrapper->set(null);
|
||||
self::assertNull($wrapper->get());
|
||||
self::assertNull($value);
|
||||
self::assertSame("Non", $wrapper->format());
|
||||
self::assertSame("", $wrapper->format("OuiNonNull"));
|
||||
self::assertSame("N", $wrapper->format("ON"));
|
||||
self::assertSame("", $wrapper->format("ONN"));
|
||||
|
||||
$wrapper->set("");
|
||||
self::assertNull($wrapper->get());
|
||||
self::assertNull($value);
|
||||
self::assertSame("Non", $wrapper->format());
|
||||
self::assertSame("", $wrapper->format("OuiNonNull"));
|
||||
self::assertSame("N", $wrapper->format("ON"));
|
||||
self::assertSame("", $wrapper->format("ONN"));
|
||||
|
||||
$wrapper->set(" ");
|
||||
self::assertNull($wrapper->get());
|
||||
self::assertNull($value);
|
||||
self::assertSame("Non", $wrapper->format());
|
||||
self::assertSame("", $wrapper->format("OuiNonNull"));
|
||||
self::assertSame("N", $wrapper->format("ON"));
|
||||
self::assertSame("", $wrapper->format("ONN"));
|
||||
|
||||
$this->commonTests($wrapper, $value, $wrapperSetter);
|
||||
}
|
||||
}
|
139
tests/wip/schema/types/floatTest.php
Normal file
139
tests/wip/schema/types/floatTest.php
Normal file
@ -0,0 +1,139 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
use Exception;
|
||||
use nulib\tests\TestCase;
|
||||
use nur\sery\wip\schema\_scalar\ScalarWrapper;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
|
||||
class floatTest extends TestCase {
|
||||
function commonTests($wrapper, &$value, callable $wrapperSetter): void {
|
||||
$wrapper->set(12);
|
||||
self::assertSame(12.0, $wrapper->get());
|
||||
self::assertSame(12.0, $value);
|
||||
self::assertSame("12", $wrapper->format());
|
||||
self::assertSame("0012", $wrapper->format("%04u"));
|
||||
|
||||
$wrapper->set("12");
|
||||
self::assertSame(12.0, $wrapper->get());
|
||||
|
||||
$wrapper->set(" 12 ");
|
||||
self::assertSame(12.0, $wrapper->get());
|
||||
|
||||
$wrapper->set(12.34);
|
||||
self::assertSame(12.34, $wrapper->get());
|
||||
|
||||
$wrapper->set(true);
|
||||
self::assertSame(1.0, $wrapper->get());
|
||||
|
||||
self::assertException(Exception::class, $wrapperSetter("a"));
|
||||
self::assertException(Exception::class, $wrapperSetter([]));
|
||||
self::assertException(Exception::class, $wrapperSetter(["a"]));
|
||||
}
|
||||
|
||||
function testFloat() {
|
||||
/** @var ScalarWrapper $wrapper */
|
||||
Schema::nw($value, null, $schema, "float", $wrapper);
|
||||
$wrapperSetter = function($value) use($wrapper) {
|
||||
return function() use($wrapper, $value) {
|
||||
$wrapper->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
self::assertException(Exception::class, $wrapperSetter(null));
|
||||
self::assertException(Exception::class, $wrapperSetter(""));
|
||||
self::assertException(Exception::class, $wrapperSetter(" "));
|
||||
|
||||
// valeur non requise donc retourne null
|
||||
$wrapper->set(false);
|
||||
self::assertNull($wrapper->get());
|
||||
|
||||
$this->commonTests($wrapper, $value, $wrapperSetter);
|
||||
}
|
||||
|
||||
function testRequiredFloat() {
|
||||
/** @var ScalarWrapper $wrapper */
|
||||
Schema::nw($value, null, $schema, [
|
||||
"float", null,
|
||||
"required" => true,
|
||||
], $wrapper);
|
||||
$wrapperSetter = function($value) use($wrapper) {
|
||||
return function() use($wrapper, $value) {
|
||||
$wrapper->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
self::assertException(Exception::class, $wrapperSetter(null));
|
||||
self::assertException(Exception::class, $wrapperSetter(""));
|
||||
self::assertException(Exception::class, $wrapperSetter(" "));
|
||||
|
||||
// valeur requise donc lance une exception
|
||||
self::assertException(Exception::class, $wrapperSetter(false));
|
||||
|
||||
$this->commonTests($wrapper, $value, $wrapperSetter);
|
||||
}
|
||||
|
||||
function testNfloat() {
|
||||
/** @var ScalarWrapper $wrapper */
|
||||
Schema::nw($value, null, $schema, "?float", $wrapper);
|
||||
$wrapperSetter = function($value) use($wrapper) {
|
||||
return function() use($wrapper, $value) {
|
||||
$wrapper->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
$wrapper->set(null);
|
||||
self::assertNull($wrapper->get());
|
||||
self::assertNull($value);
|
||||
self::assertSame("", $wrapper->format());
|
||||
|
||||
$wrapper->set("");
|
||||
self::assertNull($wrapper->get());
|
||||
self::assertNull($value);
|
||||
self::assertSame("", $wrapper->format());
|
||||
|
||||
$wrapper->set(" ");
|
||||
self::assertNull($wrapper->get());
|
||||
self::assertNull($value);
|
||||
self::assertSame("", $wrapper->format());
|
||||
|
||||
// valeur non requise donc retourne null
|
||||
$wrapper->set(false);
|
||||
self::assertNull($wrapper->get());
|
||||
|
||||
$this->commonTests($wrapper, $value, $wrapperSetter);
|
||||
}
|
||||
|
||||
function testRequiredNfloat() {
|
||||
/** @var ScalarWrapper $wrapper */
|
||||
Schema::nw($value, null, $schema, [
|
||||
"?float", null,
|
||||
"required" => true,
|
||||
], $wrapper);
|
||||
$wrapperSetter = function($value) use($wrapper) {
|
||||
return function() use($wrapper, $value) {
|
||||
$wrapper->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
$wrapper->set(null);
|
||||
self::assertNull($wrapper->get());
|
||||
self::assertNull($value);
|
||||
self::assertSame("", $wrapper->format());
|
||||
|
||||
$wrapper->set("");
|
||||
self::assertNull($wrapper->get());
|
||||
self::assertNull($value);
|
||||
self::assertSame("", $wrapper->format());
|
||||
|
||||
$wrapper->set(" ");
|
||||
self::assertNull($wrapper->get());
|
||||
self::assertNull($value);
|
||||
self::assertSame("", $wrapper->format());
|
||||
|
||||
// valeur requise donc lance une exception
|
||||
self::assertException(Exception::class, $wrapperSetter(false));
|
||||
|
||||
$this->commonTests($wrapper, $value, $wrapperSetter);
|
||||
}
|
||||
}
|
139
tests/wip/schema/types/intTest.php
Normal file
139
tests/wip/schema/types/intTest.php
Normal file
@ -0,0 +1,139 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
use Exception;
|
||||
use nulib\tests\TestCase;
|
||||
use nur\sery\wip\schema\_scalar\ScalarWrapper;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
|
||||
class intTest extends TestCase {
|
||||
function commonTests($wrapper, &$value, callable $wrapperSetter): void {
|
||||
$wrapper->set(12);
|
||||
self::assertSame(12, $wrapper->get());
|
||||
self::assertSame(12, $value);
|
||||
self::assertSame("12", $wrapper->format());
|
||||
self::assertSame("0012", $wrapper->format("%04u"));
|
||||
|
||||
$wrapper->set("12");
|
||||
self::assertSame(12, $wrapper->get());
|
||||
|
||||
$wrapper->set(" 12 ");
|
||||
self::assertSame(12, $wrapper->get());
|
||||
|
||||
$wrapper->set(12.34);
|
||||
self::assertSame(12, $wrapper->get());
|
||||
|
||||
$wrapper->set(true);
|
||||
self::assertSame(1, $wrapper->get());
|
||||
|
||||
self::assertException(Exception::class, $wrapperSetter("a"));
|
||||
self::assertException(Exception::class, $wrapperSetter([]));
|
||||
self::assertException(Exception::class, $wrapperSetter(["a"]));
|
||||
}
|
||||
|
||||
function testInt() {
|
||||
/** @var ScalarWrapper $wrapper */
|
||||
Schema::nw($value, null, $schema, "int", $wrapper);
|
||||
$wrapperSetter = function($value) use($wrapper) {
|
||||
return function() use($wrapper, $value) {
|
||||
$wrapper->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
self::assertException(Exception::class, $wrapperSetter(null));
|
||||
self::assertException(Exception::class, $wrapperSetter(""));
|
||||
self::assertException(Exception::class, $wrapperSetter(" "));
|
||||
|
||||
// valeur non requise donc retourne null
|
||||
$wrapper->set(false);
|
||||
self::assertNull($wrapper->get());
|
||||
|
||||
$this->commonTests($wrapper, $value, $wrapperSetter);
|
||||
}
|
||||
|
||||
function testRequiredInt() {
|
||||
/** @var ScalarWrapper $wrapper */
|
||||
Schema::nw($value, null, $schema, [
|
||||
"int", null,
|
||||
"required" => true,
|
||||
], $wrapper);
|
||||
$wrapperSetter = function($value) use($wrapper) {
|
||||
return function() use($wrapper, $value) {
|
||||
$wrapper->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
self::assertException(Exception::class, $wrapperSetter(null));
|
||||
self::assertException(Exception::class, $wrapperSetter(""));
|
||||
self::assertException(Exception::class, $wrapperSetter(" "));
|
||||
|
||||
// valeur requise donc lance une exception
|
||||
self::assertException(Exception::class, $wrapperSetter(false));
|
||||
|
||||
$this->commonTests($wrapper, $value, $wrapperSetter);
|
||||
}
|
||||
|
||||
function testNint() {
|
||||
/** @var ScalarWrapper $wrapper */
|
||||
Schema::nw($value, null, $schema, "?int", $wrapper);
|
||||
$wrapperSetter = function($value) use($wrapper) {
|
||||
return function() use($wrapper, $value) {
|
||||
$wrapper->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
$wrapper->set(null);
|
||||
self::assertNull($wrapper->get());
|
||||
self::assertNull($value);
|
||||
self::assertSame("", $wrapper->format());
|
||||
|
||||
$wrapper->set("");
|
||||
self::assertNull($wrapper->get());
|
||||
self::assertNull($value);
|
||||
self::assertSame("", $wrapper->format());
|
||||
|
||||
$wrapper->set(" ");
|
||||
self::assertNull($wrapper->get());
|
||||
self::assertNull($value);
|
||||
self::assertSame("", $wrapper->format());
|
||||
|
||||
// valeur non requise donc retourne null
|
||||
$wrapper->set(false);
|
||||
self::assertNull($wrapper->get());
|
||||
|
||||
$this->commonTests($wrapper, $value, $wrapperSetter);
|
||||
}
|
||||
|
||||
function testRequiredNint() {
|
||||
/** @var ScalarWrapper $wrapper */
|
||||
Schema::nw($value, null, $schema, [
|
||||
"?int", null,
|
||||
"required" => true,
|
||||
], $wrapper);
|
||||
$wrapperSetter = function($value) use($wrapper) {
|
||||
return function() use($wrapper, $value) {
|
||||
$wrapper->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
$wrapper->set(null);
|
||||
self::assertNull($wrapper->get());
|
||||
self::assertNull($value);
|
||||
self::assertSame("", $wrapper->format());
|
||||
|
||||
$wrapper->set("");
|
||||
self::assertNull($wrapper->get());
|
||||
self::assertNull($value);
|
||||
self::assertSame("", $wrapper->format());
|
||||
|
||||
$wrapper->set(" ");
|
||||
self::assertNull($wrapper->get());
|
||||
self::assertNull($value);
|
||||
self::assertSame("", $wrapper->format());
|
||||
|
||||
// valeur requise donc lance une exception
|
||||
self::assertException(Exception::class, $wrapperSetter(false));
|
||||
|
||||
$this->commonTests($wrapper, $value, $wrapperSetter);
|
||||
}
|
||||
}
|
123
tests/wip/schema/types/strTest.php
Normal file
123
tests/wip/schema/types/strTest.php
Normal file
@ -0,0 +1,123 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
use Exception;
|
||||
use nulib\tests\TestCase;
|
||||
use nur\sery\wip\schema\_scalar\ScalarWrapper;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
|
||||
class strTest extends TestCase {
|
||||
function commonTests($wrapper, &$value, callable $wrapperSetter): void {
|
||||
$wrapper->set("");
|
||||
self::assertSame("", $wrapper->get());
|
||||
self::assertSame("", $value);
|
||||
|
||||
$wrapper->set(" ");
|
||||
self::assertSame("", $wrapper->get());
|
||||
self::assertSame("", $value);
|
||||
|
||||
$wrapper->set("a");
|
||||
self::assertSame("a", $wrapper->get());
|
||||
self::assertSame("a", $value);
|
||||
|
||||
$wrapper->set("12");
|
||||
self::assertSame("12", $wrapper->get());
|
||||
|
||||
$wrapper->set(" 12 ");
|
||||
self::assertSame("12", $wrapper->get());
|
||||
|
||||
$wrapper->set(12);
|
||||
self::assertSame("12", $wrapper->get());
|
||||
|
||||
$wrapper->set(12.34);
|
||||
self::assertSame("12.34", $wrapper->get());
|
||||
|
||||
$wrapper->set(true);
|
||||
self::assertSame("1", $wrapper->get());
|
||||
|
||||
self::assertException(Exception::class, $wrapperSetter([]));
|
||||
self::assertException(Exception::class, $wrapperSetter(["a"]));
|
||||
}
|
||||
|
||||
function testStr() {
|
||||
/** @var ScalarWrapper $wrapper */
|
||||
Schema::nw($value, null, $schema, "string", $wrapper);
|
||||
$wrapperSetter = function($value) use($wrapper) {
|
||||
return function() use($wrapper, $value) {
|
||||
$wrapper->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
self::assertException(Exception::class, $wrapperSetter(null));
|
||||
|
||||
// valeur non requise donc retourne null
|
||||
$wrapper->set(false);
|
||||
self::assertNull($wrapper->get());
|
||||
|
||||
$this->commonTests($wrapper, $value, $wrapperSetter);
|
||||
}
|
||||
|
||||
function testRequiredStr() {
|
||||
/** @var ScalarWrapper $wrapper */
|
||||
Schema::nw($value, null, $schema, [
|
||||
"string", null,
|
||||
"required" => true,
|
||||
], $wrapper);
|
||||
$wrapperSetter = function($value) use($wrapper) {
|
||||
return function() use($wrapper, $value) {
|
||||
$wrapper->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
self::assertException(Exception::class, $wrapperSetter(null));
|
||||
|
||||
// valeur requise donc lance une exception
|
||||
self::assertException(Exception::class, $wrapperSetter(false));
|
||||
|
||||
$this->commonTests($wrapper, $value, $wrapperSetter);
|
||||
}
|
||||
|
||||
function testNstr() {
|
||||
/** @var ScalarWrapper $wrapper */
|
||||
Schema::nw($value, null, $schema, "?string", $wrapper);
|
||||
$wrapperSetter = function($value) use($wrapper) {
|
||||
return function() use($wrapper, $value) {
|
||||
$wrapper->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
$wrapper->set(null);
|
||||
self::assertNull($wrapper->get());
|
||||
self::assertNull($value);
|
||||
self::assertSame("", $wrapper->format());
|
||||
|
||||
// valeur non requise donc retourne null
|
||||
$wrapper->set(false);
|
||||
self::assertNull($wrapper->get());
|
||||
|
||||
$this->commonTests($wrapper, $value, $wrapperSetter);
|
||||
}
|
||||
|
||||
function testRequiredNstr() {
|
||||
/** @var ScalarWrapper $wrapper */
|
||||
Schema::nw($value, null, $schema, [
|
||||
"?string", null,
|
||||
"required" => true,
|
||||
], $wrapper);
|
||||
$wrapperSetter = function($value) use($wrapper) {
|
||||
return function() use($wrapper, $value) {
|
||||
$wrapper->set($value);
|
||||
};
|
||||
};
|
||||
|
||||
$wrapper->set(null);
|
||||
self::assertNull($wrapper->get());
|
||||
self::assertNull($value);
|
||||
self::assertSame("", $wrapper->format());
|
||||
|
||||
// valeur requise donc lance une exception
|
||||
self::assertException(Exception::class, $wrapperSetter(false));
|
||||
|
||||
$this->commonTests($wrapper, $value, $wrapperSetter);
|
||||
}
|
||||
}
|
30
tests/wip/schema/types/unionTest.php
Normal file
30
tests/wip/schema/types/unionTest.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
namespace nur\sery\wip\schema\types;
|
||||
|
||||
use nulib\tests\TestCase;
|
||||
use nur\sery\wip\schema\_scalar\ScalarWrapper;
|
||||
use nur\sery\wip\schema\Schema;
|
||||
|
||||
class unionTest extends TestCase {
|
||||
function testUnionTypes() {
|
||||
## l'ordre des types doit être respecté
|
||||
|
||||
# string puis int
|
||||
/** @var ScalarWrapper $siw */
|
||||
Schema::nw($si, null, $sis, "string|int", $siw);
|
||||
|
||||
$siw->set("12");
|
||||
self::assertSame("12", $si);
|
||||
$siw->set(12);
|
||||
self::assertSame(12, $si);
|
||||
|
||||
# int puis string
|
||||
/** @var ScalarWrapper $isw */
|
||||
Schema::nw($is, null, $iss, "int|string", $isw);
|
||||
|
||||
$isw->set("12");
|
||||
self::assertSame("12", $is);
|
||||
$isw->set(12);
|
||||
self::assertSame(12, $is);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user