Compare commits

...

45 Commits

Author SHA1 Message Date
68f5dc5209 modifs.mineures sans commentaires 2025-04-10 00:27:05 +04:00
f005692cd8 déplacer nur/sery/wip et nur/sery dans nulib 2025-04-04 06:35:07 +04:00
d844bd03ad modifs.mineures sans commentaires 2025-04-02 22:21:16 +04:00
c4e02d5bcf afficher la version de l'application 2025-04-02 18:06:51 +04:00
2a92a9a07e modifs.mineures sans commentaires 2025-03-28 16:17:12 +04:00
c274adb6e6 modifs.mineures sans commentaires 2025-03-28 15:38:57 +04:00
ff02ffdf4f modifs.mineures sans commentaires 2025-03-27 15:58:47 +04:00
9109e0fe39 modifs.mineures sans commentaires 2025-03-24 13:46:51 +04:00
fd1ebaf611 modifs.mineures sans commentaires 2025-03-23 08:19:20 +04:00
26817d2826 modifs.mineures sans commentaires 2025-03-23 08:06:40 +04:00
7257654753 modifs.mineures sans commentaires 2025-03-22 16:42:42 +04:00
e2bec38540 modifs.mineures sans commentaires 2025-03-21 07:45:22 +04:00
c2ec23be30 modifs.mineures sans commentaires 2025-03-20 09:57:07 +04:00
741a807420 modifs.mineures sans commentaires 2025-03-20 09:38:01 +04:00
e9f4826a94 modifs.mineures sans commentaires 2025-03-20 09:36:01 +04:00
fd9b3b29bc modifs.mineures sans commentaires 2025-03-20 08:41:31 +04:00
f37a53cfbd modifs.mineures sans commentaires 2025-03-20 08:01:50 +04:00
6e8245dbcb modifs.mineures sans commentaires 2025-03-19 20:34:46 +04:00
f4e252a6e0 modifs.mineures sans commentaires 2025-03-19 19:32:27 +04:00
19f6f9c9e1 modifs.mineures sans commentaires 2025-03-19 18:31:49 +04:00
baa770d969 modifs.mineures sans commentaires 2025-03-19 17:05:26 +04:00
c5bfa3940c modifs.mineures sans commentaires 2025-03-19 17:03:12 +04:00
39af99ffa4 modifs.mineures sans commentaires 2025-03-19 16:56:36 +04:00
1fc4e7637b modifs.mineures sans commentaires 2025-03-19 16:10:26 +04:00
ef7e8551aa modifs.mineures sans commentaires 2025-03-19 13:49:36 +04:00
9328aac9e9 modifs.mineures sans commentaires 2025-03-19 10:06:53 +04:00
62fc315b9e modifs.mineures sans commentaires 2025-03-19 08:37:17 +04:00
b9e91bd917 modifs.mineures sans commentaires 2025-03-19 07:18:41 +04:00
3608b02749 modifs.mineures sans commentaires 2025-03-19 06:38:19 +04:00
d148850c12 modifs.mineures sans commentaires 2025-03-18 17:37:55 +04:00
189c7aba68 modifs.mineures sans commentaires 2025-03-18 13:30:02 +04:00
91e6c0dcd2 modifs.mineures sans commentaires 2025-03-18 10:48:50 +04:00
bb311708d7 modifs.mineures sans commentaires 2025-03-18 10:43:43 +04:00
1feffb6c0f modifs.mineures sans commentaires 2025-03-18 10:35:28 +04:00
62987d576e <pman>Init changelog & version 0.4.1p82 2025-03-17 17:24:49 +04:00
5decd631e2 <pman>deps de dev 2025-03-17 17:20:12 +04:00
c98afaa98c <pman>Intégration de la branche rel74-0.4.1 2025-03-17 17:20:07 +04:00
3994855c7e <pman>deps de dist 2025-03-17 17:20:07 +04:00
6ba0a16e84 <pman>Init changelog & version 0.4.1p74 2025-03-17 17:20:02 +04:00
56fda96c78 changer le type de variables gérées par EnvConfig 2025-03-17 16:34:29 +04:00
d6078e8b52 modifs.mineures sans commentaires 2025-03-17 13:56:32 +04:00
69203352d8 modifs.mineures sans commentaires 2025-03-17 11:43:05 +04:00
26b483a29f modifs.mineures sans commentaires 2025-03-17 10:49:25 +04:00
6e93c7da62 modifs.mineures sans commentaires 2025-03-16 18:02:08 +04:00
66397a3bd0 <pman>Init changelog & version 0.4.0p82 2025-03-14 15:47:20 +04:00
103 changed files with 2921 additions and 1687 deletions

6
.idea/nur-ture.iml generated
View File

@ -4,10 +4,8 @@
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/nur_src" isTestSource="false" packagePrefix="nur\" />
<sourceFolder url="file://$MODULE_DIR$/nur_tests" isTestSource="true" packagePrefix="nur\" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="nur\sery\wip\" />
<sourceFolder url="file://$MODULE_DIR$/src_app" isTestSource="false" packagePrefix="nur\sery\" />
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" packagePrefix="nur\sery\" />
<sourceFolder url="file://$MODULE_DIR$/src_glue" isTestSource="false" packagePrefix="nulib\" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="nulib\" />
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" packagePrefix="nulib\" />
<excludeFolder url="file://$MODULE_DIR$/vendor" />
</content>
<orderEntry type="inheritedJdk" />

View File

@ -1,3 +1,11 @@
## Release 0.4.1p82 du 17/03/2025-17:23
## Release 0.4.1p74 du 17/03/2025-17:19
* `56fda96` changer le type de variables gérées par EnvConfig
## Release 0.4.0p82 du 14/03/2025-15:46
## Release 0.4.0p74 du 14/03/2025-15:44
* `4b84f11` début assocSchema

View File

@ -1 +1 @@
0.4.0
0.4.1

View File

@ -64,9 +64,7 @@
},
"autoload": {
"psr-4": {
"nulib\\": "src_glue",
"nur\\sery\\wip\\": "src",
"nur\\sery\\": "src_app",
"nulib\\": "src",
"nur\\": "nur_src"
},
"files": [
@ -75,7 +73,7 @@
},
"autoload-dev": {
"psr-4": {
"nur\\sery\\": "tests",
"nulib\\": "tests",
"nur\\": "nur_tests"
}
},

2
composer.lock generated
View File

@ -589,7 +589,7 @@
"dist": {
"type": "path",
"url": "../nulib",
"reference": "927915093af5196099ae26645c07e90ddf1b2330"
"reference": "1536e091fb0020858204f59462a7a80b5f9775d9"
},
"require": {
"ext-json": "*",

View File

@ -2,6 +2,6 @@
<?php
require $_composer_autoload_path?? __DIR__.'/../vendor/autoload.php';
use nur\sery\tools\SteamTrainApp;
use nulib\tools\SteamTrainApp;
SteamTrainApp::run();

View File

@ -2,6 +2,7 @@
namespace nur\cli;
use Exception;
use nulib\app;
use nulib\app\RunFile;
use nulib\ExitError;
use nulib\ext\yaml;
@ -16,7 +17,6 @@ use nur\config\ArrayConfig;
use nur\msg;
use nur\os;
use nur\path;
use nur\sery\app;
/**
* Class Application: application de base

View File

@ -15,10 +15,9 @@ use Throwable;
* profil par défaut est dépendant de l'implémentation de IConfigManager
* utilisée. Dans l'implémentation actuelle, 'ALL' est le profil par défaut.
* - PKEY est le chemin de clé dans lequel les caractères '.' sont remplacés
* par '__' et '-' par '_' (celà signifie qu'il n'est pas possible de définir
* un chemin de clé qui contient le caractère '_')
* par '__'
*
* par exemple, la valeur dbs.my-auth.type du profil par défaut est pris dans
* par exemple, la valeur dbs.my_auth.type du profil par défaut est pris dans
* la variable 'CONFIG_ALL_dbs__my_auth__type'. pour le profil prod c'est la
* variable 'CONFIG_prod_dbs__my_auth__type'
*
@ -51,7 +50,9 @@ class EnvConfig extends DynConfig {
$profile = substr($name, 0, $i);
$name = substr($name, $i + 1);
$pkey = str_replace("__", ".", $name);
$pkey = str_replace("_", "-", $pkey);
#XXX désactiver parce que les configurations sont plus généralement avec
# le caractères '_', par le caractères '-'
//$pkey = str_replace("_", "-", $pkey);
return [$pkey, $profile];
}

View File

@ -105,7 +105,7 @@ class ref_type {
/** comme {@link c} mais nullable */
const NCONTENT = "?".self::CONTENT;
/** comme {@link \nur\sery\FILE} mais nullable */
/** comme {@link FILE} mais nullable */
const NFILE = "?".self::FILE;
/** comme {@link DATETIME} mais nullable */

View File

@ -32,6 +32,7 @@ class nb {
}
static final function menu($text, ?array $links=null, ?array $options=null): array {
$links = array_filter($links, function($link) { return $link !== null; });
$item = ["item" => "menu", "links" => $links, "value" => $text];
if ($options !== null) $item = array_merge($item, $options);
return $item;

View File

@ -1,6 +1,7 @@
<?php
namespace nur\v\vp;
use nulib\app;
use nur\authz;
use nur\b\authnz\IAuthzUser;
use nur\config;
@ -46,6 +47,21 @@ class NavigablePage extends AInitAuthzPage implements INavigablePage {
const MENU_SULOGIN = true;
protected function getAppVersionNbtext(): ?array {
$app = app::get();
$projdir = $app->getProjdir();
$versionfile = "$projdir/VERSION.txt";
if (file_exists($versionfile)) {
$name = $app->getName();
$version = file_get_contents($versionfile);
return nb::text([
"style" => "margin: 0 15px",
"$name v$version"
]);
}
return null;
}
protected function getAuthzNbtext(IAuthzUser $user): array {
$username = $user->getUsername();
$role = $user->getRole();
@ -95,6 +111,7 @@ class NavigablePage extends AInitAuthzPage implements INavigablePage {
$user = authz::get();
navbar::nav(["align" => "right"], [
nb::menu(icon::user($user->getShortName()), [
$this->getAppVersionNbtext(),
$this->getAuthzNbtext($user),
$this->getLogoutNblink(),
]),

View File

@ -2,7 +2,7 @@
require(__DIR__.'/../../vendor/autoload.php');
use nur\cli\Application;
use nur\sery\output\msg;
use nulib\output\msg;
class TestArgs4 extends Application {
protected $query;

View File

@ -1,5 +1,5 @@
<?php
namespace nur\sery;
namespace nulib;
use nulib\A;
use nulib\app\LockFile;
@ -12,7 +12,7 @@ use nulib\php\func;
use nulib\str;
use nulib\ValueException;
use nur\cli\Application as nur_Application;
use nur\sery\app\cli\Application;
use nulib\app\cli\Application;
class app {
private static function isa_Application($app): bool {

View File

@ -1,5 +1,5 @@
<?php
namespace nur\sery\app\cli;
namespace nulib\app\cli;
use Exception;
use nulib\app\RunFile;
@ -13,7 +13,7 @@ use nulib\ValueException;
use nur\cli\ArgsException;
use nur\cli\ArgsParser;
use nur\config;
use nur\sery\app;
use nulib\app;
/**
* Class Application: application de base

View File

@ -1,5 +1,5 @@
<?php
namespace nur\sery\wip\php\access;
namespace nulib\php\access;
use nulib\cl;
@ -8,6 +8,18 @@ use nulib\cl;
* de {@link IAccess}
*/
abstract class AbstractAccess implements IAccess {
const ALLOW_EMPTY = true;
function __construct(?array $params=null) {
$this->allowEmpty = $params["allow_empty"] ?? static::ALLOW_EMPTY;
}
protected bool $allowEmpty;
function isAllowEmpty(): bool {
return $this->allowEmpty;
}
function inc(): int {
$value = (int)$this->get();
$this->set(++$value);
@ -33,4 +45,13 @@ abstract class AbstractAccess implements IAccess {
cl::set($array, $key, $value);
$this->set($array);
}
function ensureAssoc(array $keys, ?array $params=null): void {
}
function ensureKeys(array $defaults, ?array $params=null): void {
}
function ensureOrder(array $keys, ?array $params=null): void {
}
}

View File

@ -0,0 +1,8 @@
<?php
namespace nulib\php\access;
class ArrayAccess extends KeyAccess {
const ALLOW_NULL = true;
const ALLOW_FALSE = false;
const PROTECT_DEST = true;
}

View File

@ -0,0 +1,182 @@
<?php
namespace nulib\php\access;
use nulib\cl;
use nulib\StateException;
use ReflectionClass;
use ReflectionException;
class ChainAccess extends AbstractAccess {
const ACCESS_AUTO = 0, ACCESS_KEY = 1, ACCESS_PROPERTY = 2;
private static function unexpected_access_type(): StateException {
return StateException::unexpected_state("access_type");
}
function __construct(IAccess $access, $key, ?array $params=null) {
parent::__construct();
$this->access = $access;
$this->key = $key;
$this->accessType = $params["access_type"] ?? self::ACCESS_AUTO;
}
protected IAccess $access;
/** @var null|int|string|array */
protected $key;
protected int $accessType;
protected function _accessType($access, $key): int {
$accessType = $this->accessType;
if ($accessType === self::ACCESS_AUTO) {
if (is_object($access) && is_string($key)) {
$accessType = self::ACCESS_PROPERTY;
} else {
$accessType = self::ACCESS_KEY;
}
}
return $accessType;
}
protected function _has(): bool {
$src = $this->access->get();
$key = $this->key;
$accessType = $this->_accessType($src, $key);
if ($accessType === self::ACCESS_KEY) {
return cl::phas($src, $key);
} elseif ($accessType === self::ACCESS_PROPERTY) {
$class = new ReflectionClass($src);
return $class->hasProperty($key) || property_exists($src, $key);
} else {
throw self::unexpected_access_type();
}
}
protected function _get($default=null) {
$src = $this->access->get();
$key = $this->key;
$accessType = $this->_accessType($src, $key);
if ($accessType === self::ACCESS_KEY) {
return cl::pget($src, $key);
} elseif ($accessType === self::ACCESS_PROPERTY) {
$class = new ReflectionClass($src);
try {
$property = $class->getProperty($key);
$property->setAccessible(true);
} catch (ReflectionException $e) {
$property = null;
}
if ($property !== null) {
return $property->getValue($src);
} elseif (property_exists($src, $key)) {
return $src->$key;
} else {
return $default;
}
} else {
throw self::unexpected_access_type();
}
}
protected function _pset(object $dest, $name, $value): void {
$class = new ReflectionClass($dest);
try {
$property = $class->getProperty($name);
$property->setAccessible(true);
} catch (ReflectionException $e) {
$property = null;
}
if ($property !== null) {
$property->setValue($dest, $value);
} else {
$dest->$name = $value;
}
}
function isAllowEmpty(): bool {
return $this->access->isAllowEmpty();
}
function exists(): bool {
if (!$this->access->exists()) return false;
if ($this->key === null) return true;
return $this->_has();
}
function available(): bool {
if (!$this->access->available()) return false;
if ($this->key === null) return true;
if (!$this->_has()) return false;
return $this->isAllowEmpty() || $this->_get() !== "";
}
function get($default=null) {
if ($this->key === null) {
return $this->access->get($default);
}
return $this->_get($default);
}
function set($value): void {
if ($this->key === null) {
$this->access->set($value);
return;
}
$dest = $this->access->get();
$key = $this->key;
$accessType = $this->_accessType($dest, $key);
if ($accessType === self::ACCESS_KEY) {
cl::pset($dest, $key, $value);
$this->access->set($dest);
} elseif ($accessType === self::ACCESS_PROPERTY) {
$this->_pset($dest, $key, $value);
} else {
throw self::unexpected_access_type();
}
}
function del(): void {
if ($this->key === null) {
$this->access->del();
return;
}
$dest = $this->access->get();
$key = $this->key;
$accessType = $this->_accessType($dest, $key);
if ($accessType === self::ACCESS_KEY) {
cl::pdel($dest, $key);
$this->access->set($dest);
} elseif ($accessType === self::ACCESS_PROPERTY) {
$this->_pset($dest, $key, null);
} else {
throw self::unexpected_access_type();
}
}
function addKey($key, ?array $params=null): IAccess {
if ($key === null) return $this;
$accessType = $params["access_type"] ?? $this->accessType;
if ($accessType === self::ACCESS_KEY && $accessType === $this->accessType) {
if ($this->key !== null) $key = cl::merge($this->key, $key);
return new ChainAccess($this->access, $key);
} else {
return new ChainAccess($this, $key);
}
}
function ensureAssoc(array $keys, ?array $params=null): void {
#XXX fonction de $accessType?
#$this->access->ensureAssoc($keys, $params);
}
function ensureKeys(array $defaults, ?array $params=null): void {
#XXX fonction de $accessType?
#$this->access->ensureKeys($defaults, $params);
}
function ensureOrder(array $keys, ?array $params=null): void {
#XXX fonction de $accessType?
#$this->access->ensureOrder($keys, $params);
}
}

View File

@ -1,5 +1,5 @@
<?php
namespace nur\sery\wip\php\access;
namespace nulib\php\access;
use nulib\cl;
@ -7,67 +7,99 @@ use nulib\cl;
* Class FormAccess: accès à une valeur de $_POST puis $_GET, dans cet ordre
*/
class FormAccess extends AbstractAccess {
const ALLOW_EMPTY = false;
function __construct($key, ?array $params=null) {
parent::__construct($params);
$this->key = $key;
$this->allowEmpty = $params["allow_empty"] ?? false;
}
/** @var int|string */
/** @var null|int|string|array */
protected $key;
protected bool $allowEmpty;
function exists(): bool {
protected function _exists(array $first, ?array $second=null): bool {
$key = $this->key;
if ($key === null) return false;
return array_key_exists($key, $_POST) || array_key_exists($key, $_GET);
if ($key === null) return true;
if (cl::phas($first, $key)) return true;
return $second !== null && cl::phas($second, $key);
}
public function available(): bool {
function exists(): bool {
return $this->_exists($_POST, $_GET);
}
protected function _available(array $first, ?array $second=null): bool {
$key = $this->key;
if ($key === null) return false;
if (array_key_exists($key, $_POST)) {
return $this->allowEmpty || $_POST[$key] !== "";
} elseif (array_key_exists($key, $_GET)) {
return $this->allowEmpty || $_GET[$key] !== "";
if ($key === null) return true;
if (cl::phas($first, $key)) {
return $this->allowEmpty || cl::pget($first, $key) !== "";
} elseif ($second !== null && cl::phas($second, $key)) {
return $this->allowEmpty || cl::pget($second, $key) !== "";
} else {
return false;
}
}
function get($default=null) {
public function available(): bool {
return $this->_available($_POST, $_GET);
}
protected function _get($default, array $first, ?array $second=null) {
$key = $this->key;
if ($key === null) return $default;
if (array_key_exists($key, $_POST)) {
$value = $_POST[$key];
if ($value === "" && !$this->allowEmpty) return $default;
return $value;
} elseif (array_key_exists($key, $_GET)) {
$value = $_GET[$key];
if ($value === "" && !$this->allowEmpty) return $default;
return $value;
if ($key === null) return cl::merge($first, $second);
if (cl::phas($first, $key)) {
$value = cl::pget($first, $key);
if ($value !== "" || $this->allowEmpty) return $value;
} elseif ($second !== null && cl::phas($second, $key)) {
$value = cl::pget($second, $key);
if ($value !== "" || $this->allowEmpty) return $value;
}
return $default;
}
function get($default=null) {
return $this->_get($default, $_POST, $_GET);
}
function _set($value, array &$first, ?array &$second=null): void {
$key = $this->key;
if ($key === null) {
# interdire la modification de la destination
return;
}
if ($second !== null && !cl::phas($first, $key) && cl::phas($second, $key)) {
cl::pset($second, $key, $value);
} else {
return $default;
cl::pset($first, $key, $value);
}
}
function set($value): void {
$this->_set($value, $_POST, $_GET);
}
function _del(array &$first, ?array &$second=null): void {
$key = $this->key;
if ($key === null) return;
if (!array_key_exists($key, $_POST) && array_key_exists($key, $_GET)) {
cl::set($_GET, $key, $value);
if ($key === null) {
# interdire la modification de la destination
return;
}
if ($second !== null && !cl::phas($first, $key) && cl::phas($second, $key)) {
cl::pdel($second, $key);
} else {
cl::set($_POST, $key, $value);
cl::pdel($first, $key);
}
}
function del(): void {
$key = $this->key;
if ($key === null) return;
if (!array_key_exists($key, $_POST) && array_key_exists($key, $_GET)) {
cl::del($_GET, $key);
} else {
cl::del($_POST, $key);
}
$this->_del($_POST, $_GET);
}
function addKey($key): self {
if ($key === null) return $this;
if ($this->key !== null) $key = cl::merge($this->key, $key);
return new static($key, [
"allow_empty" => $this->allowEmpty
]);
}
}

View File

@ -1,5 +1,5 @@
<?php
namespace nur\sery\wip\php\access;
namespace nulib\php\access;
use nulib\cl;
@ -8,42 +8,22 @@ use nulib\cl;
*/
class GetAccess extends FormAccess {
function exists(): bool {
$key = $this->key;
if ($key === null) return false;
return array_key_exists($key, $_GET);
return $this->_exists($_GET);
}
public function available(): bool {
$key = $this->key;
if ($key === null) return false;
if (array_key_exists($key, $_GET)) {
return $this->allowEmpty || $_GET[$key] !== "";
} else {
return false;
}
return $this->_available($_GET);
}
function get($default=null) {
$key = $this->key;
if ($key === null) return $default;
if (array_key_exists($key, $_GET)) {
$value = $_GET[$key];
if ($value === "" && !$this->allowEmpty) return $default;
return $value;
} else {
return $default;
}
return $this->_get($default, $_GET);
}
function set($value): void {
$key = $this->key;
if ($key === null) return;
cl::set($_GET, $key, $value);
$this->_set($value, $_GET);
}
function del(): void {
$key = $this->key;
if ($key === null) return;
cl::del($_GET, $key);
$this->_del($_GET);
}
}

View File

@ -1,5 +1,7 @@
<?php
namespace nur\sery\wip\php\access;
namespace nulib\php\access;
use ReflectionClass;
/**
* Interface IAccess: abstraction d'un accès complet à une valeur
@ -25,4 +27,26 @@ interface IAccess extends IGetter, ISetter, IDeleter {
* tableau si $key===null
*/
function append($value, $key=null): void;
/** retourner une instance permettant d'accéder à $value[$key] */
function addKey($key): IAccess;
/**
* s'assurer que la destination est un tableau associatif en remplaçant les
* clés numériques par les clés correspondantes du tableau $keys
*/
function ensureAssoc(array $keys, ?array $params=null): void;
/**
* s'assurer que toutes les clés mentionnées dans le tableau $defaults
* existent. si elles n'existent pas, leur donner la valeur du tableau
* $defaults
*/
function ensureKeys(array $defaults, ?array $params=null): void;
/**
* s'assure que les clés de la destination sont dans l'ordre mentionné dans le
* tableau $keys. toutes les clés supplémentaires sont placées à la fin
*/
function ensureOrder(array $keys, ?array $params=null): void;
}

View File

@ -1,5 +1,5 @@
<?php
namespace nur\sery\wip\php\access;
namespace nulib\php\access;
/**
* Class IDeleter: une abstraction d'un objet qui permet de supprimer une valeur

View File

@ -1,5 +1,5 @@
<?php
namespace nur\sery\wip\php\access;
namespace nulib\php\access;
/**
* Class IGetter: une abstraction d'un objet qui permet d'obtenir une valeur
@ -11,6 +11,12 @@ interface IGetter {
*/
function exists(): bool;
/**
* @return bool true si cet objet autorise les chaines vides. si c'est le cas,
* {@link exists()} et {@link available()} sont fonctionnellement identiques
*/
function isAllowEmpty(): bool;
/** @return bool true si la valeur existe et est utilisable, false sinon */
function available(): bool;

View File

@ -1,5 +1,5 @@
<?php
namespace nur\sery\wip\php\access;
namespace nulib\php\access;
/**
* Class ISetter: une abstraction d'un objet qui permet de modifier une valeur

View File

@ -1,69 +1,188 @@
<?php
namespace nur\sery\wip\php\access;
namespace nulib\php\access;
use ArrayAccess;
use nulib\cl;
use nulib\ref\schema\ref_schema;
/**
* Class KeyAccess: accès à une valeur d'une clé dans un tableau
* Class KeyAccess: accès
* - soit à une valeur d'un chemin de clé dans un tableau (si $key !== null)
* - soit à une valeur scalaire (si $key === null)
*/
class KeyAccess extends AbstractAccess {
function __construct(&$array, $key, ?array $params=null) {
$this->array =& $array;
const ALLOW_NULL = null;
const ALLOW_FALSE = null;
const PROTECT_DEST = false;
function __construct(&$dest, $key=null, ?array $params=null) {
parent::__construct($params);
$this->protectDest = $params["protect_dest"] ?? static::PROTECT_DEST;
$this->dest =& $dest;
$this->key = $key;
$this->allowNull = $params["allow_null"] ?? true;
$this->allowFalse = $params["allow_false"] ?? false;
$this->allowEmpty = $params["allow_empty"] ?? true;
$this->allowNull = $params["allow_null"] ?? static::ALLOW_NULL;
$this->allowFalse = $params["allow_false"] ?? static::ALLOW_FALSE;
}
/** @var array|ArrayAccess */
protected $array;
protected bool $protectDest;
function reset(&$array): self {
$this->array =& $array;
/** @var mixed|array|ArrayAccess */
protected $dest;
/** @var null|int|string|array */
protected $key;
function reset(&$dest, $key=null): self {
$this->dest =& $dest;
$this->key = $key;
return $this;
}
/** @var int|string */
protected $key;
function resetKey($key=null): self {
$this->key = $key;
return $this;
}
protected bool $allowNull;
protected ?bool $allowNull;
protected bool $allowFalse;
protected function isAllowNull(): bool {
$allowNull = $this->allowNull;
if ($allowNull !== null) return $allowNull;
return $this->key !== null;
}
protected bool $allowEmpty;
protected ?bool $allowFalse;
protected function isAllowFalse(): bool {
$allowFalse = $this->allowFalse;
if ($allowFalse !== null) return $allowFalse;
return $this->key === null;
}
function exists(): bool {
$key = $this->key;
if ($key === null) return false;
return cl::has($this->array, $key);
if ($key === null) {
return $this->isAllowNull() || $this->dest !== null;
} else {
return cl::phas($this->dest, $key);
}
}
function available(): bool {
if (!$this->exists()) return false;
$value = cl::get($this->array, $this->key);
if ($value === null) return $this->allowNull;
if ($value === false) return $this->allowFalse;
$key = $this->key;
if ($key === null) $value = $this->dest;
else $value = cl::pget($this->dest, $key);
if ($value === "") return $this->allowEmpty;
if ($value === null) return $this->isAllowNull();
if ($value === false) return $this->isAllowFalse();
return true;
}
function get($default=null) {
if ($this->key === null) return $default;
$value = cl::get($this->array, $this->key, $default);
if ($value === null && !$this->allowNull) return $default;
if ($value === false && !$this->allowFalse) return $default;
$key = $this->key;
if ($key === null) $value = $this->dest;
else $value = cl::pget($this->dest, $key, $default);
if ($value === "" && !$this->allowEmpty) return $default;
if ($value === null && !$this->isAllowNull()) return $default;
if ($value === false && !$this->isAllowFalse()) return $default;
return $value;
}
function set($value): void {
if ($this->key === null) return;
cl::set($this->array, $this->key, $value);
$key = $this->key;
if ($key === null) {
if (!$this->protectDest) $this->dest = $value;
} else {
cl::pset($this->dest, $key, $value);
}
}
function del(): void {
if ($this->key === null) return;
cl::del($this->array, $this->key);
$key = $this->key;
if ($key === null) {
if (!$this->protectDest) $this->dest = null;
} else {
cl::pdel($this->dest, $key);
}
}
function addKey($key): self {
if ($key === null) return $this;
if ($this->key !== null) $key = cl::merge($this->key, $key);
return new KeyAccess($this->dest, $key, [
"allow_empty" => $this->allowEmpty,
"allow_null" => $this->allowNull,
"allow_false" => $this->allowFalse,
"protect_dest" => $this->protectDest,
]);
}
function ensureAssoc(array $keys, ?array $params=null): void {
$dest =& $this->dest;
$prefix = $params["key_prefix"] ?? null;
$suffix = $params["key_suffix"] ?? null;
$index = 0;
foreach ($keys as $key) {
if ($prefix !== null || $suffix !== null) {
$destKey = "$prefix$key$suffix";
} else {
# préserver les clés numériques
$destKey = $key;
}
if ($dest !== null && array_key_exists($destKey, $dest)) continue;
while (in_array($index, $keys, true)) {
$index++;
}
if ($dest !== null && array_key_exists($index, $dest)) {
$dest[$destKey] = $dest[$index];
unset($dest[$index]);
$index++;
}
}
}
function ensureKeys(array $defaults, ?array $params=null): void {
$dest =& $this->dest;
$keys = array_keys($defaults);
$prefix = $params["key_prefix"] ?? null;
$suffix = $params["key_suffix"] ?? null;
foreach ($keys as $key) {
$destKey = "$prefix$key$suffix";
if ($dest === null || !array_key_exists($destKey, $dest)) {
$dest[$destKey] = $defaults[$key];
}
}
}
function ensureOrder(array $keys, ?array $params=null): void {
$dest =& $this->dest;
if ($dest === null) return;
$prefix = $params["key_prefix"] ?? null;
$suffix = $params["key_suffix"] ?? null;
if ($prefix !== null || $suffix !== null) {
foreach ($keys as &$key) {
$key = "$prefix$key$suffix";
}; unset($key);
}
$destKeys = array_keys($dest);
$keyCount = count($keys);
if (array_slice($destKeys, 0, $keyCount) === $keys) {
# si le tableau a déjà les bonnes clés dans le bon ordre, rien à faire
return;
}
$ordered = [];
foreach ($keys as $key) {
if (array_key_exists($key, $dest)) {
$ordered[$key] = $dest[$key];
unset($dest[$key]);
}
}
$preserveKeys = $params["preserve_keys"] ?? false;
if ($preserveKeys) $dest = cl::merge2($ordered, $dest);
else $dest = array_merge($ordered, $dest);
}
}

View File

@ -1,5 +1,5 @@
<?php
namespace nur\sery\wip\php\access;
namespace nulib\php\access;
use nulib\cl;
@ -8,42 +8,22 @@ use nulib\cl;
*/
class PostAccess extends FormAccess {
function exists(): bool {
$key = $this->key;
if ($key === null) return false;
return array_key_exists($key, $_POST);
return $this->_exists($_POST);
}
public function available(): bool {
$key = $this->key;
if ($key === null) return false;
if (array_key_exists($key, $_POST)) {
return $this->allowEmpty || $_POST[$key] !== "";
} else {
return false;
}
return $this->_available($_POST);
}
function get($default=null) {
$key = $this->key;
if ($key === null) return $default;
if (array_key_exists($key, $_POST)) {
$value = $_POST[$key];
if ($value === "" && !$this->allowEmpty) return $default;
return $value;
} else {
return $default;
}
return $this->_get($default, $_POST);
}
function set($value): void {
$key = $this->key;
if ($key === null) return;
cl::set($_POST, $key, $value);
$this->_set($value, $_POST);
}
function del(): void {
$key = $this->key;
if ($key === null) return;
cl::del($_POST, $key);
$this->_del($_POST);
}
}

View File

@ -0,0 +1,173 @@
<?php
namespace nulib\php\access;
use nulib\StateException;
use nulib\str;
use ReflectionClass;
use ReflectionException;
use ReflectionProperty;
class PropertyAccess extends AbstractAccess {
const PROTECT_DEST = true;
const MAP_NAMES = true;
const ALLOW_NULL = true;
const ALLOW_FALSE = false;
function __construct(?object $dest, ?string $name=null, ?array $params=null) {
parent::__construct($params);
$this->protectDest = $params["protect_dest"] ?? static::PROTECT_DEST;
$this->mapNames = $params["map_names"] ?? static::MAP_NAMES;
$this->_setName($name);
$this->_setDest($dest);
$this->allowNull = $params["allow_null"] ?? static::ALLOW_NULL;
$this->allowFalse = $params["allow_false"] ?? static::ALLOW_FALSE;
}
protected bool $protectDest;
protected ?object $dest;
protected bool $mapNames;
protected ?string $name;
protected ?ReflectionProperty $property;
private function _getName(string $key): string {
return $this->mapNames? str::us2camel($key): $key;
}
private function _setName(?string $name): void {
if ($name !== null) $name = $this->_getName($name);
$this->name = $name;
}
private function _getProperty(?string $name, ?ReflectionClass $class, ?object $object=null): ?ReflectionProperty {
$property = null;
if ($class === null && $object !== null) {
$class = new ReflectionClass($object);
}
if ($class !== null && $name !== null) {
try {
$property = $class->getProperty($name);
$property->setAccessible(true);
} catch (ReflectionException $e) {
}
}
return $property;
}
private function _setDest(?object $dest): void {
$this->dest = $dest;
$this->property = $this->_getProperty($this->name, null, $dest);
}
function reset(?object $dest, ?string $name=null): self {
$this->_setName($name);
$this->_setDest($dest);
return $this;
}
function resetKey($name=null): self {
$this->_setName($name);
return $this;
}
protected bool $allowNull;
protected bool $allowFalse;
function exists(): bool {
$name = $this->name;
if ($this->dest === null) return false;
return $name === null
|| $this->property !== null
|| property_exists($this->dest, $name);
}
protected function _get($default=null) {
$name = $this->name;
$property = $this->property;
if ($this->dest === null) {
return $default;
} elseif ($name === null) {
return $this->dest;
} elseif ($property !== null) {
return $property->getValue($this->dest);
} elseif (property_exists($this->dest, $name)) {
return $this->dest->$name;
} else {
return $default;
}
}
function available(): bool {
if (!$this->exists()) return false;
$value = $this->_get();
if ($value === "") return $this->allowEmpty;
if ($value === null) return $this->allowNull;
if ($value === false) return $this->allowFalse;
return true;
}
function get($default=null) {
if (!$this->exists()) return $default;
$value = $this->_get();
if ($value === "" && !$this->allowEmpty) return $default;
if ($value === null && !$this->allowNull) return $default;
if ($value === false && !$this->allowFalse) return $default;
return $value;
}
protected function _set($value): void {
$name = $this->name;
$property = $this->property;
if ($this->dest === null) {
throw StateException::unexpected_state("dest is null");
} elseif ($name === null) {
if (!$this->protectDest) $this->_setDest($value);
} elseif ($property !== null) {
$property->setValue($this->dest, $value);
} else {
$this->dest->$name = $value;
}
}
function set($value): void {
$this->_set($value);
}
function del(): void {
$this->_set(null);
}
function addKey($key): IAccess {
if ($key === null) return $this;
return new ChainAccess($this, $key);
}
function ensureKeys(array $defaults, ?array $params=null): void {
$dest = $this->dest;
if ($dest === null) {
# comme ne connait pas la classe de l'objet destination, on n'essaie pas
# de le créer
return;
}
$class = new ReflectionClass($dest);
$keys = array_keys($defaults);
$prefix = $params["key_prefix"] ?? null;
$suffix = $params["key_suffix"] ?? null;
foreach ($keys as $key) {
$name = $this->_getName("$prefix$key$suffix");
$property = $this->_getProperty($name, $class);
if ($property !== null) {
$type = $property->getType();
if ($type !== null && !$property->isInitialized($dest) && $type->allowsNull()) {
# initialiser avec null au lieu de $defaults[$key] pour respecter le
# type de la propriété
$property->setValue($dest, null);
}
} elseif (!property_exists($dest, $name)) {
$dest->$name = $defaults[$key];
}
}
}
}

View File

@ -1,5 +1,5 @@
<?php
namespace nur\sery\wip\php\access;
namespace nulib\php\access;
/**
* Class ShadowAccess: accès en lecture depuis une instance de {@link IAccess}
@ -16,6 +16,7 @@ namespace nur\sery\wip\php\access;
*/
class ShadowAccess extends AbstractAccess {
function __construct(IAccess $reader, IAccess $writer) {
parent::__construct();
$this->reader = $reader;
$this->writer = $writer;
$this->getter = $reader;
@ -27,6 +28,10 @@ class ShadowAccess extends AbstractAccess {
protected IGetter $getter;
public function isAllowEmpty(): bool {
return $this->getter->isAllowEmpty();
}
function exists(): bool {
return $this->getter->exists();
}
@ -48,4 +53,20 @@ class ShadowAccess extends AbstractAccess {
$this->writer->del();
$this->getter = $this->reader;
}
function addKey($key): IAccess {
return new ChainAccess($this, $key);
}
function ensureAssoc(array $keys, ?array $params=null): void {
$this->writer->ensureAssoc($keys, $params);
}
function ensureKeys(array $defaults, ?array $params=null): void {
$this->writer->ensureKeys($defaults, $params);
}
function ensureOrder(array $keys, ?array $params=null): void {
$this->writer->ensureOrder($keys, $params);
}
}

View File

@ -1,56 +1,8 @@
<?php
namespace nur\sery\wip\php\access;
namespace nulib\php\access;
/**
* Class ValueAccess: accès à une valeur unitaire
*/
class ValueAccess extends AbstractAccess {
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 $value;
function reset(&$value): self {
$this->value =& $value;
return $this;
}
protected bool $allowNull;
protected bool $allowFalse;
protected bool $allowEmpty;
function exists(): bool {
return $this->allowNull || $this->value !== null;
}
function available(): bool {
if (!$this->exists()) return false;
$value = $this->value;
if ($value === false) return $this->allowFalse;
if ($value === "") return $this->allowEmpty;
return true;
}
function get($default=null) {
$value = $this->value;
if ($value === null && !$this->allowNull) return $default;
if ($value === false && !$this->allowFalse) return $default;
if ($value === "" && !$this->allowEmpty) return $default;
return $value;
}
function set($value): void {
$this->value = $value;
}
function del(): void {
$this->value = null;
}
class ValueAccess extends KeyAccess {
const ALLOW_NULL = false;
const ALLOW_FALSE = true;
const PROTECT_DEST = false;
}

View File

@ -1,11 +1,11 @@
<?php
namespace nur\sery\wip\php\coll;
namespace nulib\php\coll;
use Iterator;
use IteratorAggregate;
use nulib\cl;
use nulib\php\func;
use nur\sery\wip\php\iter;
use nulib\php\iter;
use Traversable;
/**

View File

@ -1,5 +1,5 @@
<?php # -*- coding: utf-8 mode: php -*- vim:sw=2:sts=2:et:ai:si:sta:fenc=utf-8
namespace nur\sery\wip\php;
namespace nulib\php;
use Exception;
use Generator;

View File

@ -1,30 +0,0 @@
<?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;
}

View File

@ -1,5 +1,5 @@
<?php
namespace nur\sery\wip\schema;
namespace nulib\schema;
class OldSchema {
/**

View File

@ -1,10 +1,8 @@
<?php
namespace nur\sery\wip\schema;
namespace nulib\schema;
use IteratorAggregate;
use nur\sery\wip\schema\_assoc\AssocResult;
use nur\sery\wip\schema\_list\ListResult;
use nur\sery\wip\schema\_scalar\ScalarResult;
use Throwable;
/**
* Class Result: résultat de l'analyse ou de la normalisation d'une valeur
@ -17,6 +15,8 @@ use nur\sery\wip\schema\_scalar\ScalarResult;
* @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 Throwable|null $exception l'exception qui a fait échouer la
* validation le cas échéant
* @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
@ -26,7 +26,7 @@ abstract class Result implements IteratorAggregate {
const KEYS = [
"resultAvailable",
"present", "available", "null", "valid", "normalized",
"messageKey", "message",
"messageKey", "message", "exception",
"origValue", "normalizedValue",
];
@ -34,10 +34,6 @@ abstract class Result implements IteratorAggregate {
$this->reset();
}
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
* objet

View File

@ -1,22 +1,45 @@
<?php
namespace nur\sery\wip\schema;
namespace nulib\schema;
use ArrayAccess;
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;
use nulib\schema\_assoc\AssocSchema;
use nulib\schema\_list\ListSchema;
use nulib\schema\_scalar\ScalarSchema;
use nulib\schema\types\IType;
use nulib\schema\types\tarray;
use nulib\schema\types\tbool;
use nulib\schema\types\tfunc;
use nulib\schema\types\tcontent;
use nulib\schema\types\tpkey;
use nulib\schema\types\trawstring;
/**
* Class Schema
*
* @property-read array|IType $type
* @property-read mixed $default
* @property-read string|null $title
* @property-read bool $required
* @property-read bool $nullable
* @property-read string|array|null $desc
* @property-read callable|null $analyzerFunc
* @property-read callable|null $extractorFunc
* @property-read callable|null $parserFunc
* @property-read callable|null $normalizerFunc
* @property-read array|null $messages
* @property-read callable|null $formatterFunc
* @property-read mixed $format
* @property-read array $nature
* @property-read array|null $schema
* @property-read string|int|null $name
* @property-read string|array|null $pkey
* @property-read string|null $header
* @property-read bool|null $computed
*/
abstract class Schema implements ArrayAccess {
/**
* créer le cas échéant une nouvelle instance de {@link Schema} à partir d'une
@ -27,7 +50,7 @@ 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, bool $normalize=true): self {
static function ns($definition=null, $definitionKey=null, &$schema=null, bool $normalize=true): self {
if (is_array($schema)) {
$definition = $schema;
$schema = null;
@ -51,13 +74,13 @@ abstract class Schema implements ArrayAccess {
* variable $value (si $valueKey===null) ou $value[$valueKey] si $valueKey
* n'est pas null
*/
static function nw(&$value=null, $valueKey=null, &$schema=null, $definition=null, ?Wrapper &$wrapper=null): Wrapper {
static function nw(&$value=null, $valueKey=null, $definition=null, &$schema=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)->getWrapper($value, $valueKey, $wrapper);
return self::ns($definition, null, $schema)->getWrapper($value, $valueKey, null, $wrapper);
}
protected static function have_nature(array $definition, ?string &$nature=null): bool {
@ -75,18 +98,18 @@ abstract class Schema implements ArrayAccess {
return false;
}
protected static function _normalize(&$definition, $definitionKey=null): void {
protected static function _normalize_definition(&$definition, $definitionKey=null, ?array $natureMetaschema=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) {
foreach (array_keys(ref_schema::VALUE_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];
$definition[$key] = ref_schema::VALUE_METASCHEMA[$key][1];
}
}
}
@ -138,6 +161,12 @@ abstract class Schema implements ArrayAccess {
# nature
$nature = $definition[""];
tarray::ensure_array($nature);
$natureMetaschema ??= ref_schema::NATURE_METASCHEMA;
foreach (array_keys($natureMetaschema) as $key) {
if (!array_key_exists($key, $nature)) {
$nature[$key] = $natureMetaschema[$key][1];
}
}
$definition[""] = $nature;
# name, pkey, header
$name = $definition["name"];
@ -158,22 +187,22 @@ abstract class Schema implements ArrayAccess {
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"]);
tfunc::ensure_nfunc($definition["analyzer_func"]);
tfunc::ensure_nfunc($definition["extractor_func"]);
tfunc::ensure_nfunc($definition["parser_func"]);
tfunc::ensure_nfunc($definition["normalizer_func"]);
tarray::ensure_narray($definition["messages"]);
tcallable::ensure_ncallable($definition["formatter_func"]);
tbool::ensure_nbool($definition["composite"]);
tfunc::ensure_nfunc($definition["formatter_func"]);
tbool::ensure_nbool($definition["computed"]);
switch ($nature[0] ?? null) {
case "assoc":
foreach ($definition["schema"] as $key => &$keydef) {
self::_normalize($keydef, $key);
self::_normalize_definition($keydef, $key);
}; unset($keydef);
break;
case "list":
self::_normalize($definition["schema"]);
self::_normalize_definition($definition["schema"]);
break;
}
}
@ -223,11 +252,11 @@ abstract class Schema implements ArrayAccess {
case "assoc":
foreach ($definition["schema"] as &$keydef) {
self::_ensure_schema_instances($keydef);
Schema::ns($keydef, null, null, false);
Schema::ns(null, null, $keydef, false);
}; unset($keydef);
break;
case "list":
Schema::ns($definition["schema"], null, null, false);
Schema::ns(null, null, $definition["schema"], false);
break;
}
}
@ -246,14 +275,16 @@ abstract class Schema implements ArrayAccess {
return $this->_definition;
}
/** retourner true si le schéma est de nature tableau associatif */
function isAssoc(?AssocSchema &$schema=null): bool { return false; }
/** retourner true si le schéma est de nature liste */
function isList(?ListSchema &$schema=null): bool { return false; }
/** retourner true si le schéma est de nature scalaire */
function isScalar(?ScalarSchema &$schema=null): bool { return false; }
/**
* retourner la liste des clés valides pour l'accès aux valeurs et résultats
*/
abstract function getKeys(): array;
abstract function getWrapper(&$value=null, $valueKey=null, ?Wrapper &$wrapper=null): Wrapper;
abstract function getSchema($key=false): Schema;
abstract protected function newWrapper(): Wrapper;
abstract function getWrapper(&$value=null, $valueKey=null, ?array $params=null, ?Wrapper &$wrapper=null): Wrapper;
#############################################################################
# key & properties
@ -272,7 +303,15 @@ abstract class Schema implements ArrayAccess {
throw AccessException::read_only(null, $offset);
}
const _PROPERTY_PKEYS = [];
const _PROPERTY_PKEYS = [
"analyzerFunc" => "analyzer_func",
"extractorFunc" => "extractor_func",
"parserFunc" => "parser_func",
"normalizerFunc" => "normalizer_func",
"formatterFunc" => "formatter_func",
"nature" => ["", 0],
];
function __get($name) {
$pkey = cl::get(static::_PROPERTY_PKEYS, $name, $name);
return cl::pget($this->definition, $pkey);

View File

@ -1,5 +1,5 @@
<?php
namespace nur\sery\wip\schema;
namespace nulib\schema;
use Exception;

View File

@ -1,23 +1,37 @@
# nulib\schema
* l'ordre est `ensureAssoc [--> ensureKeys] [--> orderKeys]`
* si false, supprimer la clé du tableau sauf si ensureKeys
* pour AssocResult, les clés suivantes sont supportées:
* false pour la clé courante
* null pour un résultat aggrégé
* "" pour le résultat du tableau
* $key pour le résultat de la clé correspondante
* rajouter l'attribut "size" pour spécifier la taille maximale des valeurs
* cela pourrait servir pour générer automatiquement des tables SQL
* ou pour modéliser un schéma FSV
* support allowed_values
* valeurs composite/computed
* analyse / vérification de la valeur complète après calcul du résultat, si
tous les résultats sont bons
* calcul des valeurs composites/computed par une fonction avant/après l'analyse
globale si résultat ok
* fonction getter_func, setter_func, deleter_func pour les propriétés de type
computed
* tdate et tdatetime. qu'en est-il des autres classes (delay, etc.)
* possibilité de spécifier le format de la date à analyser
* parse_format pour spécifier le format d'analyse au lieu de l'auto-détecter
* 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)`
* l'argument $format de AssocWrapper::format() est un tableau associatif
`[$key => $format]`
cela permet de spécifier des format spécifiques pour certains champs.
* cela signifie que la valeur de retour n'est pas string :-(
retourner string|array
* dans AssocSchema, support `[key_prefix]` qui permet de spécifier un préfixe
commun aux champs dans le tableau destination, e.g
@ -62,6 +76,8 @@
la définition de ces "circonstances" est encore à faire: soit un paramètre
lors de la définition du schéma, soit un truc magique du genre "toutes les
valeurs séquentielles sont des clés du schéma"
valeurs séquentielles sont des clés du schéma", soit un mode automatique
activé par un paramètre où une valeur "val" devient "val"=>true si la clé
"val" existe dans le schéma
-*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary

View File

@ -1,20 +1,107 @@
<?php
namespace nur\sery\wip\schema;
namespace nulib\schema;
use ArrayAccess;
use IteratorAggregate;
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;
use nulib\php\func;
use nulib\schema\_assoc\AssocWrapper;
use nulib\schema\_list\ListWrapper;
use nulib\schema\_scalar\ScalarResult;
use nulib\schema\_scalar\ScalarWrapper;
use nulib\schema\input\Input;
use nulib\schema\types\IType;
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; }
protected WrapperContext $context;
/** spécifier la valeur destination gérée par cet objet */
abstract function reset(&$value, $valueKey=null, ?bool $verifix=null): self;
/** changer les paramètres de gestion des valeurs */
function resetParams(?array $params): void {
$this->context->resetParams($params);
}
protected function resetContext($resetSelectedKey): void {
$context = $this->context;
$type = $context->schema->type;
if (is_array($type)) $type = $type[0];
if (is_string($type)) $type = types::get($context->schema->nullable, $type);
$context->type = $type;
$context->result->reset();
$context->analyzed = false;
$context->normalized = false;
if ($resetSelectedKey) $context->selectedKey = null;
}
protected function afterModify(?array $params, $resetSelectedKey=false): void {
$context = $this->context;
$this->resetContext($resetSelectedKey);
if ($params["analyze"] ?? $context->analyze) {
$this->analyze($params);
}
if ($context->analyzed) {
if ($params["normalize"] ?? $context->normalize) {
$this->normalize($params);
}
}
}
protected function newInput(&$value): Input {
return new Input($value);
}
/**
* spécifier la valeur destination gérée par cet objet.
*
* @param ?array $params paramètres spécifique à cet appel, qui peuvent être
* différent des paramètres par défaut
*/
function reset(&$value, $valueKey=null, ?array $params=null): Wrapper {
$context = $this->context;
if ($value instanceof Input) $input = $value;
else $input = $this->newInput($value);
$context->input = $input;
$context->valueKey = $valueKey;
$this->afterModify($params, true);
return $this;
}
/** analyser la valeur */
abstract static function _analyze(WrapperContext $context, Wrapper $wrapper, ?array $params): int;
function analyze(?array $params=null): bool {
$context = $this->context;
$reanalyze = $params["reanalyze"] ?? false;
if ($context->analyzed && !$reanalyze) return false;
static::_analyze($context, $this, $params);
$context->analyzed = true;
return true;
}
/** normaliser la valeur */
abstract static function _normalize(WrapperContext $context, Wrapper $wrapper, ?array $params): bool;
function normalize(?array $params=null): bool {
$context = $this->context;
// il faut que la valeur soit analysée avant de la normaliser
static::analyze($params);
if (!$context->analyzed) return false;
$renormalize = $params["renormalize"] ?? false;
if ($renormalize || !$context->normalized) {
$modified = static::_normalize($context, $this, $params);
$context->normalized = true;
} else {
$modified = false;
}
/** @var ScalarResult $result */
$result = $context->result;
if (!$result->valid) {
$result->throw($params["throw"] ?? $context->throw);
}
return $modified;
}
/**
* Obtenir la liste des clés valides pour les valeurs accessibles via cet
@ -38,37 +125,80 @@ abstract class Wrapper implements ArrayAccess, IteratorAggregate {
}
/**
* obtenir le résultat de l'appel d'une des fonctions {@link set()} ou
* {@link unset()}
* obtenir le résultat de l'analyse de la valeur du wrapper sélectionné
*
* cette fonction doit être appelée après {@link set()} ou {@link unset()} et
* après que le wrapper aie été sélectionné avec {@link select()}
*/
abstract function getResult(): Result;
function getResult($key=false): Result {
return $this->context->result;
}
/** retourner true si la valeur existe */
abstract function isPresent(): bool;
function isPresent($key=false): bool {
return $this->getResult($key)->present;
}
/** retourner le type associé à la valeur */
abstract function getType(): IType;
function getType($key=false): IType {
return $this->context->type;
}
/** retourner true si la valeur est disponible */
abstract function isAvailable(): bool;
function isAvailable($key=false): bool {
return $this->getResult($key)->available;
}
/** retourner true si la valeur est valide */
abstract function isValid(): bool;
function isValid($key=false): bool {
return $this->getResult($key)->valid;
}
/** retourner true si la valeur est dans sa forme normalisée */
abstract function isNormalized(): bool;
function isNormalized($key=false): bool {
return $this->getResult($key)->normalized;
}
/** obtenir la valeur */
abstract function get($default=null);
function get($default=null, $key=false) {
$context = $this->context;
if (!$context->result->available) return $default;
return $context->input->get($context->valueKey);
}
/** remplacer la valeur */
abstract function set($value): self;
function set($value, ?array $params=null, $key=false): self {
$context = $this->context;
$context->input->set($value, $context->valueKey);
$this->afterModify($params);
return $this;
}
/** supprimer la valeur */
abstract function unset(): self;
function unset(?array $params=null, $key=false): self {
$context = $this->context;
$context->input->unset($context->valueKey);
$this->afterModify($params);
return $this;
}
protected function _format(WrapperContext $context, $format=null): string {
$value = $context->input->get($context->valueKey);
/** @var func $formatterFunc */
$formatterFunc = $context->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 ??= $context->schema->format;
return $formatterFunc->invoke([$value, $format, $context, $this]);
} else {
# on assume que le type a été initialisé avec le format de la définition
# le cas échéant
return $context->type->format($value, $format);
}
}
/** formatter la valeur pour affichage */
abstract function format($format=null): string;
function format($format=null, $key=false): string {
return $this->_format($this->context, $format);
}
#############################################################################
# key & properties
@ -78,14 +208,14 @@ abstract class Wrapper implements ArrayAccess, IteratorAggregate {
}
function offsetGet($offset) {
return $this->select($offset);
return $this->get(null, $offset);
}
function offsetSet($offset, $value): void {
$this->select($offset)->set($value);
$this->set($value, null, $offset);
}
function offsetUnset($offset): void {
$this->select($offset)->unset();
$this->unset(null, $offset);
}
}

View File

@ -0,0 +1,46 @@
<?php
namespace nulib\schema;
use nulib\ref\schema\ref_schema;
use nulib\schema\input\Input;
use nulib\schema\types\IType;
class WrapperContext {
function __construct(Schema $schema, ?Input $input, $valueKey, ?array $params) {
$this->resetParams($params);
$this->schema = $schema;
if ($input !== null) $this->input = $input;
$this->valueKey = $valueKey;
}
public ?array $params;
public bool $analyze, $analyzed = false;
public bool $normalize, $normalized = false;
public ?bool $throw;
function resetParams(?array $params): void {
$this->params = $params;
$this->analyze = $params["analyze"] ?? ref_schema::PARAMS_SCHEMA["analyze"][1];
$this->normalize = $params["normalize"] ?? ref_schema::PARAMS_SCHEMA["normalize"][1];
$this->throw = $params["throw"] ?? ref_schema::PARAMS_SCHEMA["throw"][1];
}
/** schéma de la valeur */
public Schema $schema;
/** source et destination de la valeur */
public Input $input;
/** @var string|int|null clé de la valeur dans le tableau destination */
public $valueKey;
/** @var mixed */
public $origValue = null;
/** @var mixed */
public $value = null;
/** @var string|int|null clé sélectionnée */
public $selectedKey = null;
/** type de la valeur de la clé sélectionnée après analyse */
public ?IType $type = null;
/** résultat de l'analyse de la valeur de la clé sélectionnée */
public ?Result $result = null;
}

View File

@ -1,53 +0,0 @@
<?php
namespace nur\sery\wip\schema\_assoc;
use nulib\ValueException;
use nur\sery\wip\schema\Result;
class AssocResult extends Result {
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;
}
}

View File

@ -1,21 +1,19 @@
<?php
namespace nur\sery\wip\schema\_assoc;
namespace nulib\schema\_assoc;
use nulib\cl;
use nulib\ref\schema\ref_schema;
use nur\sery\wip\schema\Schema;
use nur\sery\wip\schema\Wrapper;
use nulib\ValueException;
use nulib\schema\Schema;
use nulib\schema\Wrapper;
/**
* Class AssocSchema
*/
class AssocSchema extends Schema {
/** @var array meta-schema d'un schéma de nature tableau associatif */
const METASCHEMA = ref_schema::ASSOC_METASCHEMA;
/**
* indiquer si $definition est une définition de schéma de nature tableau
* associatif que {@link normalize()} pourrait normaliser
* associatif que {@link normalize_definition()} pourrait normaliser
*/
static function isa_definition($definition): bool {
if (!is_array($definition)) return false;
@ -27,7 +25,7 @@ class AssocSchema extends Schema {
return !cl::have_num_keys($definition);
}
static function normalize($definition, $definitionKey=null): array {
static function normalize_definition($definition, $definitionKey=null): array {
if (!is_array($definition)) $definition = [$definition];
if (!self::have_nature($definition)) {
$definition = [
@ -36,7 +34,8 @@ class AssocSchema extends Schema {
"schema" => $definition,
];
}
self::_normalize($definition, $definitionKey);
$natureMetaschema = array_merge(ref_schema::NATURE_METASCHEMA, ref_schema::ASSOC_NATURE_METASCHEMA);
self::_normalize_definition($definition, $definitionKey, $natureMetaschema);
self::_ensure_nature($definition, "assoc", "array");
return $definition;
}
@ -44,25 +43,54 @@ class AssocSchema extends Schema {
function __construct($definition=null, $definitionKey=null, bool $normalize=true) {
if ($definition === null) $definition = static::SCHEMA;
if ($normalize) {
$definition = self::normalize($definition, $definitionKey);
$definition = self::normalize_definition($definition, $definitionKey);
$this->_definition = $definition;
self::_ensure_type($definition);
self::_ensure_schema_instances($definition);
} else {
# ici, $definition contient un schema déjà instancié, mais c'est le mieux
# qu'on puisse faire
$this->_definition = $definition;
}
$this->definition = $definition;
$keys = [];
foreach ($definition["schema"] as $key => $schema) {
if (!$schema["computed"]) $keys[] = $key;
}
$this->keys = $keys;
}
function isAssoc(?AssocSchema &$schema=null): bool {
$schema = $this;
return true;
protected array $keys;
function getKeys(): array {
return $this->keys;
}
function getSchema($key=false): Schema {
if ($key === null || $key === false) return $this;
$schema = $this->definition["schema"][$key] ?? null;
if ($schema === null) throw ValueException::invalid_key($key);
return $schema;
}
protected function newWrapper(): AssocWrapper {
return new AssocWrapper($this);
}
function getWrapper(&$array=null, $arrayKey=null, ?Wrapper &$wrapper=null): AssocWrapper {
function getWrapper(&$value=null, $valueKey=null, ?array $params=null, ?Wrapper &$wrapper=null): AssocWrapper {
# si pas de valeur ni de wrapper, pas d'analyse et donc pas d'exception
# cf le code similaire dans AssocWrapper::__construct()
$dontAnalyze = $value === null && $wrapper === null;
if (!($wrapper instanceof AssocWrapper)) $wrapper = $this->newWrapper();
return $wrapper->reset($array, $arrayKey);
# la nature du schéma peut contenir des paramètres par défaut
$nature = $this->definition[""];
foreach (array_keys(ref_schema::ASSOC_PARAMS_SCHEMA) as $paramKey) {
$paramValue = $nature[$paramKey] ?? null;
if ($paramValue !== null) $params[$paramKey] = $paramValue;
}
if ($params !== null) $wrapper->resetParams($params);
return $wrapper->reset($value, $valueKey, $dontAnalyze? ["analyze" => false]: null);
}
}

View File

@ -1,140 +1,185 @@
<?php
namespace nur\sery\wip\schema\_assoc;
namespace nulib\schema\_assoc;
use nulib\cl;
use nulib\ref\schema\ref_analyze;
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;
use nulib\schema\_scalar\ScalarResult;
use nulib\schema\_scalar\ScalarWrapper;
use nulib\schema\input\Input;
use nulib\schema\Result;
use nulib\schema\types\IType;
use nulib\schema\Wrapper;
use nulib\schema\WrapperContext;
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;
function __construct(AssocSchema $schema, &$value=null, $valueKey=null, ?array $params=null) {
$keys = $schema->getKeys();
$keyParams = cl::merge($params, [
"throw" => false,
]);
$keyWrappers = [];
foreach ($keys as $key) {
$value = null;
$keyWrappers[$key] = $schema->getSchema($key)->getWrapper($value, null, $keyParams);
}
$this->context = $context = new AssocWrapperContext($schema, null, null, $params);
$arrayParams = cl::merge($params, [
"throw" => false,
]);
$context->arrayWrapper = new ScalarWrapper($schema, $dummy, null, $arrayParams, $context);
$context->keys = $keys;
$context->keyWrappers = $keyWrappers;
if ($value !== null) {
# n'initialiser que si $value n'est pas null
$this->reset($value, $valueKey);
}
$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; }
/** @var AssocWrapperContext */
protected WrapperContext $context;
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);
protected function resetContext($resetSelectedKey): void {
parent::resetContext($resetSelectedKey);
$context = $this->context;
$context->arrayWrapper->getResult()->reset();
foreach ($context->keyWrappers as $wrapper) {
$wrapper->getResult()->reset();
}
}
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();
function reset(&$value, $valueKey=null, ?array $params=null): Wrapper {
$context = $this->context;
if ($value instanceof Input) $input = $value;
else $input = $this->newInput($value);
$context->input = $input;
$context->valueKey = $valueKey;
foreach ($context->keyWrappers as $key => $keyWrapper) {
$keyInput = $input->addKey($valueKey);
$keyWrapper->reset($keyInput, $key, ["analyze" => false]);
}
$this->afterModify($params, true);
return $this;
}
function getKeys(): array {
return $this->keys;
return $this->context->keys;
}
function select($key=null): ScalarWrapper {
$wrapper = $this->wrappers[$key] ?? null;
if ($key !== null) return $wrapper;
throw ValueException::invalid_key($key);
protected function _getWrapper($key): Wrapper {
$context = $this->context;
if ($key === null) return $context->arrayWrapper;
$wrapper = $context->keyWrappers[$key] ?? null;
if ($wrapper === null) throw ValueException::invalid_key($key);
return $wrapper;
}
/** @param Result[] $results */
function verifix(?bool $throw=null, ?array &$results=null): bool {
/** @param string|int|null $key */
function select($key=null): Wrapper {
$wrapper = $this->_getWrapper($key);
$this->context->selectedKey = $key;
return $wrapper;
}
/**
* @param AssocWrapperContext $context
* @param AssocWrapper $wrapper
*/
static function _analyze(WrapperContext $context, Wrapper $wrapper, ?array $params): int {
if ($params["ensure_array"] ?? $context->ensureArray) {
$valueKey = $context->valueKey;
$array = $context->input->get($valueKey);
if ($array === null) $context->input->set([], $valueKey);
}
function getResult(): AssocResult {
return $this->result;
if ($params["ensure_assoc"] ?? $context->ensureAssoc) {
$context->input->ensureAssoc($context->schema->getKeys());
}
$what = ScalarWrapper::_analyze($context, $wrapper, $params);
/** @var ScalarResult $result */
$result = $context->result;
if (!$result->valid) return $what;
foreach ($context->keyWrappers as $keyWrapper) {
$keyWrapper->analyze($params);
if (!$keyWrapper->isValid()) {
#XXX distinguer MISSING, UNAVAILABLE, NULL et !VALID
$what = ref_analyze::INVALID;
$result->addInvalidMessage($keyWrapper);
}
}
#XXX supprimer les clés "missing" ou "unavailable" sauf si $ensureKeys
return $what;
}
function isPresent(): bool {
return $this->result->present;
/**
* @param AssocWrapperContext $context
* @param AssocWrapper $wrapper
*/
static function _normalize(WrapperContext $context, Wrapper $wrapper, ?array $params): bool {
$ensureKeys = $params["ensure_keys"] ?? $context->ensureKeys;
$ensureOrder = $params["ensure_order"] ?? $context->ensureOrder;
if ($ensureKeys || $ensureOrder) {
$schema = $context->schema;
$keys = $schema->getKeys();
if ($ensureKeys) {
$defaults = [];
foreach ($keys as $key) {
$default = $schema->getSchema($key)->default;
if ($default === null) {
$default = $wrapper->getType($key)->getNullValue();
}
$defaults[$key] = $default;
}
}
if ($ensureKeys) $context->input->ensureKeys($defaults, $params);
if ($ensureOrder) $context->input->ensureOrder($keys, $params);
}
$modified = ScalarWrapper::_normalize($context, $wrapper, $params);
foreach ($context->keyWrappers as $keyWrapper) {
if ($keyWrapper->normalize($params)) $modified = true;
}
return $modified;
}
function getType(): IType {
return $this->arrayType;
function getResult($key=false): Result {
if ($key === false) $key = $this->context->selectedKey;
return $this->_getWrapper($key)->getResult();
}
function isAvailable(): bool {
return $this->result->available;
function getType($key=false): IType {
if ($key === false) $key = $this->context->selectedKey;
return $this->_getWrapper($key)->getType();
}
function isValid(): bool {
return $this->result->valid;
function get($default=null, $key=false) {
$context = $this->context;
if (!$context->arrayWrapper->isAvailable()) return $default;
if ($key === false) $key = $context->selectedKey;
return $this->_getWrapper($key)->get($default);
}
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();
function set($value, ?array $params=null, $key=false): Wrapper {
$context = $this->context;
if ($key === false) $key = $context->selectedKey;
$this->_getWrapper($key)->set($value);
return $this;
}
function unset(?bool $verifix=null): AssocWrapper {
$this->input->unset($this->arrayKey);
$this->analyze();
if ($verifix ?? $this->verifix) $this->verifix();
function unset(?array $params=null, $key=false): Wrapper {
$context = $this->context;
if ($key === false) $key = $context->selectedKey;
$this->_getWrapper($key)->unset();
return $this;
}
function format($format = null): string {
// TODO: Implement format() method.
}
function ensureKeys(): bool {
}
function orderKeys(): bool {
function format($format=null, $key=false): string {
$context = $this->context;
if ($key === false) $key = $context->selectedKey;
return $this->_getWrapper($key)->format($format);
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace nulib\schema\_assoc;
use nulib\ref\schema\ref_schema;
use nulib\schema\_scalar\ScalarWrapper;
use nulib\schema\Wrapper;
use nulib\schema\WrapperContext;
class AssocWrapperContext extends WrapperContext {
public bool $ensureArray;
public bool $ensureAssoc;
public bool $ensureKeys;
public bool $ensureOrder;
public function resetParams(?array $params): void {
parent::resetParams($params);
$this->ensureArray = $params["ensure_array"] ?? ref_schema::ASSOC_PARAMS_SCHEMA["ensure_array"][1];
$this->ensureAssoc = $params["ensure_assoc"] ?? ref_schema::ASSOC_PARAMS_SCHEMA["ensure_assoc"][1];
$this->ensureKeys = $params["ensure_keys"] ?? ref_schema::ASSOC_PARAMS_SCHEMA["ensure_keys"][1];
$this->ensureOrder = $params["ensure_order"] ?? ref_schema::ASSOC_PARAMS_SCHEMA["ensure_order"][1];
}
public ?ScalarWrapper $arrayWrapper = null;
/** liste des clés valides */
public array $keys;
/** @var Wrapper[] */
public array $keyWrappers;
}

View File

@ -1,8 +1,8 @@
<?php
namespace nur\sery\wip\schema\_list;
namespace nulib\schema\_list;
use nulib\ValueException;
use nur\sery\wip\schema\Result;
use nulib\schema\Result;
class ListResult extends Result {
function __construct(Result $arrayResult, array &$keyResults) {
@ -12,8 +12,6 @@ class ListResult extends Result {
parent::__construct();
}
function isList(?ListResult &$result=null): bool { $result = $this; return true;}
protected Result $arrayResult;
/** @var Result[] */

View File

@ -1,9 +1,10 @@
<?php
namespace nur\sery\wip\schema\_list;
namespace nulib\schema\_list;
use nulib\ref\schema\ref_schema;
use nur\sery\wip\schema\Schema;
use nur\sery\wip\schema\Wrapper;
use nulib\ValueException;
use nulib\schema\Schema;
use nulib\schema\Wrapper;
class ListSchema extends Schema {
/** @var array meta-schema d'un schéma de nature liste */
@ -34,7 +35,7 @@ class ListSchema extends Schema {
"schema" => $definition[0],
];
}
self::_normalize($definition, $definitionKey);
self::_normalize_definition($definition, $definitionKey);
self::_ensure_nature($definition, "list", "array");
return $definition;
}
@ -50,17 +51,26 @@ class ListSchema extends Schema {
$this->definition = $definition;
}
function isList(?ListSchema &$schema=null): bool {
$schema = $this;
return true;
const KEYS = [null];
function getKeys(): array {
return self::KEYS;
}
public function getSchema($key=false): Schema {
if ($key !== null) throw ValueException::invalid_key($key);
return $this;
}
protected function newWrapper(): ListWrapper {
return new ListWrapper($this);
}
function getWrapper(&$value=null, $valueKey=null, ?Wrapper &$wrapper=null): ListWrapper {
function getWrapper(&$value=null, $valueKey=null, ?array $params = null, ?Wrapper &$wrapper=null): ListWrapper {
# si pas de valeur ni de wrapper, pas de vérification et donc pas d'exception
# cf le code similaire dans ScalarWrapper::__construct()
$verifix = $value !== null || $wrapper !== null;
if (!($wrapper instanceof ListWrapper)) $wrapper = $this->newWrapper();
return $wrapper->reset($value, $valueKey);
return $wrapper->reset($value, $valueKey, $verifix);
}
}

View File

@ -1,12 +1,10 @@
<?php
namespace nur\sery\wip\schema\_list;
namespace nulib\schema\_list;
use nur\sery\wip\schema\Result;
use nur\sery\wip\schema\Wrapper;
use nulib\schema\Result;
use nulib\schema\Wrapper;
abstract/*XXX*/ class ListWrapper extends Wrapper {
function isList(?ListWrapper &$wrapper=null): bool { $wrapper = $this; return true; }
function ensureKeys(): bool {
}

View File

@ -1,22 +1,21 @@
<?php
namespace nur\sery\wip\schema\_scalar;
namespace nulib\schema\_scalar;
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 nulib\schema\Result;
use nulib\schema\Schema;
use nulib\schema\Wrapper;
use Throwable;
/**
* Class ScalarResult: résultat de l'analyse ou de la normalisation d'une valeur
*/
class ScalarResult extends Result {
function isScalar(?ScalarResult &$result=null): bool { $result = $this; return true; }
function getKeys(): array {
return [null];
return ScalarSchema::KEYS;
}
function select($key): Result {
@ -24,8 +23,7 @@ class ScalarResult extends Result {
return $this;
}
/** @var array */
protected $result;
protected array $result;
function reset(): void {
$this->result = array_merge(
@ -47,26 +45,13 @@ class ScalarResult extends Result {
$this->result[$name] = $value;
}
protected static function replace_key(string &$message, ?string $key): void {
if ($key) {
$message = str_replace("{key}", $key, $message);
} else {
$message = str_replace("{key}: ", "", $message);
$message = str_replace("cette valeur", "la valeur", $message);
}
}
protected static function replace_orig(string &$message, $origValue): void {
$message = str_replace("{orig}", strval($origValue), $message);
}
protected function getMessage(string $key, ScalarSchema $schema): string {
protected function getMessage(string $key, Schema $schema): string {
$message = cl::get($schema->messages, $key);
if ($message !== null) return $message;
return cl::get(ref_schema::MESSAGES, $key);
}
function setMissing(ScalarSchema $schema): int {
function setMissing( Schema $schema): int {
$this->resultAvailable = true;
$this->present = false;
$this->available = false;
@ -76,15 +61,13 @@ class ScalarResult extends Result {
$this->normalized = true;
return ref_analyze::NORMALIZED;
} else {
$messageKey = $this->messageKey = "missing";
$message = $this->getMessage($messageKey, $schema);
self::replace_key($message, $schema->name);
$this->message = $message;
$this->messageKey = $messageKey = "missing";
$this->message = $this->getMessage($messageKey, $schema);
return ref_analyze::MISSING;
}
}
function setUnavailable(ScalarSchema $schema): int {
function setUnavailable( Schema $schema): int {
$this->resultAvailable = true;
$this->present = true;
$this->available = false;
@ -94,15 +77,13 @@ class ScalarResult extends Result {
$this->normalized = true;
return ref_analyze::NORMALIZED;
} else {
$messageKey = $this->messageKey = "unavailable";
$message = $this->getMessage($messageKey, $schema);
self::replace_key($message, $schema->name);
$this->message = $message;
$this->messageKey = $messageKey = "unavailable";
$this->message = $this->getMessage($messageKey, $schema);
return ref_analyze::UNAVAILABLE;
}
}
function setNull(ScalarSchema $schema): int {
function setNull( Schema $schema): int {
$this->resultAvailable = true;
$this->present = true;
$this->available = true;
@ -112,33 +93,53 @@ class ScalarResult extends Result {
$this->normalized = true;
return ref_analyze::NORMALIZED;
} else {
$messageKey = $this->messageKey = "null";
$message = $this->getMessage($messageKey, $schema);
self::replace_key($message, $schema->name);
$this->message = $message;
$this->messageKey = $messageKey = "null";
$this->message = $this->getMessage($messageKey, $schema);
return ref_analyze::NULL;
}
}
function setInvalid($value, ScalarSchema $schema, ?Throwable $t=null): int {
function setInvalid($value, Schema $schema, ?Throwable $exception=null): int {
$this->resultAvailable = true;
$this->present = true;
$this->available = true;
$this->null = false;
$this->valid = false;
$this->origValue = $value;
$messageKey = $this->messageKey = "invalid";
$this->messageKey = $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";
if ($exception !== null) {
$tmessage = ValueException::get_message($exception);
if ($tmessage) $message = $tmessage;
}
$this->message = $message;
$this->exception = $exception;
return ref_analyze::INVALID;
}
function addInvalidMessage(Wrapper $wrapper): void {
$this->resultAvailable = true;
$this->present = true;
$this->available = true;
$this->null = false;
$this->valid = false;
$this->messageKey = "invalid";
$result = $wrapper->getResult();
$resultException = $result->exception;
$resultMessage = $result->message;
if ($resultException !== null) {
$tmessage = ValueException::get_message($resultException);
if ($tmessage) {
if ($resultMessage !== null) $resultMessage .= ": ";
$resultMessage .= $tmessage;
}
}
$message = $this->message;
if ($message) $message .= "\n";
$message .= $resultMessage;
$this->message = $message;
}
function setValid($normalizedValue=null): int {
$this->resultAvailable = true;
$this->present = true;
@ -160,6 +161,10 @@ class ScalarResult extends Result {
}
function throw(bool $throw): void {
if ($throw) throw new ValueException($this->message);
if ($throw) {
$exception = $this->exception;
if ($exception !== null) throw $exception;
else throw new ValueException($this->message);
}
}
}

View File

@ -1,41 +1,19 @@
<?php
namespace nur\sery\wip\schema\_scalar;
namespace nulib\schema\_scalar;
use nulib\cl;
use nulib\ref\schema\ref_schema;
use nur\sery\wip\schema\Schema;
use nur\sery\wip\schema\types\IType;
use nur\sery\wip\schema\Wrapper;
use nulib\ValueException;
use nulib\schema\Schema;
use nulib\schema\Wrapper;
/**
* Class ScalarSchema
*
* @property-read array|IType $type
* @property-read mixed $default
* @property-read string|null $title
* @property-read bool $required
* @property-read bool $nullable
* @property-read string|array|null $desc
* @property-read callable|null $analyzerFunc
* @property-read callable|null $extractorFunc
* @property-read callable|null $parserFunc
* @property-read callable|null $normalizerFunc
* @property-read array|null $messages
* @property-read callable|null $formatterFunc
* @property-read mixed $format
* @property-read array $nature
* @property-read array|null $schema
* @property-read string|int|null $name
* @property-read string|array|null $pkey
* @property-read string|null $header
* @property-read bool|null $composite
*/
class ScalarSchema extends Schema {
/** @var array meta-schema d'un schéma de nature scalaire */
const METASCHEMA = ref_schema::SCALAR_METASCHEMA;
/**
* indiquer si $definition est une définition de schéma scalaire que
* {@link normalize()} pourrait normaliser
* {@link normalize_definition()} pourrait normaliser
*/
static function isa_definition($definition): bool {
# chaine ou null
@ -64,8 +42,9 @@ class ScalarSchema extends Schema {
return $haveIndex0 && $count > 1;
}
static function normalize($definition, $definitionKey=null): array {
self::_normalize($definition, $definitionKey);
static function normalize_definition($definition, $definitionKey=null): array {
$natureMetaschema = array_merge(ref_schema::NATURE_METASCHEMA, ref_schema::SCALAR_NATURE_METASCHEMA);
self::_normalize_definition($definition, $definitionKey, $natureMetaschema);
self::_ensure_nature($definition, "scalar");
return $definition;
}
@ -73,37 +52,47 @@ class ScalarSchema extends Schema {
function __construct($definition=null, $definitionKey=null, bool $normalize=true) {
if ($definition === null) $definition = static::SCHEMA;
if ($normalize) {
$definition = self::normalize($definition, $definitionKey);
$definition = self::normalize_definition($definition, $definitionKey);
$this->_definition = $definition;
self::_ensure_type($definition);
self::_ensure_schema_instances($definition);
} else {
# ici, $definition contient un schema déjà instancié, mais c'est le mieux
# qu'on puisse faire
$this->_definition = $definition;
}
$this->definition = $definition;
}
function isScalar(?ScalarSchema &$schema=null): bool {
$schema = $this;
return true;
const KEYS = [null];
function getKeys(): array {
return self::KEYS;
}
function getSchema($key=false): Schema {
if ($key === null || $key === false) return $this;
throw ValueException::invalid_key($key);
}
protected function newWrapper(): ScalarWrapper {
return new ScalarWrapper($this);
}
function getWrapper(&$value=null, $valueKey=null, ?Wrapper &$wrapper=null): ScalarWrapper {
function getWrapper(&$value=null, $valueKey=null, ?array $params=null, ?Wrapper &$wrapper=null): ScalarWrapper {
# si pas de valeur ni de wrapper, pas de vérification et donc pas d'exception
# cf le code similaire dans ScalarWrapper::__construct()
$dontAnalyze = $value === null && $wrapper === null;
if (!($wrapper instanceof ScalarWrapper)) $wrapper = $this->newWrapper();
return $wrapper->reset($value, $valueKey);
# la nature du schéma peut contenir des paramètres par défaut
$nature = $this->definition[""];
foreach (array_keys(ref_schema::SCALAR_PARAMS_SCHEMA) as $paramKey) {
$paramValue = $nature[$paramKey] ?? null;
if ($paramValue !== null) $params[$paramKey] = $paramValue;
}
if ($params !== null) $wrapper->resetParams($params);
return $wrapper->reset($value, $valueKey, $dontAnalyze? ["analyze" => false]: null);
}
#############################################################################
# key & properties
const _PROPERTY_PKEYS = [
"analyzerFunc" => "analyzer_func",
"extractorFunc" => "extractor_func",
"parserFunc" => "parser_func",
"normalizerFunc" => "normalizer_func",
"formatterFunc" => "formatter_func",
"nature" => ["", 0],
];
}

View File

@ -1,70 +1,42 @@
<?php
namespace nur\sery\wip\schema\_scalar;
namespace nulib\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;
use nulib\schema\Schema;
use nulib\schema\types;
use nulib\schema\types\IType;
use nulib\schema\Wrapper;
use nulib\schema\WrapperContext;
/**
* Class ScalarWrapper
*
* @method ScalarWrapper reset(&$value, $valueKey=null, ?array $params=null)
* @method ScalarResult getResult($key=false)
* @method self set($value, ?array $params=null, $key=false)
* @method self unset(?array $params=null, $key=false)
*/
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;
function __construct(Schema $schema, &$value=null, $valueKey=null, ?array $params=null, ?WrapperContext $context=null) {
if ($context === null) $context = new WrapperContext($schema, null, null, $params);
$context->result = new ScalarResult();
$this->context = $context;
if ($value !== null) {
# n'initialiser que si $value n'est pas null
$this->reset($value, $valueKey);
} else {
# il faut au moins que le type soit disponible
$this->resetContext(false);
}
$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;
}
protected WrapperContext $context;
function getKeys(): array {
return [null];
return ScalarSchema::KEYS;
}
/** @param string|int|null $key */
@ -74,7 +46,7 @@ class ScalarWrapper extends Wrapper {
}
/** analyser la valeur et résoudre son type */
protected function analyze0(AnalyzerContext $context): int {
protected static function _analyze0(WrapperContext $context): int {
/** @var ScalarSchema $schema */
$schema = $context->schema;
$input = $context->input;
@ -112,7 +84,7 @@ class ScalarWrapper extends Wrapper {
$args = $name;
$name = $key;
}
$type = types::get($schema->nullable, $name, $args, $this->schema->getDefinition());
$type = types::get($schema->nullable, $name, $args, $schema->getDefinition());
if ($firstType === null) $firstType = $type;
$types[] = $type;
if ($type->isAvailable($input, $valueKey)) {
@ -140,7 +112,7 @@ class ScalarWrapper extends Wrapper {
$type = $firstType;
}
}
$context->type = $this->type = $type;
$context->type = $type;
if (!$type->isAvailable($input, $valueKey)) {
if ($default !== null) {
@ -165,25 +137,28 @@ class ScalarWrapper extends Wrapper {
}
}
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);
/**
* @param ScalarWrapper $wrapper
*/
static function _analyze(WrapperContext $context, Wrapper $wrapper, ?array $params): int {
/** @var ScalarSchema $schema */
$schema = $context->schema;
$input = $context->input;
$valueKey = $context->valueKey;
/** @var ScalarResult $result */
$result = $context->result;
/** @var func $analyzerFunc */
$analyzerFunc = $schema->analyzerFunc;
if ($analyzerFunc !== null) $what = $analyzerFunc->invoke([$context]);
else $what = $this->analyze0($context);
if ($analyzerFunc !== null) $what = $analyzerFunc->invoke([$context, $wrapper]);
else $what = self::_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]);
if ($extractorFunc !== null) $extracted = $extractorFunc->invoke([$value, $context, $wrapper]);
else $extracted = $context->type->extract($value);
$context->value = $extracted;
} catch (ValueException $e) {
@ -194,7 +169,7 @@ class ScalarWrapper extends Wrapper {
try {
/** @var func $parserFunc */
$parserFunc = $schema->parserFunc;
if ($parserFunc !== null) $parsed = $parserFunc->invoke([$extracted, $context]);
if ($parserFunc !== null) $parsed = $parserFunc->invoke([$extracted, $context, $wrapper]);
else $parsed = $context->type->parse($extracted);
$context->value = $parsed;
} catch (ValueException $e) {
@ -211,107 +186,53 @@ class ScalarWrapper extends Wrapper {
}
}
function verifix(?bool $throw=null): bool {
$result = $this->result;
$valueKey = $this->valueKey;
$verifix = false;
/**
* @param ScalarWrapper $wrapper
*/
static function _normalize(WrapperContext $context, Wrapper $wrapper, ?array $params): bool {
/** @var ScalarSchema $schema */
$schema = $context->schema;
$input = $context->input;
$valueKey = $context->valueKey;
/** @var ScalarResult $result */
$result = $context->result;
$normalize = 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);
$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);
$input->set($normalizedValue, $valueKey);
$result->normalizedValue = null;
$modified = true;
} else {
# normaliser la valeur
$verifix = true;
$normalize = true;
}
}
} else {
$verifix = true;
$normalize = true;
}
if ($verifix) {
$value = $this->input->get($valueKey);
$schema = $this->schema;
if ($normalize) {
$value = $input->get($valueKey);
/** @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]);
$value = $normalizerFunc->invoke([$orig, $context, $wrapper]);
$modified = $value !== $orig;
} else {
$modified = $this->type->verifix($value, $result, $this->schema);
$modified = $context->type->normalize($value, $result, $schema);
}
if ($result->valid) $this->input->set($value, $valueKey);
if ($result->valid) $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);
}
}
}

View File

@ -1,12 +1,11 @@
<?php
namespace nur\sery\wip\schema\input;
namespace nulib\schema\input;
#XXX implémenter le renommage de paramètres et faire des méthodes pour
# construire des querystring et paramètres de formulaires
use nur\sery\wip\php\access\FormAccess;
use nur\sery\wip\php\access\IAccess;
use nur\sery\wip\php\access\KeyAccess;
use nur\sery\wip\php\access\ShadowAccess;
use nulib\php\access\FormAccess;
use nulib\php\access\IAccess;
use nulib\php\access\ShadowAccess;
/**
* Class FormInput: accès à des paramètres de formulaire (POST ou GET, dans cet
@ -18,15 +17,14 @@ use nur\sery\wip\php\access\ShadowAccess;
class FormInput extends Input {
const ALLOW_EMPTY = false;
protected function formAccess($key): IAccess {
return new FormAccess($key, [
"allow_empty" => $this->allowEmpty,
]);
function __construct(&$dest=null, ?array $params=null) {
parent::__construct($dest, $params);
$this->access = new ShadowAccess($this->formAccess($this->access), $this->access);
}
protected function access($key): IAccess {
return $this->keyAccess[$key] ??= new ShadowAccess($this->formAccess($key), new KeyAccess($this->value, $key, [
"allow_empty" => $this->allowEmpty,
]));
protected function formAccess(IAccess $access): IAccess {
return new FormAccess(null, [
"allow_empty" => $access->isAllowEmpty(),
]);
}
}

View File

@ -1,8 +1,8 @@
<?php
namespace nur\sery\wip\schema\input;
namespace nulib\schema\input;
use nur\sery\wip\php\access\GetAccess;
use nur\sery\wip\php\access\IAccess;
use nulib\php\access\GetAccess;
use nulib\php\access\IAccess;
/**
* Class GetInput: accès à des paramètres de formulaire de type GET uniquement
@ -11,9 +11,9 @@ use nur\sery\wip\php\access\IAccess;
* une référence
*/
class GetInput extends FormInput {
protected function formAccess($key): IAccess {
return new GetAccess($key, [
"allow_empty" => $this->allowEmpty,
protected function formAccess(IAccess $access): IAccess {
return new GetAccess(null, [
"allow_empty" => $access->isAllowEmpty(),
]);
}
}

View File

@ -1,9 +1,11 @@
<?php
namespace nur\sery\wip\schema\input;
namespace nulib\schema\input;
use nur\sery\wip\php\access\IAccess;
use nur\sery\wip\php\access\KeyAccess;
use nur\sery\wip\php\access\ValueAccess;
use nulib\ref\schema\ref_input;
use nulib\StateException;
use nulib\php\access\IAccess;
use nulib\php\access\KeyAccess;
use nulib\php\access\PropertyAccess;
/**
* Class Input: accès à une valeur
@ -13,54 +15,72 @@ use nur\sery\wip\php\access\ValueAccess;
class Input {
const ALLOW_EMPTY = true;
function __construct(&$value=null, ?array $params=null) {
$this->value =& $value;
$this->allowEmpty = $params["allow_empty"] ?? static::ALLOW_EMPTY;
private static function unexpected_access_type(): StateException {
return StateException::unexpected_state("access_type");
}
/** @var mixed */
protected $value;
function __construct(&$dest=null, ?array $params=null) {
$accessType = $params["access_type"] ?? ref_input::ACCESS_AUTO;
if ($accessType === ref_input::ACCESS_AUTO) {
$accessType = is_object($dest)? ref_input::ACCESS_PROPERTY : ref_input::ACCESS_KEY;
}
/**
* @var bool comment considérer une chaine vide: "" si allowEmpty, null sinon
*/
protected $allowEmpty;
protected ?ValueAccess $valueAccess = null;
protected ?array $keyAccess = null;
protected function access($key): IAccess {
if ($key === null) {
return $this->valueAccess ??= new ValueAccess($this->value, [
$allowEmpty = $params["allow_empty"] ?? static::ALLOW_EMPTY;
if ($accessType == ref_input::ACCESS_PROPERTY) {
$this->access = new PropertyAccess($dest, null, [
"allow_empty" => $allowEmpty,
"allow_null" => true,
]);
} elseif ($accessType == ref_input::ACCESS_KEY) {
$this->access = new KeyAccess($dest, null, [
"allow_empty" => $allowEmpty,
"allow_null" => true,
"allow_empty" => $this->allowEmpty,
]);
} else {
return $this->keyAccess[$key] ??= new KeyAccess($this->value, $key, [
"allow_empty" => $this->allowEmpty,
]);
throw self::unexpected_access_type();
}
}
protected IAccess $access;
/** tester si la valeur existe sans tenir compte de $allowEmpty */
function isPresent($key=null): bool {
return $this->access($key)->exists();
return $this->access->resetKey($key)->exists();
}
/** tester si la valeur est disponible en tenant compte de $allowEmpty */
function isAvailable($key=null): bool {
return $this->access($key)->available();
return $this->access->resetKey($key)->available();
}
function get($key=null) {
return $this->access($key)->get();
return $this->access->resetKey($key)->get();
}
function set($value, $key=null): void {
$this->access($key)->set($value);
$this->access->resetKey($key)->set($value);
}
function unset($key=null): void {
$this->access($key)->del();
$this->access->resetKey($key)->del();
}
function addKey($key): Input {
if ($key === null) return $this;
$input = clone $this;
$input->access = $this->access->addKey($key);
return $input;
}
function ensureAssoc(array $keys, ?array $params=null): void {
$this->access->ensureAssoc($keys, $params);
}
function ensureKeys(array $defaults, ?array $params=null): void {
$this->access->ensureKeys($defaults, $params);
}
function ensureOrder(array $keys, ?array $params=null): void {
$this->access->ensureOrder($keys, $params);
}
}

View File

@ -1,8 +1,8 @@
<?php
namespace nur\sery\wip\schema\input;
namespace nulib\schema\input;
use nur\sery\wip\php\access\IAccess;
use nur\sery\wip\php\access\PostAccess;
use nulib\php\access\IAccess;
use nulib\php\access\PostAccess;
/**
* Class PostInput: accès à des paramètres de formulaire de type POST uniquement
@ -11,9 +11,9 @@ use nur\sery\wip\php\access\PostAccess;
* une référence
*/
class PostInput extends FormInput {
protected function formAccess($key): IAccess {
return new PostAccess($key, [
"allow_empty" => $this->allowEmpty,
protected function formAccess(IAccess $access): IAccess {
return new PostAccess(null, [
"allow_empty" => $access->isAllowEmpty(),
]);
}
}

View File

@ -1,21 +1,22 @@
<?php
namespace nur\sery\wip\schema;
namespace nulib\schema;
use nur\sery\wip\schema\types\IType;
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;
use nulib\ValueException;
use nulib\schema\types\IType;
use nulib\schema\types\Registry;
use nulib\schema\types\tarray;
use nulib\schema\types\tbool;
use nulib\schema\types\tfunc;
use nulib\schema\types\tcontent;
use nulib\schema\types\tfloat;
use nulib\schema\types\tint;
use nulib\schema\types\tkey;
use nulib\schema\types\tmixed;
use nulib\schema\types\tpkey;
use nulib\schema\types\traw;
use nulib\schema\types\trawstring;
use nulib\schema\types\tstring;
use nulib\schema\types\ttext;
/**
* Class types: classe outil pour gérer le registre de types
@ -31,7 +32,11 @@ class types {
return self::$registry;
}
static function get(bool $nullable, ?string $name, ?array $args=null, ?array $definition=null): IType {
static function get(bool $nullable, $name, ?array $args=null, ?array $definition=null): IType {
if ($name instanceof IType) return $name;
if ($name !== null && !is_string($name)) {
throw ValueException::invalid_type($name, "string");
}
return self::registry()->get($nullable, $name, $args, $definition);
}
@ -42,7 +47,7 @@ class types {
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 callable(bool $nullable=true): tfunc { 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"); }

View File

@ -1,15 +1,17 @@
<?php
namespace nur\sery\wip\schema\types;
namespace nulib\schema\types;
use nulib\ValueException;
use nur\sery\wip\schema\input\Input;
use nur\sery\wip\schema\Result;
use nur\sery\wip\schema\Schema;
use nulib\schema\input\Input;
use nulib\schema\Result;
use nulib\schema\Schema;
/**
* Interface IType: un type de données
*/
interface IType {
static function get_params_from_definition(?array $definition): ?array;
/**
* obtenir, pour information, le nom officiel de ce type, utilisable dans une
* définition de schéma
@ -21,7 +23,7 @@ interface IType {
/**
* @return string la classe des objets gérés par ce format: le type attendu
* par {@link format()} et le type retourné par {@link verifix()}
* par {@link format()} et le type retourné par {@link normalize()}
*
* Les valeurs "mixed", "bool", "float", "int", "string" et "array" peuvent
* aussi être retournées, bien qu'elles ne soient pas à proprement parler des
@ -45,6 +47,9 @@ interface IType {
*/
function getPhpType(bool $allowNullable=true): ?string;
/** obtenir la valeur "nulle" pour les objets de ce type */
function getNullValue();
/**
* indiquer si c'est le type d'une valeur qui ne peut prendre que 2 états: une
* "vraie" et une "fausse"
@ -96,15 +101,18 @@ interface IType {
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
* normaliser la valeur. elle *doit* déjà être valide.
* 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.
* - si $result indique que la valeur est déjà normalisée, cette méthode ne
* fait rien
* - si la valeur était déjà normalisée, mettre à jour $result pour indiquer
* que la valeur est normalisée et retourner false
* - sinon, retourner true pour indiquer qu'il a fallut normaliser la valeur.
* $result n'est pas modifié
*/
function verifix(&$value, Result $result, Schema $schema): bool;
function normalize(&$value, Result $result, Schema $schema): bool;
/**
* formatter la valeur pour affichage. si $value n'est pas null, elle est

View File

@ -1,8 +1,9 @@
<?php
namespace nur\sery\wip\schema\types;
namespace nulib\schema\types;
use nulib\cl;
use nulib\php\func;
use nulib\ValueException;
class Registry {
const TYPES = [
@ -11,12 +12,11 @@ class Registry {
"text" => ttext::class,
"bool" => tbool::class, "boolean" => tbool::class,
"int" => tint::class, "integer" => tint::class,
"float" => tfloat::class, "flt" => tfloat::class,
"double" => tfloat::class, "dbl" => tfloat::class,
"float" => tfloat::class, "flt" => tfloat::class, "double" => tfloat::class, "dbl" => tfloat::class,
"array" => tarray::class,
"callable" => tcallable::class,
"func" => tfunc::class, "function" => tfunc::class, "callable" => tfunc::class,
# types spéciaux
"raw" => tmixed::class,
"raw" => traw::class,
"mixed" => tmixed::class,
"key" => tkey::class,
"pkey" => tpkey::class,
@ -31,8 +31,6 @@ class Registry {
protected $types;
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];
@ -41,6 +39,16 @@ class Registry {
$params = $args;
$args = null;
}
$name ??= "raw";
$class = cl::get(self::TYPES, $name);
if ($class === null) {
$class = $name;
if (!class_exists($class)) {
throw ValueException::invalid_type($class, IType::class);
} elseif (!is_subclass_of($class, IType::class)) {
return new tgeneric($class, $nullable, $params);
}
}
$params = cl::merge($class::get_params_from_definition($definition), $params);
if ($args || $params !== null) {
$args ??= [];

View File

@ -1,5 +1,5 @@
<?php
namespace nur\sery\wip\schema\types;
namespace nulib\schema\types;
abstract class _tformatable extends _tsimple {
const FORMAT = null;

View File

@ -1,9 +1,9 @@
<?php
namespace nur\sery\wip\schema\types;
namespace nulib\schema\types;
use nulib\StateException;
use nur\prop;
use nur\sery\wip\schema\input\Input;
use nulib\schema\input\Input;
use nur\str;
abstract class _tsimple implements IType {

View File

@ -1,5 +1,5 @@
<?php
namespace nur\sery\wip\schema\types;
namespace nulib\schema\types;
use nulib\str;

View File

@ -1,5 +1,5 @@
<?php
namespace nur\sery\wip\schema\types;
namespace nulib\schema\types;
abstract class _tunion extends _tsimple {
function getPhpType(bool $allowNullable=true): ?string {

View File

@ -1,12 +1,12 @@
<?php
namespace nur\sery\wip\schema\types;
namespace nulib\schema\types;
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;
use nulib\schema\_scalar\ScalarResult;
use nulib\schema\_scalar\ScalarSchema;
use nulib\schema\Result;
use nulib\schema\Schema;
class tarray extends _tstring {
const NAME = "array";
@ -35,9 +35,13 @@ class tarray extends _tstring {
return "array";
}
function getNullValue() {
return $this->nullable? null: [];
}
function isValid($value, ?bool &$normalized=null): bool {
$normalized = is_array($value);
return is_scalar($value) || is_array($value);
return $normalized || is_scalar($value);
}
function parse(string $value) {
@ -49,23 +53,14 @@ class tarray extends _tstring {
* @var ScalarResult $result
* @var ScalarSchema $schema
*/
function verifix(&$value, Result $result, Schema $schema): bool {
if (is_array($value)) {
function normalize(&$value, Result $result, Schema $schema): bool {
if ($result->normalized) {
} elseif (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;
}

View File

@ -1,14 +1,14 @@
<?php
namespace nur\sery\wip\schema\types;
namespace nulib\schema\types;
use nulib\cl;
use nulib\ValueException;
use nur\prop;
use nur\sery\wip\schema\_scalar\ScalarResult;
use nur\sery\wip\schema\_scalar\ScalarSchema;
use nur\sery\wip\schema\input\Input;
use nur\sery\wip\schema\Result;
use nur\sery\wip\schema\Schema;
use nulib\schema\_scalar\ScalarResult;
use nulib\schema\_scalar\ScalarSchema;
use nulib\schema\input\Input;
use nulib\schema\Result;
use nulib\schema\Schema;
class tbool extends _tformatable {
const NAME = "bool";
@ -76,6 +76,10 @@ class tbool extends _tformatable {
return [false, true, null];
}
function getNullValue() {
return $this->nullable? null: false;
}
function isAvailable(Input $input, $valueKey): bool {
return $input->isAvailable($valueKey);
}
@ -99,23 +103,14 @@ class tbool extends _tformatable {
* @var ScalarResult $result
* @var ScalarSchema $schema
*/
function verifix(&$value, Result $result, Schema $schema): bool {
if (is_bool($value)) {
function normalize(&$value, Result $result, Schema $schema): bool {
if ($result->normalized) {
} elseif (is_bool($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 = boolval($value);
$result->setValid();
return true;
}
$result->setInvalid($value, $schema);
return false;
}

View File

@ -1,68 +0,0 @@
<?php
namespace nur\sery\wip\schema\types;
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;
class tcallable extends _tsimple {
const NAME = "callable";
const ALIASES = ["func", "function"];
static function ensure_callable(&$callable): void {
$callable = func::ensure($callable);
}
static function ensure_ncallable(&$callable): void {
if ($callable !== null) self::ensure_callable($callable);
}
function getClass(): string {
return func::class;
}
function isValid($value, ?bool &$normalized=null): bool {
$normalized = is_callable($value);
return func::check($value);
}
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 {
}
}

View File

@ -1,11 +1,11 @@
<?php
namespace nur\sery\wip\schema\types;
namespace nulib\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;
use nulib\schema\_scalar\ScalarResult;
use nulib\schema\_scalar\ScalarSchema;
use nulib\schema\Result;
use nulib\schema\Schema;
abstract class tcontent extends _tunion {
const NAME = "content";
@ -23,9 +23,13 @@ abstract class tcontent extends _tunion {
return "string|array";
}
function getNullValue() {
return $this->nullable? null: [];
}
function isValid($value, ?bool &$normalized=null): bool {
$normalized = is_string($value) || is_array($value);
return is_scalar($value) || is_array($value);
return $normalized || is_scalar($value);
}
function parse(string $value) {
@ -36,18 +40,15 @@ abstract class tcontent extends _tunion {
* @var ScalarResult $result
* @var ScalarSchema $schema
*/
function verifix(&$value, Result $result, Schema $schema): bool {
if (is_string($value) || is_array($value)) {
function normalize(&$value, Result $result, Schema $schema): bool {
if ($result->normalized) {
} elseif (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;
}
return false;
}
function format($value, $format=null): string {

View File

@ -1,11 +1,11 @@
<?php
namespace nur\sery\wip\schema\types;
namespace nulib\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;
use nulib\schema\_scalar\ScalarResult;
use nulib\schema\_scalar\ScalarSchema;
use nulib\schema\Result;
use nulib\schema\Schema;
class tfloat extends _tformatable {
const NAME = "float";
@ -24,6 +24,10 @@ class tfloat extends _tformatable {
return "float";
}
function getNullValue() {
return $this->nullable? null: 0.0;
}
function isValid($value, ?bool &$normalized=null): bool {
$normalized = is_float($value);
return is_scalar($value);
@ -43,23 +47,14 @@ class tfloat extends _tformatable {
* @var ScalarResult $result
* @var ScalarSchema $schema
*/
function verifix(&$value, Result $result, Schema $schema): bool {
if (is_float($value)) {
function normalize(&$value, Result $result, Schema $schema): bool {
if ($result->normalized) {
} elseif (is_float($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 = floatval($value);
$result->setValid();
return true;
}
$result->setInvalid($value, $schema);
return false;
}
}

View File

@ -0,0 +1,63 @@
<?php
namespace nulib\schema\types;
use Exception;
use nulib\php\func;
use nulib\ValueException;
use nulib\schema\_scalar\ScalarResult;
use nulib\schema\_scalar\ScalarSchema;
use nulib\schema\Result;
use nulib\schema\Schema;
class tfunc extends _tsimple {
const NAME = "func";
const ALIASES = ["function", "callable"];
static function ensure_func(&$func): void {
$func = func::ensure($func);
}
static function ensure_nfunc(&$func): void {
if ($func !== null) self::ensure_func($func);
}
function getClass(): string {
return func::class;
}
function getNullValue() {
return null;
}
function isValid($value, ?bool &$normalized=null): bool {
$normalized = $value instanceof func;
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 normalize(&$value, Result $result, Schema $schema): bool {
if ($result->normalized) {
} elseif ($value instanceof func) {
$result->setNormalized();
} elseif (is_callable($value)) {
$value = func::with($value);
return true;
}
return false;
}
function format($value, $format=null): string {
}
}

View File

@ -0,0 +1,56 @@
<?php
namespace nulib\schema\types;
use nulib\ValueException;
use nulib\schema\_scalar\ScalarResult;
use nulib\schema\_scalar\ScalarSchema;
use nulib\schema\input\Input;
use nulib\schema\Result;
use nulib\schema\Schema;
class tgeneric extends _tsimple {
function __construct(string $class, bool $nullable, ?array $params=null) {
$this->class = $class;
parent::__construct($nullable, $params);
}
protected string $class;
function getClass(): string {
return $this->class;
}
function getNullValue() {
return null;
}
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 = $value instanceof $this->class;
return $normalized;
}
function parse(string $value) {
throw ValueException::invalid_type($value, $this->class);
}
/**
* @var ScalarResult $result
* @var ScalarSchema $schema
*/
function normalize(&$value, Result $result, Schema $schema): bool {
if (!$result->normalized) $result->setNormalized();
return false;
}
function format($value, $format=null): string {
return strval($value);
}
}

View File

@ -1,11 +1,11 @@
<?php
namespace nur\sery\wip\schema\types;
namespace nulib\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;
use nulib\schema\_scalar\ScalarResult;
use nulib\schema\_scalar\ScalarSchema;
use nulib\schema\Result;
use nulib\schema\Schema;
class tint extends _tformatable {
const NAME = "int";
@ -26,6 +26,10 @@ class tint extends _tformatable {
return "int";
}
function getNullValue() {
return $this->nullable? null: 0;
}
function isValid($value, ?bool &$normalized=null): bool {
$normalized = is_int($value);
return is_scalar($value);
@ -45,23 +49,14 @@ class tint extends _tformatable {
* @var ScalarResult $result
* @var ScalarSchema $schema
*/
function verifix(&$value, Result $result, Schema $schema): bool {
if (is_int($value)) {
function normalize(&$value, Result $result, Schema $schema): bool {
if ($result->normalized) {
} elseif (is_int($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 = intval($value);
$result->setValid();
return true;
}
$result->setInvalid($value, $schema);
return false;
}
}

View File

@ -1,10 +1,10 @@
<?php
namespace nur\sery\wip\schema\types;
namespace nulib\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;
use nulib\schema\_scalar\ScalarResult;
use nulib\schema\_scalar\ScalarSchema;
use nulib\schema\Result;
use nulib\schema\Schema;
class tkey extends _tunion {
const NAME = "key";
@ -23,9 +23,13 @@ class tkey extends _tunion {
return "string|int";
}
function getNullValue() {
return $this->nullable? null: "";
}
function isValid($value, ?bool &$normalized=null): bool {
$normalized = is_string($value) || is_int($value);
return is_scalar($value);
return $normalized || is_scalar($value);
}
function parse(string $value) {
@ -36,18 +40,15 @@ class tkey extends _tunion {
* @var ScalarResult $result
* @var ScalarSchema $schema
*/
function verifix(&$value, Result $result, Schema $schema): bool {
if (is_string($value) || is_int($value)) {
function normalize(&$value, Result $result, Schema $schema): bool {
if ($result->normalized) {
} elseif (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;
}
return false;
}
function format($value, $format=null): string {

View File

@ -1,11 +1,11 @@
<?php
namespace nur\sery\wip\schema\types;
namespace nulib\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;
use nulib\schema\_scalar\ScalarResult;
use nulib\schema\_scalar\ScalarSchema;
use nulib\schema\input\Input;
use nulib\schema\Result;
use nulib\schema\Schema;
class tmixed extends _tsimple {
const NAME = "mixed";
@ -14,6 +14,10 @@ class tmixed extends _tsimple {
return "mixed";
}
function getNullValue() {
return null;
}
function isAvailable(Input $input, $valueKey): bool {
return $input->isAvailable($valueKey);
}
@ -35,12 +39,12 @@ class tmixed extends _tsimple {
* @var ScalarResult $result
* @var ScalarSchema $schema
*/
function verifix(&$value, Result $result, Schema $schema): bool {
$result->setNormalized();
function normalize(&$value, Result $result, Schema $schema): bool {
if (!$result->normalized) $result->setNormalized();
return false;
}
function format($value, $format=null): string {
return var_export($value, true);
return strval($value);
}
}

View File

@ -1,10 +1,10 @@
<?php
namespace nur\sery\wip\schema\types;
namespace nulib\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;
use nulib\schema\_scalar\ScalarResult;
use nulib\schema\_scalar\ScalarSchema;
use nulib\schema\Result;
use nulib\schema\Schema;
class tpkey extends _tunion {
const NAME = "pkey";
@ -28,9 +28,13 @@ class tpkey extends _tunion {
return "string|int|array";
}
function getNullValue() {
return $this->nullable? null: [];
}
function isValid($value, ?bool &$normalized=null): bool {
$normalized = is_string($value) || is_int($value) || is_array($value);
return is_scalar($value) || is_array($value);
return $normalized || is_scalar($value);
}
function parse(string $value) {
@ -41,18 +45,15 @@ class tpkey extends _tunion {
* @var ScalarResult $result
* @var ScalarSchema $schema
*/
function verifix(&$value, Result $result, Schema $schema): bool {
if (is_string($value) || is_int($value) || is_array($value)) {
function normalize(&$value, Result $result, Schema $schema): bool {
if ($result->normalized) {
} elseif (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;
}
return false;
}
function format($value, $format=null): string {

View File

@ -1,7 +1,7 @@
<?php
namespace nur\sery\wip\schema\types;
namespace nulib\schema\types;
use nur\sery\wip\schema\input\Input;
use nulib\schema\input\Input;
class traw extends tmixed {
const NAME = "raw";

View File

@ -1,11 +1,11 @@
<?php
namespace nur\sery\wip\schema\types;
namespace nulib\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;
use nulib\schema\_scalar\ScalarResult;
use nulib\schema\_scalar\ScalarSchema;
use nulib\schema\Result;
use nulib\schema\Schema;
class trawstring extends _tstring {
const NAME = "rawstring";
@ -24,6 +24,10 @@ class trawstring extends _tstring {
return "string";
}
function getNullValue() {
return $this->nullable? null: "";
}
function isNull($value): bool {
return $value === null;
}
@ -44,18 +48,15 @@ class trawstring extends _tstring {
* @var ScalarResult $result
* @var ScalarSchema $schema
*/
function verifix(&$value, Result $result, Schema $schema): bool {
if (is_string($value)) {
function normalize(&$value, Result $result, Schema $schema): bool {
if ($result->normalized) {
} elseif (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;
}
return false;
}
function format($value, $format=null): string {

View File

@ -1,5 +1,5 @@
<?php
namespace nur\sery\wip\schema\types;
namespace nulib\schema\types;
class tstring extends trawstring {
const NAME = "string";

View File

@ -1,5 +1,5 @@
<?php
namespace nur\sery\wip\schema\types;
namespace nulib\schema\types;
class ttext extends trawstring {
const NAME = "text";

View File

@ -1,5 +1,5 @@
<?php
namespace nur\sery\wip\web\content;
namespace nulib\web\content;
use nulib\A;

View File

@ -1,5 +1,5 @@
<?php
namespace nur\sery\wip\web\content;
namespace nulib\web\content;
/**
* Class v: classe outil pour gérer du contenu pour le web

View File

@ -1,5 +0,0 @@
<?php
namespace nulib;
class app extends \nur\sery\app {
}

View File

@ -1,5 +0,0 @@
<?php
namespace nulib\app\cli;
abstract class Application extends \nur\sery\app\cli\Application {
}

132
tests/appTest.php Normal file
View File

@ -0,0 +1,132 @@
<?php
namespace nulib {
use nulib\tests\TestCase;
use nulib\impl\config;
use nulib\impl\myapp;
use nulib\impl\MyApplication1;
use nulib\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 nulib\impl {
use nulib\app\cli\Application;
use nulib\os\path;
use nulib\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() {
}
}
}

View File

@ -0,0 +1,215 @@
<?php
namespace nulib\php\access;
use nulib\tests\TestCase;
use stdClass;
class KeyAccessTest extends TestCase {
function testValueAccess() {
$default = new stdClass();
#
$i = null;
$a = new KeyAccess($i);
self::assertFalse($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$i = false;
$a = new KeyAccess($i);
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame(false, $a->get($default));
$i = "";
$a = new KeyAccess($i);
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame("", $a->get($default));
#
$i = null;
$a = new KeyAccess($i, null, ["allow_null" => false]);
self::assertFalse($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$i = null;
$a = new KeyAccess($i, null, ["allow_null" => true]);
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame(null, $a->get($default));
#
$i = false;
$a = new KeyAccess($i, null, ["allow_false" => false]);
self::assertTrue($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$i = false;
$a = new KeyAccess($i, null, ["allow_false" => true]);
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame(false, $a->get($default));
#
$i = "";
$a = new KeyAccess($i, null, ["allow_empty" => false]);
self::assertTrue($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$i = "";
$a = new KeyAccess($i, null, ["allow_empty" => true]);
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame("", $a->get($default));
}
function testArrayAccess() {
$default = new stdClass();
$array = ["null" => null, "false" => false, "empty" => ""];
#
$a = new KeyAccess($array, "inexistant");
self::assertFalse($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$a = new KeyAccess($array, "null");
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame(null, $a->get($default));
$a = new KeyAccess($array, "false");
self::assertTrue($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$a = new KeyAccess($array, "empty");
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame("", $a->get($default));
#
$a = new KeyAccess($array, "null", ["allow_null" => false]);
self::assertTrue($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$a = new KeyAccess($array, "null", ["allow_null" => true]);
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame(null, $a->get($default));
#
$a = new KeyAccess($array, "false", ["allow_false" => false]);
self::assertTrue($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$a = new KeyAccess($array, "false", ["allow_false" => true]);
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame(false, $a->get($default));
#
$a = new KeyAccess($array, "empty", ["allow_empty" => false]);
self::assertTrue($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$a = new KeyAccess($array, "empty", ["allow_empty" => true]);
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame("", $a->get($default));
}
private function _ensureAssoc(?array $orig, ?array $expected, array $keys, ?array $params=null) {
$v = $orig; $a = new KeyAccess($v);
$a->ensureAssoc($keys, $params);
self::assertSame($expected, $v);
}
function testEnsureAssoc() {
$keys = ["a", "b", "c"];
$this->_ensureAssoc(null, null, $keys);
$this->_ensureAssoc([], [], $keys);
$this->_ensureAssoc([1], ["a" => 1], $keys);
$this->_ensureAssoc([1, 2, 3], ["a" => 1, "b" => 2, "c" => 3], $keys);
$this->_ensureAssoc([1, 2, 3, 4], [3 => 4, "a" => 1, "b" => 2, "c" => 3], $keys);
$this->_ensureAssoc(["c" => 3, 1], ["c" => 3, "a" => 1], $keys);
$this->_ensureAssoc(["c" => 3, "b" => 2, 1], ["c" => 3, "b" => 2, "a" => 1], $keys);
$this->_ensureAssoc(["c" => 3, "b" => 2, "a" => 1], ["c" => 3, "b" => 2, "a" => 1], $keys);
$this->_ensureAssoc(["a" => 1, 2], ["a" => 1, "b" => 2], $keys);
$this->_ensureAssoc([2, "a" => 1], ["a" => 1, "b" => 2], $keys);
$keys = [0, "a", "b"];
$this->_ensureAssoc([1], [1], $keys);
$this->_ensureAssoc([1, 2], [1, "a" => 2], $keys);
}
private function _ensureKeys(?array $orig, ?array $expected, array $defaults, ?array $params=null) {
$v = $orig; $a = new KeyAccess($v);
$a->ensureKeys($defaults, $params);
self::assertSame($expected, $v);
}
function testEnsureKeys() {
$defaults = ["a" => false, "b" => false, "c" => false];
$this->_ensureKeys(null, ["a" => false, "b" => false, "c" => false], $defaults);
$this->_ensureKeys([], ["a" => false, "b" => false, "c" => false], $defaults);
$this->_ensureKeys(["a" => 1], ["a" => 1, "b" => false, "c" => false], $defaults);
$this->_ensureKeys(["a" => 1, "b" => 2, "c" => 3], ["a" => 1, "b" => 2, "c" => 3], $defaults);
$this->_ensureKeys(["x"], ["x", "a" => false, "b" => false, "c" => false], $defaults);
$this->_ensureKeys(["x", "a" => 1], ["x", "a" => 1, "b" => false, "c" => false], $defaults);
$this->_ensureKeys(["a" => 1, "x"], ["a" => 1, "x", "b" => false, "c" => false], $defaults);
$this->_ensureKeys(["a" => 1, "b" => 2, "c" => 3, "x"], ["a" => 1, "b" => 2, "c" => 3, "x"], $defaults);
}
private function _ensureOrder(?array $orig, ?array $expected, array $keys, ?array $params=null) {
$v = $orig; $a = new KeyAccess($v);
$a->ensureOrder($keys, $params);
self::assertSame($expected, $v);
}
function testEnsureOrder() {
$keys = ["a", "b", "c"];
$this->_ensureOrder(null, null, $keys);
$this->_ensureOrder([], [], $keys);
$this->_ensureOrder([1], [1], $keys);
$this->_ensureOrder(["b" => 2, "a" => 1], ["a" => 1, "b" => 2], $keys);
$this->_ensureOrder(["c" => 3, "a" => 1], ["a" => 1, "c" => 3], $keys);
}
private function _ensureAssocKeysOrder(?array $orig, ?array $expected, array $defaults, ?array $params=null) {
$v = $orig; $a = new KeyAccess($v);
$keys = array_keys($defaults);
$a->ensureAssoc($keys, $params);
$a->ensureKeys($defaults, $params);
$a->ensureOrder($keys, $params);
self::assertSame($expected, $v);
}
function testEnsureAssocKeysOrder() {
$defaults = ["a" => false, "b" => false, "c" => false];
$this->_ensureAssocKeysOrder(null, ["a" => false, "b" => false, "c" => false], $defaults);
$this->_ensureAssocKeysOrder([], ["a" => false, "b" => false, "c" => false], $defaults);
$this->_ensureAssocKeysOrder([1], ["a" => 1, "b" => false, "c" => false], $defaults);
$this->_ensureAssocKeysOrder([1, 2, 3], ["a" => 1, "b" => 2, "c" => 3], $defaults);
$this->_ensureAssocKeysOrder([1, 2, 3, 4], ["a" => 1, "b" => 2, "c" => 3, 4], $defaults);
$this->_ensureAssocKeysOrder([1, 2, 3, 4], ["a" => 1, "b" => 2, "c" => 3, 3 => 4], $defaults, [
"preserve_keys" => true,
]);
$this->_ensureAssocKeysOrder(["c" => 3, 1], ["a" => 1, "b" => false, "c" => 3], $defaults);
$this->_ensureAssocKeysOrder(["c" => 3, "b" => 2, 1], ["a" => 1, "b" => 2, "c" => 3], $defaults);
$this->_ensureAssocKeysOrder(["c" => 3, "b" => 2, "a" => 1], ["a" => 1, "b" => 2, "c" => 3], $defaults);
$this->_ensureAssocKeysOrder(["a" => 1, 2], ["a" => 1, "b" => 2, "c" => false], $defaults);
$this->_ensureAssocKeysOrder([2, "a" => 1], ["a" => 1, "b" => 2, "c" => false], $defaults);
$this->_ensureAssocKeysOrder([1], ["x_a" => 1, "x_b" => false, "x_c" => false], $defaults, [
"key_prefix" => "x_",
]);
}
}

View File

@ -1,5 +1,5 @@
<?php
namespace nur\sery\wip\php\coll;
namespace nulib\php\coll;
use Exception;
use nulib\cl;

View File

@ -1,9 +1,9 @@
<?php
namespace nur\sery\wip\php\content;
namespace nulib\php\content;
use nulib\php\content\c;
use nur\sery\wip\php\content\impl\html;
use nur\sery\wip\web\content\v;
use nulib\php\content\impl\html;
use nulib\web\content\v;
use PHPUnit\Framework\TestCase;
class cTest extends TestCase {

View File

@ -1,5 +1,5 @@
<?php
namespace nur\sery\wip\php\content\impl;
namespace nulib\php\content\impl;
use nulib\php\content\IContent;

View File

@ -1,5 +1,5 @@
<?php
namespace nur\sery\wip\php\content\impl;
namespace nulib\php\content\impl;
use nulib\php\content\IPrintable;

View File

@ -1,5 +1,5 @@
<?php
namespace nur\sery\wip\php\content\impl;
namespace nulib\php\content\impl;
use nulib\php\content\c;
use nulib\php\content\IContent;

View File

@ -1,5 +1,5 @@
<?php
namespace nur\sery\wip\php\content\impl;
namespace nulib\php\content\impl;
class html {
const H1 = [self::class, "h1"];

View File

@ -0,0 +1,353 @@
<?php
namespace nulib\schema\_assoc;
use nulib\ext\yaml;
use nulib\tests\TestCase;
use nulib\ValueException;
use nulib\schema\_scalar\ScalarSchemaTest;
use nulib\schema\Schema;
class AssocSchemaTest extends TestCase {
const NULL_SCHEMA = [
"" => [
"assoc",
"compute_func" => null,
"validate_func" => null,
"ensure_array" => null,
"ensure_assoc" => null,
"ensure_keys" => null,
"ensure_order" => null,
],
"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,
"computed" => 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_definition(["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_definition([
"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());
}
function testWrapper() {
$schema = new AssocSchema([
"a" => "?string",
"b" => "?int",
"c" => "?bool",
]);
$array = ["a" => " string ", "b" => " 42 ", "c" => false];
$schema->getWrapper($array);
self::assertSame([
"a" => "string",
"b" => 42,
"c" => false,
], $array);
###########################################################################
$schema = new AssocSchema([
"a" => "string",
"b" => "int",
"c" => "bool",
]);
$array = ["a" => " string "];
$schema->getWrapper($array);
self::assertSame([
"a" => "string",
"b" => 0,
"c" => false,
], $array);
$array = ["c" => false, "a" => " string "];
$schema->getWrapper($array);
self::assertSame([
"a" => "string",
"b" => 0,
"c" => false,
], $array);
$array = ["a" => " string "];
$schema->getWrapper($array, null, ["ensure_order" => false]);
self::assertSame([
"a" => "string",
"b" => 0,
"c" => false,
], $array);
$array = ["c" => false, "a" => " string "];
$schema->getWrapper($array, null, ["ensure_order" => false]);
self::assertSame([
"c" => false,
"a" => "string",
"b" => 0,
], $array);
$array = ["a" => " string "];
$schema->getWrapper($array, null, ["ensure_keys" => false]);
self::assertSame([
"a" => "string",
], $array);
$array = ["c" => false, "a" => " string "];
$schema->getWrapper($array, null, ["ensure_keys" => false]);
self::assertSame([
"a" => "string",
"c" => false,
], $array);
}
const STRING_SCHEMA = [
"s" => "string",
"f" => "string",
"m" => "string",
];
const NSTRING_SCHEMA = [
"s" => "?string",
"f" => "?string",
"m" => "?string",
];
const RSTRING_SCHEMA = [
"s" => ["string", "required" => true],
"f" => ["string", "required" => true],
"m" => ["string", "required" => true],
];
const RNSTRING_SCHEMA = [
"s" => ["?string", "required" => true],
"f" => ["?string", "required" => true],
"m" => ["?string", "required" => true],
];
const STRINGS = ["s" => "string", "f" => false];
const NSTRINGS = ["s" => null, "f" => null];
function testString() {
/** @var AssocSchema $schema */
$schema = Schema::ns(self::STRING_SCHEMA);
$array = self::STRINGS;
$wrapper = $schema->getWrapper($array, null, ["throw" => false]);
self::assertSame(["s" => "string", "f" => false, "m" => ""], $array);
$result = $wrapper->getResult("s");
self::assertTrue($result->normalized);
$result = $wrapper->getResult("f");
self::assertTrue($result->present);
self::assertFalse($result->available);
$result = $wrapper->getResult("m");
self::assertFalse($result->present);
self::assertNotException(function() use ($schema) {
$array = self::STRINGS;
$schema->getWrapper($array);
});
$array = self::NSTRINGS;
$wrapper = $schema->getWrapper($array, null, ["throw" => false]);
self::assertSame(["s" => null, "f" => null, "m" => ""], $array);
$result = $wrapper->getResult("s");
self::assertFalse($result->valid);
self::assertSame("null", $result->messageKey);
$result = $wrapper->getResult("f");
self::assertFalse($result->valid);
self::assertSame("null", $result->messageKey);
$result = $wrapper->getResult("m");
self::assertFalse($result->present);
self::assertException(ValueException::class, function() use ($schema) {
$array = self::NSTRINGS;
$schema->getWrapper($array);
});
}
function testNstring() {
/** @var AssocSchema $schema */
$schema = Schema::ns(self::NSTRING_SCHEMA);
$array = self::STRINGS;
$wrapper = $schema->getWrapper($array, null, ["throw" => false]);
self::assertSame(["s" => "string", "f" => false, "m" => null], $array);
$result = $wrapper->getResult("s");
self::assertTrue($result->normalized);
$result = $wrapper->getResult("f");
self::assertTrue($result->present);
self::assertFalse($result->available);
$result = $wrapper->getResult("m");
self::assertFalse($result->present);
self::assertNotException(function() use ($schema) {
$array = self::STRINGS;
$schema->getWrapper($array);
});
$array = self::NSTRINGS;
$wrapper = $schema->getWrapper($array, null, ["throw" => false]);
self::assertSame(["s" => null, "f" => null, "m" => null], $array);
$result = $wrapper->getResult("s");
self::assertTrue($result->normalized);
$result = $wrapper->getResult("f");
self::assertTrue($result->normalized);
$result = $wrapper->getResult("m");
self::assertFalse($result->present);
self::assertNotException(function() use ($schema) {
$array = self::NSTRINGS;
$schema->getWrapper($array);
});
}
function testRstring() {
/** @var AssocSchema $schema */
$schema = Schema::ns(self::RSTRING_SCHEMA);
$array = self::STRINGS;
$wrapper = $schema->getWrapper($array, null, ["throw" => false]);
self::assertSame(["s" => "string", "f" => false, "m" => ""], $array);
$result = $wrapper->getResult("s");
self::assertTrue($result->normalized);
$result = $wrapper->getResult("f");
self::assertTrue($result->present);
self::assertFalse($result->available);
self::assertSame("unavailable", $result->messageKey);
$result = $wrapper->getResult("m");
self::assertFalse($result->present);
self::assertSame("missing", $result->messageKey);
self::assertException(ValueException::class, function() use ($schema) {
$array = self::STRINGS;
$schema->getWrapper($array);
});
$array = self::NSTRINGS;
$wrapper = $schema->getWrapper($array, null, ["throw" => false]);
self::assertSame(["s" => null, "f" => null, "m" => ""], $array);
$result = $wrapper->getResult("s");
self::assertFalse($result->valid);
self::assertSame("null", $result->messageKey);
$result = $wrapper->getResult("f");
self::assertFalse($result->valid);
self::assertSame("null", $result->messageKey);
$result = $wrapper->getResult("m");
self::assertFalse($result->present);
self::assertSame("missing", $result->messageKey);
self::assertException(ValueException::class, function() use ($schema) {
$array = self::NSTRINGS;
$schema->getWrapper($array);
});
}
function testRnstring() {
/** @var AssocSchema $schema */
$schema = Schema::ns(self::RNSTRING_SCHEMA);
$array = self::STRINGS;
$wrapper = $schema->getWrapper($array, null, ["throw" => false]);
self::assertSame(["s" => "string", "f" => false, "m" => null], $array);
$result = $wrapper->getResult("s");
self::assertTrue($result->normalized);
$result = $wrapper->getResult("f");
self::assertTrue($result->present);
self::assertFalse($result->available);
self::assertSame("unavailable", $result->messageKey);
$result = $wrapper->getResult("m");
self::assertFalse($result->present);
self::assertSame("missing", $result->messageKey);
self::assertException(ValueException::class, function() use ($schema) {
$array = self::STRINGS;
$schema->getWrapper($array);
});
$array = self::NSTRINGS;
$wrapper = $schema->getWrapper($array, null, ["throw" => false]);
self::assertSame(["s" => null, "f" => null, "m" => null], $array);
$result = $wrapper->getResult("s");
self::assertTrue($result->normalized);
$result = $wrapper->getResult("f");
self::assertTrue($result->normalized);
$result = $wrapper->getResult("m");
self::assertFalse($result->present);
self::assertSame("missing", $result->messageKey);
self::assertException(ValueException::class, function() use ($schema) {
$array = self::NSTRINGS;
$schema->getWrapper($array);
});
}
}

View File

@ -0,0 +1,68 @@
<?php
namespace nulib\schema\_scalar;
use nulib\tests\TestCase;
use nulib\schema\SchemaException;
class ScalarSchemaTest extends TestCase {
const NULL_SCHEMA = [
"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,
"" => [
"scalar",
"compute_func" => null,
"validate_func" => null,
],
"schema" => null,
"name" => null,
"pkey" => null,
"header" => null,
"computed" => null,
];
static function schema(array $schema): array {
return array_merge(self::NULL_SCHEMA, $schema);
}
function testNormalize() {
self::assertSame(self::NULL_SCHEMA, ScalarSchema::normalize_definition(null));
self::assertSame(self::NULL_SCHEMA, ScalarSchema::normalize_definition([]));
self::assertSame(self::NULL_SCHEMA, ScalarSchema::normalize_definition([null]));
self::assertException(SchemaException::class, function () {
ScalarSchema::normalize_definition([[]]);
});
self::assertException(SchemaException::class, function () {
ScalarSchema::normalize_definition([[null]]);
});
$string = self::schema(["type" => ["string"], "nullable" => false]);
self::assertSame($string, ScalarSchema::normalize_definition("string"));
self::assertSame($string, ScalarSchema::normalize_definition(["string"]));
$nstring = self::schema(["type" => ["string"]]);
self::assertSame($nstring, ScalarSchema::normalize_definition(["?string"]));
self::assertSame($nstring, ScalarSchema::normalize_definition(["?string|null"]));
self::assertSame($nstring, ScalarSchema::normalize_definition(["string|null"]));
self::assertSame($nstring, ScalarSchema::normalize_definition([["?string", "null"]]));
self::assertSame($nstring, ScalarSchema::normalize_definition([["string", "null"]]));
self::assertSame($nstring, ScalarSchema::normalize_definition([["string", null]]));
$key = self::schema(["type" => ["string", "int"], "nullable" => false]);
self::assertSame($key, ScalarSchema::normalize_definition("string|int"));
$nkey = self::schema(["type" => ["string", "int"], "nullable" => true]);
self::assertSame($nkey, ScalarSchema::normalize_definition("?string|int"));
self::assertSame($nkey, ScalarSchema::normalize_definition("string|?int"));
}
}

View File

@ -0,0 +1,296 @@
<?php
namespace nulib\schema\_scalar;
use nulib\tests\TestCase;
use nulib\ValueException;
use nulib\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 checkNormalize(ScalarSchema $schema, $orig, bool $normalize, $value, bool $present, bool $available, bool $valid, bool $normalized, ?array $inputParams=null): void {
$wrapper = $schema->getWrapper();
$wrapper->resetParams(["normalize" => $normalize]);
if ($inputParams !== null) $input = new Input($orig, $inputParams);
else $input = $orig;
$wrapper->reset($input);
$this->checkValue($wrapper, $value, $present, $available, $valid, $normalized);
}
function checkException(ScalarSchema $schema, $orig, bool $normalize, string $exceptionClass, ?array $inputParams=null) {
$wrapper = $schema->getWrapper();
if ($inputParams !== null) $orig = new Input($orig, $inputParams);
self::assertException($exceptionClass, function() use ($wrapper, &$orig, $normalize) {
$wrapper->resetParams(["normalize" => $normalize]);
$wrapper->reset($orig);
});
}
function testRaw() {
$schema = new ScalarSchema();
$this->checkNormalize($schema, false, false, false, true, true, true, true);
$this->checkNormalize($schema, false, true, false, true, true, true, true);
$this->checkNormalize($schema, null, false, null, true, true, true, true);
$this->checkNormalize($schema, null, true, null, true, true, true, true);
$obj = new stdClass();
$this->checkNormalize($schema, $obj, false, $obj, true, true, true, true);
$this->checkNormalize($schema, $obj, true, $obj, true, true, true, true);
$schema = new ScalarSchema("raw");
$this->checkNormalize($schema, false, false, false, true, true, true, true);
$this->checkNormalize($schema, false, true, false, true, true, true, true);
$this->checkNormalize($schema, null, false, null, true, true, true, true);
$this->checkNormalize($schema, null, true, null, true, true, true, true);
$obj = new stdClass();
$this->checkNormalize($schema, $obj, false, $obj, true, true, true, true);
$this->checkNormalize($schema, $obj, true, $obj, true, true, true, true);
}
function testMixed() {
$schema = new ScalarSchema("mixed");
$this->checkNormalize($schema, false, false, false, true, true, true, true);
$this->checkNormalize($schema, false, true, false, true, true, true, true);
$this->checkNormalize($schema, null, false, null, true, true, false, false);
$this->checkException($schema, null, true, ValueException::class);
$obj = new stdClass();
$this->checkNormalize($schema, $obj, false, $obj, true, true, true, true);
$this->checkNormalize($schema, $obj, true, $obj, true, true, true, true);
$schema = new ScalarSchema("?mixed");
$this->checkNormalize($schema, false, false, false, true, true, true, true);
$this->checkNormalize($schema, false, true, false, true, true, true, true);
$this->checkNormalize($schema, null, false, null, true, true, true, true);
$this->checkNormalize($schema, null, true, null, true, true, true, true);
$obj = new stdClass();
$this->checkNormalize($schema, $obj, false, $obj, true, true, true, true);
$this->checkNormalize($schema, $obj, true, $obj, true, true, true, true);
}
function testRawstring() {
$schema = new ScalarSchema("rawstring");
$this->checkNormalize($schema, false, false, null, true, false, true, true);
$this->checkNormalize($schema, false, true, null, true, false, true, true);
$this->checkNormalize($schema, null, false, null, true, true, false, false);
$this->checkException($schema, null, true, ValueException::class);
$this->checkNormalize($schema, "", false, "", true, true, true, true);
$this->checkNormalize($schema, "", true, "", true, true, true, true);
$this->checkNormalize($schema, " ", false, " ", true, true, true, true);
$this->checkNormalize($schema, " ", true, " ", true, true, true, true);
$this->checkNormalize($schema, "text", false, "text", true, true, true, true);
$this->checkNormalize($schema, "text", true, "text", true, true, true, true);
$this->checkNormalize($schema, " text ", false, " text ", true, true, true, true);
$this->checkNormalize($schema, " text ", true, " text ", true, true, true, true);
$this->checkNormalize($schema, true, false, true, true, true, true, false);
$this->checkNormalize($schema, true, true, "1", true, true, true, false);
$this->checkNormalize($schema, 42, false, 42, true, true, true, false);
$this->checkNormalize($schema, 42, true, "42", true, true, true, false);
$this->checkNormalize($schema, [], false, [], true, true, false, false);
$this->checkException($schema, [], true, ValueException::class);
## Tester valeur par défaut
$schema = new ScalarSchema(["rawstring", null]);
$this->checkNormalize($schema, false, false, null, true, false, true, true);
$this->checkNormalize($schema, false, true, null, true, false, true, true);
$this->checkNormalize($schema, null, false, null, true, true, false, false);
$this->checkException($schema, null, true, ValueException::class);
$schema = new ScalarSchema(["rawstring", "default"]);
$this->checkNormalize($schema, false, false, "default", true, true, true, true);
$this->checkNormalize($schema, false, true, "default", true, true, true, true);
$this->checkNormalize($schema, null, false, null, true, true, false, false);
$this->checkException($schema, null, true, ValueException::class);
## Tester nullable
$schema = new ScalarSchema("?rawstring");
$this->checkNormalize($schema, null, false, null, true, true, true, true);
$this->checkNormalize($schema, null, true, null, true, true, true, true);
## Tester required
$schema = new ScalarSchema(["rawstring", "required" => true]);
$this->checkNormalize($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->checkNormalize($schema, null, false, null, true, true, false, false, $inputParams);
$this->checkException($schema, null, true, ValueException::class, $inputParams);
$this->checkNormalize($schema, "", false, null, true, false, true, true, $inputParams);
$this->checkNormalize($schema, "", true, null, true, false, true, true, $inputParams);
$schema = new ScalarSchema("?rawstring");
$this->checkNormalize($schema, null, false, null, true, true, true, true, $inputParams);
$this->checkNormalize($schema, null, true, null, true, true, true, true, $inputParams);
$this->checkNormalize($schema, "", false, null, true, false, true, true, $inputParams);
$this->checkNormalize($schema, "", true, null, true, false, true, true, $inputParams);
}
function testString() {
$schema = new ScalarSchema("string");
$this->checkNormalize($schema, false, false, null, true, false, true, true);
$this->checkNormalize($schema, false, true, null, true, false, true, true);
$this->checkNormalize($schema, null, false, null, true, true, false, false);
$this->checkException($schema, null, true, ValueException::class);
$this->checkNormalize($schema, "", false, "", true, true, true, true);
$this->checkNormalize($schema, "", true, "", true, true, true, true);
$this->checkNormalize($schema, " ", false, "", true, true, true, false);
$this->checkNormalize($schema, " ", true, "", true, true, true, false);
$this->checkNormalize($schema, "text", false, "text", true, true, true, true);
$this->checkNormalize($schema, "text", true, "text", true, true, true, true);
$this->checkNormalize($schema, " text ", false, "text", true, true, true, false);
$this->checkNormalize($schema, " text ", true, "text", true, true, true, false);
$this->checkNormalize($schema, true, false, true, true, true, true, false);
$this->checkNormalize($schema, true, true, "1", true, true, true, false);
$this->checkNormalize($schema, 42, false, 42, true, true, true, false);
$this->checkNormalize($schema, 42, true, "42", true, true, true, false);
$this->checkNormalize($schema, [], false, [], true, true, false, false);
$this->checkException($schema, [], true, ValueException::class);
## Tester nullable
$schema = new ScalarSchema("?string");
$this->checkNormalize($schema, null, false, null, true, true, true, true);
$this->checkNormalize($schema, null, true, null, true, true, true, true);
## Tester required
$schema = new ScalarSchema(["string", "required" => true]);
$this->checkNormalize($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->checkNormalize($schema, null, false, null, true, true, false, false, $inputParams);
$this->checkException($schema, null, true, ValueException::class, $inputParams);
$this->checkNormalize($schema, "", false, null, true, false, true, true, $inputParams);
$this->checkNormalize($schema, "", true, null, true, false, true, true, $inputParams);
$schema = new ScalarSchema("?string");
$this->checkNormalize($schema, null, false, null, true, true, true, true, $inputParams);
$this->checkNormalize($schema, null, true, null, true, true, true, true, $inputParams);
$this->checkNormalize($schema, "", false, null, true, false, true, true, $inputParams);
$this->checkNormalize($schema, "", true, null, true, false, true, true, $inputParams);
}
function testInt() {
$schema = new ScalarSchema("int");
$this->checkNormalize($schema, false, false, null, true, false, true, true);
$this->checkNormalize($schema, false, true, null, true, false, true, true);
$this->checkNormalize($schema, null, false, null, true, true, false, false);
$this->checkException($schema, null, true, ValueException::class);
$this->checkNormalize($schema, 42, false, 42, true, true, true, true);
$this->checkNormalize($schema, 42, true, 42, true, true, true, true);
$this->checkNormalize($schema, "42", false, "42", true, true, true, false);
$this->checkNormalize($schema, "42", true, 42, true, true, true, false);
$this->checkNormalize($schema, "42.5", false, "42.5", true, true, true, false);
$this->checkNormalize($schema, "42.5", true, 42, true, true, true, false);
$this->checkNormalize($schema, "42,5", false, "42,5", true, true, true, false);
$this->checkNormalize($schema, "42,5", true, 42, true, true, true, false);
$this->checkNormalize($schema, " 42 ", false, "42", true, true, true, false);
$this->checkNormalize($schema, " 42 ", true, 42, true, true, true, false);
$this->checkNormalize($schema, "", false, "", true, true, false, false);
$this->checkException($schema, "", true, ValueException::class);
$this->checkNormalize($schema, " ", false, " ", true, true, false, false);
$this->checkException($schema, " ", true, ValueException::class);
$this->checkNormalize($schema, "text", false, "text", true, true, false, false);
$this->checkException($schema, "text", true, ValueException::class);
$this->checkNormalize($schema, true, false, true, true, true, true, false);
$this->checkNormalize($schema, true, true, 1, true, true, true, false);
$this->checkNormalize($schema, [], false, [], true, true, false, false);
$this->checkException($schema, [], true, ValueException::class);
## Tester nullable
$schema = new ScalarSchema("?int");
$this->checkNormalize($schema, null, false, null, true, true, true, true);
$this->checkNormalize($schema, null, true, null, true, true, true, true);
## Tester required
$schema = new ScalarSchema(["int", "required" => true]);
$this->checkNormalize($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->checkNormalize($schema, null, false, null, true, true, false, false, $inputParams);
$this->checkException($schema, null, true, ValueException::class, $inputParams);
$this->checkNormalize($schema, "", false, null, true, false, true, true, $inputParams);
$this->checkNormalize($schema, "", true, null, true, false, true, true, $inputParams);
$schema = new ScalarSchema("?int");
$this->checkNormalize($schema, null, false, null, true, true, true, true, $inputParams);
$this->checkNormalize($schema, null, true, null, true, true, true, true, $inputParams);
$this->checkNormalize($schema, "", false, null, true, false, true, true, $inputParams);
$this->checkNormalize($schema, "", true, null, true, false, true, true, $inputParams);
}
}

View File

@ -1,10 +1,10 @@
<?php
namespace nur\sery\wip\schema\types;
namespace nulib\schema\types;
use Exception;
use nulib\tests\TestCase;
use nur\sery\wip\schema\_scalar\ScalarWrapper;
use nur\sery\wip\schema\Schema;
use nulib\schema\_scalar\ScalarWrapper;
use nulib\schema\Schema;
class boolTest extends TestCase {
function commonTests($wrapper, &$value, callable $wrapperSetter): void {
@ -59,7 +59,7 @@ class boolTest extends TestCase {
function testBool() {
/** @var ScalarWrapper $wrapper */
Schema::nw($value, null, $schema, "bool", $wrapper);
Schema::nw($value, null, "bool", $schema, $wrapper);
$wrapperSetter = function($value) use($wrapper) {
return function() use($wrapper, $value) {
$wrapper->set($value);
@ -75,7 +75,7 @@ class boolTest extends TestCase {
function testNbool() {
/** @var ScalarWrapper $wrapper */
Schema::nw($value, null, $schema, "?bool", $wrapper);
Schema::nw($value, null, "?bool", $schema, $wrapper);
$wrapperSetter = function($value) use($wrapper) {
return function() use($wrapper, $value) {
$wrapper->set($value);

View File

@ -1,10 +1,10 @@
<?php
namespace nur\sery\wip\schema\types;
namespace nulib\schema\types;
use Exception;
use nulib\tests\TestCase;
use nur\sery\wip\schema\_scalar\ScalarWrapper;
use nur\sery\wip\schema\Schema;
use nulib\schema\_scalar\ScalarWrapper;
use nulib\schema\Schema;
class floatTest extends TestCase {
function commonTests($wrapper, &$value, callable $wrapperSetter): void {
@ -33,7 +33,7 @@ class floatTest extends TestCase {
function testFloat() {
/** @var ScalarWrapper $wrapper */
Schema::nw($value, null, $schema, "float", $wrapper);
Schema::nw($value, null, "float", $schema, $wrapper);
$wrapperSetter = function($value) use($wrapper) {
return function() use($wrapper, $value) {
$wrapper->set($value);
@ -53,10 +53,10 @@ class floatTest extends TestCase {
function testRequiredFloat() {
/** @var ScalarWrapper $wrapper */
Schema::nw($value, null, $schema, [
Schema::nw($value, null, [
"float", null,
"required" => true,
], $wrapper);
], $schema, $wrapper);
$wrapperSetter = function($value) use($wrapper) {
return function() use($wrapper, $value) {
$wrapper->set($value);
@ -75,7 +75,7 @@ class floatTest extends TestCase {
function testNfloat() {
/** @var ScalarWrapper $wrapper */
Schema::nw($value, null, $schema, "?float", $wrapper);
Schema::nw($value, null, "?float", $schema, $wrapper);
$wrapperSetter = function($value) use($wrapper) {
return function() use($wrapper, $value) {
$wrapper->set($value);
@ -106,10 +106,10 @@ class floatTest extends TestCase {
function testRequiredNfloat() {
/** @var ScalarWrapper $wrapper */
Schema::nw($value, null, $schema, [
Schema::nw($value, null, [
"?float", null,
"required" => true,
], $wrapper);
], $schema, $wrapper);
$wrapperSetter = function($value) use($wrapper) {
return function() use($wrapper, $value) {
$wrapper->set($value);

View File

@ -1,10 +1,10 @@
<?php
namespace nur\sery\wip\schema\types;
namespace nulib\schema\types;
use Exception;
use nulib\tests\TestCase;
use nur\sery\wip\schema\_scalar\ScalarWrapper;
use nur\sery\wip\schema\Schema;
use nulib\schema\_scalar\ScalarWrapper;
use nulib\schema\Schema;
class intTest extends TestCase {
function commonTests($wrapper, &$value, callable $wrapperSetter): void {
@ -33,7 +33,7 @@ class intTest extends TestCase {
function testInt() {
/** @var ScalarWrapper $wrapper */
Schema::nw($value, null, $schema, "int", $wrapper);
Schema::nw($value, null, "int", $schema, $wrapper);
$wrapperSetter = function($value) use($wrapper) {
return function() use($wrapper, $value) {
$wrapper->set($value);
@ -53,10 +53,10 @@ class intTest extends TestCase {
function testRequiredInt() {
/** @var ScalarWrapper $wrapper */
Schema::nw($value, null, $schema, [
Schema::nw($value, null, [
"int", null,
"required" => true,
], $wrapper);
], $schema, $wrapper);
$wrapperSetter = function($value) use($wrapper) {
return function() use($wrapper, $value) {
$wrapper->set($value);
@ -75,7 +75,7 @@ class intTest extends TestCase {
function testNint() {
/** @var ScalarWrapper $wrapper */
Schema::nw($value, null, $schema, "?int", $wrapper);
Schema::nw($value, null, "?int", $schema, $wrapper);
$wrapperSetter = function($value) use($wrapper) {
return function() use($wrapper, $value) {
$wrapper->set($value);
@ -106,10 +106,10 @@ class intTest extends TestCase {
function testRequiredNint() {
/** @var ScalarWrapper $wrapper */
Schema::nw($value, null, $schema, [
Schema::nw($value, null, [
"?int", null,
"required" => true,
], $wrapper);
], $schema, $wrapper);
$wrapperSetter = function($value) use($wrapper) {
return function() use($wrapper, $value) {
$wrapper->set($value);

View File

@ -1,10 +1,10 @@
<?php
namespace nur\sery\wip\schema\types;
namespace nulib\schema\types;
use Exception;
use nulib\tests\TestCase;
use nur\sery\wip\schema\_scalar\ScalarWrapper;
use nur\sery\wip\schema\Schema;
use nulib\schema\_scalar\ScalarWrapper;
use nulib\schema\Schema;
class strTest extends TestCase {
function commonTests($wrapper, &$value, callable $wrapperSetter): void {
@ -41,7 +41,7 @@ class strTest extends TestCase {
function testStr() {
/** @var ScalarWrapper $wrapper */
Schema::nw($value, null, $schema, "string", $wrapper);
Schema::nw($value, null, "string", $schema, $wrapper);
$wrapperSetter = function($value) use($wrapper) {
return function() use($wrapper, $value) {
$wrapper->set($value);
@ -59,10 +59,10 @@ class strTest extends TestCase {
function testRequiredStr() {
/** @var ScalarWrapper $wrapper */
Schema::nw($value, null, $schema, [
Schema::nw($value, null, [
"string", null,
"required" => true,
], $wrapper);
], $schema, $wrapper);
$wrapperSetter = function($value) use($wrapper) {
return function() use($wrapper, $value) {
$wrapper->set($value);
@ -79,7 +79,7 @@ class strTest extends TestCase {
function testNstr() {
/** @var ScalarWrapper $wrapper */
Schema::nw($value, null, $schema, "?string", $wrapper);
Schema::nw($value, null, "?string", $schema, $wrapper);
$wrapperSetter = function($value) use($wrapper) {
return function() use($wrapper, $value) {
$wrapper->set($value);
@ -100,10 +100,10 @@ class strTest extends TestCase {
function testRequiredNstr() {
/** @var ScalarWrapper $wrapper */
Schema::nw($value, null, $schema, [
Schema::nw($value, null, [
"?string", null,
"required" => true,
], $wrapper);
], $schema, $wrapper);
$wrapperSetter = function($value) use($wrapper) {
return function() use($wrapper, $value) {
$wrapper->set($value);

View File

@ -1,9 +1,9 @@
<?php
namespace nur\sery\wip\schema\types;
namespace nulib\schema\types;
use nulib\tests\TestCase;
use nur\sery\wip\schema\_scalar\ScalarWrapper;
use nur\sery\wip\schema\Schema;
use nulib\schema\_scalar\ScalarWrapper;
use nulib\schema\Schema;
class unionTest extends TestCase {
function testUnionTypes() {
@ -11,7 +11,7 @@ class unionTest extends TestCase {
# string puis int
/** @var ScalarWrapper $siw */
Schema::nw($si, null, $sis, "string|int", $siw);
Schema::nw($si, null, "string|int", $sis, $siw);
$siw->set("12");
self::assertSame("12", $si);
@ -20,7 +20,7 @@ class unionTest extends TestCase {
# int puis string
/** @var ScalarWrapper $isw */
Schema::nw($is, null, $iss, "int|string", $isw);
Schema::nw($is, null, "int|string", $iss, $isw);
$isw->set("12");
self::assertSame("12", $is);

View File

@ -1,66 +0,0 @@
<?php
namespace nur\sery\wip\php\access;
use nulib\tests\TestCase;
use stdClass;
class KeyAccessTest extends TestCase {
function testAccess() {
$default = new stdClass();
$array = ["null" => null, "false" => false, "empty" => ""];
#
$a = new KeyAccess($array, "inexistant");
self::assertFalse($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$a = new KeyAccess($array, "null");
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame(null, $a->get($default));
$a = new KeyAccess($array, "false");
self::assertTrue($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$a = new KeyAccess($array, "empty");
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame("", $a->get($default));
#
$a = new KeyAccess($array, "null", ["allow_null" => false]);
self::assertTrue($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$a = new KeyAccess($array, "null", ["allow_null" => true]);
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame(null, $a->get($default));
#
$a = new KeyAccess($array, "false", ["allow_false" => false]);
self::assertTrue($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$a = new KeyAccess($array, "false", ["allow_false" => true]);
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame(false, $a->get($default));
#
$a = new KeyAccess($array, "empty", ["allow_empty" => false]);
self::assertTrue($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$a = new KeyAccess($array, "empty", ["allow_empty" => true]);
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame("", $a->get($default));
}
}

View File

@ -1,69 +0,0 @@
<?php
namespace nur\sery\wip\php\access;
use nulib\tests\TestCase;
use stdClass;
class ValueAccessTest extends TestCase {
function testAccess() {
$default = new stdClass();
#
$i = null;
$a = new ValueAccess($i);
self::assertFalse($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$i = false;
$a = new ValueAccess($i);
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame(false, $a->get($default));
$i = "";
$a = new ValueAccess($i);
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame("", $a->get($default));
#
$i = null;
$a = new ValueAccess($i, ["allow_null" => false]);
self::assertFalse($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$i = null;
$a = new ValueAccess($i, ["allow_null" => true]);
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame(null, $a->get($default));
#
$i = false;
$a = new ValueAccess($i, ["allow_false" => false]);
self::assertTrue($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$i = false;
$a = new ValueAccess($i, ["allow_false" => true]);
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame(false, $a->get($default));
#
$i = "";
$a = new ValueAccess($i, ["allow_empty" => false]);
self::assertTrue($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$i = "";
$a = new ValueAccess($i, ["allow_empty" => true]);
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame("", $a->get($default));
}
}

Some files were not shown because too many files have changed in this diff Show More