Compare commits
	
		
			No commits in common. "62b8b76ae5f70d12aa4d612703c46e216a57385c" and "cf5da535b3d306cb0195c814330fa39d69c359fe" have entirely different histories.
		
	
	
		
			62b8b76ae5
			...
			cf5da535b3
		
	
		
							
								
								
									
										7
									
								
								.idea/inspectionProfiles/Project_Default.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										7
									
								
								.idea/inspectionProfiles/Project_Default.xml
									
									
									
										generated
									
									
									
								
							@ -2,12 +2,5 @@
 | 
			
		||||
  <profile version="1.0">
 | 
			
		||||
    <option name="myName" value="Project Default" />
 | 
			
		||||
    <inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
 | 
			
		||||
    <inspection_tool class="GrazieInspection" enabled="false" level="GRAMMAR_ERROR" enabled_by_default="false" />
 | 
			
		||||
    <inspection_tool class="LanguageDetectionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
 | 
			
		||||
    <inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
 | 
			
		||||
      <option name="processCode" value="true" />
 | 
			
		||||
      <option name="processLiterals" value="true" />
 | 
			
		||||
      <option name="processComments" value="true" />
 | 
			
		||||
    </inspection_tool>
 | 
			
		||||
  </profile>
 | 
			
		||||
</component>
 | 
			
		||||
							
								
								
									
										15
									
								
								.idea/php.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										15
									
								
								.idea/php.xml
									
									
									
										generated
									
									
									
								
							@ -10,11 +10,6 @@
 | 
			
		||||
    <option name="highlightLevel" value="WARNING" />
 | 
			
		||||
    <option name="transferred" value="true" />
 | 
			
		||||
  </component>
 | 
			
		||||
  <component name="PhpCodeSniffer">
 | 
			
		||||
    <phpcs_settings>
 | 
			
		||||
      <phpcs_by_interpreter asDefaultInterpreter="true" interpreter_id="846389f7-9fb5-4173-a868-1dc6b8fbb3fa" timeout="30000" />
 | 
			
		||||
    </phpcs_settings>
 | 
			
		||||
  </component>
 | 
			
		||||
  <component name="PhpIncludePathManager">
 | 
			
		||||
    <include_path>
 | 
			
		||||
      <path value="$PROJECT_DIR$/vendor/sebastian/code-unit-reverse-lookup" />
 | 
			
		||||
@ -69,11 +64,6 @@
 | 
			
		||||
    </include_path>
 | 
			
		||||
  </component>
 | 
			
		||||
  <component name="PhpProjectSharedConfiguration" php_language_level="7.4" />
 | 
			
		||||
  <component name="PhpStan">
 | 
			
		||||
    <PhpStan_settings>
 | 
			
		||||
      <phpstan_by_interpreter asDefaultInterpreter="true" interpreter_id="846389f7-9fb5-4173-a868-1dc6b8fbb3fa" timeout="60000" />
 | 
			
		||||
    </PhpStan_settings>
 | 
			
		||||
  </component>
 | 
			
		||||
  <component name="PhpStanOptionsConfiguration">
 | 
			
		||||
    <option name="transferred" value="true" />
 | 
			
		||||
  </component>
 | 
			
		||||
@ -82,11 +72,6 @@
 | 
			
		||||
      <PhpUnitSettings custom_loader_path="$PROJECT_DIR$/vendor/autoload.php" />
 | 
			
		||||
    </phpunit_settings>
 | 
			
		||||
  </component>
 | 
			
		||||
  <component name="Psalm">
 | 
			
		||||
    <Psalm_settings>
 | 
			
		||||
      <psalm_fixer_by_interpreter asDefaultInterpreter="true" interpreter_id="846389f7-9fb5-4173-a868-1dc6b8fbb3fa" timeout="60000" />
 | 
			
		||||
    </Psalm_settings>
 | 
			
		||||
  </component>
 | 
			
		||||
  <component name="PsalmOptionsConfiguration">
 | 
			
		||||
    <option name="transferred" value="true" />
 | 
			
		||||
  </component>
 | 
			
		||||
 | 
			
		||||
@ -12,16 +12,12 @@ DIST=
 | 
			
		||||
NOAUTO=
 | 
			
		||||
 | 
			
		||||
AFTER_CREATE_RELEASE='
 | 
			
		||||
set -x
 | 
			
		||||
pman --composer-select-profile dist
 | 
			
		||||
composer u || exit 1
 | 
			
		||||
composer u
 | 
			
		||||
git commit -am "<pman>deps de dist"
 | 
			
		||||
true
 | 
			
		||||
'
 | 
			
		||||
AFTER_MERGE_RELEASE='
 | 
			
		||||
set -x
 | 
			
		||||
pman --composer-select-profile dev
 | 
			
		||||
composer u || exit 1
 | 
			
		||||
composer u
 | 
			
		||||
git commit -am "<pman>deps de dev"
 | 
			
		||||
true
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										11
									
								
								CHANGES.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								CHANGES.md
									
									
									
									
									
								
							@ -1,14 +1,3 @@
 | 
			
		||||
## Release 0.4.0p74 du 14/03/2025-15:44
 | 
			
		||||
 | 
			
		||||
* `4b84f11` début assocSchema
 | 
			
		||||
* `7227cd7` maj TODO
 | 
			
		||||
* `089e487` renommer dest en value; tenir compte de la valeur par défaut
 | 
			
		||||
* `fc523bf` instancier type le plus vite possible
 | 
			
		||||
* `f8eec57` renommer Value en Wrapper
 | 
			
		||||
* `1aa266b` tstring et trawstring
 | 
			
		||||
* `1a5ca79` support des colonnes
 | 
			
		||||
* `9438aaf` ajout config .pman.yml
 | 
			
		||||
 | 
			
		||||
## Release 0.3.0p82 du 01/03/2025-13:49
 | 
			
		||||
 | 
			
		||||
## Release 0.3.0p74 du 01/03/2025-13:44
 | 
			
		||||
 | 
			
		||||
@ -1 +1 @@
 | 
			
		||||
0.4.0
 | 
			
		||||
0.3.0
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										6
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							@ -589,7 +589,7 @@
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "path",
 | 
			
		||||
                "url": "../nulib",
 | 
			
		||||
                "reference": "927915093af5196099ae26645c07e90ddf1b2330"
 | 
			
		||||
                "reference": "939f7726ab139071e8a3ef5c83fc147fba859d9d"
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "ext-json": "*",
 | 
			
		||||
@ -637,7 +637,7 @@
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "path",
 | 
			
		||||
                "url": "../nulib-phpss",
 | 
			
		||||
                "reference": "9e4f41e38deef10993d859202988567db9d4fada"
 | 
			
		||||
                "reference": "a78623f5ae6891144b9581709847328b93342e1d"
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "nulib/php": "^7.4-dev",
 | 
			
		||||
@ -681,7 +681,7 @@
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "path",
 | 
			
		||||
                "url": "../nulib-spout",
 | 
			
		||||
                "reference": "65c74a1db6dda718aa20970ede3dfa4b4d32c791"
 | 
			
		||||
                "reference": "f9c420058015d02e913f0d65c41242ec7b8a0cee"
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "ext-dom": "*",
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\php\access;
 | 
			
		||||
 | 
			
		||||
use nulib\cl;
 | 
			
		||||
use nur\sery\cl;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class AbstractAccess: implémentation par défaut pour des instances standard
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\php\access;
 | 
			
		||||
 | 
			
		||||
use nulib\cl;
 | 
			
		||||
use nur\sery\cl;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class FormAccess: accès à une valeur de $_POST puis $_GET, dans cet ordre
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\php\access;
 | 
			
		||||
 | 
			
		||||
use nulib\cl;
 | 
			
		||||
use nur\sery\cl;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class GetAccess: accès à une valeur de $_GET
 | 
			
		||||
 | 
			
		||||
@ -5,10 +5,10 @@ namespace nur\sery\wip\php\access;
 | 
			
		||||
 * Interface IAccess: abstraction d'un accès complet à une valeur
 | 
			
		||||
 */
 | 
			
		||||
interface IAccess extends IGetter, ISetter, IDeleter {
 | 
			
		||||
  /** incrémenter la valeur et la retourner */
 | 
			
		||||
  /** incrémenter la valeur */
 | 
			
		||||
  function inc(): int;
 | 
			
		||||
 | 
			
		||||
  /** décrémenter la valeur et la retourner */
 | 
			
		||||
  /** décrémenter la valeur */
 | 
			
		||||
  function dec(bool $allowNegative=false): int;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
 | 
			
		||||
@ -2,14 +2,14 @@
 | 
			
		||||
namespace nur\sery\wip\php\access;
 | 
			
		||||
 | 
			
		||||
use ArrayAccess;
 | 
			
		||||
use nulib\cl;
 | 
			
		||||
use nur\sery\cl;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class KeyAccess: accès à une valeur d'une clé dans un tableau
 | 
			
		||||
 */
 | 
			
		||||
class KeyAccess extends AbstractAccess {
 | 
			
		||||
  function __construct(&$array, $key, ?array $params=null) {
 | 
			
		||||
    $this->array =& $array;
 | 
			
		||||
  function __construct(&$dest, $key, ?array $params=null) {
 | 
			
		||||
    $this->dest =& $dest;
 | 
			
		||||
    $this->key = $key;
 | 
			
		||||
    $this->allowNull = $params["allow_null"] ?? true;
 | 
			
		||||
    $this->allowFalse = $params["allow_false"] ?? false;
 | 
			
		||||
@ -17,10 +17,10 @@ class KeyAccess extends AbstractAccess {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** @var array|ArrayAccess */
 | 
			
		||||
  protected $array;
 | 
			
		||||
  protected $dest;
 | 
			
		||||
 | 
			
		||||
  function reset(&$array): self {
 | 
			
		||||
    $this->array =& $array;
 | 
			
		||||
  function reset(&$dest): self {
 | 
			
		||||
    $this->dest =& $dest;
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -36,12 +36,12 @@ class KeyAccess extends AbstractAccess {
 | 
			
		||||
  function exists(): bool {
 | 
			
		||||
    $key = $this->key;
 | 
			
		||||
    if ($key === null) return false;
 | 
			
		||||
    return cl::has($this->array, $key);
 | 
			
		||||
    return cl::has($this->dest, $key);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function available(): bool {
 | 
			
		||||
    if (!$this->exists()) return false;
 | 
			
		||||
    $value = cl::get($this->array, $this->key);
 | 
			
		||||
    $value = cl::get($this->dest, $this->key);
 | 
			
		||||
    if ($value === null) return $this->allowNull;
 | 
			
		||||
    if ($value === false) return $this->allowFalse;
 | 
			
		||||
    if ($value === "") return $this->allowEmpty;
 | 
			
		||||
@ -50,7 +50,7 @@ class KeyAccess extends AbstractAccess {
 | 
			
		||||
 | 
			
		||||
  function get($default=null) {
 | 
			
		||||
    if ($this->key === null) return $default;
 | 
			
		||||
    $value = cl::get($this->array, $this->key, $default);
 | 
			
		||||
    $value = cl::get($this->dest, $this->key, $default);
 | 
			
		||||
    if ($value === null && !$this->allowNull) return $default;
 | 
			
		||||
    if ($value === false && !$this->allowFalse) return $default;
 | 
			
		||||
    if ($value === "" && !$this->allowEmpty) return $default;
 | 
			
		||||
@ -59,11 +59,11 @@ class KeyAccess extends AbstractAccess {
 | 
			
		||||
 | 
			
		||||
  function set($value): void {
 | 
			
		||||
    if ($this->key === null) return;
 | 
			
		||||
    cl::set($this->array, $this->key, $value);
 | 
			
		||||
    cl::set($this->dest, $this->key, $value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function del(): void {
 | 
			
		||||
    if ($this->key === null) return;
 | 
			
		||||
    cl::del($this->array, $this->key);
 | 
			
		||||
    cl::del($this->dest, $this->key);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\php\access;
 | 
			
		||||
 | 
			
		||||
use nulib\cl;
 | 
			
		||||
use nur\sery\cl;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class PostAccess: accès à une valeur de $_POST
 | 
			
		||||
 | 
			
		||||
@ -5,18 +5,18 @@ namespace nur\sery\wip\php\access;
 | 
			
		||||
 * Class ValueAccess: accès à une valeur unitaire
 | 
			
		||||
 */
 | 
			
		||||
class ValueAccess extends AbstractAccess {
 | 
			
		||||
  function __construct(&$value, ?array $params=null) {
 | 
			
		||||
    $this->value =& $value;
 | 
			
		||||
  function __construct(&$dest, ?array $params=null) {
 | 
			
		||||
    $this->dest =& $dest;
 | 
			
		||||
    $this->allowNull = $params["allow_null"] ?? false;
 | 
			
		||||
    $this->allowFalse = $params["allow_false"] ?? true;
 | 
			
		||||
    $this->allowEmpty = $params["allow_empty"] ?? true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** @var mixed */
 | 
			
		||||
  protected $value;
 | 
			
		||||
  protected $dest;
 | 
			
		||||
 | 
			
		||||
  function reset(&$value): self {
 | 
			
		||||
    $this->value =& $value;
 | 
			
		||||
  function reset(&$dest): self {
 | 
			
		||||
    $this->dest =& $dest;
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -27,19 +27,19 @@ class ValueAccess extends AbstractAccess {
 | 
			
		||||
  protected bool $allowEmpty;
 | 
			
		||||
 | 
			
		||||
  function exists(): bool {
 | 
			
		||||
    return $this->allowNull || $this->value !== null;
 | 
			
		||||
    return $this->allowNull || $this->dest !== null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function available(): bool {
 | 
			
		||||
    if (!$this->exists()) return false;
 | 
			
		||||
    $value = $this->value;
 | 
			
		||||
    $value = $this->dest;
 | 
			
		||||
    if ($value === false) return $this->allowFalse;
 | 
			
		||||
    if ($value === "") return $this->allowEmpty;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function get($default=null) {
 | 
			
		||||
    $value = $this->value;
 | 
			
		||||
    $value = $this->dest;
 | 
			
		||||
    if ($value === null && !$this->allowNull) return $default;
 | 
			
		||||
    if ($value === false && !$this->allowFalse) return $default;
 | 
			
		||||
    if ($value === "" && !$this->allowEmpty) return $default;
 | 
			
		||||
@ -47,10 +47,10 @@ class ValueAccess extends AbstractAccess {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function set($value): void {
 | 
			
		||||
    $this->value = $value;
 | 
			
		||||
    $this->dest = $value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function del(): void {
 | 
			
		||||
    $this->value = null;
 | 
			
		||||
    $this->dest = null;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,6 @@
 | 
			
		||||
namespace nur\sery\wip\php\coll;
 | 
			
		||||
 | 
			
		||||
use Iterator;
 | 
			
		||||
use IteratorAggregate;
 | 
			
		||||
use nulib\cl;
 | 
			
		||||
use nulib\php\func;
 | 
			
		||||
use nur\sery\wip\php\iter;
 | 
			
		||||
@ -34,7 +33,7 @@ class Cursor implements Iterator {
 | 
			
		||||
   * alors retourner le tableau
 | 
			
		||||
   *   ["a" => $row["a"], "b" => $row["x"], "c" => "y", "d" => null]
 | 
			
		||||
   */
 | 
			
		||||
  protected static function map_row(array $row, ?array $map): array {
 | 
			
		||||
  private static function map_row(array $row, ?array $map): array {
 | 
			
		||||
    if ($map === null) return $row;
 | 
			
		||||
    $index = 0;
 | 
			
		||||
    $mapped = [];
 | 
			
		||||
@ -49,7 +48,7 @@ class Cursor implements Iterator {
 | 
			
		||||
        $mapped[$key] = $func->invoke([$value, $key, $row]);
 | 
			
		||||
      } else {
 | 
			
		||||
        if ($value === null) $mapped[$key] = null;
 | 
			
		||||
        else $mapped[$key] = cl::get($row, $value);
 | 
			
		||||
        else $mapped[$key] = cl::get($row, $key);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return $mapped;
 | 
			
		||||
@ -68,7 +67,7 @@ class Cursor implements Iterator {
 | 
			
		||||
   * - une valeur associative $key => $value indique que la clé correspondante
 | 
			
		||||
   * doit exiter avec la valeur spécifiée
 | 
			
		||||
   */
 | 
			
		||||
  protected static function filter_row(array $row, $filter): bool {
 | 
			
		||||
  private static function filter_row(array $row, $filter): bool {
 | 
			
		||||
    if ($filter === null) return false;
 | 
			
		||||
    if (!is_array($filter)) $filter = [$filter];
 | 
			
		||||
    if (!$filter) return false;
 | 
			
		||||
@ -80,12 +79,12 @@ class Cursor implements Iterator {
 | 
			
		||||
        if (!array_key_exists($value, $row)) return false;
 | 
			
		||||
      } elseif (is_bool($value)) {
 | 
			
		||||
        if ($value) {
 | 
			
		||||
          if (!array_key_exists($key, $row)) return false;
 | 
			
		||||
          if (!array_key_exists($value, $row)) return false;
 | 
			
		||||
        } else {
 | 
			
		||||
          if (array_key_exists($key, $row)) return false;
 | 
			
		||||
          if (array_key_exists($value, $row)) return false;
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        if (!array_key_exists($key, $row)) return false;
 | 
			
		||||
        if (!array_key_exists($value, $row)) return false;
 | 
			
		||||
        if ($row[$key] !== $value) return false;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
@ -115,11 +114,6 @@ class Cursor implements Iterator {
 | 
			
		||||
    $this->rowsGenerator = $rowsGenerator;
 | 
			
		||||
    $this->rowsFunc = $rowsFunc;
 | 
			
		||||
 | 
			
		||||
    $this->cols = $params["cols"] ?? null;
 | 
			
		||||
    $colsFunc = $params["cols_func"] ?? null;
 | 
			
		||||
    if ($colsFunc !== null) $colsFunc = func::with($colsFunc);
 | 
			
		||||
    $this->colsFunc = $colsFunc;
 | 
			
		||||
 | 
			
		||||
    $map = $params["map"] ?? null;
 | 
			
		||||
    $mapFunc = $params["map_func"] ?? null;
 | 
			
		||||
    if ($mapFunc !== null) {
 | 
			
		||||
@ -179,10 +173,6 @@ class Cursor implements Iterator {
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function cols(): ?array {
 | 
			
		||||
    return $this->row !== null? array_keys($this->row): null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function filter(): bool {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
@ -195,24 +185,20 @@ class Cursor implements Iterator {
 | 
			
		||||
  # Iterator
 | 
			
		||||
 | 
			
		||||
  function rewind() {
 | 
			
		||||
    $this->cols = null;
 | 
			
		||||
    $this->index = 0;
 | 
			
		||||
    $this->origIndex = 0;
 | 
			
		||||
    $this->key = null;
 | 
			
		||||
    $this->raw = null;
 | 
			
		||||
    $this->row = null;
 | 
			
		||||
    if ($this->rowsGenerator !== null) {
 | 
			
		||||
      $rows = $this->rowsGenerator;
 | 
			
		||||
      if ($rows instanceof IteratorAggregate) $rows = $rows->getIterator();
 | 
			
		||||
      $rows->rewind();
 | 
			
		||||
      $this->rows = $rows;
 | 
			
		||||
      $this->rows = $this->rowsGenerator;
 | 
			
		||||
      $this->rows->rewind();
 | 
			
		||||
    } else {
 | 
			
		||||
      $this->rows = $this->rowsFunc->invoke();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function valid(): bool {
 | 
			
		||||
    $cols = $this->colsFunc;
 | 
			
		||||
  function valid() {
 | 
			
		||||
    $filter = $this->filterFunc;
 | 
			
		||||
    $map = $this->mapFunc;
 | 
			
		||||
    while ($valid = iter::valid($this->rows)) {
 | 
			
		||||
@ -224,10 +210,6 @@ class Cursor implements Iterator {
 | 
			
		||||
      if (!$filtered) {
 | 
			
		||||
        if ($map === null) $this->row = $this->map();
 | 
			
		||||
        else $this->row = $map->invoke([$this]);
 | 
			
		||||
        if ($this->cols === null) {
 | 
			
		||||
          if ($cols === null) $this->cols = $this->cols();
 | 
			
		||||
          else $this->cols = $cols->invoke([$this]);
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      } else {
 | 
			
		||||
        iter::next($this->rows);
 | 
			
		||||
@ -237,7 +219,6 @@ class Cursor implements Iterator {
 | 
			
		||||
    if (!$valid) {
 | 
			
		||||
      iter::close($this->rows);
 | 
			
		||||
      $this->rows = null;
 | 
			
		||||
      $this->cols = null;
 | 
			
		||||
      $this->index = -1;
 | 
			
		||||
      $this->origIndex = -1;
 | 
			
		||||
      $this->key = null;
 | 
			
		||||
@ -247,7 +228,7 @@ class Cursor implements Iterator {
 | 
			
		||||
    return $valid;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function current(): ?array {
 | 
			
		||||
  function current() {
 | 
			
		||||
    return $this->row;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
}
 | 
			
		||||
@ -1,60 +1,70 @@
 | 
			
		||||
# nulib\schema
 | 
			
		||||
# nur\sery\schema
 | 
			
		||||
 | 
			
		||||
les classes de ce package permettent de s'assurer que des données soit dans un
 | 
			
		||||
type particulier, en les convertissant si nécessaire. la source de ces données
 | 
			
		||||
peut-être diverse: formulaire web, résultat d'une requête SQL, flux CSV, etc.
 | 
			
		||||
objet: s'assurer que des données soit dans un type particulier, en les
 | 
			
		||||
convertissant si nécessaire. la source de ces données peut-être diverse:
 | 
			
		||||
formulaire web, résultat d'une requête SQL, flux CSV, etc.
 | 
			
		||||
 | 
			
		||||
les données dont on peut modéliser le schéma sont de 3 types: scalaire, tableau
 | 
			
		||||
associatif ou liste. la nature du schéma (la valeur de la clé `"""`) indique le
 | 
			
		||||
type de donnée modélisée
 | 
			
		||||
* donnée scalaire
 | 
			
		||||
les données dont on peut modéliser le schéma sont de 3 types:
 | 
			
		||||
* scalaire
 | 
			
		||||
* tableau associatif
 | 
			
		||||
* liste (tableau séquentiel ou associatif d'éléments du même type)
 | 
			
		||||
 | 
			
		||||
  forme courante:
 | 
			
		||||
chaque type de données a une syntaxe spécifique pour la définition du schéma.
 | 
			
		||||
 | 
			
		||||
## Nature de schéma
 | 
			
		||||
 | 
			
		||||
Un schéma se présente sous la forme d'un tableau associatif avec des clés qui
 | 
			
		||||
dépendent de la nature du schéma. La nature du schéma est indiquée avec la clé
 | 
			
		||||
`""` (chaine vide), e.g
 | 
			
		||||
~~~php
 | 
			
		||||
  const SCALAR_SCHEMA = [
 | 
			
		||||
    $type, [$default, $title, ...]
 | 
			
		||||
const SCHEMA = [
 | 
			
		||||
  "" => NATURE,
 | 
			
		||||
];
 | 
			
		||||
~~~
 | 
			
		||||
  forme normalisée:
 | 
			
		||||
 | 
			
		||||
La nature indique le type de données représenté par le schéma.
 | 
			
		||||
* nature scalaire: modélise une donnée scalaire
 | 
			
		||||
  ~~~php
 | 
			
		||||
  const SCALAR_SCHEMA = [
 | 
			
		||||
    $type, [$default, $title, ...]
 | 
			
		||||
    "" => "scalar",
 | 
			
		||||
  ];
 | 
			
		||||
  ~~~
 | 
			
		||||
* tableau associatif
 | 
			
		||||
  le tableau modélisé peut avoir des clés numériques ou chaines --> seules les
 | 
			
		||||
  clés décrites par le schéma sont validées
 | 
			
		||||
 | 
			
		||||
  forme courante:
 | 
			
		||||
  Si le type est "array" ou "?array", on peut préciser le schéma de la donnée
 | 
			
		||||
  ~~~php
 | 
			
		||||
  const SCALAR_SCHEMA = [
 | 
			
		||||
    "?array", [$default, $title, ...]
 | 
			
		||||
    "" => "scalar",
 | 
			
		||||
    "schema" => NAKED_SCHEMA,
 | 
			
		||||
  ];
 | 
			
		||||
  ~~~
 | 
			
		||||
* nature tableau associatif: modélise un tableau associatif (le tableau peut
 | 
			
		||||
  avoir des clés numériques ou chaines --> seules les clés décrites par le
 | 
			
		||||
  schéma sont validées)
 | 
			
		||||
  ~~~php
 | 
			
		||||
  const ASSOC_SCHEMA = [
 | 
			
		||||
    KEY => VALUE_SCHEMA,
 | 
			
		||||
    ...
 | 
			
		||||
    "" => "assoc",
 | 
			
		||||
  ];
 | 
			
		||||
  ~~~
 | 
			
		||||
  forme normalisée:
 | 
			
		||||
  la nature "tableau associatif" est du sucre syntaxique pour une valeur
 | 
			
		||||
  scalaire de type "?array" dont on précise le schéma
 | 
			
		||||
  ~~~php
 | 
			
		||||
  // la valeur ci-dessus est strictement équivalent à
 | 
			
		||||
  const ASSOC_SCHEMA = [
 | 
			
		||||
    "?array", [$default, $title, ...]
 | 
			
		||||
    "" => "assoc",
 | 
			
		||||
    "?array",
 | 
			
		||||
    "" => "scalar",
 | 
			
		||||
    "schema" => [
 | 
			
		||||
      KEY => VALUE_SCHEMA,
 | 
			
		||||
      ...
 | 
			
		||||
    ],
 | 
			
		||||
  ];
 | 
			
		||||
  ~~~
 | 
			
		||||
* liste (tableau d'éléments du même type)
 | 
			
		||||
  le tableau modélisé peut avoir des clés numériques ou chaines --> on ne
 | 
			
		||||
  modélise ni le type ni la valeur des clés
 | 
			
		||||
 | 
			
		||||
  forme courante:
 | 
			
		||||
  ~~~php
 | 
			
		||||
  const LIST_SCHEMA = [[
 | 
			
		||||
    ITEM_SCHEMA,
 | 
			
		||||
  ]];
 | 
			
		||||
  ~~~
 | 
			
		||||
  forme normalisée:
 | 
			
		||||
* nature liste: modélise une liste de valeurs du même type (le tableau peut
 | 
			
		||||
  avoir des clés numériques ou chaines --> on ne modélise ni le type ni la
 | 
			
		||||
  valeur des clés)
 | 
			
		||||
  ~~~php
 | 
			
		||||
  const LIST_SCHEMA = [
 | 
			
		||||
    "?array", [$default, $title, ...]
 | 
			
		||||
@ -75,8 +85,7 @@ const SCALAR_SCHEMA = [
 | 
			
		||||
  "required" => "la valeur est-elle requise? si oui, elle doit exister",
 | 
			
		||||
  "nullable" => "si la valeur existe, peut-elle être nulle?",
 | 
			
		||||
  "desc" => "description de la valeur",
 | 
			
		||||
  "analyzer_func" => "XXX",
 | 
			
		||||
  "extractor_func" => "XXX",
 | 
			
		||||
  "checker_func" => "une fonction qui vérifie une valeur et la classifie",
 | 
			
		||||
  "parser_func" => "une fonction qui analyse une chaine pour produire la valeur",
 | 
			
		||||
  "messages" => "messages à afficher en cas d'erreur d'analyse",
 | 
			
		||||
  "formatter_func" => "une fonction qui formatte la valeur pour affichage",
 | 
			
		||||
@ -109,9 +118,9 @@ nature scalaire si:
 | 
			
		||||
* c'est un tableau avec un élément à l'index 0, ainsi que d'autres éléments,
 | 
			
		||||
  e.g `["string", null, "required" => true]`
 | 
			
		||||
 | 
			
		||||
`messages` indique les messages à afficher en cas d'erreur d'analyse. les clés
 | 
			
		||||
sont  normalisées et correspondent à différents états de la valeur tels
 | 
			
		||||
qu'analysés par `analyzer_func`
 | 
			
		||||
message indique les messages à afficher en cas d'erreur d'analyse. les clés sont
 | 
			
		||||
normalisées et correspondent à différents états de la valeur tels qu'analysés
 | 
			
		||||
par `checker_func`
 | 
			
		||||
~~~php
 | 
			
		||||
const MESSAGE_SCHEMA = [
 | 
			
		||||
  "missing" => "message si la valeur n'existe pas dans la source et qu'elle est requise",
 | 
			
		||||
@ -124,26 +133,22 @@ const MESSAGE_SCHEMA = [
 | 
			
		||||
 | 
			
		||||
## Schéma d'un tableau associatif
 | 
			
		||||
 | 
			
		||||
Dans la forme courante, on considère que c'est un schéma de nature associative si:
 | 
			
		||||
* c'est un tableau uniquement associatif avec aucun élément séquentiel, e.g
 | 
			
		||||
  `["name" => "string", "age" => "int"]`
 | 
			
		||||
 | 
			
		||||
La forme normalisée est
 | 
			
		||||
Dans sa forme *non normalisée*, un tableau associatif est généralement modélisé
 | 
			
		||||
de cette manière:
 | 
			
		||||
~~~php
 | 
			
		||||
const ASSOC_SCHEMA = [
 | 
			
		||||
  "?array",
 | 
			
		||||
  "" => "assoc",
 | 
			
		||||
  "schema" => [
 | 
			
		||||
  KEY => VALUE_SCHEMA,
 | 
			
		||||
  ...
 | 
			
		||||
  ],
 | 
			
		||||
  "" => "assoc",
 | 
			
		||||
];
 | 
			
		||||
~~~
 | 
			
		||||
le type "?array" ou "array" indique si la liste est nullable ou non. la valeur
 | 
			
		||||
par défaut est "?array"
 | 
			
		||||
où chaque occurrence de `KEY => VALUE_SCHEMA` définit le schéma de la valeur
 | 
			
		||||
dont la clé est `KEY`
 | 
			
		||||
 | 
			
		||||
chaque occurrence de `KEY => VALUE_SCHEMA` définit le schéma de la valeur dont
 | 
			
		||||
la clé est `KEY`
 | 
			
		||||
Si la nature du schéma n'est pas spécifiée, on considère que c'est un schéma de
 | 
			
		||||
nature associative si:
 | 
			
		||||
* c'est un tableau uniquement associatif avec aucun élément séquentiel, e.g
 | 
			
		||||
  `["name" => "string", "age" => "int"]`
 | 
			
		||||
 | 
			
		||||
VALUE_SCHEMA peut-être n'importe quel schéma valide, qui sera analysé
 | 
			
		||||
récursivement, avec cependant l'ajout de quelques clés supplémentaires:
 | 
			
		||||
@ -166,11 +171,14 @@ récursivement, avec cependant l'ajout de quelques clés supplémentaires:
 | 
			
		||||
 | 
			
		||||
## Schéma d'une liste (tableau séquentiel ou associatif d'éléments du même type)
 | 
			
		||||
 | 
			
		||||
Dans la forme courante, on considère que c'est un schéma de nature liste si:
 | 
			
		||||
* c'est un tableau avec un unique élément de type tableau à l'index 0, e.g
 | 
			
		||||
  `[["string", null, "required" => true]]`
 | 
			
		||||
Dans sa forme *non normalisée*, une liste est généralement modélisée de cette
 | 
			
		||||
manière:
 | 
			
		||||
~~~php
 | 
			
		||||
const LIST_SCHEMA = [ITEM_SCHEMA];
 | 
			
		||||
~~~
 | 
			
		||||
où ITEM_SCHEMA est le schéma des éléments de la liste
 | 
			
		||||
 | 
			
		||||
La forme normalisée est
 | 
			
		||||
Pour information, la forme normalisée est plutôt de la forme
 | 
			
		||||
~~~php
 | 
			
		||||
const LIST_SCHEMA = [
 | 
			
		||||
  "?array",
 | 
			
		||||
@ -181,4 +189,9 @@ const LIST_SCHEMA = [
 | 
			
		||||
le type "?array" ou "array" indique si la liste est nullable ou non. la valeur
 | 
			
		||||
par défaut est "?array"
 | 
			
		||||
 | 
			
		||||
Si la nature du schéma n'est pas spécifiée, on considère que c'est un schéma de
 | 
			
		||||
nature liste si:
 | 
			
		||||
* c'est un tableau avec un unique élément de type tableau à l'index 0, e.g
 | 
			
		||||
  `[["string", null, "required" => true]]`
 | 
			
		||||
 | 
			
		||||
-*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary
 | 
			
		||||
@ -1,42 +1,21 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema;
 | 
			
		||||
 | 
			
		||||
use IteratorAggregate;
 | 
			
		||||
use nur\sery\wip\schema\_assoc\AssocResult;
 | 
			
		||||
use nur\sery\wip\schema\_list\ListResult;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarResult;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class Result: résultat de l'analyse ou de la normalisation d'une valeur
 | 
			
		||||
 *
 | 
			
		||||
 * @property bool $resultAvailable le résultat est-il disponible?
 | 
			
		||||
 * @property bool $present la valeur existe-t-elle?
 | 
			
		||||
 * @property bool $available si la valeur existe, est-elle disponible?
 | 
			
		||||
 * @property bool $null si la valeur est disponible, est-elle nulle?
 | 
			
		||||
 * @property bool $valid si la valeur est disponible, est-elle valide?
 | 
			
		||||
 * @property bool $normalized si la valeur est valide, est-elle normalisée?
 | 
			
		||||
 * @property string|null $messageKey clé de message si la valeur n'est pas valide
 | 
			
		||||
 * @property string|null $message message si la valeur n'est pas valide
 | 
			
		||||
 * @property string|null $origValue valeur originale avant extraction et analyse
 | 
			
		||||
 * @property mixed|null $normalizedValue la valeur normalisée si elle est
 | 
			
		||||
 *  disponible, null sinon. ce champ est utilisé comme optimisation si la valeur
 | 
			
		||||
 *  normalisée a déjà été calculée
 | 
			
		||||
 */
 | 
			
		||||
abstract class Result implements IteratorAggregate {
 | 
			
		||||
  const KEYS = [
 | 
			
		||||
    "resultAvailable",
 | 
			
		||||
    "present", "available", "null", "valid", "normalized",
 | 
			
		||||
    "messageKey", "message",
 | 
			
		||||
    "origValue", "normalizedValue",
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
abstract class Result {
 | 
			
		||||
  function __construct() {
 | 
			
		||||
    $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; }
 | 
			
		||||
  function isAssoc(?AssocResult &$assoc=null): bool { return false; }
 | 
			
		||||
  function isList(?ListResult &$list=null): bool { return false; }
 | 
			
		||||
  function isScalar(?ScalarResult &$scalar=null): bool { return false; }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Obtenir la liste des clés valides pour les valeurs accessibles via cet
 | 
			
		||||
@ -44,21 +23,8 @@ abstract class Result implements IteratorAggregate {
 | 
			
		||||
   */
 | 
			
		||||
  abstract function getKeys(): array;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * sélectionner le résultat associé à la clé spécifiée
 | 
			
		||||
   *
 | 
			
		||||
   * @param string|int|null $key
 | 
			
		||||
   * @return Result $this
 | 
			
		||||
   */
 | 
			
		||||
  abstract function select($key): Result;
 | 
			
		||||
  /** obtenir un objet pour gérer la valeur spécifiée */
 | 
			
		||||
  abstract function getResult($key=null): Result;
 | 
			
		||||
 | 
			
		||||
  function getIterator() {
 | 
			
		||||
    foreach ($this->getKeys() as $key) {
 | 
			
		||||
      yield $key => $this->select($key);
 | 
			
		||||
    }
 | 
			
		||||
    $this->select(null);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** réinitialiser tous les objets résultats accessibles via cet objet */
 | 
			
		||||
  abstract function reset(): void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2,24 +2,15 @@
 | 
			
		||||
namespace nur\sery\wip\schema;
 | 
			
		||||
 | 
			
		||||
use ArrayAccess;
 | 
			
		||||
use nulib\AccessException;
 | 
			
		||||
use nulib\cl;
 | 
			
		||||
use nulib\ref\schema\ref_schema;
 | 
			
		||||
use nulib\ref\schema\ref_types;
 | 
			
		||||
use nur\sery\AccessException;
 | 
			
		||||
use nur\sery\cl;
 | 
			
		||||
use nur\sery\wip\schema\_assoc\AssocSchema;
 | 
			
		||||
use nur\sery\wip\schema\_list\ListSchema;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarSchema;
 | 
			
		||||
use nur\sery\wip\schema\types\IType;
 | 
			
		||||
use nur\sery\wip\schema\types\tarray;
 | 
			
		||||
use nur\sery\wip\schema\types\tbool;
 | 
			
		||||
use nur\sery\wip\schema\types\tcallable;
 | 
			
		||||
use nur\sery\wip\schema\types\tcontent;
 | 
			
		||||
use nur\sery\wip\schema\types\tpkey;
 | 
			
		||||
use nur\sery\wip\schema\types\trawstring;
 | 
			
		||||
 | 
			
		||||
abstract class Schema implements ArrayAccess {
 | 
			
		||||
  /**
 | 
			
		||||
   * créer le cas échéant une nouvelle instance de {@link Schema} à partir d'une
 | 
			
		||||
   * créer si besoin une nouvelle instance de {@link Schema} à partir d'une
 | 
			
		||||
   * définition de schéma
 | 
			
		||||
   *
 | 
			
		||||
   * - si $schema est une instance de schéma, la retourner
 | 
			
		||||
@ -27,18 +18,18 @@ abstract class Schema implements ArrayAccess {
 | 
			
		||||
   * l'instance de Schema nouvelle créée
 | 
			
		||||
   * - sinon, prendre $definition comme définition
 | 
			
		||||
   */
 | 
			
		||||
  static function ns(&$schema, $definition=null, $definitionKey=null, bool $normalize=true): self {
 | 
			
		||||
  static function ns(&$schema, $definition=null, $definitionKey=null): self {
 | 
			
		||||
    if (is_array($schema)) {
 | 
			
		||||
      $definition = $schema;
 | 
			
		||||
      $schema = null;
 | 
			
		||||
    }
 | 
			
		||||
    if ($schema === null) {
 | 
			
		||||
      if (AssocSchema::isa_definition($definition)) {
 | 
			
		||||
        $schema = new AssocSchema($definition, $definitionKey, $normalize);
 | 
			
		||||
        $schema = new AssocSchema($definition, $definitionKey);
 | 
			
		||||
      } elseif (ListSchema::isa_definition($definition)) {
 | 
			
		||||
        $schema = new ListSchema($definition, $definitionKey, $normalize);
 | 
			
		||||
        $schema = new ListSchema($definition, $definitionKey);
 | 
			
		||||
      } elseif (ScalarSchema::isa_definition($definition)) {
 | 
			
		||||
        $schema = new ScalarSchema($definition, $definitionKey, $normalize);
 | 
			
		||||
        $schema = new ScalarSchema($definition, $definitionKey);
 | 
			
		||||
      } else {
 | 
			
		||||
        throw SchemaException::invalid_schema();
 | 
			
		||||
      }
 | 
			
		||||
@ -47,189 +38,17 @@ abstract class Schema implements ArrayAccess {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Créer une nouvelle instance de {@link Wrapper} qui référence la
 | 
			
		||||
   * variable $value (si $valueKey===null) ou $value[$valueKey] si $valueKey
 | 
			
		||||
   * n'est pas null
 | 
			
		||||
   * Créer si besoin une nouvelle instance de {@link Value} qui référence la
 | 
			
		||||
   * variable $dest (si $destKey===null) ou $dest[$destKey] si $destKey n'est
 | 
			
		||||
   * pas null
 | 
			
		||||
   */
 | 
			
		||||
  static function nw(&$value=null, $valueKey=null, &$schema=null, $definition=null, ?Wrapper &$wrapper=null): Wrapper {
 | 
			
		||||
  static function nv(?Value &$destv=null, &$dest=null, $destKey=null, &$schema=null, $definition=null): Value {
 | 
			
		||||
    if ($definition === null) {
 | 
			
		||||
      # bien que techniquement, $definition peut être null (il s'agit alors du
 | 
			
		||||
      # schéma d'un scalaire quelconque), on ne l'autorise pas ici
 | 
			
		||||
      throw SchemaException::invalid_schema("definition is required");
 | 
			
		||||
    }
 | 
			
		||||
    return self::ns($schema, $definition)->getWrapper($value, $valueKey, $wrapper);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected static function have_nature(array $definition, ?string &$nature=null): bool {
 | 
			
		||||
    $definitionNature = $definition[""] ?? null;
 | 
			
		||||
    if (is_string($definitionNature)) {
 | 
			
		||||
      $nature = $definitionNature;
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    if (is_array($definitionNature)
 | 
			
		||||
      && array_key_exists(0, $definitionNature)
 | 
			
		||||
      && is_string($definitionNature[0])) {
 | 
			
		||||
      $nature = $definitionNature;
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected static function _normalize(&$definition, $definitionKey=null): void {
 | 
			
		||||
    if (!is_array($definition)) $definition = [$definition];
 | 
			
		||||
    # s'assurer que toutes les clés existent avec leur valeur par défaut
 | 
			
		||||
    $index = 0;
 | 
			
		||||
    foreach (array_keys(ref_schema::SCALAR_METASCHEMA) as $key) {
 | 
			
		||||
      if (!array_key_exists($key, $definition)) {
 | 
			
		||||
        if (array_key_exists($index, $definition)) {
 | 
			
		||||
          $definition[$key] = $definition[$index];
 | 
			
		||||
          unset($definition[$index]);
 | 
			
		||||
          $index++;
 | 
			
		||||
        } else {
 | 
			
		||||
          $definition[$key] = ref_schema::SCALAR_METASCHEMA[$key][1];
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    # réordonner les clés numériques
 | 
			
		||||
    if (cl::have_num_keys($definition)) {
 | 
			
		||||
      $keys = array_keys($definition);
 | 
			
		||||
      $index = 0;
 | 
			
		||||
      foreach ($keys as $key) {
 | 
			
		||||
        if (!is_int($key)) continue;
 | 
			
		||||
        if ($key !== $index) {
 | 
			
		||||
          $definition[$index] = $definition[$key];
 | 
			
		||||
          unset($definition[$key]);
 | 
			
		||||
        }
 | 
			
		||||
        $index++;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    # type
 | 
			
		||||
    $types = [];
 | 
			
		||||
    $deftype = $definition["type"];
 | 
			
		||||
    $nullable = $definition["nullable"] ?? false;
 | 
			
		||||
    if ($deftype === null) {
 | 
			
		||||
      $types[] = null;
 | 
			
		||||
      $nullable = true;
 | 
			
		||||
    } else {
 | 
			
		||||
      if (!is_array($deftype)) {
 | 
			
		||||
        if (!is_string($deftype)) throw SchemaException::invalid_type($deftype);
 | 
			
		||||
        $deftype = explode("|", $deftype);
 | 
			
		||||
      }
 | 
			
		||||
      foreach ($deftype as $type) {
 | 
			
		||||
        if ($type !== null) $type = trim($type);
 | 
			
		||||
        if ($type === null || $type === "null") {
 | 
			
		||||
          $nullable = true;
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
        if (!is_string($type)) throw SchemaException::invalid_type($type);
 | 
			
		||||
        if (substr($type, 0, 1) == "?") {
 | 
			
		||||
          $type = substr($type, 1);
 | 
			
		||||
          $nullable = true;
 | 
			
		||||
        }
 | 
			
		||||
        if ($type === "") throw SchemaException::invalid_type($type);
 | 
			
		||||
        $type = cl::get(ref_types::ALIASES, $type, $type);
 | 
			
		||||
        $types = array_merge($types, explode("|", $type));
 | 
			
		||||
      }
 | 
			
		||||
      if (!$types) throw SchemaException::invalid_schema("scalar: type is required");
 | 
			
		||||
      $types = array_keys(array_fill_keys($types, true));
 | 
			
		||||
    }
 | 
			
		||||
    $definition["type"] = $types;
 | 
			
		||||
    $definition["nullable"] = $nullable;
 | 
			
		||||
    # nature
 | 
			
		||||
    $nature = $definition[""];
 | 
			
		||||
    tarray::ensure_array($nature);
 | 
			
		||||
    $definition[""] = $nature;
 | 
			
		||||
    # name, pkey, header
 | 
			
		||||
    $name = $definition["name"];
 | 
			
		||||
    $pkey = $definition["pkey"];
 | 
			
		||||
    $header = $definition["header"];
 | 
			
		||||
    if ($name === null) $name = $definitionKey;
 | 
			
		||||
    trawstring::ensure_nstring($name);
 | 
			
		||||
    tpkey::ensure_npkey($pkey);
 | 
			
		||||
    trawstring::ensure_nstring($header);
 | 
			
		||||
    if ($pkey === null) $pkey = $name;
 | 
			
		||||
    if ($header === null) $header = $name;
 | 
			
		||||
    $definition["name"] = $name;
 | 
			
		||||
    $definition["pkey"] = $pkey;
 | 
			
		||||
    $definition["header"] = $header;
 | 
			
		||||
    # autres éléments
 | 
			
		||||
    tarray::ensure_narray($definition["schema"]);
 | 
			
		||||
    trawstring::ensure_nstring($definition["title"]);
 | 
			
		||||
    tbool::ensure_bool($definition["required"]);
 | 
			
		||||
    tbool::ensure_bool($definition["nullable"]);
 | 
			
		||||
    tcontent::ensure_ncontent($definition["desc"]);
 | 
			
		||||
    tcallable::ensure_ncallable($definition["analyzer_func"]);
 | 
			
		||||
    tcallable::ensure_ncallable($definition["extractor_func"]);
 | 
			
		||||
    tcallable::ensure_ncallable($definition["parser_func"]);
 | 
			
		||||
    tcallable::ensure_ncallable($definition["normalizer_func"]);
 | 
			
		||||
    tarray::ensure_narray($definition["messages"]);
 | 
			
		||||
    tcallable::ensure_ncallable($definition["formatter_func"]);
 | 
			
		||||
    tbool::ensure_nbool($definition["composite"]);
 | 
			
		||||
 | 
			
		||||
    switch ($nature[0] ?? null) {
 | 
			
		||||
    case "assoc":
 | 
			
		||||
      foreach ($definition["schema"] as $key => &$keydef) {
 | 
			
		||||
        self::_normalize($keydef, $key);
 | 
			
		||||
      }; unset($keydef);
 | 
			
		||||
      break;
 | 
			
		||||
    case "list":
 | 
			
		||||
      self::_normalize($definition["schema"]);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected static function _ensure_nature(array $definition, string $expectedNature, ?string $expectedType=null): void {
 | 
			
		||||
    $nature = $definition[""];
 | 
			
		||||
    if (!array_key_exists(0, $nature) || $nature[0] !== $expectedNature) {
 | 
			
		||||
      throw SchemaException::invalid_schema("$nature: invalid nature. expected $expectedNature");
 | 
			
		||||
    }
 | 
			
		||||
    if ($expectedType !== null) {
 | 
			
		||||
      $types = $definition["type"];
 | 
			
		||||
      if (count($types) !== 1 || $types[0] !== $expectedType) {
 | 
			
		||||
        throw new SchemaException("{$types[O]}: invalide type. expected $expectedType");
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected static function _ensure_type(array &$definition): void {
 | 
			
		||||
    $types = $definition["type"];
 | 
			
		||||
    $nullable = $definition["nullable"];
 | 
			
		||||
    # s'il n'y a qu'une seul type, l'instancier tout de suite
 | 
			
		||||
    if (is_array($types) && count($types) == 1 && $types[0] !== null) {
 | 
			
		||||
      foreach ($types as $key => $name) {
 | 
			
		||||
        if ($key === 0) {
 | 
			
		||||
          $args = null;
 | 
			
		||||
        } else {
 | 
			
		||||
          $args = $name;
 | 
			
		||||
          $name = $key;
 | 
			
		||||
        }
 | 
			
		||||
        $definition["type"] = types::get($nullable, $name, $args, $definition);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    switch ($definition[""][0]) {
 | 
			
		||||
    case "assoc":
 | 
			
		||||
      foreach ($definition["schema"] as &$keydef) {
 | 
			
		||||
        self::_ensure_type($keydef);
 | 
			
		||||
      }; unset($keydef);
 | 
			
		||||
      break;
 | 
			
		||||
    case "list":
 | 
			
		||||
      self::_ensure_type($definition["schema"]);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected static function _ensure_schema_instances(array &$definition): void {
 | 
			
		||||
    switch ($definition[""][0]) {
 | 
			
		||||
    case "assoc":
 | 
			
		||||
      foreach ($definition["schema"] as &$keydef) {
 | 
			
		||||
        self::_ensure_schema_instances($keydef);
 | 
			
		||||
        Schema::ns($keydef, null, null, false);
 | 
			
		||||
      }; unset($keydef);
 | 
			
		||||
      break;
 | 
			
		||||
    case "list":
 | 
			
		||||
      Schema::ns($definition["schema"], null, null, false);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    return self::ns($schema, $definition)->newValue($destv, $dest, $destKey);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
@ -238,22 +57,17 @@ abstract class Schema implements ArrayAccess {
 | 
			
		||||
   */
 | 
			
		||||
  const SCHEMA = null;
 | 
			
		||||
 | 
			
		||||
  protected array $_definition;
 | 
			
		||||
 | 
			
		||||
  protected array $definition;
 | 
			
		||||
 | 
			
		||||
  function getDefinition(): array {
 | 
			
		||||
    return $this->_definition;
 | 
			
		||||
  }
 | 
			
		||||
  /** @var array */
 | 
			
		||||
  protected $definition;
 | 
			
		||||
 | 
			
		||||
  /** retourner true si le schéma est de nature tableau associatif */
 | 
			
		||||
  function isAssoc(?AssocSchema &$schema=null): bool { return false; }
 | 
			
		||||
  function isAssoc(?AssocSchema &$assoc=null): bool { return false; }
 | 
			
		||||
  /** retourner true si le schéma est de nature liste */
 | 
			
		||||
  function isList(?ListSchema &$schema=null): bool { return false; }
 | 
			
		||||
  function isList(?ListSchema &$list=null): bool { return false; }
 | 
			
		||||
  /** retourner true si le schéma est de nature scalaire */
 | 
			
		||||
  function isScalar(?ScalarSchema &$schema=null): bool { return false; }
 | 
			
		||||
  function isScalar(?ScalarSchema &$scalar=null): bool { return false; }
 | 
			
		||||
 | 
			
		||||
  abstract function getWrapper(&$value=null, $valueKey=null, ?Wrapper &$wrapper=null): Wrapper;
 | 
			
		||||
  abstract function newValue(?Value &$destv=null, &$dest=null, $destKey=null): Value;
 | 
			
		||||
 | 
			
		||||
  #############################################################################
 | 
			
		||||
  # key & properties
 | 
			
		||||
 | 
			
		||||
@ -1,36 +1,19 @@
 | 
			
		||||
# nulib\schema
 | 
			
		||||
 | 
			
		||||
* tdate et tdatetime. qu'en est-il des autres classes (delay, etc.)
 | 
			
		||||
  * possibilité de spécifier le format de la date à analyser 
 | 
			
		||||
* ScalarSchema::from_property()
 | 
			
		||||
* possibilité de spécifier un type via sa classe, e.g
 | 
			
		||||
  ~~~php
 | 
			
		||||
  Schema::ns($schema, [
 | 
			
		||||
    MyType::class, null, "une valeur de type MyType"
 | 
			
		||||
  ]);
 | 
			
		||||
  ~~~
 | 
			
		||||
  MyType doit implémenter IType
 | 
			
		||||
* type générique construit à partir d'un nom de classe, e.g
 | 
			
		||||
  ~~~php
 | 
			
		||||
  Schema::ns($schema, [
 | 
			
		||||
    MyClass::class, null, "une valeur de type MyClass"
 | 
			
		||||
  ]);
 | 
			
		||||
  ~~~
 | 
			
		||||
  MyClass ne doit pas implémenter IType, et le type correspondant est créé avec
 | 
			
		||||
  `new tgeneric(MyClass::class)`
 | 
			
		||||
# nur\sery\schema
 | 
			
		||||
 | 
			
		||||
* implémenter support `analyzer_func`, `extractor_func`, `parser_func`,
 | 
			
		||||
  `normalizer_func`, `formatter_func`
 | 
			
		||||
* dans AssocSchema, support `[key_prefix]` qui permet de spécifier un préfixe
 | 
			
		||||
  commun aux champs dans le tableau destination, e.g
 | 
			
		||||
  ~~~php
 | 
			
		||||
  $wrapper = Schema::ns($schema, [
 | 
			
		||||
  $value = Schema::ns($schema, [
 | 
			
		||||
    "a" => "?string",
 | 
			
		||||
    "b" => "?int",
 | 
			
		||||
  ])->newWrapper();
 | 
			
		||||
  $value = ["x_a" => 5, "x_b" => "10"],
 | 
			
		||||
  $wrapper->reset($value, null, [
 | 
			
		||||
  ])->newValue();
 | 
			
		||||
  $dest = ["x_a" => 5, "x_b" => "10"],
 | 
			
		||||
  $value->reset($dest, null, [
 | 
			
		||||
    "key_prefix" => "x_",
 | 
			
		||||
  ]);
 | 
			
		||||
  # $value vaut ["x_a" => "5", "x_b" => 10];
 | 
			
		||||
  # $dest vaut ["x_a" => "5", "x_b" => 10];
 | 
			
		||||
  ~~~
 | 
			
		||||
  définir si le préfixe doit être spécifié sur le schéma ou sur la valeur...
 | 
			
		||||
  actuellement, le code ne permet pas de définir de tels paramètres...
 | 
			
		||||
@ -38,16 +21,48 @@
 | 
			
		||||
  alternative: c'est lors de la *définition* du schéma que le préfixe est ajouté
 | 
			
		||||
  e.g
 | 
			
		||||
  ~~~php
 | 
			
		||||
  $wrapper = Schema::ns($schema, [
 | 
			
		||||
  $value = Schema::ns($schema, [
 | 
			
		||||
    "a" => "?string",
 | 
			
		||||
    "b" => "?int",
 | 
			
		||||
  ], [
 | 
			
		||||
    "key_prefix" => "x_",
 | 
			
		||||
  ])->newWrapper();
 | 
			
		||||
  $value = ["x_a" => 5, "x_b" => "10"],
 | 
			
		||||
  $wrapper->reset($value);
 | 
			
		||||
  # $value vaut ["x_a" => "5", "x_b" => 10];
 | 
			
		||||
  ])->newValue();
 | 
			
		||||
  $dest = ["x_a" => 5, "x_b" => "10"],
 | 
			
		||||
  $value->reset($dest);
 | 
			
		||||
  # $dest vaut ["x_a" => "5", "x_b" => 10];
 | 
			
		||||
  ~~~
 | 
			
		||||
* dans la définition, `[type]` est remplacé par l'instance de IType lors de sa
 | 
			
		||||
  résolution?
 | 
			
		||||
* implémenter l'instanciation de types avec des paramètres particuliers. *si*
 | 
			
		||||
  des paramètres sont fournis, le type est instancié avec la signature 
 | 
			
		||||
  `IType($typeDefinition, $schemaDefinition)` e.g
 | 
			
		||||
  ~~~php
 | 
			
		||||
  const SCHEMA = ["type", default, "required" => true];
 | 
			
		||||
  # le type est instancié comme suit:
 | 
			
		||||
  $type = new ttype();
 | 
			
		||||
 | 
			
		||||
  const SCHEMA = [[["type", ...]], default, "required" => true];
 | 
			
		||||
  # le type est instancié comme suit:
 | 
			
		||||
  # le tableau peut être une liste ou associatif, c'est au type de décider ce 
 | 
			
		||||
  # qu'il en fait
 | 
			
		||||
  $type = new ttype(["type", ...], SCHEMA);
 | 
			
		||||
  ~~~
 | 
			
		||||
* ajouter à IType les méthodes getName() pour le nom officiel du type,
 | 
			
		||||
  getAliases() pour les alias supportés, et getClass() pour la définition de la
 | 
			
		||||
  classe dans les méthodes et propriétés
 | 
			
		||||
  getName() et getAliases() sont juste pour information, ils ne sont pas utilisés
 | 
			
		||||
  lors de la résolution du type effectif.
 | 
			
		||||
* si cela a du sens, dans AssocSchema, n'instancier les schémas de chaque clé qu'à la demande.
 | 
			
		||||
  l'idée est de ne pas perdre du temps à instancier un schéma qui ne serait pas utilisé
 | 
			
		||||
 | 
			
		||||
  on pourrait avoir d'une manière générale quelque chose comme:
 | 
			
		||||
  ~~~
 | 
			
		||||
  Schema::ensure(&$schema, ?array $def=null, $defKey=null): Schema;
 | 
			
		||||
  ~~~
 | 
			
		||||
  * si $schema est une instance de Schema, la retourner
 | 
			
		||||
  * si c'est un array, c'est une définition et il faut la remplacer par l'instance de Schema correspondant
 | 
			
		||||
  * sinon, prendre $def comme définition
 | 
			
		||||
  $key est la clé si $schema est dans un autre schema
 | 
			
		||||
* actuellement, pour un schéma associatif, si on normalise un tableau séquentiel,
 | 
			
		||||
  chaque valeur correspond à la clé de même rang, eg. pour un schéma
 | 
			
		||||
  ~~~php
 | 
			
		||||
 | 
			
		||||
@ -3,18 +3,18 @@ namespace nur\sery\wip\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\_assoc\AssocValue;
 | 
			
		||||
use nur\sery\wip\schema\_list\ListValue;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarValue;
 | 
			
		||||
use nur\sery\wip\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; }
 | 
			
		||||
abstract class Value implements ArrayAccess, IteratorAggregate {
 | 
			
		||||
  function isAssoc(?AssocValue &$assoc=null): bool { return false; }
 | 
			
		||||
  function isList(?ListValue &$list=null): bool { return false; }
 | 
			
		||||
  function isScalar(?ScalarValue &$scalar=null): bool { return false; }
 | 
			
		||||
 | 
			
		||||
  /** spécifier la valeur destination gérée par cet objet */
 | 
			
		||||
  abstract function reset(&$value, $valueKey=null, ?bool $verifix=null): self;
 | 
			
		||||
  abstract function reset(&$dest, $destKey=null, ?bool $verifix=null): self;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Obtenir la liste des clés valides pour les valeurs accessibles via cet
 | 
			
		||||
@ -22,19 +22,13 @@ abstract class Wrapper implements ArrayAccess, IteratorAggregate {
 | 
			
		||||
   */
 | 
			
		||||
  abstract function getKeys(): array;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * sélectionner le wrapper associé à la clé spécifiée
 | 
			
		||||
   *
 | 
			
		||||
   * @param string|int|null $key
 | 
			
		||||
   * @return Wrapper $this
 | 
			
		||||
   */
 | 
			
		||||
  abstract function select($key): Wrapper;
 | 
			
		||||
  /** obtenir un objet pour gérer la valeur spécifiée */
 | 
			
		||||
  abstract function getValue($key=null): Value;
 | 
			
		||||
 | 
			
		||||
  function getIterator() {
 | 
			
		||||
    foreach ($this->getKeys() as $key) {
 | 
			
		||||
      yield $key => $this->select($key);
 | 
			
		||||
      yield $key => $this->getValue($key);
 | 
			
		||||
    }
 | 
			
		||||
    $this->select(null);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
@ -78,14 +72,14 @@ abstract class Wrapper implements ArrayAccess, IteratorAggregate {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function offsetGet($offset) {
 | 
			
		||||
    return $this->select($offset);
 | 
			
		||||
    return $this->getValue($offset);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function offsetSet($offset, $value): void {
 | 
			
		||||
    $this->select($offset)->set($value);
 | 
			
		||||
    $this->getValue($offset)->set($value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function offsetUnset($offset): void {
 | 
			
		||||
    $this->select($offset)->unset();
 | 
			
		||||
    $this->getValue($offset)->unset();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,53 +1,8 @@
 | 
			
		||||
<?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;
 | 
			
		||||
  }
 | 
			
		||||
  function isAssoc(?AssocResult &$assoc=null): bool { $assoc = $this; return true;}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,10 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\_assoc;
 | 
			
		||||
 | 
			
		||||
use nulib\cl;
 | 
			
		||||
use nulib\ref\schema\ref_schema;
 | 
			
		||||
use nur\sery\cl;
 | 
			
		||||
use nur\sery\ref\schema\ref_schema;
 | 
			
		||||
use nur\sery\wip\schema\Schema;
 | 
			
		||||
use nur\sery\wip\schema\Wrapper;
 | 
			
		||||
use nur\sery\wip\schema\Value;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class AssocSchema
 | 
			
		||||
@ -20,49 +20,36 @@ class AssocSchema extends Schema {
 | 
			
		||||
  static function isa_definition($definition): bool {
 | 
			
		||||
    if (!is_array($definition)) return false;
 | 
			
		||||
    # nature explicitement spécifiée
 | 
			
		||||
    if (self::have_nature($definition, $nature)) {
 | 
			
		||||
      return $nature === "assoc";
 | 
			
		||||
    if (array_key_exists("", $definition)) {
 | 
			
		||||
      $nature = $definition[""];
 | 
			
		||||
      if ($nature === "assoc") return true;
 | 
			
		||||
      if (is_array($nature)
 | 
			
		||||
        && array_key_exists(0, $nature)
 | 
			
		||||
        && $nature[0] === "assoc") {
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
    # tableau associatif
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    # un tableau associatif
 | 
			
		||||
    return !cl::have_num_keys($definition);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static function normalize($definition, $definitionKey=null): array {
 | 
			
		||||
    if (!is_array($definition)) $definition = [$definition];
 | 
			
		||||
    if (!self::have_nature($definition)) {
 | 
			
		||||
      $definition = [
 | 
			
		||||
        "?array",
 | 
			
		||||
        "" => "assoc",
 | 
			
		||||
        "schema" => $definition,
 | 
			
		||||
      ];
 | 
			
		||||
    }
 | 
			
		||||
    self::_normalize($definition, $definitionKey);
 | 
			
		||||
    self::_ensure_nature($definition, "assoc", "array");
 | 
			
		||||
    return $definition;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function __construct($definition=null, $definitionKey=null, bool $normalize=true) {
 | 
			
		||||
    if ($definition === null) $definition = static::SCHEMA;
 | 
			
		||||
    if ($normalize) {
 | 
			
		||||
      $definition = self::normalize($definition, $definitionKey);
 | 
			
		||||
      $this->_definition = $definition;
 | 
			
		||||
      self::_ensure_type($definition);
 | 
			
		||||
      self::_ensure_schema_instances($definition);
 | 
			
		||||
    }
 | 
			
		||||
    if ($normalize) $definition = self::normalize($definition, $definitionKey);
 | 
			
		||||
    $this->definition = $definition;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isAssoc(?AssocSchema &$schema=null): bool {
 | 
			
		||||
    $schema = $this;
 | 
			
		||||
  function isAssoc(?AssocSchema &$assoc=null): bool {
 | 
			
		||||
    $assoc = $this;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function newWrapper(): AssocWrapper {
 | 
			
		||||
    return new AssocWrapper($this);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getWrapper(&$array=null, $arrayKey=null, ?Wrapper &$wrapper=null): AssocWrapper {
 | 
			
		||||
    if (!($wrapper instanceof AssocWrapper)) $wrapper = $this->newWrapper();
 | 
			
		||||
    return $wrapper->reset($array, $arrayKey);
 | 
			
		||||
  function newValue(?Value &$destv=null, &$dest=null, $destKey=null): AssocValue {
 | 
			
		||||
    if ($destv instanceof AssocValue) return $destv->reset($dest, $destKey);
 | 
			
		||||
    else return ($destv = new AssocValue($this, $dest, $destKey));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										18
									
								
								src/schema/_assoc/AssocValue.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/schema/_assoc/AssocValue.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\_assoc;
 | 
			
		||||
 | 
			
		||||
use nur\sery\wip\schema\Result;
 | 
			
		||||
use nur\sery\wip\schema\Value;
 | 
			
		||||
 | 
			
		||||
class AssocValue extends Value {
 | 
			
		||||
  function isAssoc(?AssocValue &$assoc=null): bool { $assoc = $this; return true; }
 | 
			
		||||
 | 
			
		||||
  function ensureKeys(): bool {
 | 
			
		||||
  }
 | 
			
		||||
  function orderKeys(): bool {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** @param Result[] $results */
 | 
			
		||||
  function verifix(bool $throw=true, ?array &$results=null): bool {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,140 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\_assoc;
 | 
			
		||||
 | 
			
		||||
use nulib\ValueException;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarResult;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarWrapper;
 | 
			
		||||
use nur\sery\wip\schema\input\Input;
 | 
			
		||||
use nur\sery\wip\schema\Result;
 | 
			
		||||
use nur\sery\wip\schema\types\IType;
 | 
			
		||||
use nur\sery\wip\schema\Wrapper;
 | 
			
		||||
 | 
			
		||||
class AssocWrapper extends Wrapper {
 | 
			
		||||
  function __construct(AssocSchema $schema, &$array=null, $arrayKey=null, ?array $params=null) {
 | 
			
		||||
    $verifix = $params["verifix"] ?? true;
 | 
			
		||||
    $throw = $params["throw"] ?? null;
 | 
			
		||||
    if ($array !== null && $throw === null) {
 | 
			
		||||
      # Si $value est null, ne pas lancer d'exception, parce qu'on considère que
 | 
			
		||||
      # c'est une initialisation sans conséquences
 | 
			
		||||
      $throw = true;
 | 
			
		||||
    }
 | 
			
		||||
    $this->schema = $schema;
 | 
			
		||||
    $this->verifix = $verifix;
 | 
			
		||||
    $this->throw = $throw ?? false;
 | 
			
		||||
    $this->result = new AssocResult();
 | 
			
		||||
    $this->reset($array, $arrayKey);
 | 
			
		||||
    $this->throw = $throw ?? true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isAssoc(?AssocWrapper &$wrapper=null): bool { $wrapper = $this; return true; }
 | 
			
		||||
 | 
			
		||||
  protected bool $verifix;
 | 
			
		||||
 | 
			
		||||
  protected bool $throw;
 | 
			
		||||
 | 
			
		||||
  /** schéma de ce tableau */
 | 
			
		||||
  protected AssocSchema $schema;
 | 
			
		||||
 | 
			
		||||
  /** source et destination de la valeur */
 | 
			
		||||
  protected Input $input;
 | 
			
		||||
 | 
			
		||||
  /** @var string|int|null clé du tableau dans le tableau destination */
 | 
			
		||||
  protected $arrayKey;
 | 
			
		||||
 | 
			
		||||
  protected IType $arrayType;
 | 
			
		||||
 | 
			
		||||
  protected ScalarResult $arrayResult;
 | 
			
		||||
 | 
			
		||||
  /** @var IType[] */
 | 
			
		||||
  protected array $keyTypes;
 | 
			
		||||
 | 
			
		||||
  /** @var Result[] */
 | 
			
		||||
  protected array $keyResults;
 | 
			
		||||
 | 
			
		||||
  protected AssocResult $result;
 | 
			
		||||
 | 
			
		||||
  protected ?array $keys;
 | 
			
		||||
 | 
			
		||||
  protected ?array $wrappers;
 | 
			
		||||
 | 
			
		||||
  protected function newInput(&$value): Input {
 | 
			
		||||
    return new Input($value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function reset(&$array, $arrayKey=null, ?bool $verifix=null): Wrapper {
 | 
			
		||||
    if ($array instanceof Input) $input = $array;
 | 
			
		||||
    else $input = $this->newInput($array);
 | 
			
		||||
    $this->input = $input;
 | 
			
		||||
    $this->arrayKey = $arrayKey;
 | 
			
		||||
    $this->analyze();
 | 
			
		||||
    if ($verifix ?? $this->verifix) $this->verifix();
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getKeys(): array {
 | 
			
		||||
    return $this->keys;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function select($key=null): ScalarWrapper {
 | 
			
		||||
    $wrapper = $this->wrappers[$key] ?? null;
 | 
			
		||||
    if ($key !== null) return $wrapper;
 | 
			
		||||
    throw ValueException::invalid_key($key);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** @param Result[] $results */
 | 
			
		||||
  function verifix(?bool $throw=null, ?array &$results=null): bool {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  function getResult(): AssocResult {
 | 
			
		||||
    return $this->result;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isPresent(): bool {
 | 
			
		||||
    return $this->result->present;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getType(): IType {
 | 
			
		||||
    return $this->arrayType;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isAvailable(): bool {
 | 
			
		||||
    return $this->result->available;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isValid(): bool {
 | 
			
		||||
    return $this->result->valid;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isNormalized(): bool {
 | 
			
		||||
    return $this->result->normalized;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function get($default=null) {
 | 
			
		||||
    if ($this->result->available) return $this->input->get($this->arrayKey);
 | 
			
		||||
    else return $default;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function set($value, ?bool $verifix=null): AssocWrapper {
 | 
			
		||||
    $this->input->set($value, $this->arrayKey);
 | 
			
		||||
    $this->analyze();
 | 
			
		||||
    if ($verifix ?? $this->verifix) $this->verifix();
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function unset(?bool $verifix=null): AssocWrapper {
 | 
			
		||||
    $this->input->unset($this->arrayKey);
 | 
			
		||||
    $this->analyze();
 | 
			
		||||
    if ($verifix ?? $this->verifix) $this->verifix();
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function format($format = null): string {
 | 
			
		||||
    // TODO: Implement format() method.
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function ensureKeys(): bool {
 | 
			
		||||
  }
 | 
			
		||||
  function orderKeys(): bool {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,53 +1,8 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\_list;
 | 
			
		||||
 | 
			
		||||
use nulib\ValueException;
 | 
			
		||||
use nur\sery\wip\schema\Result;
 | 
			
		||||
 | 
			
		||||
class ListResult extends Result {
 | 
			
		||||
  function __construct(Result $arrayResult, array &$keyResults) {
 | 
			
		||||
    $this->arrayResult = $arrayResult;
 | 
			
		||||
    $this->keyResults =& $keyResults;
 | 
			
		||||
    $this->result =& $this->arrayResult;
 | 
			
		||||
      parent::__construct();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isList(?ListResult &$result=null): bool { $result = $this; return true;}
 | 
			
		||||
 | 
			
		||||
  protected Result $arrayResult;
 | 
			
		||||
 | 
			
		||||
  /** @var Result[] */
 | 
			
		||||
  protected array $keyResults;
 | 
			
		||||
 | 
			
		||||
  function getKeys(): array {
 | 
			
		||||
    return array_keys($this->keyResults);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected Result $result;
 | 
			
		||||
 | 
			
		||||
  function select($key): Result {
 | 
			
		||||
    if ($key === null) {
 | 
			
		||||
      $this->result =& $this->arrayResult;
 | 
			
		||||
    } elseif (array_key_exists($key, $this->keyResults)) {
 | 
			
		||||
      $this->result =& $this->keyResults[$key];
 | 
			
		||||
    } else {
 | 
			
		||||
      throw ValueException::invalid_key($key);
 | 
			
		||||
    }
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function reset(): void {
 | 
			
		||||
    $this->arrayResult->reset();
 | 
			
		||||
    foreach ($this->keyResults as $result) {
 | 
			
		||||
      $result->reset();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function __get(string $name) {
 | 
			
		||||
    return $this->result[$name];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function __set(string $name, $value): void {
 | 
			
		||||
    $this->result[$name] = $value;
 | 
			
		||||
  }
 | 
			
		||||
  function isList(?ListResult &$list=null): bool { $list = $this; return true;}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,9 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\_list;
 | 
			
		||||
 | 
			
		||||
use nulib\ref\schema\ref_schema;
 | 
			
		||||
use nur\sery\ref\schema\ref_schema;
 | 
			
		||||
use nur\sery\wip\schema\Schema;
 | 
			
		||||
use nur\sery\wip\schema\Wrapper;
 | 
			
		||||
use nur\sery\wip\schema\Value;
 | 
			
		||||
 | 
			
		||||
class ListSchema extends Schema {
 | 
			
		||||
  /** @var array meta-schema d'un schéma de nature liste */
 | 
			
		||||
@ -16,8 +16,15 @@ class ListSchema extends Schema {
 | 
			
		||||
  static function isa_definition($definition): bool {
 | 
			
		||||
    if (!is_array($definition)) return false;
 | 
			
		||||
    # nature explicitement spécifiée
 | 
			
		||||
    if (self::have_nature($definition, $nature)) {
 | 
			
		||||
      return $nature === "list";
 | 
			
		||||
    if (array_key_exists("", $definition)) {
 | 
			
		||||
      $nature = $definition[""];
 | 
			
		||||
      if ($nature === "list") return true;
 | 
			
		||||
      if (is_array($nature)
 | 
			
		||||
        && array_key_exists(0, $nature)
 | 
			
		||||
        && $nature[0] === "list") {
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    # un unique élément tableau à l'index 0
 | 
			
		||||
    $count = count($definition);
 | 
			
		||||
@ -26,41 +33,21 @@ class ListSchema extends Schema {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static function normalize($definition, $definitionKey=null): array {
 | 
			
		||||
    if (!is_array($definition)) $definition = [$definition];
 | 
			
		||||
    if (!self::have_nature($definition)) {
 | 
			
		||||
      $definition = [
 | 
			
		||||
        "?array",
 | 
			
		||||
        "" => "list",
 | 
			
		||||
        "schema" => $definition[0],
 | 
			
		||||
      ];
 | 
			
		||||
    }
 | 
			
		||||
    self::_normalize($definition, $definitionKey);
 | 
			
		||||
    self::_ensure_nature($definition, "list", "array");
 | 
			
		||||
    return $definition;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function __construct($definition=null, $definitionKey=null, bool $normalize=true) {
 | 
			
		||||
    if ($definition === null) $definition = static::SCHEMA;
 | 
			
		||||
    if ($normalize) {
 | 
			
		||||
      $definition = self::normalize($definition, $definitionKey);
 | 
			
		||||
      $this->_definition = $definition;
 | 
			
		||||
      self::_ensure_type($definition);
 | 
			
		||||
      self::_ensure_schema_instances($definition);
 | 
			
		||||
    }
 | 
			
		||||
    if ($normalize) $definition = self::normalize($definition, $definitionKey);
 | 
			
		||||
    $this->definition = $definition;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isList(?ListSchema &$schema=null): bool {
 | 
			
		||||
    $schema = $this;
 | 
			
		||||
  function isList(?ListSchema &$list=null): bool {
 | 
			
		||||
    $list = $this;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function newWrapper(): ListWrapper {
 | 
			
		||||
    return new ListWrapper($this);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getWrapper(&$value=null, $valueKey=null, ?Wrapper &$wrapper=null): ListWrapper {
 | 
			
		||||
    if (!($wrapper instanceof ListWrapper)) $wrapper = $this->newWrapper();
 | 
			
		||||
    return $wrapper->reset($value, $valueKey);
 | 
			
		||||
  function newValue(?Value &$destv=null, &$dest=null, $destKey=null): ListValue {
 | 
			
		||||
    if ($destv instanceof ListValue) return $destv->reset($dest, $destKey);
 | 
			
		||||
    else return ($destv = new ListValue($this, $dest, $destKey));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2,10 +2,10 @@
 | 
			
		||||
namespace nur\sery\wip\schema\_list;
 | 
			
		||||
 | 
			
		||||
use nur\sery\wip\schema\Result;
 | 
			
		||||
use nur\sery\wip\schema\Wrapper;
 | 
			
		||||
use nur\sery\wip\schema\Value;
 | 
			
		||||
 | 
			
		||||
abstract/*XXX*/ class ListWrapper extends Wrapper {
 | 
			
		||||
  function isList(?ListWrapper &$wrapper=null): bool { $wrapper = $this; return true; }
 | 
			
		||||
class ListValue extends Value {
 | 
			
		||||
  function isList(?ListValue &$list=null): bool { $list = $this; return true; }
 | 
			
		||||
 | 
			
		||||
  function ensureKeys(): bool {
 | 
			
		||||
  }
 | 
			
		||||
@ -1,27 +1,36 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\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\cl;
 | 
			
		||||
use nur\sery\ref\schema\ref_analyze;
 | 
			
		||||
use nur\sery\ref\schema\ref_schema;
 | 
			
		||||
use nur\sery\ValueException;
 | 
			
		||||
use nur\sery\wip\schema\Result;
 | 
			
		||||
use Throwable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class ScalarResult: résultat de l'analyse ou de la normalisation d'une valeur
 | 
			
		||||
 *
 | 
			
		||||
 * @property bool $resultAvailable le résultat est-il disponible?
 | 
			
		||||
 * @property bool $present la valeur existe-t-elle?
 | 
			
		||||
 * @property bool $available si la valeur existe, est-elle disponible?
 | 
			
		||||
 * @property bool $null si la valeur est disponible, est-elle nulle?
 | 
			
		||||
 * @property bool $valid si la valeur est disponible, est-elle valide?
 | 
			
		||||
 * @property bool $normalized si la valeur est valide, est-elle normalisée?
 | 
			
		||||
 * @property string|null $orig valeur originale avant analyse avec parse()
 | 
			
		||||
 * @property string|null $message message si la valeur n'est pas valide
 | 
			
		||||
 */
 | 
			
		||||
class ScalarResult extends Result {
 | 
			
		||||
  function isScalar(?ScalarResult &$result=null): bool { $result = $this; return true; }
 | 
			
		||||
  const KEYS = ["resultAvailable", "present", "available", "null", "valid", "normalized", "orig", "message"];
 | 
			
		||||
 | 
			
		||||
  function isScalar(?ScalarResult &$scalar=null): bool { $scalar = $this; return true; }
 | 
			
		||||
 | 
			
		||||
  function getKeys(): array {
 | 
			
		||||
    return [null];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function select($key): Result {
 | 
			
		||||
    if ($key !== null) throw ValueException::invalid_key($key);
 | 
			
		||||
    return $this;
 | 
			
		||||
  function getResult($key=null): Result {
 | 
			
		||||
    if ($key === null) return $this;
 | 
			
		||||
    else throw ValueException::invalid_key($key);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** @var array  */
 | 
			
		||||
@ -56,8 +65,8 @@ class ScalarResult extends Result {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected static function replace_orig(string &$message, $origValue): void {
 | 
			
		||||
    $message = str_replace("{orig}", strval($origValue), $message);
 | 
			
		||||
  protected static function replace_orig(string &$message, $orig): void {
 | 
			
		||||
    $message = str_replace("{orig}", strval($orig), $message);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function getMessage(string $key, ScalarSchema $schema): string {
 | 
			
		||||
@ -76,8 +85,7 @@ class ScalarResult extends Result {
 | 
			
		||||
      $this->normalized = true;
 | 
			
		||||
      return ref_analyze::NORMALIZED;
 | 
			
		||||
    } else {
 | 
			
		||||
      $messageKey = $this->messageKey = "missing";
 | 
			
		||||
      $message = $this->getMessage($messageKey, $schema);
 | 
			
		||||
      $message = $this->getMessage("missing", $schema);
 | 
			
		||||
      self::replace_key($message, $schema->name);
 | 
			
		||||
      $this->message = $message;
 | 
			
		||||
      return ref_analyze::MISSING;
 | 
			
		||||
@ -94,8 +102,7 @@ class ScalarResult extends Result {
 | 
			
		||||
      $this->normalized = true;
 | 
			
		||||
      return ref_analyze::NORMALIZED;
 | 
			
		||||
    } else {
 | 
			
		||||
      $messageKey = $this->messageKey = "unavailable";
 | 
			
		||||
      $message = $this->getMessage($messageKey, $schema);
 | 
			
		||||
      $message = $this->getMessage("unavailable", $schema);
 | 
			
		||||
      self::replace_key($message, $schema->name);
 | 
			
		||||
      $this->message = $message;
 | 
			
		||||
      return ref_analyze::UNAVAILABLE;
 | 
			
		||||
@ -112,40 +119,33 @@ class ScalarResult extends Result {
 | 
			
		||||
      $this->normalized = true;
 | 
			
		||||
      return ref_analyze::NORMALIZED;
 | 
			
		||||
    } else {
 | 
			
		||||
      $messageKey = $this->messageKey = "null";
 | 
			
		||||
      $message = $this->getMessage($messageKey, $schema);
 | 
			
		||||
      $message = $this->getMessage("null", $schema);
 | 
			
		||||
      self::replace_key($message, $schema->name);
 | 
			
		||||
      $this->message = $message;
 | 
			
		||||
      return ref_analyze::NULL;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function setInvalid($value, ScalarSchema $schema, ?Throwable $t=null): int {
 | 
			
		||||
  function setInvalid($value, ScalarSchema $schema): int {
 | 
			
		||||
    $this->resultAvailable = true;
 | 
			
		||||
    $this->present = true;
 | 
			
		||||
    $this->available = true;
 | 
			
		||||
    $this->null = false;
 | 
			
		||||
    $this->valid = false;
 | 
			
		||||
    $this->origValue = $value;
 | 
			
		||||
    $messageKey = $this->messageKey = "invalid";
 | 
			
		||||
    $message = $this->getMessage($messageKey, $schema);
 | 
			
		||||
    $this->orig = $value;
 | 
			
		||||
    $message = $this->getMessage("invalid", $schema);
 | 
			
		||||
    self::replace_key($message, $schema->name);
 | 
			
		||||
    self::replace_orig($message, $schema->orig);
 | 
			
		||||
    if ($t !== null) {
 | 
			
		||||
      $tmessage = ValueException::get_message($t);
 | 
			
		||||
      if ($tmessage) $message .= ": $tmessage";
 | 
			
		||||
    }
 | 
			
		||||
    $this->message = $message;
 | 
			
		||||
    return ref_analyze::INVALID;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function setValid($normalizedValue=null): int {
 | 
			
		||||
  function setValid(): int {
 | 
			
		||||
    $this->resultAvailable = true;
 | 
			
		||||
    $this->present = true;
 | 
			
		||||
    $this->available = true;
 | 
			
		||||
    $this->null = false;
 | 
			
		||||
    $this->valid = true;
 | 
			
		||||
    $this->normalizedValue = $normalizedValue;
 | 
			
		||||
    return ref_analyze::VALID;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,15 +1,23 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\_scalar;
 | 
			
		||||
 | 
			
		||||
use nulib\ref\schema\ref_schema;
 | 
			
		||||
use nur\sery\cl;
 | 
			
		||||
use nur\sery\ref\schema\ref_schema;
 | 
			
		||||
use nur\sery\ref\schema\ref_types;
 | 
			
		||||
use nur\sery\wip\schema\Schema;
 | 
			
		||||
use nur\sery\wip\schema\types\IType;
 | 
			
		||||
use nur\sery\wip\schema\Wrapper;
 | 
			
		||||
use nur\sery\wip\schema\SchemaException;
 | 
			
		||||
use nur\sery\wip\schema\types\tarray;
 | 
			
		||||
use nur\sery\wip\schema\types\tbool;
 | 
			
		||||
use nur\sery\wip\schema\types\tcallable;
 | 
			
		||||
use nur\sery\wip\schema\types\tcontent;
 | 
			
		||||
use nur\sery\wip\schema\types\tpkey;
 | 
			
		||||
use nur\sery\wip\schema\types\tstring;
 | 
			
		||||
use nur\sery\wip\schema\Value;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class ScalarSchema
 | 
			
		||||
 * 
 | 
			
		||||
 * @property-read array|IType $type
 | 
			
		||||
 * @property-read array $type
 | 
			
		||||
 * @property-read mixed $default
 | 
			
		||||
 * @property-read string|null $title
 | 
			
		||||
 * @property-read bool $required
 | 
			
		||||
@ -23,7 +31,6 @@ use nur\sery\wip\schema\Wrapper;
 | 
			
		||||
 * @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
 | 
			
		||||
@ -65,34 +72,111 @@ class ScalarSchema extends Schema {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static function normalize($definition, $definitionKey=null): array {
 | 
			
		||||
    self::_normalize($definition, $definitionKey);
 | 
			
		||||
    self::_ensure_nature($definition, "scalar");
 | 
			
		||||
    if (!is_array($definition)) $definition = [$definition];
 | 
			
		||||
    # s'assurer que toutes les clés existent avec leur valeur par défaut
 | 
			
		||||
    $index = 0;
 | 
			
		||||
    foreach (array_keys(self::METASCHEMA) as $key) {
 | 
			
		||||
      if (!array_key_exists($key, $definition)) {
 | 
			
		||||
        if (array_key_exists($index, $definition)) {
 | 
			
		||||
          $definition[$key] = $definition[$index];
 | 
			
		||||
          unset($definition[$index]);
 | 
			
		||||
          $index++;
 | 
			
		||||
        } else {
 | 
			
		||||
          $definition[$key] = self::METASCHEMA[$key][1];
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    # réordonner les clés numériques
 | 
			
		||||
    if (cl::have_num_keys($definition)) {
 | 
			
		||||
      $keys = array_keys($definition);
 | 
			
		||||
      $index = 0;
 | 
			
		||||
      foreach ($keys as $key) {
 | 
			
		||||
        if (!is_int($key)) continue;
 | 
			
		||||
        $definition[$index] = $definition[$key];
 | 
			
		||||
        unset($definition[$key]);
 | 
			
		||||
        $index++;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    # type
 | 
			
		||||
    $types = [];
 | 
			
		||||
    $deftype = $definition["type"];
 | 
			
		||||
    $nullable = $definition["nullable"];
 | 
			
		||||
    if ($deftype === null) {
 | 
			
		||||
      $types[] = null;
 | 
			
		||||
      $nullable = true;
 | 
			
		||||
    } else {
 | 
			
		||||
      if (!is_array($deftype)) {
 | 
			
		||||
        if (!is_string($deftype)) throw SchemaException::invalid_type($deftype);
 | 
			
		||||
        $deftype = explode("|", $deftype);
 | 
			
		||||
      }
 | 
			
		||||
      foreach ($deftype as $type) {
 | 
			
		||||
        if ($type === null || $type === "null") {
 | 
			
		||||
          $nullable = true;
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
        if (!is_string($type)) throw SchemaException::invalid_type($type);
 | 
			
		||||
        if (substr($type, 0, 1) == "?") {
 | 
			
		||||
          $type = substr($type, 1);
 | 
			
		||||
          $nullable = true;
 | 
			
		||||
        }
 | 
			
		||||
        if ($type === "") throw SchemaException::invalid_type($type);
 | 
			
		||||
        $type = cl::get(ref_types::ALIASES, $type, $type);
 | 
			
		||||
        $types = array_merge($types, explode("|", $type));
 | 
			
		||||
      }
 | 
			
		||||
      if (!$types) throw SchemaException::invalid_schema("scalar: type is required");
 | 
			
		||||
      $types = array_keys(array_fill_keys($types, true));
 | 
			
		||||
    }
 | 
			
		||||
    $definition["type"] = $types;
 | 
			
		||||
    $definition["nullable"] = $nullable;
 | 
			
		||||
    # nature
 | 
			
		||||
    $nature = $definition[""];
 | 
			
		||||
    tarray::ensure_array($nature);
 | 
			
		||||
    if (!array_key_exists(0, $nature) || $nature[0] !== "scalar") {
 | 
			
		||||
      throw SchemaException::invalid_schema("expected scalar nature");
 | 
			
		||||
    }
 | 
			
		||||
    $definition[""] = $nature;
 | 
			
		||||
    # name, pkey, header
 | 
			
		||||
    $name = $definition["name"];
 | 
			
		||||
    $pkey = $definition["pkey"];
 | 
			
		||||
    $header = $definition["header"];
 | 
			
		||||
    if ($name === null) $name = $definitionKey;
 | 
			
		||||
    tstring::ensure_nstring($name);
 | 
			
		||||
    tpkey::ensure_npkey($pkey);
 | 
			
		||||
    tstring::ensure_nstring($header);
 | 
			
		||||
    if ($pkey === null) $pkey = $name;
 | 
			
		||||
    if ($header === null) $header = $name;
 | 
			
		||||
    $definition["name"] = $name;
 | 
			
		||||
    $definition["pkey"] = $pkey;
 | 
			
		||||
    $definition["header"] = $header;
 | 
			
		||||
    # autres éléments
 | 
			
		||||
    tstring::ensure_nstring($definition["title"]);
 | 
			
		||||
    tbool::ensure_bool($definition["required"]);
 | 
			
		||||
    tbool::ensure_bool($definition["nullable"]);
 | 
			
		||||
    tcontent::ensure_ncontent($definition["desc"]);
 | 
			
		||||
    tcallable::ensure_ncallable($definition["analyzer_func"]);
 | 
			
		||||
    tcallable::ensure_ncallable($definition["extractor_func"]);
 | 
			
		||||
    tcallable::ensure_ncallable($definition["parser_func"]);
 | 
			
		||||
    tcallable::ensure_ncallable($definition["normalizer_func"]);
 | 
			
		||||
    tarray::ensure_narray($definition["messages"]);
 | 
			
		||||
    tcallable::ensure_ncallable($definition["formatter_func"]);
 | 
			
		||||
    tbool::ensure_nbool($definition["composite"]);
 | 
			
		||||
    return $definition;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function __construct($definition=null, $definitionKey=null, bool $normalize=true) {
 | 
			
		||||
    if ($definition === null) $definition = static::SCHEMA;
 | 
			
		||||
    if ($normalize) {
 | 
			
		||||
      $definition = self::normalize($definition, $definitionKey);
 | 
			
		||||
      $this->_definition = $definition;
 | 
			
		||||
      self::_ensure_type($definition);
 | 
			
		||||
      self::_ensure_schema_instances($definition);
 | 
			
		||||
    }
 | 
			
		||||
    if ($normalize) $definition = self::normalize($definition, $definitionKey);
 | 
			
		||||
    $this->definition = $definition;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isScalar(?ScalarSchema &$schema=null): bool {
 | 
			
		||||
    $schema = $this;
 | 
			
		||||
  function isScalar(?ScalarSchema &$scalar=null): bool {
 | 
			
		||||
    $scalar = $this;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function newWrapper(): ScalarWrapper {
 | 
			
		||||
    return new ScalarWrapper($this);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getWrapper(&$value=null, $valueKey=null, ?Wrapper &$wrapper=null): ScalarWrapper {
 | 
			
		||||
    if (!($wrapper instanceof ScalarWrapper)) $wrapper = $this->newWrapper();
 | 
			
		||||
    return $wrapper->reset($value, $valueKey);
 | 
			
		||||
  function newValue(?Value &$destv=null, &$dest=null, $destKey=null): ScalarValue {
 | 
			
		||||
    if ($destv instanceof ScalarValue) return $destv->reset($dest, $destKey);
 | 
			
		||||
    else return ($destv = new ScalarValue($this, $dest, $destKey));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  #############################################################################
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										198
									
								
								src/schema/_scalar/ScalarValue.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										198
									
								
								src/schema/_scalar/ScalarValue.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,198 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\_scalar;
 | 
			
		||||
 | 
			
		||||
use nur\sery\ref\schema\ref_analyze;
 | 
			
		||||
use nur\sery\ValueException;
 | 
			
		||||
use nur\sery\wip\schema\input\Input;
 | 
			
		||||
use nur\sery\wip\schema\types;
 | 
			
		||||
use nur\sery\wip\schema\types\IType;
 | 
			
		||||
use nur\sery\wip\schema\Value;
 | 
			
		||||
 | 
			
		||||
class ScalarValue extends Value {
 | 
			
		||||
  function __construct(ScalarSchema $schema, &$dest=null, $destKey=null, bool $defaultVerifix=true, ?bool $defaultThrow=null) {
 | 
			
		||||
    if ($dest !== null && $defaultThrow = null) {
 | 
			
		||||
      # Si $dest est null, ne pas lancer d'exception, parce qu'on considère que
 | 
			
		||||
      # c'est une initialisation sans conséquences
 | 
			
		||||
      $defaultThrow = true;
 | 
			
		||||
    }
 | 
			
		||||
    $this->schema = $schema;
 | 
			
		||||
    $this->defaultVerifix = $defaultVerifix;
 | 
			
		||||
    $this->defaultThrow = $defaultThrow !== null? $defaultThrow: false;
 | 
			
		||||
    $this->result = new ScalarResult();
 | 
			
		||||
    $this->reset($dest, $destKey);
 | 
			
		||||
    $this->defaultThrow = $defaultThrow !== null? $defaultThrow: true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isScalar(?ScalarValue &$scalar=null): bool { $scalar = $this; return true; }
 | 
			
		||||
 | 
			
		||||
  /** @var ScalarSchema schéma de cette valeur */
 | 
			
		||||
  protected $schema;
 | 
			
		||||
 | 
			
		||||
  /** @var Input source et destination de la valeur */
 | 
			
		||||
  protected $input;
 | 
			
		||||
 | 
			
		||||
  /** @var string|int|null clé de la valeur dans le tableau destination */
 | 
			
		||||
  protected $destKey;
 | 
			
		||||
 | 
			
		||||
  /** @var bool */
 | 
			
		||||
  protected $defaultVerifix;
 | 
			
		||||
 | 
			
		||||
  /** @var bool */
 | 
			
		||||
  protected $defaultThrow;
 | 
			
		||||
 | 
			
		||||
  /** @var IType type de la valeur après analyse */
 | 
			
		||||
  protected $type;
 | 
			
		||||
 | 
			
		||||
  /** @var ?ScalarResult résultat de l'analyse de la valeur */
 | 
			
		||||
  protected $result;
 | 
			
		||||
 | 
			
		||||
  function reset(&$dest, $destKey=null, ?bool $verifix=null): Value {
 | 
			
		||||
    if ($dest instanceof Input) $input = $dest;
 | 
			
		||||
    else $input = new Input($dest);
 | 
			
		||||
    $this->input = $input;
 | 
			
		||||
    $this->destKey = $destKey;
 | 
			
		||||
    $this->type = null;
 | 
			
		||||
    $this->_analyze();
 | 
			
		||||
    if ($verifix == null) $verifix = $this->defaultVerifix;
 | 
			
		||||
    if ($verifix) $this->verifix();
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getKeys(): array {
 | 
			
		||||
    return [null];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getValue($key=null): ScalarValue {
 | 
			
		||||
    if ($key === null) return $this;
 | 
			
		||||
    throw ValueException::invalid_key($key);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** analyser la valeur et résoudre son type */
 | 
			
		||||
  function _analyze(): int {
 | 
			
		||||
    $schema = $this->schema;
 | 
			
		||||
    $input = $this->input;
 | 
			
		||||
    $destKey = $this->destKey;
 | 
			
		||||
    $result = $this->result;
 | 
			
		||||
    $result->reset();
 | 
			
		||||
    if (!$input->isPresent($destKey)) return $result->setMissing($schema);
 | 
			
		||||
    $haveType = false;
 | 
			
		||||
    $types = [];
 | 
			
		||||
    $type = $firstType = null;
 | 
			
		||||
    $haveValue = false;
 | 
			
		||||
    $value = null;
 | 
			
		||||
    # d'abord chercher un type pour lequel c'est une valeur normalisée
 | 
			
		||||
    foreach ($schema->type as $name) {
 | 
			
		||||
      $type = types::get($name);
 | 
			
		||||
      if ($firstType === null) $firstType = $type;
 | 
			
		||||
      $types[] = $type;
 | 
			
		||||
      if ($type->isAvailable($input, $destKey)) {
 | 
			
		||||
        if (!$haveValue) {
 | 
			
		||||
          $value = $input->get($destKey);
 | 
			
		||||
          $haveValue = true;
 | 
			
		||||
        }
 | 
			
		||||
        if ($type->isValid($value, $normalized) && $normalized) {
 | 
			
		||||
          $haveType = true;
 | 
			
		||||
          $this->type = $type;
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if (!$haveType) {
 | 
			
		||||
      # ensuite chercher un type pour lequel la valeur est valide
 | 
			
		||||
      foreach ($types as $type) {
 | 
			
		||||
        if ($type->isAvailable($input, $destKey) && $type->isValid($value)) {
 | 
			
		||||
          $haveType = true;
 | 
			
		||||
          $this->type = $type;
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    # sinon prendre le premier type
 | 
			
		||||
    if (!$haveType) $type = $this->type = $firstType;
 | 
			
		||||
    if (!$type->isAvailable($input, $destKey)) return $result->setUnavailable($schema);
 | 
			
		||||
    $value = $input->get($destKey);
 | 
			
		||||
    if ($type->isNull($value)) return $result->setNull($schema);
 | 
			
		||||
    if ($type->isValid($value, $normalized)) {
 | 
			
		||||
      if ($normalized) return $result->setNormalized();
 | 
			
		||||
      else return $result->setValid();
 | 
			
		||||
    }
 | 
			
		||||
    if (is_string($value)) return ref_analyze::STRING;
 | 
			
		||||
    else return $result->setInvalid($value, $schema);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function verifix(?bool $throw=null): bool {
 | 
			
		||||
    if ($throw === null) $throw = $this->defaultThrow;
 | 
			
		||||
    $destKey = $this->destKey;
 | 
			
		||||
    $verifix = false;
 | 
			
		||||
    $result =& $this->result;
 | 
			
		||||
    $modified = false;
 | 
			
		||||
    if ($result->resultAvailable) {
 | 
			
		||||
      if ($result->null) {
 | 
			
		||||
        # forcer la valeur null, parce que la valeur actuelle est peut-être une
 | 
			
		||||
        # valeur assimilée à null
 | 
			
		||||
        $this->input->set(null, $destKey);
 | 
			
		||||
      } elseif ($result->valid && !$result->normalized) {
 | 
			
		||||
        # normaliser la valeur
 | 
			
		||||
        $verifix = true;
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      $verifix = true;
 | 
			
		||||
    }
 | 
			
		||||
    if ($verifix) {
 | 
			
		||||
      $value = $this->input->get($destKey);
 | 
			
		||||
      $modified = $this->type->verifix($value, $result, $this->schema);
 | 
			
		||||
      if ($result->valid) $this->input->set($value, $destKey);
 | 
			
		||||
    }
 | 
			
		||||
    if (!$result->valid) $result->throw($throw);
 | 
			
		||||
    return $modified;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getResult(): ScalarResult {
 | 
			
		||||
    return $this->result;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isPresent(): bool {
 | 
			
		||||
    return $this->result->present;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getType(): IType {
 | 
			
		||||
    return $this->type;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isAvailable(): bool {
 | 
			
		||||
    return $this->result->available;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isValid(): bool {
 | 
			
		||||
    return $this->result->valid;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isNormalized(): bool {
 | 
			
		||||
    return $this->result->normalized;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function get($default=null) {
 | 
			
		||||
    if ($this->result->available) return $this->input->get($this->destKey);
 | 
			
		||||
    else return $default;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function set($value, ?bool $verifix=null): ScalarValue {
 | 
			
		||||
    $this->input->set($value, $this->destKey);
 | 
			
		||||
    $this->_analyze();
 | 
			
		||||
    if ($verifix === null) $verifix = $this->defaultVerifix;
 | 
			
		||||
    if ($verifix) $this->verifix();
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function unset(?bool $verifix=null): ScalarValue {
 | 
			
		||||
    $this->input->unset($this->destKey);
 | 
			
		||||
    $this->_analyze();
 | 
			
		||||
    if ($verifix === null) $verifix = $this->defaultVerifix;
 | 
			
		||||
    if ($verifix) $this->verifix();
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function format($format=null): string {
 | 
			
		||||
    return $this->type->format($this->input->get($this->destKey), $format);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,317 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\_scalar;
 | 
			
		||||
 | 
			
		||||
use nulib\php\func;
 | 
			
		||||
use nulib\ref\schema\ref_analyze;
 | 
			
		||||
use nulib\ValueException;
 | 
			
		||||
use nur\sery\wip\schema\AnalyzerContext;
 | 
			
		||||
use nur\sery\wip\schema\input\Input;
 | 
			
		||||
use nur\sery\wip\schema\types;
 | 
			
		||||
use nur\sery\wip\schema\types\IType;
 | 
			
		||||
use nur\sery\wip\schema\Wrapper;
 | 
			
		||||
 | 
			
		||||
class ScalarWrapper extends Wrapper {
 | 
			
		||||
  function __construct(ScalarSchema $schema, &$value=null, $valueKey=null, ?array $params=null) {
 | 
			
		||||
    $verifix = $params["verifix"] ?? true;
 | 
			
		||||
    $throw = $params["throw"] ?? null;
 | 
			
		||||
    if ($value !== null && $throw === null) {
 | 
			
		||||
      # Si $value est null, ne pas lancer d'exception, parce qu'on considère que
 | 
			
		||||
      # c'est une initialisation sans conséquences
 | 
			
		||||
      $throw = true;
 | 
			
		||||
    }
 | 
			
		||||
    $this->verifix = $verifix;
 | 
			
		||||
    $this->throw = $throw ?? false;
 | 
			
		||||
    $this->schema = $schema;
 | 
			
		||||
    $this->result = new ScalarResult();
 | 
			
		||||
    $this->reset($value, $valueKey);
 | 
			
		||||
    $this->throw = $throw ?? true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isScalar(?ScalarWrapper &$wrapper=null): bool { $wrapper = $this; return true; }
 | 
			
		||||
 | 
			
		||||
  protected bool $verifix;
 | 
			
		||||
 | 
			
		||||
  protected bool $throw;
 | 
			
		||||
 | 
			
		||||
  /** schéma de cette valeur */
 | 
			
		||||
  protected ScalarSchema $schema;
 | 
			
		||||
 | 
			
		||||
  /** source et destination de la valeur */
 | 
			
		||||
  protected Input $input;
 | 
			
		||||
 | 
			
		||||
  /** @var string|int|null clé de la valeur dans le tableau destination */
 | 
			
		||||
  protected $valueKey;
 | 
			
		||||
 | 
			
		||||
  /** type de la valeur après analyse */
 | 
			
		||||
  protected ?IType $type;
 | 
			
		||||
 | 
			
		||||
  /** résultat de l'analyse de la valeur */
 | 
			
		||||
  protected ScalarResult $result;
 | 
			
		||||
 | 
			
		||||
  protected function newInput(&$value): Input {
 | 
			
		||||
    return new Input($value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function reset(&$value, $valueKey=null, ?bool $verifix=null): Wrapper {
 | 
			
		||||
    if ($value instanceof Input) $input = $value;
 | 
			
		||||
    else $input = $this->newInput($value);
 | 
			
		||||
    $this->input = $input;
 | 
			
		||||
    $this->valueKey = $valueKey;
 | 
			
		||||
    $this->type = null;
 | 
			
		||||
    $this->analyze();
 | 
			
		||||
    if ($verifix ?? $this->verifix) $this->verifix();
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getKeys(): array {
 | 
			
		||||
    return [null];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** @param string|int|null $key */
 | 
			
		||||
  function select($key): ScalarWrapper {
 | 
			
		||||
    if ($key !== null) throw ValueException::invalid_key($key);
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** analyser la valeur et résoudre son type */
 | 
			
		||||
  protected function analyze0(AnalyzerContext $context): int {
 | 
			
		||||
    /** @var ScalarSchema $schema */
 | 
			
		||||
    $schema = $context->schema;
 | 
			
		||||
    $input = $context->input;
 | 
			
		||||
    $valueKey = $context->valueKey;
 | 
			
		||||
    /** @var ScalarResult $result */
 | 
			
		||||
    $result = $context->result;
 | 
			
		||||
 | 
			
		||||
    $default = $schema->default;
 | 
			
		||||
    if (!$input->isPresent($valueKey)) {
 | 
			
		||||
      if ($default !== null) {
 | 
			
		||||
        $input->set($default, $valueKey);
 | 
			
		||||
        return $result->setNormalized();
 | 
			
		||||
      } else {
 | 
			
		||||
        return $result->setMissing($schema);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $schemaTypes = $schema->type;
 | 
			
		||||
    if ($schemaTypes instanceof IType) {
 | 
			
		||||
      $type = $schemaTypes;
 | 
			
		||||
    } else {
 | 
			
		||||
      # type union
 | 
			
		||||
      $haveType = false;
 | 
			
		||||
      $types = [];
 | 
			
		||||
      $type = $firstType = null;
 | 
			
		||||
      $value = null;
 | 
			
		||||
      # d'abord chercher un type pour lequel c'est une valeur normalisée
 | 
			
		||||
      $index = 0;
 | 
			
		||||
      $haveValue = false;
 | 
			
		||||
      foreach ($schemaTypes as $key => $name) {
 | 
			
		||||
        if ($key === $index) {
 | 
			
		||||
          $index++;
 | 
			
		||||
          $args = null;
 | 
			
		||||
        } else {
 | 
			
		||||
          $args = $name;
 | 
			
		||||
          $name = $key;
 | 
			
		||||
        }
 | 
			
		||||
        $type = types::get($schema->nullable, $name, $args, $this->schema->getDefinition());
 | 
			
		||||
        if ($firstType === null) $firstType = $type;
 | 
			
		||||
        $types[] = $type;
 | 
			
		||||
        if ($type->isAvailable($input, $valueKey)) {
 | 
			
		||||
          if (!$haveValue) {
 | 
			
		||||
            $value = $input->get($valueKey);
 | 
			
		||||
            $haveValue = true;
 | 
			
		||||
          }
 | 
			
		||||
          if ($type->isValid($value, $normalized) && $normalized) {
 | 
			
		||||
            $haveType = true;
 | 
			
		||||
            break;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      # ensuite chercher un type pour lequel la valeur est valide
 | 
			
		||||
      if (!$haveType) {
 | 
			
		||||
        foreach ($types as $type) {
 | 
			
		||||
          if ($type->isAvailable($input, $valueKey) && $type->isValid($value)) {
 | 
			
		||||
            $haveType = true;
 | 
			
		||||
            break;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      # sinon prendre le premier type
 | 
			
		||||
      if (!$haveType) {
 | 
			
		||||
        $type = $firstType;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    $context->type = $this->type = $type;
 | 
			
		||||
 | 
			
		||||
    if (!$type->isAvailable($input, $valueKey)) {
 | 
			
		||||
      if ($default !== null) {
 | 
			
		||||
        $input->set($default, $valueKey);
 | 
			
		||||
        return $result->setNormalized();
 | 
			
		||||
      } else {
 | 
			
		||||
        return $result->setUnavailable($schema);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $value = $input->get($valueKey);
 | 
			
		||||
    $context->origValue = $context->value = $value;
 | 
			
		||||
    if ($type->isNull($value)) {
 | 
			
		||||
      return $result->setNull($schema);
 | 
			
		||||
    } elseif (is_string($value)) {
 | 
			
		||||
      return ref_analyze::STRING;
 | 
			
		||||
    } elseif ($type->isValid($value, $normalized)) {
 | 
			
		||||
      if ($normalized) return $result->setNormalized();
 | 
			
		||||
      else return $result->setValid();
 | 
			
		||||
    } else {
 | 
			
		||||
      return $result->setInvalid($value, $schema);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function analyze(): int {
 | 
			
		||||
    $schema = $this->schema;
 | 
			
		||||
    $input = $this->input;
 | 
			
		||||
    $valueKey = $this->valueKey;
 | 
			
		||||
    $result = $this->result;
 | 
			
		||||
    $result->reset();
 | 
			
		||||
    $context = new AnalyzerContext($schema, $this, $input, $valueKey, $result);
 | 
			
		||||
 | 
			
		||||
    /** @var func $analyzerFunc */
 | 
			
		||||
    $analyzerFunc = $schema->analyzerFunc;
 | 
			
		||||
    if ($analyzerFunc !== null) $what = $analyzerFunc->invoke([$context]);
 | 
			
		||||
    else $what = $this->analyze0($context);
 | 
			
		||||
    if ($what !== ref_analyze::STRING) return $what;
 | 
			
		||||
 | 
			
		||||
    $value = $context->value;
 | 
			
		||||
    try {
 | 
			
		||||
      /** @var func $extractorFunc */
 | 
			
		||||
      $extractorFunc = $schema->extractorFunc;
 | 
			
		||||
      if ($extractorFunc !== null) $extracted = $extractorFunc->invoke([$value, $context]);
 | 
			
		||||
      else $extracted = $context->type->extract($value);
 | 
			
		||||
      $context->value = $extracted;
 | 
			
		||||
    } catch (ValueException $e) {
 | 
			
		||||
      return $result->setInvalid($context->origValue, $schema, $e);
 | 
			
		||||
    }
 | 
			
		||||
    if ($context->type->isNull($extracted)) return $result->setNull($schema);
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      /** @var func $parserFunc */
 | 
			
		||||
      $parserFunc = $schema->parserFunc;
 | 
			
		||||
      if ($parserFunc !== null) $parsed = $parserFunc->invoke([$extracted, $context]);
 | 
			
		||||
      else $parsed = $context->type->parse($extracted);
 | 
			
		||||
      $context->value = $parsed;
 | 
			
		||||
    } catch (ValueException $e) {
 | 
			
		||||
      return $result->setInvalid($context->origValue, $schema, $e);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $normalized = $parsed === $context->origValue;
 | 
			
		||||
    if ($normalized) {
 | 
			
		||||
      $input->set($parsed, $valueKey);
 | 
			
		||||
      return $result->setNormalized();
 | 
			
		||||
    } else {
 | 
			
		||||
      $input->set($extracted, $valueKey);
 | 
			
		||||
      return $result->setValid($parsed);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function verifix(?bool $throw=null): bool {
 | 
			
		||||
    $result = $this->result;
 | 
			
		||||
    $valueKey = $this->valueKey;
 | 
			
		||||
    $verifix = false;
 | 
			
		||||
    $modified = false;
 | 
			
		||||
    if ($result->resultAvailable) {
 | 
			
		||||
      if ($result->null) {
 | 
			
		||||
        # forcer la valeur null, parce que la valeur actuelle est peut-être une
 | 
			
		||||
        # valeur assimilée à null
 | 
			
		||||
        $this->input->set(null, $valueKey);
 | 
			
		||||
      } elseif ($result->valid && !$result->normalized) {
 | 
			
		||||
        $normalizedValue = $result->normalizedValue;
 | 
			
		||||
        if ($normalizedValue !== null) {
 | 
			
		||||
          # la valeur normalisée est disponible
 | 
			
		||||
          $this->input->set($normalizedValue);
 | 
			
		||||
          $result->normalizedValue = null;
 | 
			
		||||
          $modified = true;
 | 
			
		||||
        } else {
 | 
			
		||||
          # normaliser la valeur
 | 
			
		||||
          $verifix = true;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      $verifix = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ($verifix) {
 | 
			
		||||
      $value = $this->input->get($valueKey);
 | 
			
		||||
      $schema = $this->schema;
 | 
			
		||||
      /** @var func $normalizerFunc */
 | 
			
		||||
      $normalizerFunc = $schema->normalizerFunc;
 | 
			
		||||
      if ($normalizerFunc !== null) {
 | 
			
		||||
        $context = new AnalyzerContext($schema, $this, $this->input, $valueKey, $result);
 | 
			
		||||
        $orig = $value;
 | 
			
		||||
        $value = $normalizerFunc->invoke([$orig, $context]);
 | 
			
		||||
        $modified = $value !== $orig;
 | 
			
		||||
      } else {
 | 
			
		||||
        $modified = $this->type->verifix($value, $result, $this->schema);
 | 
			
		||||
      }
 | 
			
		||||
      if ($result->valid) $this->input->set($value, $valueKey);
 | 
			
		||||
    }
 | 
			
		||||
    if (!$result->valid) $result->throw($throw ?? $this->throw);
 | 
			
		||||
    return $modified;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getResult(): ScalarResult {
 | 
			
		||||
    return $this->result;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isPresent(): bool {
 | 
			
		||||
    return $this->result->present;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getType(): IType {
 | 
			
		||||
    return $this->type;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isAvailable(): bool {
 | 
			
		||||
    return $this->result->available;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isValid(): bool {
 | 
			
		||||
    return $this->result->valid;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isNormalized(): bool {
 | 
			
		||||
    return $this->result->normalized;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function get($default=null) {
 | 
			
		||||
    if ($this->result->available) return $this->input->get($this->valueKey);
 | 
			
		||||
    else return $default;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function set($value, ?bool $verifix=null): ScalarWrapper {
 | 
			
		||||
    $this->input->set($value, $this->valueKey);
 | 
			
		||||
    $this->analyze();
 | 
			
		||||
    if ($verifix ?? $this->verifix) $this->verifix();
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function unset(?bool $verifix=null): ScalarWrapper {
 | 
			
		||||
    $this->input->unset($this->valueKey);
 | 
			
		||||
    $this->analyze();
 | 
			
		||||
    if ($verifix ?? $this->verifix) $this->verifix();
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function format($format=null): string {
 | 
			
		||||
    $value = $this->input->get($this->valueKey);
 | 
			
		||||
    /** @var func $formatterFunc */
 | 
			
		||||
    $formatterFunc = $this->schema->formatterFunc;
 | 
			
		||||
    if ($formatterFunc !== null) {
 | 
			
		||||
      # la fonction formatter n'a pas forcément accès au format de la définition
 | 
			
		||||
      # le lui fournir ici
 | 
			
		||||
      $format ??= $this->schema->format;
 | 
			
		||||
      return $formatterFunc->invoke([$value, $format]);
 | 
			
		||||
    } else {
 | 
			
		||||
      # on assume que le type a été initialisé avec le format de la définition
 | 
			
		||||
      # le cas échéant
 | 
			
		||||
      return $this->type->format($value, $format);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -25,7 +25,7 @@ class FormInput extends Input {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function access($key): IAccess {
 | 
			
		||||
    return $this->keyAccess[$key] ??= new ShadowAccess($this->formAccess($key), new KeyAccess($this->value, $key, [
 | 
			
		||||
    return $this->keyAccess[$key] ??= new ShadowAccess($this->formAccess($key), new KeyAccess($this->dest, $key, [
 | 
			
		||||
      "allow_empty" => $this->allowEmpty,
 | 
			
		||||
    ]));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -13,13 +13,13 @@ use nur\sery\wip\php\access\ValueAccess;
 | 
			
		||||
class Input {
 | 
			
		||||
  const ALLOW_EMPTY = true;
 | 
			
		||||
 | 
			
		||||
  function __construct(&$value=null, ?array $params=null) {
 | 
			
		||||
    $this->value =& $value;
 | 
			
		||||
  function __construct(&$dest=null, ?array $params=null) {
 | 
			
		||||
    $this->dest =& $dest;
 | 
			
		||||
    $this->allowEmpty = $params["allow_empty"] ?? static::ALLOW_EMPTY;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** @var mixed */
 | 
			
		||||
  protected $value;
 | 
			
		||||
  protected $dest;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @var bool comment considérer une chaine vide: "" si allowEmpty, null sinon
 | 
			
		||||
@ -31,12 +31,12 @@ class Input {
 | 
			
		||||
 | 
			
		||||
  protected function access($key): IAccess {
 | 
			
		||||
    if ($key === null) {
 | 
			
		||||
      return $this->valueAccess ??= new ValueAccess($this->value, [
 | 
			
		||||
      return $this->valueAccess ??= new ValueAccess($this->dest, [
 | 
			
		||||
        "allow_null" => true,
 | 
			
		||||
        "allow_empty" => $this->allowEmpty,
 | 
			
		||||
      ]);
 | 
			
		||||
    } else {
 | 
			
		||||
      return $this->keyAccess[$key] ??= new KeyAccess($this->value, $key, [
 | 
			
		||||
      return $this->keyAccess[$key] ??= new KeyAccess($this->dest, $key, [
 | 
			
		||||
        "allow_empty" => $this->allowEmpty,
 | 
			
		||||
      ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -6,16 +6,9 @@ use nur\sery\wip\schema\types\Registry;
 | 
			
		||||
use nur\sery\wip\schema\types\tarray;
 | 
			
		||||
use nur\sery\wip\schema\types\tbool;
 | 
			
		||||
use nur\sery\wip\schema\types\tcallable;
 | 
			
		||||
use nur\sery\wip\schema\types\tcontent;
 | 
			
		||||
use nur\sery\wip\schema\types\tfloat;
 | 
			
		||||
use nur\sery\wip\schema\types\tint;
 | 
			
		||||
use nur\sery\wip\schema\types\tkey;
 | 
			
		||||
use nur\sery\wip\schema\types\tmixed;
 | 
			
		||||
use nur\sery\wip\schema\types\tpkey;
 | 
			
		||||
use nur\sery\wip\schema\types\traw;
 | 
			
		||||
use nur\sery\wip\schema\types\trawstring;
 | 
			
		||||
use nur\sery\wip\schema\types\tstring;
 | 
			
		||||
use nur\sery\wip\schema\types\ttext;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class types: classe outil pour gérer le registre de types
 | 
			
		||||
@ -31,21 +24,14 @@ class types {
 | 
			
		||||
    return self::$registry;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static function get(bool $nullable, ?string $name, ?array $args=null, ?array $definition=null): IType {
 | 
			
		||||
    return self::registry()->get($nullable, $name, $args, $definition);
 | 
			
		||||
  static function get(string $name): IType {
 | 
			
		||||
    return self::registry()->get($name);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static function rawstring(bool $nullable=true): trawstring { return self::get($nullable, "rawstring"); }
 | 
			
		||||
  static function string(bool $nullable=true): tstring { return self::get($nullable, "string"); }
 | 
			
		||||
  static function text(bool $nullable=true): ttext { return self::get($nullable, "text"); }
 | 
			
		||||
  static function bool(bool $nullable=true): tbool { return self::get($nullable, "bool"); }
 | 
			
		||||
  static function int(bool $nullable=true): tint { return self::get($nullable, "int"); }
 | 
			
		||||
  static function float(bool $nullable=true): tfloat { return self::get($nullable, "float"); }
 | 
			
		||||
  static function array(bool $nullable=true): tarray { return self::get($nullable, "array"); }
 | 
			
		||||
  static function callable(bool $nullable=true): tcallable { return self::get($nullable, "callable"); }
 | 
			
		||||
  static function raw(bool $nullable=true): traw { return self::get($nullable, "raw"); }
 | 
			
		||||
  static function mixed(bool $nullable=true): tmixed { return self::get($nullable, "mixed"); }
 | 
			
		||||
  static function key(bool $nullable=true): tkey { return self::get($nullable, "key"); }
 | 
			
		||||
  static function pkey(bool $nullable=true): tpkey { return self::get($nullable, "pkey"); }
 | 
			
		||||
  static function content(bool $nullable=true): tcontent { return self::get($nullable, "content"); }
 | 
			
		||||
  static function string(): tstring { return self::get("string"); }
 | 
			
		||||
  static function bool(): tbool { return self::get("bool"); }
 | 
			
		||||
  static function int(): tint { return self::get("int"); }
 | 
			
		||||
  static function float(): tfloat { return self::get("float"); }
 | 
			
		||||
  static function array(): tarray { return self::get("array"); }
 | 
			
		||||
  static function callable(): tcallable { return self::get("callable"); }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,6 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\types;
 | 
			
		||||
 | 
			
		||||
use nulib\ValueException;
 | 
			
		||||
use nur\sery\wip\schema\input\Input;
 | 
			
		||||
use nur\sery\wip\schema\Result;
 | 
			
		||||
use nur\sery\wip\schema\Schema;
 | 
			
		||||
@ -10,130 +9,25 @@ use nur\sery\wip\schema\Schema;
 | 
			
		||||
 * Interface IType: un type de données
 | 
			
		||||
 */
 | 
			
		||||
interface IType {
 | 
			
		||||
  /**
 | 
			
		||||
   * obtenir, pour information, le nom officiel de ce type, utilisable dans une
 | 
			
		||||
   * définition de schéma
 | 
			
		||||
   */
 | 
			
		||||
  function getName(): string;
 | 
			
		||||
 | 
			
		||||
  /** obtenir la liste des aliases valides pour ce type */
 | 
			
		||||
  function getAliases(): array;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return string la classe des objets gérés par ce format: le type attendu
 | 
			
		||||
   * par {@link format()} et le type retourné par {@link verifix()}
 | 
			
		||||
   *
 | 
			
		||||
   * Les valeurs "mixed", "bool", "float", "int", "string" et "array" peuvent
 | 
			
		||||
   * aussi être retournées, bien qu'elles ne soient pas à proprement parler des
 | 
			
		||||
   * classes.
 | 
			
		||||
   *
 | 
			
		||||
   * La valeur "mixed" signifie qu'il peut s'agir de n'importe quelle classe
 | 
			
		||||
   * et/ou que la valeur ne peut pas être déterminée à l'avance.
 | 
			
		||||
   */
 | 
			
		||||
  function getClass(): string;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * comme {@link getClass()} mais peut être utilisé directement comme type dans
 | 
			
		||||
   * une déclaration PHP. notamment, si le type est nullable et que
 | 
			
		||||
   * $allowNullable==true, il y a "?" devant le nom.
 | 
			
		||||
   *
 | 
			
		||||
   * Par exemple:
 | 
			
		||||
   * - pour un type chaine nullable, {@link getClass()} retournerait "string"
 | 
			
		||||
   * alors que cette méthode retournerait "?string".
 | 
			
		||||
   * - pour un type mixed, {@link getClass()} retournerait "mixed" alors que
 | 
			
		||||
   * cette méthode retournerait null
 | 
			
		||||
   */
 | 
			
		||||
  function getPhpType(bool $allowNullable=true): ?string;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * indiquer si c'est le type d'une valeur qui ne peut prendre que 2 états: une
 | 
			
		||||
   * "vraie" et une "fausse"
 | 
			
		||||
   */
 | 
			
		||||
  function is2States(): bool;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Si {@link is2States()} est vrai, retourner les deux valeurs [faux, vrai]
 | 
			
		||||
   */
 | 
			
		||||
  function get2States(): array;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * indiquer si c'est le type d'une valeur qui ne peut prendre que 3 états: une
 | 
			
		||||
   * "vraie", une "fausse", et une "indéterminée"
 | 
			
		||||
   */
 | 
			
		||||
  function is3States(): bool;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Si {@link is3States()} est vrai, retourner les 3 valeurs [faux, vrai, undef]
 | 
			
		||||
   */
 | 
			
		||||
  function get3States(): array;
 | 
			
		||||
 | 
			
		||||
  /** la donnée $input($valueKey) est-elle disponible? */
 | 
			
		||||
  function isAvailable(Input $input, $valueKey): bool;
 | 
			
		||||
  /** la donnée $input($destKey) est-elle disponible? */
 | 
			
		||||
  function isAvailable(Input $input, $destKey): bool;
 | 
			
		||||
 | 
			
		||||
  /** la valeur $value est-elle nulle? */
 | 
			
		||||
  function isNull($value): bool;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * la valeur $value est-elle valide et normalisée le cas échéant?
 | 
			
		||||
   *
 | 
			
		||||
   * NB: si $value est un string. elle doit avoir déjà été traitée au préalable
 | 
			
		||||
   * par extract() et parse()
 | 
			
		||||
   */
 | 
			
		||||
  /** la valeur $value est-elle valide et normalisée le cas échéant? */
 | 
			
		||||
  function isValid($value, ?bool &$normalized=null): bool;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * extraire de la chaine la valeur à analyser
 | 
			
		||||
   *
 | 
			
		||||
   * @throws ValueException en cas d'erreur d'analyse
 | 
			
		||||
   */
 | 
			
		||||
  function extract(string $value): string;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * analyser la chaine et retourner la valeur "convertie"
 | 
			
		||||
   *
 | 
			
		||||
   * @throws ValueException en cas d'erreur d'analyse
 | 
			
		||||
   */
 | 
			
		||||
  function parse(string $value);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * analyser, corriger éventuellement et normaliser la valeur
 | 
			
		||||
   *
 | 
			
		||||
   * NB: si $value est un string. elle doit avoir déjà été traitée au préalable
 | 
			
		||||
   * par extract() et parse()
 | 
			
		||||
   *
 | 
			
		||||
   * si la valeur était déjà normalisée, ou si une erreur s'est produite,
 | 
			
		||||
   * retourner false.
 | 
			
		||||
   */
 | 
			
		||||
  function verifix(&$value, Result $result, Schema $schema): bool;
 | 
			
		||||
  function verifix(&$value, Result &$result, Schema $schema): bool;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * formatter la valeur pour affichage. si $value n'est pas null, elle est
 | 
			
		||||
   * garantie d'être du bon type
 | 
			
		||||
   * formatter la valeur pour affichage. $value est garanti d'être du bon type
 | 
			
		||||
   */
 | 
			
		||||
  function format($value, $format=null): string;
 | 
			
		||||
 | 
			
		||||
  #############################################################################
 | 
			
		||||
 | 
			
		||||
  /** @return string le nom d'un getter pour une valeur de ce type */
 | 
			
		||||
  function getGetterName(string $name): string;
 | 
			
		||||
 | 
			
		||||
  /** @return string le nom d'un setter pour une valeur de ce type */
 | 
			
		||||
  function getSetterName(string $name): string;
 | 
			
		||||
 | 
			
		||||
  /** @return string le nom d'un deleter pour une valeur de ce type */
 | 
			
		||||
  function getDeleterName(string $name): string;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return string le nom d'une constante de classe pour une valeur de ce type
 | 
			
		||||
   */
 | 
			
		||||
  function getClassConstName(string $name): string;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return string le nom d'une propriété d'une classe pour une valeur de ce
 | 
			
		||||
   * type
 | 
			
		||||
   */
 | 
			
		||||
  function getObjectPropertyName(string $name): string;
 | 
			
		||||
 | 
			
		||||
  /** @return string le nom d'une clé d'un tableau pour une valeur de ce type */
 | 
			
		||||
  function getArrayKeyName(string $name): string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,14 +1,11 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\types;
 | 
			
		||||
 | 
			
		||||
use nulib\cl;
 | 
			
		||||
use nulib\php\func;
 | 
			
		||||
use nur\sery\cl;
 | 
			
		||||
 | 
			
		||||
class Registry {
 | 
			
		||||
  const TYPES = [
 | 
			
		||||
    "rawstring" => trawstring::class,
 | 
			
		||||
    "string" => tstring::class,
 | 
			
		||||
    "text" => ttext::class,
 | 
			
		||||
    "bool" => tbool::class, "boolean" => tbool::class,
 | 
			
		||||
    "int" => tint::class, "integer" => tint::class,
 | 
			
		||||
    "float" => tfloat::class, "flt" => tfloat::class,
 | 
			
		||||
@ -16,8 +13,6 @@ class Registry {
 | 
			
		||||
    "array" => tarray::class,
 | 
			
		||||
    "callable" => tcallable::class,
 | 
			
		||||
    # types spéciaux
 | 
			
		||||
    "raw" => tmixed::class,
 | 
			
		||||
    "mixed" => tmixed::class,
 | 
			
		||||
    "key" => tkey::class,
 | 
			
		||||
    "pkey" => tpkey::class,
 | 
			
		||||
    "content" => tcontent::class,
 | 
			
		||||
@ -30,25 +25,12 @@ class Registry {
 | 
			
		||||
  /** @var IType[] */
 | 
			
		||||
  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];
 | 
			
		||||
      unset($args[$key]);
 | 
			
		||||
    } else {
 | 
			
		||||
      $params = $args;
 | 
			
		||||
      $args = null;
 | 
			
		||||
    }
 | 
			
		||||
    $params = cl::merge($class::get_params_from_definition($definition), $params);
 | 
			
		||||
    if ($args || $params !== null) {
 | 
			
		||||
      $args ??= [];
 | 
			
		||||
      return func::with([$class, false, ...$args, $nullable, $params])->invoke();
 | 
			
		||||
    }
 | 
			
		||||
    if ($nullable) $name = "?$name";
 | 
			
		||||
  function get(string $name): IType {
 | 
			
		||||
    $type = cl::get($this->types, $name);
 | 
			
		||||
    if ($type === null) $type = $this->types[$name] = new $class($nullable);
 | 
			
		||||
    if ($type === null) {
 | 
			
		||||
      $class = self::TYPES[$name];
 | 
			
		||||
      $type = $this->types[$name] = new $class();
 | 
			
		||||
    }
 | 
			
		||||
    return $type;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,19 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\types;
 | 
			
		||||
 | 
			
		||||
abstract class _tformatable extends _tsimple {
 | 
			
		||||
  const FORMAT = null;
 | 
			
		||||
 | 
			
		||||
  static function get_params_from_definition(?array $definition): ?array {
 | 
			
		||||
    $params = null;
 | 
			
		||||
    $format = $definition["format"] ?? null;
 | 
			
		||||
    if ($format !== null) $params["format"] = $format;
 | 
			
		||||
    return $params;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function format($value, $format=null): string {
 | 
			
		||||
    $format ??= $this->params["format"] ?? static::FORMAT;
 | 
			
		||||
    if ($format !== null) return sprintf($format, $value);
 | 
			
		||||
    else return strval($value);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,99 +1,14 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\types;
 | 
			
		||||
 | 
			
		||||
use nulib\StateException;
 | 
			
		||||
use nur\prop;
 | 
			
		||||
use nur\sery\wip\schema\input\Input;
 | 
			
		||||
use nur\str;
 | 
			
		||||
 | 
			
		||||
abstract class _tsimple implements IType {
 | 
			
		||||
  const NAME = null;
 | 
			
		||||
 | 
			
		||||
  const ALIASES = [];
 | 
			
		||||
 | 
			
		||||
  static function get_params_from_definition(?array $definition): ?array {
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * $nullable et $params doivent toujours être les derniers arguments du
 | 
			
		||||
   * constructeur
 | 
			
		||||
   */
 | 
			
		||||
  function __construct(bool $nullable, ?array $params=null) {
 | 
			
		||||
    $this->nullable = $nullable;
 | 
			
		||||
    $this->params = $params;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected bool $nullable;
 | 
			
		||||
 | 
			
		||||
  protected ?array $params;
 | 
			
		||||
 | 
			
		||||
  function getName(): string {
 | 
			
		||||
    return static::NAME;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getAliases(): array {
 | 
			
		||||
    return static::ALIASES;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getPhpType(bool $allowNullable=true): ?string {
 | 
			
		||||
    $phpType = $this->getClass();
 | 
			
		||||
    if ($phpType === "mixed") return null;
 | 
			
		||||
    if ($this->nullable && $allowNullable) $phpType = "?$phpType";
 | 
			
		||||
    return $phpType;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function is2States(): bool {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function get2States(): array {
 | 
			
		||||
    throw StateException::not_implemented();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function is3States(): bool {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function get3States(): array {
 | 
			
		||||
    throw StateException::not_implemented();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isAvailable(Input $input, $valueKey): bool {
 | 
			
		||||
    return $input->isAvailable($valueKey) && $input->get($valueKey) !== false;
 | 
			
		||||
  function isAvailable(Input $input, $destKey): bool {
 | 
			
		||||
    return $input->isAvailable($destKey) && $input->get($destKey) !== false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isNull($value): bool {
 | 
			
		||||
    return $value === null || $value === "";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function extract(string $value): string {
 | 
			
		||||
    return $value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  #############################################################################
 | 
			
		||||
 | 
			
		||||
  function getGetterName(string $name): string {
 | 
			
		||||
    return prop::get_getter_name($name);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getSetterName(string $name): string {
 | 
			
		||||
    return prop::get_setter_name($name);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getDeleterName(string $name): string {
 | 
			
		||||
    return prop::get_deletter_name($name);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getClassConstName(string $name): string {
 | 
			
		||||
    return strtoupper($name);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getObjectPropertyName(string $name): string {
 | 
			
		||||
    return str::us2camel($name);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getArrayKeyName(string $name): string {
 | 
			
		||||
    return $name;
 | 
			
		||||
    return $value === null || (is_string($value) && trim($value) === "");
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,26 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\types;
 | 
			
		||||
 | 
			
		||||
use nulib\str;
 | 
			
		||||
 | 
			
		||||
abstract class _tstring extends _tsimple {
 | 
			
		||||
  /** @var bool faut-il trimmer la valeur */
 | 
			
		||||
  const TRIM = false;
 | 
			
		||||
  /** @var bool faut-il normaliser les caractères fin de ligne */
 | 
			
		||||
  const NORM_NL = false;
 | 
			
		||||
 | 
			
		||||
  static function get_params_from_definition(?array $definition): ?array {
 | 
			
		||||
    $params = null;
 | 
			
		||||
    $trim = $definition["trim"] ?? null;
 | 
			
		||||
    if ($trim !== null) $params["trim"] = $trim;
 | 
			
		||||
    $normNl = $definition["norm_nl"] ?? null;
 | 
			
		||||
    if ($normNl !== null) $params["norm_nl"] = $normNl;
 | 
			
		||||
    return $params;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function extract(string $value): string {
 | 
			
		||||
    if ($this->params["trim"] ?? static::TRIM) $value = trim($value);
 | 
			
		||||
    if ($this->params["norm_nl"] ?? static::NORM_NL) $value = str::norm_nl($value);
 | 
			
		||||
    return $value;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,10 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\types;
 | 
			
		||||
 | 
			
		||||
abstract class _tunion extends _tsimple {
 | 
			
		||||
  function getPhpType(bool $allowNullable=true): ?string {
 | 
			
		||||
    # assumer mixed pour le moment
 | 
			
		||||
    #XXX à terme, lister les types de l'union
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,28 +1,11 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\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\cl;
 | 
			
		||||
use nur\sery\wip\schema\Result;
 | 
			
		||||
use nur\sery\wip\schema\Schema;
 | 
			
		||||
 | 
			
		||||
class tarray extends _tstring {
 | 
			
		||||
  const NAME = "array";
 | 
			
		||||
 | 
			
		||||
  const SPLIT_PATTERN = '/\s+/';
 | 
			
		||||
  const FORMAT = " ";
 | 
			
		||||
 | 
			
		||||
  public static function get_params_from_definition(?array $definition): ?array {
 | 
			
		||||
    $params = parent::get_params_from_definition($definition);
 | 
			
		||||
    $splitPattern = $definition["split_pattern"] ?? null;
 | 
			
		||||
    if ($splitPattern !== null) $params["split_pattern"] = $splitPattern;
 | 
			
		||||
    $format = $definition["format"] ?? null;
 | 
			
		||||
    if ($format !== null) $params["format"] = $format;
 | 
			
		||||
    return $params;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
class tarray extends _tsimple {
 | 
			
		||||
  static function ensure_array(&$array): void {
 | 
			
		||||
    if (!is_array($array)) $array = cl::with($array);
 | 
			
		||||
  }
 | 
			
		||||
@ -31,47 +14,14 @@ class tarray extends _tstring {
 | 
			
		||||
    if ($array !== null) self::ensure_array($array);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getClass(): string {
 | 
			
		||||
    return "array";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isValid($value, ?bool &$normalized=null): bool {
 | 
			
		||||
    $normalized = is_array($value);
 | 
			
		||||
    return is_scalar($value) || is_array($value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function parse(string $value) {
 | 
			
		||||
    $pattern = $this->params["split_pattern"] ?? static::SPLIT_PATTERN;
 | 
			
		||||
    return preg_split($pattern, $value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @var ScalarResult $result
 | 
			
		||||
   * @var ScalarSchema $schema
 | 
			
		||||
   */
 | 
			
		||||
  function verifix(&$value, Result $result, Schema $schema): bool {
 | 
			
		||||
    if (is_array($value)) {
 | 
			
		||||
      $result->setNormalized();
 | 
			
		||||
      return false;
 | 
			
		||||
    } elseif (is_string($value)) {
 | 
			
		||||
      try {
 | 
			
		||||
        $value = $this->parse($value);
 | 
			
		||||
        $result->setValid();
 | 
			
		||||
        return true;
 | 
			
		||||
      } catch (ValueException $e) {
 | 
			
		||||
      }
 | 
			
		||||
    } elseif (is_scalar($value)) {
 | 
			
		||||
      $value = cl::with($value);
 | 
			
		||||
      $result->setValid();
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    $result->setInvalid($value, $schema);
 | 
			
		||||
    return false;
 | 
			
		||||
  function verifix(&$value, Result &$result, Schema $schema): bool {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function format($value, $format=null): string {
 | 
			
		||||
    if ($value === null) return "";
 | 
			
		||||
    $format ??= $this->params["format"] ?? static::FORMAT;
 | 
			
		||||
    return implode($format, $value);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,28 +1,25 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\types;
 | 
			
		||||
 | 
			
		||||
use nulib\cl;
 | 
			
		||||
use nulib\ValueException;
 | 
			
		||||
use nur\prop;
 | 
			
		||||
use nur\sery\cl;
 | 
			
		||||
use nur\sery\ValueException;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarResult;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarSchema;
 | 
			
		||||
use nur\sery\wip\schema\input\Input;
 | 
			
		||||
use nur\sery\wip\schema\Result;
 | 
			
		||||
use nur\sery\wip\schema\Schema;
 | 
			
		||||
 | 
			
		||||
class tbool extends _tformatable {
 | 
			
		||||
  const NAME = "bool";
 | 
			
		||||
 | 
			
		||||
  const ALIASES = ["boolean"];
 | 
			
		||||
 | 
			
		||||
class tbool extends _tsimple {
 | 
			
		||||
  /** liste de valeurs chaines à considérer comme 'OUI' */
 | 
			
		||||
  const YES_VALUES = [
 | 
			
		||||
    # IMPORTANT: ordonner par taille décroissante pour compatibilité avec parse()
 | 
			
		||||
    "true", "vrai", "yes", "oui",
 | 
			
		||||
    "t", "v", "y", "o", "1",
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  /** liste de valeurs chaines à considérer comme 'NON' */
 | 
			
		||||
  const NO_VALUES = [
 | 
			
		||||
    # IMPORTANT: ordonner par taille décroissante pour compatibilité avec parse()
 | 
			
		||||
    "false", "faux", "non", "no",
 | 
			
		||||
    "f", "n", "0",
 | 
			
		||||
  ];
 | 
			
		||||
@ -56,68 +53,42 @@ class tbool extends _tformatable {
 | 
			
		||||
    if ($bool !== null) self::ensure_bool($bool);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getClass(): string {
 | 
			
		||||
    return "bool";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function is2States(): bool {
 | 
			
		||||
    return !$this->nullable;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function get2States(): array {
 | 
			
		||||
    return [false, true];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function is3States(): bool {
 | 
			
		||||
    return $this->nullable;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function get3States(): array {
 | 
			
		||||
    return [false, true, null];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isAvailable(Input $input, $valueKey): bool {
 | 
			
		||||
    return $input->isAvailable($valueKey);
 | 
			
		||||
  function isAvailable(Input $input, $destKey): bool {
 | 
			
		||||
    return $input->isAvailable($destKey);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isValid($value, ?bool &$normalized=null): bool {
 | 
			
		||||
    $normalized = is_bool($value);
 | 
			
		||||
    return is_scalar($value);
 | 
			
		||||
    if (is_string($value)) {
 | 
			
		||||
      $value = trim($value);
 | 
			
		||||
      $valid = self::is_yes($value) || self::is_no($value);
 | 
			
		||||
    } else {
 | 
			
		||||
      $valid = is_scalar($value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  function extract(string $value): string {
 | 
			
		||||
    return trim($value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function parse(string $value) {
 | 
			
		||||
    if (self::is_yes($value)) return true;
 | 
			
		||||
    elseif (self::is_no($value)) return false;
 | 
			
		||||
    throw new ValueException("une valeur booléenne est attendue");
 | 
			
		||||
    return $valid;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @var ScalarResult $result
 | 
			
		||||
   * @var ScalarSchema $schema
 | 
			
		||||
   */
 | 
			
		||||
  function verifix(&$value, Result $result, Schema $schema): bool {
 | 
			
		||||
  function verifix(&$value, Result &$result, Schema $schema): bool {
 | 
			
		||||
    if (is_bool($value)) {
 | 
			
		||||
      $result->setNormalized();
 | 
			
		||||
      return false;
 | 
			
		||||
    } elseif (is_string($value)) {
 | 
			
		||||
      try {
 | 
			
		||||
        $value = $this->parse($value);
 | 
			
		||||
        $result->setValid();
 | 
			
		||||
        return true;
 | 
			
		||||
      } catch (ValueException $e) {
 | 
			
		||||
      }
 | 
			
		||||
      $bool = trim($value);
 | 
			
		||||
      if (self::is_yes($bool)) $value = true;
 | 
			
		||||
      elseif (self::is_no($bool)) $value = false;
 | 
			
		||||
      else return $result->setInvalid($value, $schema);
 | 
			
		||||
    } elseif (is_scalar($value)) {
 | 
			
		||||
      $value = boolval($value);
 | 
			
		||||
    } else {
 | 
			
		||||
      return $result->setInvalid($value, $schema);
 | 
			
		||||
    }
 | 
			
		||||
    $result->setValid();
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
    $result->setInvalid($value, $schema);
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const OUINON_FORMAT = ["Oui", "Non", false];
 | 
			
		||||
  const OUINONNULL_FORMAT = ["Oui", "Non", ""];
 | 
			
		||||
@ -134,10 +105,10 @@ class tbool extends _tformatable {
 | 
			
		||||
    "oz" => self::OZ_FORMAT,
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  const FORMAT = self::OUINON_FORMAT;
 | 
			
		||||
  const DEFAULT_FORMAT = self::OUINON_FORMAT;
 | 
			
		||||
 | 
			
		||||
  function format($value, $format=null): string {
 | 
			
		||||
    $format ??= $this->params["format"] ?? static::FORMAT;
 | 
			
		||||
    if ($format === null) $format = static::DEFAULT_FORMAT;
 | 
			
		||||
    if (is_string($format)) {
 | 
			
		||||
      $oformat = $format;
 | 
			
		||||
      $format = cl::get(self::FORMATS, strtolower($oformat));
 | 
			
		||||
@ -149,8 +120,4 @@ class tbool extends _tformatable {
 | 
			
		||||
    }
 | 
			
		||||
    return $value? $format[0]: $format[1];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getGetterName(string $name): string {
 | 
			
		||||
    return prop::get_getter_name($name, !$this->nullable);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,66 +1,27 @@
 | 
			
		||||
<?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\php\nur_func;
 | 
			
		||||
use nur\sery\ValueException;
 | 
			
		||||
use nur\sery\wip\schema\Result;
 | 
			
		||||
use nur\sery\wip\schema\Schema;
 | 
			
		||||
use stdClass;
 | 
			
		||||
 | 
			
		||||
class tcallable extends _tsimple {
 | 
			
		||||
  const NAME = "callable";
 | 
			
		||||
 | 
			
		||||
  const ALIASES = ["func", "function"];
 | 
			
		||||
 | 
			
		||||
  static function ensure_callable(&$callable): void {
 | 
			
		||||
    $callable = func::ensure($callable);
 | 
			
		||||
    if (!is_callable($callable)) throw ValueException::invalid_type($callable, "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);
 | 
			
		||||
    return nur_func::check_func($value, stdClass::class);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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 verifix(&$value, Result &$result, Schema $schema): bool {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function format($value, $format=null): string {
 | 
			
		||||
 | 
			
		||||
@ -1,56 +1,26 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\types;
 | 
			
		||||
 | 
			
		||||
use nulib\php\content\c;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarResult;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarSchema;
 | 
			
		||||
use nur\sery\wip\schema\Result;
 | 
			
		||||
use nur\sery\wip\schema\Schema;
 | 
			
		||||
 | 
			
		||||
abstract class tcontent extends _tunion {
 | 
			
		||||
  const NAME = "content";
 | 
			
		||||
 | 
			
		||||
abstract class tcontent extends _tsimple {
 | 
			
		||||
  static function ensure_content(&$content): void {
 | 
			
		||||
    if ($content === null || $content === false) $content = [];
 | 
			
		||||
    elseif (!is_string($content) && !is_array($content)) $content = strval($content);
 | 
			
		||||
    if (!is_string($content) && !is_array($content)) $content = strval($content);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static function ensure_ncontent(&$content): void {
 | 
			
		||||
    if ($content !== null) self::ensure_content($content);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getClass(): string {
 | 
			
		||||
    return "string|array";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isValid($value, ?bool &$normalized=null): bool {
 | 
			
		||||
    $normalized = is_string($value) || is_array($value);
 | 
			
		||||
    return is_scalar($value) || is_array($value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function parse(string $value) {
 | 
			
		||||
    return $value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @var ScalarResult $result
 | 
			
		||||
   * @var ScalarSchema $schema
 | 
			
		||||
   */
 | 
			
		||||
  function verifix(&$value, Result $result, Schema $schema): bool {
 | 
			
		||||
    if (is_string($value) || is_array($value)) {
 | 
			
		||||
      $result->setNormalized();
 | 
			
		||||
      return false;
 | 
			
		||||
    } elseif (is_scalar($value)) {
 | 
			
		||||
      $value = strval($value);
 | 
			
		||||
      $result->setValid();
 | 
			
		||||
      return true;
 | 
			
		||||
    } else {
 | 
			
		||||
      $result->setInvalid($value, $schema);
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  function verifix(&$value, Result &$result, Schema $schema): bool {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function format($value, $format=null): string {
 | 
			
		||||
    return c::to_string($value);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,17 +1,12 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\types;
 | 
			
		||||
 | 
			
		||||
use nulib\ValueException;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarResult;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarSchema;
 | 
			
		||||
use nur\sery\wip\schema\Result;
 | 
			
		||||
use nur\sery\wip\schema\Schema;
 | 
			
		||||
 | 
			
		||||
class tfloat extends _tformatable {
 | 
			
		||||
  const NAME = "float";
 | 
			
		||||
 | 
			
		||||
  const ALIASES = ["flt", "double", "dbl"];
 | 
			
		||||
 | 
			
		||||
class tfloat extends _tsimple {
 | 
			
		||||
  static function ensure_float(&$float): void {
 | 
			
		||||
    if (!is_float($float)) $float = floatval($float);
 | 
			
		||||
  }
 | 
			
		||||
@ -20,46 +15,36 @@ class tfloat extends _tformatable {
 | 
			
		||||
    if ($float !== null) self::ensure_float($float);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getClass(): string {
 | 
			
		||||
    return "float";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isValid($value, ?bool &$normalized=null): bool {
 | 
			
		||||
    $normalized = is_float($value);
 | 
			
		||||
    return is_scalar($value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function extract(string $value): string {
 | 
			
		||||
    return trim($value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function parse(string $value) {
 | 
			
		||||
    $value = str_replace(",", ".", trim($value));
 | 
			
		||||
    if (is_numeric($value)) return floatval($value);
 | 
			
		||||
    throw new ValueException("une valeur numérique flottante est attendue");
 | 
			
		||||
    if (is_string($value)) $valid = is_numeric(trim($value));
 | 
			
		||||
    else $valid = is_scalar($value);
 | 
			
		||||
    return $valid;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @var ScalarResult $result
 | 
			
		||||
   * @var ScalarSchema $schema
 | 
			
		||||
   */
 | 
			
		||||
  function verifix(&$value, Result $result, Schema $schema): bool {
 | 
			
		||||
  function verifix(&$value, Result &$result, Schema $schema): bool {
 | 
			
		||||
    if (is_float($value)) {
 | 
			
		||||
      $result->setNormalized();
 | 
			
		||||
      return false;
 | 
			
		||||
    } elseif (is_string($value)) {
 | 
			
		||||
      try {
 | 
			
		||||
        $value = $this->parse($value);
 | 
			
		||||
        $result->setValid();
 | 
			
		||||
        return true;
 | 
			
		||||
      } catch (ValueException $e) {
 | 
			
		||||
      }
 | 
			
		||||
      $float = trim($value);
 | 
			
		||||
      if (is_numeric($float)) $value = floatval($float);
 | 
			
		||||
      else return $result->setInvalid($value, $schema);
 | 
			
		||||
    } elseif (is_scalar($value)) {
 | 
			
		||||
      $value = floatval($value);
 | 
			
		||||
    } else {
 | 
			
		||||
      return $result->setInvalid($value, $schema);
 | 
			
		||||
    }
 | 
			
		||||
    $result->setValid();
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
    $result->setInvalid($value, $schema);
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
  function format($value, $format=null): string {
 | 
			
		||||
    if ($format !== null) return sprintf($format, $value);
 | 
			
		||||
    else return strval($value);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,17 +1,12 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\types;
 | 
			
		||||
 | 
			
		||||
use nulib\ValueException;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarResult;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarSchema;
 | 
			
		||||
use nur\sery\wip\schema\Result;
 | 
			
		||||
use nur\sery\wip\schema\Schema;
 | 
			
		||||
 | 
			
		||||
class tint extends _tformatable {
 | 
			
		||||
  const NAME = "int";
 | 
			
		||||
 | 
			
		||||
  const ALIASES = ["integer"];
 | 
			
		||||
 | 
			
		||||
class tint extends _tsimple {
 | 
			
		||||
  static function ensure_int(&$int): void {
 | 
			
		||||
    if (!is_int($int)) $int = intval($int);
 | 
			
		||||
  }
 | 
			
		||||
@ -20,48 +15,38 @@ class tint extends _tformatable {
 | 
			
		||||
    if ($int !== null) self::ensure_int($int);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //const INT_PATTERN = '/^[-+]?[0-9]+(?:\.[0-9]*)?$/';
 | 
			
		||||
 | 
			
		||||
  function getClass(): string {
 | 
			
		||||
    return "int";
 | 
			
		||||
  }
 | 
			
		||||
  const INT_PATTERN = '/^[-+]?[0-9]+(?:\.[0-9]*)?$/';
 | 
			
		||||
 | 
			
		||||
  function isValid($value, ?bool &$normalized=null): bool {
 | 
			
		||||
    $normalized = is_int($value);
 | 
			
		||||
    return is_scalar($value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function extract(string $value): string {
 | 
			
		||||
    return trim($value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function parse(string $value) {
 | 
			
		||||
    $value = str_replace(",", ".", trim($value));
 | 
			
		||||
    if (is_numeric($value)) return intval($value);
 | 
			
		||||
    throw new ValueException("une valeur numérique entière est attendue");
 | 
			
		||||
    if (is_string($value)) $valid = is_numeric(trim($value));
 | 
			
		||||
    else $valid = is_scalar($value);
 | 
			
		||||
    return $valid;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @var ScalarResult $result
 | 
			
		||||
   * @var ScalarSchema $schema
 | 
			
		||||
   */
 | 
			
		||||
  function verifix(&$value, Result $result, Schema $schema): bool {
 | 
			
		||||
  function verifix(&$value, Result &$result, Schema $schema): bool {
 | 
			
		||||
    if (is_int($value)) {
 | 
			
		||||
      $result->setNormalized();
 | 
			
		||||
      return false;
 | 
			
		||||
    } elseif (is_string($value)) {
 | 
			
		||||
      try {
 | 
			
		||||
        $value = $this->parse($value);
 | 
			
		||||
        $result->setValid();
 | 
			
		||||
        return true;
 | 
			
		||||
      } catch (ValueException $e) {
 | 
			
		||||
      }
 | 
			
		||||
      $int = trim($value);
 | 
			
		||||
      if (is_numeric($int)) $value = intval($int);
 | 
			
		||||
      else return $result->setInvalid($value, $schema);
 | 
			
		||||
    } elseif (is_scalar($value)) {
 | 
			
		||||
      $value = intval($value);
 | 
			
		||||
    } else {
 | 
			
		||||
      return $result->setInvalid($value, $schema);
 | 
			
		||||
    }
 | 
			
		||||
    $result->setValid();
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
    $result->setInvalid($value, $schema);
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
  function format($value, $format=null): string {
 | 
			
		||||
    if ($format !== null) return sprintf($format, $value);
 | 
			
		||||
    else return strval($value);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,56 +1,26 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\types;
 | 
			
		||||
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarResult;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarSchema;
 | 
			
		||||
use nur\sery\wip\schema\Result;
 | 
			
		||||
use nur\sery\wip\schema\Schema;
 | 
			
		||||
 | 
			
		||||
class tkey extends _tunion {
 | 
			
		||||
  const NAME = "key";
 | 
			
		||||
 | 
			
		||||
class tkey extends _tsimple {
 | 
			
		||||
  static function ensure_key(&$key): void {
 | 
			
		||||
    if ($key === null) $key = "";
 | 
			
		||||
    elseif ($key === false) $key = 0;
 | 
			
		||||
    elseif (!is_string($key) && !is_int($key)) $key = strval($key);
 | 
			
		||||
    if (!is_string($key) && !is_int($key)) $key = strval($key);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static function ensure_nkey(&$key): void {
 | 
			
		||||
    if ($key !== null) self::ensure_key($key);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getClass(): string {
 | 
			
		||||
    return "string|int";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isValid($value, ?bool &$normalized=null): bool {
 | 
			
		||||
    $normalized = is_string($value) || is_int($value);
 | 
			
		||||
    return is_scalar($value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function parse(string $value) {
 | 
			
		||||
    return $value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @var ScalarResult $result
 | 
			
		||||
   * @var ScalarSchema $schema
 | 
			
		||||
   */
 | 
			
		||||
  function verifix(&$value, Result $result, Schema $schema): bool {
 | 
			
		||||
    if (is_string($value) || is_int($value)) {
 | 
			
		||||
      $result->setNormalized();
 | 
			
		||||
      return false;
 | 
			
		||||
    } elseif (is_scalar($value)) {
 | 
			
		||||
      $value = strval($value);
 | 
			
		||||
      $result->setValid();
 | 
			
		||||
      return true;
 | 
			
		||||
    } else {
 | 
			
		||||
      $result->setInvalid($value, $schema);
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  function verifix(&$value, Result &$result, Schema $schema): bool {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function format($value, $format=null): string {
 | 
			
		||||
    return strval($value);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,46 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\types;
 | 
			
		||||
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarResult;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarSchema;
 | 
			
		||||
use nur\sery\wip\schema\input\Input;
 | 
			
		||||
use nur\sery\wip\schema\Result;
 | 
			
		||||
use nur\sery\wip\schema\Schema;
 | 
			
		||||
 | 
			
		||||
class tmixed extends _tsimple {
 | 
			
		||||
  const NAME = "mixed";
 | 
			
		||||
 | 
			
		||||
  function getClass(): string {
 | 
			
		||||
    return "mixed";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isAvailable(Input $input, $valueKey): bool {
 | 
			
		||||
    return $input->isAvailable($valueKey);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function isNull($value): bool {
 | 
			
		||||
    return $value === null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isValid($value, ?bool &$normalized=null): bool {
 | 
			
		||||
    $normalized = true;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function parse(string $value) {
 | 
			
		||||
    return $value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @var ScalarResult $result
 | 
			
		||||
   * @var ScalarSchema $schema
 | 
			
		||||
   */
 | 
			
		||||
  function verifix(&$value, Result $result, Schema $schema): bool {
 | 
			
		||||
    $result->setNormalized();
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function format($value, $format=null): string {
 | 
			
		||||
    return var_export($value, true);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,22 +1,17 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\types;
 | 
			
		||||
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarResult;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarSchema;
 | 
			
		||||
use nur\sery\wip\schema\Result;
 | 
			
		||||
use nur\sery\wip\schema\Schema;
 | 
			
		||||
 | 
			
		||||
class tpkey extends _tunion {
 | 
			
		||||
  const NAME = "pkey";
 | 
			
		||||
 | 
			
		||||
class tpkey extends _tsimple {
 | 
			
		||||
  static function ensure_pkey(&$pkey): void {
 | 
			
		||||
    if ($pkey === null) $pkey = "";
 | 
			
		||||
    elseif ($pkey === false) $pkey = 0;
 | 
			
		||||
    elseif (!is_string($pkey) && !is_int($pkey) && !is_array($pkey)) $pkey = strval($pkey);
 | 
			
		||||
    if (!is_string($pkey) && !is_int($pkey) && !is_array($pkey)) $pkey = strval($pkey);
 | 
			
		||||
    if (is_array($pkey)) {
 | 
			
		||||
      foreach ($pkey as &$key) {
 | 
			
		||||
        tkey::ensure_key($key);
 | 
			
		||||
      }; unset($key);
 | 
			
		||||
      };
 | 
			
		||||
      unset($key);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -24,39 +19,14 @@ class tpkey extends _tunion {
 | 
			
		||||
    if ($pkey !== null) self::ensure_pkey($pkey);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getClass(): string {
 | 
			
		||||
    return "string|int|array";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isValid($value, ?bool &$normalized=null): bool {
 | 
			
		||||
    $normalized = is_string($value) || is_int($value) || is_array($value);
 | 
			
		||||
    return is_scalar($value) || is_array($value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function parse(string $value) {
 | 
			
		||||
    return $value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @var ScalarResult $result
 | 
			
		||||
   * @var ScalarSchema $schema
 | 
			
		||||
   */
 | 
			
		||||
  function verifix(&$value, Result $result, Schema $schema): bool {
 | 
			
		||||
    if (is_string($value) || is_int($value) || is_array($value)) {
 | 
			
		||||
      $result->setNormalized();
 | 
			
		||||
      return false;
 | 
			
		||||
    } elseif (is_scalar($value)) {
 | 
			
		||||
      $value = strval($value);
 | 
			
		||||
      $result->setValid();
 | 
			
		||||
      return true;
 | 
			
		||||
    } else {
 | 
			
		||||
      $result->setInvalid($value, $schema);
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  function verifix(&$value, Result &$result, Schema $schema): bool {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function format($value, $format=null): string {
 | 
			
		||||
    if (is_array($value)) return implode(".", $value);
 | 
			
		||||
    else return strval($value);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,16 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\types;
 | 
			
		||||
 | 
			
		||||
use nur\sery\wip\schema\input\Input;
 | 
			
		||||
 | 
			
		||||
class traw extends tmixed {
 | 
			
		||||
  const NAME = "raw";
 | 
			
		||||
 | 
			
		||||
  function isAvailable(Input $input, $valueKey): bool {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function isNull($value): bool {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,64 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\types;
 | 
			
		||||
 | 
			
		||||
use nulib\str;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarResult;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarSchema;
 | 
			
		||||
use nur\sery\wip\schema\Result;
 | 
			
		||||
use nur\sery\wip\schema\Schema;
 | 
			
		||||
 | 
			
		||||
class trawstring extends _tstring {
 | 
			
		||||
  const NAME = "rawstring";
 | 
			
		||||
 | 
			
		||||
  static function ensure_string(&$string): void {
 | 
			
		||||
    if (!is_string($string)) $string = strval($string);
 | 
			
		||||
    if (static::TRIM) $string = trim($string);
 | 
			
		||||
    if (static::NORM_NL) $string = str::norm_nl($string);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static function ensure_nstring(&$string): void {
 | 
			
		||||
    if ($string !== null) self::ensure_string($string);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getClass(): string {
 | 
			
		||||
    return "string";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isNull($value): bool {
 | 
			
		||||
    return $value === null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isValid($value, ?bool &$normalized=null): bool {
 | 
			
		||||
    if (is_string($value)) {
 | 
			
		||||
      $normalized = true;
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    return is_scalar($value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function parse(string $value) {
 | 
			
		||||
    return $value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @var ScalarResult $result
 | 
			
		||||
   * @var ScalarSchema $schema
 | 
			
		||||
   */
 | 
			
		||||
  function verifix(&$value, Result $result, Schema $schema): bool {
 | 
			
		||||
    if (is_string($value)) {
 | 
			
		||||
      $result->setNormalized();
 | 
			
		||||
      return false;
 | 
			
		||||
    } elseif (is_scalar($value)) {
 | 
			
		||||
      $value = strval($value);
 | 
			
		||||
      $result->setValid();
 | 
			
		||||
      return true;
 | 
			
		||||
    } else {
 | 
			
		||||
      $result->setInvalid($value, $schema);
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function format($value, $format=null): string {
 | 
			
		||||
    return strval($value);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,8 +1,48 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\types;
 | 
			
		||||
 | 
			
		||||
class tstring extends trawstring {
 | 
			
		||||
  const NAME = "string";
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
  const TRIM = true;
 | 
			
		||||
class tstring extends _tsimple {
 | 
			
		||||
  static function ensure_string(&$string): void {
 | 
			
		||||
    if (!is_string($string)) $string = strval($string);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static function ensure_nstring(&$string): void {
 | 
			
		||||
    if ($string !== null) self::ensure_string($string);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isNull($value): bool {
 | 
			
		||||
    return $value === null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function isValid($value, ?bool &$normalized=null): bool {
 | 
			
		||||
    $normalized = is_string($value);
 | 
			
		||||
    return is_scalar($value);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  /**
 | 
			
		||||
   * @var ScalarResult $result
 | 
			
		||||
   * @var ScalarSchema $schema
 | 
			
		||||
   */
 | 
			
		||||
  function verifix(&$value, Result &$result, Schema $schema): bool {
 | 
			
		||||
    if (is_string($value)) {
 | 
			
		||||
      $result->setNormalized();
 | 
			
		||||
      return false;
 | 
			
		||||
    } elseif (is_scalar($value)) {
 | 
			
		||||
      $value = strval($value);
 | 
			
		||||
      $result->setValid();
 | 
			
		||||
      return true;
 | 
			
		||||
    } else {
 | 
			
		||||
      $result->setInvalid($value, $schema);
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function format($value, $format=null): string {
 | 
			
		||||
    return strval($value);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,9 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\types;
 | 
			
		||||
 | 
			
		||||
class ttext extends trawstring {
 | 
			
		||||
  const NAME = "text";
 | 
			
		||||
 | 
			
		||||
  const TRIM = true;
 | 
			
		||||
  const NORM_NL = true;
 | 
			
		||||
}
 | 
			
		||||
@ -1,10 +1,9 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\web\content;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
use nulib\A;
 | 
			
		||||
use nulib\php\content\c;
 | 
			
		||||
use nulib\php\content\IContent;
 | 
			
		||||
use nur\sery\A;
 | 
			
		||||
use nur\sery\php\content\c;
 | 
			
		||||
use nur\sery\php\content\IContent;
 | 
			
		||||
 | 
			
		||||
class Tag implements IContent {
 | 
			
		||||
  function __construct(string $tag, $content=null) {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										26
									
								
								tests/app/argsTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								tests/app/argsTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace nur\sery\app;
 | 
			
		||||
 | 
			
		||||
use nulib\tests\TestCase;
 | 
			
		||||
use nur\sery\app\args;
 | 
			
		||||
 | 
			
		||||
class argsTest extends TestCase {
 | 
			
		||||
  function testFrom_array() {
 | 
			
		||||
    self::assertSame([], args::from_array(null));
 | 
			
		||||
    self::assertSame([], args::from_array([]));
 | 
			
		||||
    self::assertSame([], args::from_array([false]));
 | 
			
		||||
    self::assertSame(["x"], args::from_array(["x", false]));
 | 
			
		||||
 | 
			
		||||
    self::assertSame(["--opt"], args::from_array(["--opt"]));
 | 
			
		||||
    self::assertSame(["--opt", "value"], args::from_array(["--opt", "value"]));
 | 
			
		||||
 | 
			
		||||
    self::assertSame([], args::from_array(["opt" => false]));
 | 
			
		||||
    self::assertSame(["--opt"], args::from_array(["opt" => true]));
 | 
			
		||||
    self::assertSame(["--opt", "value"], args::from_array(["opt" => "value"]));
 | 
			
		||||
    self::assertSame(["--opt", "42"], args::from_array(["opt" => 42]));
 | 
			
		||||
    self::assertSame(["--opt", "1", "2", "3", "--"], args::from_array(["opt" => [1, 2, 3]]));
 | 
			
		||||
 | 
			
		||||
    self::assertSame(["x", "1", "2", "3", "y"], args::from_array(["x", [1, 2, 3], "y"]));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										132
									
								
								tests/appTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								tests/appTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,132 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery {
 | 
			
		||||
  use nulib\tests\TestCase;
 | 
			
		||||
  use nur\sery\impl\config;
 | 
			
		||||
  use nur\sery\impl\myapp;
 | 
			
		||||
  use nur\sery\impl\MyApplication1;
 | 
			
		||||
  use nur\sery\impl\MyApplication2;
 | 
			
		||||
 | 
			
		||||
  class appTest extends TestCase {
 | 
			
		||||
    function testWith() {
 | 
			
		||||
      $projdir = config::get_projdir();
 | 
			
		||||
      $cwd = getcwd();
 | 
			
		||||
 | 
			
		||||
      myapp::reset();
 | 
			
		||||
      $app1 = myapp::with(MyApplication1::class);
 | 
			
		||||
      self::assertSame([
 | 
			
		||||
        "projdir" => $projdir,
 | 
			
		||||
        "vendor" => [
 | 
			
		||||
          "bindir" => "$projdir/vendor/bin",
 | 
			
		||||
          "autoload" => "$projdir/vendor/autoload.php",
 | 
			
		||||
        ],
 | 
			
		||||
        "appcode" => "nur-sery",
 | 
			
		||||
        "cwd" => $cwd,
 | 
			
		||||
        "datadir" => "$projdir/devel",
 | 
			
		||||
        "etcdir" => "$projdir/devel/etc",
 | 
			
		||||
        "vardir" => "$projdir/devel/var",
 | 
			
		||||
        "logdir" => "$projdir/devel/log",
 | 
			
		||||
        "profile" => "devel",
 | 
			
		||||
        "appgroup" => null,
 | 
			
		||||
        "name" => "my-application1",
 | 
			
		||||
        "title" => null,
 | 
			
		||||
      ], $app1->getParams());
 | 
			
		||||
 | 
			
		||||
      $app2 = myapp::with(MyApplication2::class, $app1);
 | 
			
		||||
      self::assertSame([
 | 
			
		||||
        "projdir" => $projdir,
 | 
			
		||||
        "vendor" => [
 | 
			
		||||
          "bindir" => "$projdir/vendor/bin",
 | 
			
		||||
          "autoload" => "$projdir/vendor/autoload.php",
 | 
			
		||||
        ],
 | 
			
		||||
        "appcode" => "nur-sery",
 | 
			
		||||
        "cwd" => $cwd,
 | 
			
		||||
        "datadir" => "$projdir/devel",
 | 
			
		||||
        "etcdir" => "$projdir/devel/etc",
 | 
			
		||||
        "vardir" => "$projdir/devel/var",
 | 
			
		||||
        "logdir" => "$projdir/devel/log",
 | 
			
		||||
        "profile" => "devel",
 | 
			
		||||
        "appgroup" => null,
 | 
			
		||||
        "name" => "my-application2",
 | 
			
		||||
        "title" => null,
 | 
			
		||||
      ], $app2->getParams());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testInit() {
 | 
			
		||||
      $projdir = config::get_projdir();
 | 
			
		||||
      $cwd = getcwd();
 | 
			
		||||
 | 
			
		||||
      myapp::reset();
 | 
			
		||||
      myapp::init(MyApplication1::class);
 | 
			
		||||
      self::assertSame([
 | 
			
		||||
        "projdir" => $projdir,
 | 
			
		||||
        "vendor" => [
 | 
			
		||||
          "bindir" => "$projdir/vendor/bin",
 | 
			
		||||
          "autoload" => "$projdir/vendor/autoload.php",
 | 
			
		||||
        ],
 | 
			
		||||
        "appcode" => "nur-sery",
 | 
			
		||||
        "cwd" => $cwd,
 | 
			
		||||
        "datadir" => "$projdir/devel",
 | 
			
		||||
        "etcdir" => "$projdir/devel/etc",
 | 
			
		||||
        "vardir" => "$projdir/devel/var",
 | 
			
		||||
        "logdir" => "$projdir/devel/log",
 | 
			
		||||
        "profile" => "devel",
 | 
			
		||||
        "appgroup" => null,
 | 
			
		||||
        "name" => "my-application1",
 | 
			
		||||
        "title" => null,
 | 
			
		||||
      ], myapp::get()->getParams());
 | 
			
		||||
 | 
			
		||||
      myapp::init(MyApplication2::class);
 | 
			
		||||
      self::assertSame([
 | 
			
		||||
        "projdir" => $projdir,
 | 
			
		||||
        "vendor" => [
 | 
			
		||||
          "bindir" => "$projdir/vendor/bin",
 | 
			
		||||
          "autoload" => "$projdir/vendor/autoload.php",
 | 
			
		||||
        ],
 | 
			
		||||
        "appcode" => "nur-sery",
 | 
			
		||||
        "cwd" => $cwd,
 | 
			
		||||
        "datadir" => "$projdir/devel",
 | 
			
		||||
        "etcdir" => "$projdir/devel/etc",
 | 
			
		||||
        "vardir" => "$projdir/devel/var",
 | 
			
		||||
        "logdir" => "$projdir/devel/log",
 | 
			
		||||
        "profile" => "devel",
 | 
			
		||||
        "appgroup" => null,
 | 
			
		||||
        "name" => "my-application2",
 | 
			
		||||
        "title" => null,
 | 
			
		||||
      ], myapp::get()->getParams());
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace nur\sery\impl {
 | 
			
		||||
 | 
			
		||||
  use nur\sery\app\cli\Application;
 | 
			
		||||
  use nur\sery\os\path;
 | 
			
		||||
  use nur\sery\app;
 | 
			
		||||
 | 
			
		||||
  class config {
 | 
			
		||||
    const PROJDIR = __DIR__.'/..';
 | 
			
		||||
 | 
			
		||||
    static function get_projdir(): string {
 | 
			
		||||
      return path::abspath(self::PROJDIR);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  class myapp extends app {
 | 
			
		||||
    static function reset(): void {
 | 
			
		||||
      self::$app = null;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  class MyApplication1 extends Application {
 | 
			
		||||
    const PROJDIR = config::PROJDIR;
 | 
			
		||||
 | 
			
		||||
    function main() {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  class MyApplication2 extends Application {
 | 
			
		||||
    const PROJDIR = null;
 | 
			
		||||
 | 
			
		||||
    function main() {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								tests/db/sqlite/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/db/sqlite/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
/capacitor.db*
 | 
			
		||||
							
								
								
									
										344
									
								
								tests/db/sqlite/SqliteStorageTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										344
									
								
								tests/db/sqlite/SqliteStorageTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,344 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\db\sqlite;
 | 
			
		||||
 | 
			
		||||
use nulib\tests\TestCase;
 | 
			
		||||
use nur\sery\cl;
 | 
			
		||||
use nur\sery\db\Capacitor;
 | 
			
		||||
use nur\sery\db\CapacitorChannel;
 | 
			
		||||
 | 
			
		||||
class SqliteStorageTest extends TestCase {
 | 
			
		||||
  function _testChargeStrings(SqliteStorage $storage, ?string $channel) {
 | 
			
		||||
    $storage->reset($channel);
 | 
			
		||||
    $storage->charge($channel, "first");
 | 
			
		||||
    $storage->charge($channel, "second");
 | 
			
		||||
    $storage->charge($channel, "third");
 | 
			
		||||
    $items = cl::all($storage->discharge($channel, false));
 | 
			
		||||
    self::assertSame(["first", "second", "third"], $items);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function _testChargeArrays(SqliteStorage $storage, ?string $channel) {
 | 
			
		||||
    $storage->reset($channel);
 | 
			
		||||
    $storage->charge($channel, ["id" => 10, "name" => "first"]);
 | 
			
		||||
    $storage->charge($channel, ["name" => "second", "id" => 20]);
 | 
			
		||||
    $storage->charge($channel, ["name" => "third", "id" => "30"]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testChargeStrings() {
 | 
			
		||||
    $storage = new SqliteStorage(__DIR__.'/capacitor.db');
 | 
			
		||||
    $this->_testChargeStrings($storage, null);
 | 
			
		||||
    $storage->close();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testChargeArrays() {
 | 
			
		||||
    $storage = new SqliteStorage(__DIR__.'/capacitor.db');
 | 
			
		||||
    $storage->addChannel(new class extends CapacitorChannel {
 | 
			
		||||
      const NAME = "arrays";
 | 
			
		||||
      const COLUMN_DEFINITIONS = ["id" => "integer"];
 | 
			
		||||
 | 
			
		||||
      function getItemValues($item): ?array {
 | 
			
		||||
        return ["id" => $item["id"] ?? null];
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $this->_testChargeStrings($storage, "strings");
 | 
			
		||||
    $this->_testChargeArrays($storage, "arrays");
 | 
			
		||||
    $storage->close();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testEach() {
 | 
			
		||||
    $storage = new SqliteStorage(__DIR__.'/capacitor.db');
 | 
			
		||||
    $capacitor = new Capacitor($storage, new class extends CapacitorChannel {
 | 
			
		||||
      const NAME = "each";
 | 
			
		||||
      const COLUMN_DEFINITIONS = [
 | 
			
		||||
        "age" => "integer",
 | 
			
		||||
        "done" => "integer default 0",
 | 
			
		||||
      ];
 | 
			
		||||
 | 
			
		||||
      function getItemValues($item): ?array {
 | 
			
		||||
        return [
 | 
			
		||||
          "age" => $item["age"],
 | 
			
		||||
        ];
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $capacitor->reset();
 | 
			
		||||
    $capacitor->charge(["name" => "first", "age" => 5]);
 | 
			
		||||
    $capacitor->charge(["name" => "second", "age" => 10]);
 | 
			
		||||
    $capacitor->charge(["name" => "third", "age" => 15]);
 | 
			
		||||
    $capacitor->charge(["name" => "fourth", "age" => 20]);
 | 
			
		||||
 | 
			
		||||
    $setDone = function ($item, $row, $suffix=null) {
 | 
			
		||||
      $updates = ["done" => 1];
 | 
			
		||||
      if ($suffix !== null) {
 | 
			
		||||
        $item["name"] .= $suffix;
 | 
			
		||||
        $updates["item"] = $item;
 | 
			
		||||
      }
 | 
			
		||||
      return $updates;
 | 
			
		||||
    };
 | 
			
		||||
    $capacitor->each(["age" => [">", 10]], $setDone, ["++"]);
 | 
			
		||||
    $capacitor->each(["done" => 0], $setDone, null);
 | 
			
		||||
 | 
			
		||||
    Txx(cl::all($capacitor->discharge(false)));
 | 
			
		||||
    $capacitor->close();
 | 
			
		||||
    self::assertTrue(true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testPrimayKey() {
 | 
			
		||||
    $storage = new SqliteStorage(__DIR__.'/capacitor.db');
 | 
			
		||||
    $capacitor = new Capacitor($storage, new class extends CapacitorChannel {
 | 
			
		||||
      const NAME = "pk";
 | 
			
		||||
      const COLUMN_DEFINITIONS = [
 | 
			
		||||
        "id_" => "varchar primary key",
 | 
			
		||||
        "done" => "integer default 0",
 | 
			
		||||
      ];
 | 
			
		||||
 | 
			
		||||
      function getItemValues($item): ?array {
 | 
			
		||||
        return [
 | 
			
		||||
          "id_" => $item["numero"],
 | 
			
		||||
        ];
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $capacitor->charge(["numero" => "a", "name" => "first", "age" => 5]);
 | 
			
		||||
    $capacitor->charge(["numero" => "b", "name" => "second", "age" => 10]);
 | 
			
		||||
    $capacitor->charge(["numero" => "c", "name" => "third", "age" => 15]);
 | 
			
		||||
    $capacitor->charge(["numero" => "d", "name" => "fourth", "age" => 20]);
 | 
			
		||||
    sleep(2);
 | 
			
		||||
    $capacitor->charge(["numero" => "b", "name" => "second", "age" => 100]);
 | 
			
		||||
    $capacitor->charge(["numero" => "d", "name" => "fourth", "age" => 200]);
 | 
			
		||||
 | 
			
		||||
    $capacitor->close();
 | 
			
		||||
    self::assertTrue(true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testSum() {
 | 
			
		||||
    $storage = new SqliteStorage(__DIR__.'/capacitor.db');
 | 
			
		||||
    $capacitor = new Capacitor($storage, new class extends CapacitorChannel {
 | 
			
		||||
      const NAME = "sum";
 | 
			
		||||
      const COLUMN_DEFINITIONS = [
 | 
			
		||||
        "a__" => "varchar",
 | 
			
		||||
        "b__" => "varchar",
 | 
			
		||||
        "b__sum_" => self::SUM_DEFINITION,
 | 
			
		||||
      ];
 | 
			
		||||
 | 
			
		||||
      function getItemValues($item): ?array {
 | 
			
		||||
        return [
 | 
			
		||||
          "a" => $item["a"],
 | 
			
		||||
          "b" => $item["b"],
 | 
			
		||||
        ];
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $capacitor->reset();
 | 
			
		||||
    $capacitor->charge(["a" => null, "b" => null]);
 | 
			
		||||
    $capacitor->charge(["a" => "first", "b" => "second"]);
 | 
			
		||||
 | 
			
		||||
    Txx("=== all");
 | 
			
		||||
    /** @var Sqlite $sqlite */
 | 
			
		||||
    $sqlite = $capacitor->getStorage()->db();
 | 
			
		||||
    Txx(cl::all($sqlite->all([
 | 
			
		||||
      "select",
 | 
			
		||||
      "from" => $capacitor->getChannel()->getTableName(),
 | 
			
		||||
    ])));
 | 
			
		||||
    Txx("=== each");
 | 
			
		||||
    $capacitor->each(null, function ($item, $values) {
 | 
			
		||||
      Txx($values);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $capacitor->close();
 | 
			
		||||
    self::assertTrue(true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testEachValues() {
 | 
			
		||||
    # tester que values contient bien toutes les valeurs de la ligne
 | 
			
		||||
    $storage = new SqliteStorage(__DIR__.'/capacitor.db');
 | 
			
		||||
    $capacitor = new Capacitor($storage, new class extends CapacitorChannel {
 | 
			
		||||
      const NAME = "each_values";
 | 
			
		||||
      const COLUMN_DEFINITIONS = [
 | 
			
		||||
        "name" => "varchar primary key",
 | 
			
		||||
        "age" => "integer",
 | 
			
		||||
        "done" => "integer default 0",
 | 
			
		||||
        "notes" => "text",
 | 
			
		||||
      ];
 | 
			
		||||
 | 
			
		||||
      function getItemValues($item): ?array {
 | 
			
		||||
        return [
 | 
			
		||||
          "name" => $item["name"],
 | 
			
		||||
          "age" => $item["age"],
 | 
			
		||||
        ];
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $capacitor->reset();
 | 
			
		||||
    $capacitor->charge(["name" => "first", "age" => 5], function($item, ?array $values, ?array $pvalues) {
 | 
			
		||||
      self::assertSame("first", $item["name"]);
 | 
			
		||||
      self::assertSame(5, $item["age"]);
 | 
			
		||||
      self::assertnotnull($values);
 | 
			
		||||
      self::assertSame(["name", "age", "item", "item__sum_", "created_", "modified_"], array_keys($values));
 | 
			
		||||
      self::assertSame([
 | 
			
		||||
        "name" => "first",
 | 
			
		||||
        "age" => 5,
 | 
			
		||||
        "item" => $item,
 | 
			
		||||
      ], cl::select($values, ["name", "age", "item"]));
 | 
			
		||||
      self::assertNull($pvalues);
 | 
			
		||||
    });
 | 
			
		||||
    $capacitor->charge(["name" => "first", "age" => 10], function($item, ?array $values, ?array $pvalues) {
 | 
			
		||||
      self::assertSame("first", $item["name"]);
 | 
			
		||||
      self::assertSame(10, $item["age"]);
 | 
			
		||||
      self::assertnotnull($values);
 | 
			
		||||
      self::assertSame(["name", "age", "done", "notes", "item", "item__sum_", "created_", "modified_"], array_keys($values));
 | 
			
		||||
      self::assertSame([
 | 
			
		||||
        "name" => "first",
 | 
			
		||||
        "age" => 10,
 | 
			
		||||
        "done" => 0,
 | 
			
		||||
        "notes" => null,
 | 
			
		||||
        "item" => $item,
 | 
			
		||||
      ], cl::select($values, ["name", "age", "done", "notes", "item"]));
 | 
			
		||||
      self::assertNotNull($pvalues);
 | 
			
		||||
      self::assertSame([
 | 
			
		||||
        "name" => "first",
 | 
			
		||||
        "age" => 5,
 | 
			
		||||
        "done" => 0,
 | 
			
		||||
        "notes" => null,
 | 
			
		||||
        "item" => ["name" => "first", "age" => 5],
 | 
			
		||||
      ], cl::select($pvalues, ["name", "age", "done", "notes", "item"]));
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $capacitor->each(null, function($item, ?array $values) {
 | 
			
		||||
      self::assertSame("first", $item["name"]);
 | 
			
		||||
      self::assertSame(10, $item["age"]);
 | 
			
		||||
      self::assertnotnull($values);
 | 
			
		||||
      self::assertSame(["name", "age", "done", "notes", "item", "item__sum_", "created_", "modified_"], array_keys($values));
 | 
			
		||||
      self::assertSame([
 | 
			
		||||
        "name" => "first",
 | 
			
		||||
        "age" => 10,
 | 
			
		||||
        "done" => 0,
 | 
			
		||||
        "notes" => null,
 | 
			
		||||
        "item" => $item,
 | 
			
		||||
      ], cl::select($values, ["name", "age", "done", "notes", "item"]));
 | 
			
		||||
      return [
 | 
			
		||||
        "done" => 1,
 | 
			
		||||
        "notes" => "modified",
 | 
			
		||||
      ];
 | 
			
		||||
    });
 | 
			
		||||
    $capacitor->charge(["name" => "first", "age" => 10], function($item, ?array $values, ?array $pvalues) {
 | 
			
		||||
      self::assertSame("first", $item["name"]);
 | 
			
		||||
      self::assertSame(10, $item["age"]);
 | 
			
		||||
      self::assertnotnull($values);
 | 
			
		||||
      self::assertSame(["name", "age", "done", "notes", "item", "item__sum_", "created_", "modified_"], array_keys($values));
 | 
			
		||||
      self::assertSame([
 | 
			
		||||
        "name" => "first",
 | 
			
		||||
        "age" => 10,
 | 
			
		||||
        "done" => 1,
 | 
			
		||||
        "notes" => "modified",
 | 
			
		||||
        "item" => $item,
 | 
			
		||||
      ], cl::select($values, ["name", "age", "done", "notes", "item"]));
 | 
			
		||||
      self::assertNotNull($pvalues);
 | 
			
		||||
      self::assertSame([
 | 
			
		||||
        "name" => "first",
 | 
			
		||||
        "age" => 10,
 | 
			
		||||
        "done" => 1,
 | 
			
		||||
        "notes" => "modified",
 | 
			
		||||
        "item" => $item,
 | 
			
		||||
      ], cl::select($pvalues, ["name", "age", "done", "notes", "item"]));
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $capacitor->charge(["name" => "first", "age" => 20], function($item, ?array $values, ?array $pvalues) {
 | 
			
		||||
      self::assertSame("first", $item["name"]);
 | 
			
		||||
      self::assertSame(20, $item["age"]);
 | 
			
		||||
      self::assertnotnull($values);
 | 
			
		||||
      self::assertSame(["name", "age", "done", "notes", "item", "item__sum_", "created_", "modified_"], array_keys($values));
 | 
			
		||||
      self::assertSame([
 | 
			
		||||
        "name" => "first",
 | 
			
		||||
        "age" => 20,
 | 
			
		||||
        "done" => 1,
 | 
			
		||||
        "notes" => "modified",
 | 
			
		||||
        "item" => $item,
 | 
			
		||||
      ], cl::select($values, ["name", "age", "done", "notes", "item"]));
 | 
			
		||||
      self::assertNotNull($pvalues);
 | 
			
		||||
      self::assertSame([
 | 
			
		||||
        "name" => "first",
 | 
			
		||||
        "age" => 10,
 | 
			
		||||
        "done" => 1,
 | 
			
		||||
        "notes" => "modified",
 | 
			
		||||
        "item" => ["name" => "first", "age" => 10],
 | 
			
		||||
      ], cl::select($pvalues, ["name", "age", "done", "notes", "item"]));
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testSetItemNull() {
 | 
			
		||||
    # tester le forçage de $îtem à null pour économiser la place
 | 
			
		||||
    $storage = new SqliteStorage(__DIR__.'/capacitor.db');
 | 
			
		||||
    $capacitor = new Capacitor($storage, new class extends CapacitorChannel {
 | 
			
		||||
      const NAME = "set_item_null";
 | 
			
		||||
      const COLUMN_DEFINITIONS = [
 | 
			
		||||
        "name" => "varchar primary key",
 | 
			
		||||
        "age" => "integer",
 | 
			
		||||
        "done" => "integer default 0",
 | 
			
		||||
        "notes" => "text",
 | 
			
		||||
      ];
 | 
			
		||||
 | 
			
		||||
      function getItemValues($item): ?array {
 | 
			
		||||
        return [
 | 
			
		||||
          "name" => $item["name"],
 | 
			
		||||
          "age" => $item["age"],
 | 
			
		||||
        ];
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $capacitor->reset();
 | 
			
		||||
    $nbModified = $capacitor->charge(["name" => "first", "age" => 5], function ($item, ?array $values, ?array $pvalues) {
 | 
			
		||||
      self::assertSame([
 | 
			
		||||
        "name" => "first", "age" => 5,
 | 
			
		||||
        "item" => $item,
 | 
			
		||||
      ], cl::select($values, ["name", "age", "item"]));
 | 
			
		||||
      return ["item" => null];
 | 
			
		||||
    });
 | 
			
		||||
    self::assertSame(1, $nbModified);
 | 
			
		||||
    sleep(1);
 | 
			
		||||
    # nb: on met des sleep() pour que la date de modification soit systématiquement différente
 | 
			
		||||
 | 
			
		||||
    $nbModified = $capacitor->charge(["name" => "first", "age" => 10], function ($item, ?array $values, ?array $pvalues) {
 | 
			
		||||
      self::assertSame([
 | 
			
		||||
        "name" => "first", "age" => 10,
 | 
			
		||||
        "item" => $item, "item__sum_" => "9181336dfca20c86313d6065d89aa2ad5070b0fc",
 | 
			
		||||
      ], cl::select($values, ["name", "age", "item", "item__sum_"]));
 | 
			
		||||
      self::assertSame([
 | 
			
		||||
        "name" => "first", "age" => 5,
 | 
			
		||||
        "item" => null, "item__sum_" => null,
 | 
			
		||||
      ], cl::select($pvalues, ["name", "age", "item", "item__sum_"]));
 | 
			
		||||
      return ["item" => null];
 | 
			
		||||
    });
 | 
			
		||||
    self::assertSame(1, $nbModified);
 | 
			
		||||
    sleep(1);
 | 
			
		||||
 | 
			
		||||
    # pas de modification ici
 | 
			
		||||
    $nbModified = $capacitor->charge(["name" => "first", "age" => 10], function ($item, ?array $values, ?array $pvalues) {
 | 
			
		||||
      self::assertSame([
 | 
			
		||||
        "name" => "first", "age" => 10,
 | 
			
		||||
        "item" => $item, "item__sum_" => "9181336dfca20c86313d6065d89aa2ad5070b0fc",
 | 
			
		||||
      ], cl::select($values, ["name", "age", "item", "item__sum_"]));
 | 
			
		||||
      self::assertSame([
 | 
			
		||||
        "name" => "first", "age" => 10,
 | 
			
		||||
        "item" => null, "item__sum_" => null,
 | 
			
		||||
      ], cl::select($pvalues, ["name", "age", "item", "item__sum_"]));
 | 
			
		||||
      return ["item" => null];
 | 
			
		||||
    });
 | 
			
		||||
    self::assertSame(0, $nbModified);
 | 
			
		||||
    sleep(1);
 | 
			
		||||
 | 
			
		||||
    $nbModified = $capacitor->charge(["name" => "first", "age" => 20], function ($item, ?array $values, ?array $pvalues) {
 | 
			
		||||
      self::assertSame([
 | 
			
		||||
        "name" => "first", "age" => 20,
 | 
			
		||||
        "item" => $item, "item__sum_" => "001b91982b4e0883b75428c0eb28573a5dc5f7a5",
 | 
			
		||||
      ], cl::select($values, ["name", "age", "item", "item__sum_"]));
 | 
			
		||||
      self::assertSame([
 | 
			
		||||
        "name" => "first", "age" => 10,
 | 
			
		||||
        "item" => null, "item__sum_" => null,
 | 
			
		||||
      ], cl::select($pvalues, ["name", "age", "item", "item__sum_"]));
 | 
			
		||||
      return ["item" => null];
 | 
			
		||||
    });
 | 
			
		||||
    self::assertSame(1, $nbModified);
 | 
			
		||||
    sleep(1);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										146
									
								
								tests/db/sqlite/SqliteTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								tests/db/sqlite/SqliteTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,146 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\db\sqlite;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
use nulib\tests\TestCase;
 | 
			
		||||
 | 
			
		||||
class SqliteTest extends TestCase {
 | 
			
		||||
  const CREATE_PERSON = "create table person(nom varchar, prenom varchar, age integer)";
 | 
			
		||||
  const INSERT_JEPHTE = "insert into person(nom, prenom, age) values ('clain', 'jephte', 50)";
 | 
			
		||||
  const INSERT_JEAN = "insert into person(nom, prenom, age) values ('payet', 'jean', 32)";
 | 
			
		||||
 | 
			
		||||
  function testMigration() {
 | 
			
		||||
    $sqlite = new Sqlite(":memory:", [
 | 
			
		||||
      "migrate" => [
 | 
			
		||||
        self::CREATE_PERSON,
 | 
			
		||||
        self::INSERT_JEPHTE,
 | 
			
		||||
      ],
 | 
			
		||||
    ]);
 | 
			
		||||
    self::assertSame("clain", $sqlite->get("select nom, age from person"));
 | 
			
		||||
    self::assertSame([
 | 
			
		||||
      "nom" => "clain",
 | 
			
		||||
      "age" => 50,
 | 
			
		||||
    ], $sqlite->get("select nom, age from person", null, true));
 | 
			
		||||
 | 
			
		||||
    $sqlite->exec(self::INSERT_JEAN);
 | 
			
		||||
    self::assertSame("payet", $sqlite->get("select nom, age from person where nom = 'payet'"));
 | 
			
		||||
    self::assertSame([
 | 
			
		||||
      "nom" => "payet",
 | 
			
		||||
      "age" => 32,
 | 
			
		||||
    ], $sqlite->get("select nom, age from person where nom = 'payet'", null, true));
 | 
			
		||||
 | 
			
		||||
    self::assertSame([
 | 
			
		||||
      ["key" => "0", "value" => self::CREATE_PERSON, "done" => 1],
 | 
			
		||||
      ["key" => "1", "value" => self::INSERT_JEPHTE, "done" => 1],
 | 
			
		||||
    ], iterator_to_array($sqlite->all("select key, value, done from _migration")));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testException() {
 | 
			
		||||
    $sqlite = new Sqlite(":memory:");
 | 
			
		||||
    self::assertException(Exception::class, [$sqlite, "exec"], "prout");
 | 
			
		||||
    self::assertException(SqliteException::class, [$sqlite, "exec"], ["prout"]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function assertInserted(Sqlite $sqlite, array $row, array $query): void {
 | 
			
		||||
    $sqlite->exec($query);
 | 
			
		||||
    self::assertSame($row, $sqlite->one("select * from mapping where i = :i", [
 | 
			
		||||
      "i" => $query["values"]["i"],
 | 
			
		||||
    ]));
 | 
			
		||||
  }
 | 
			
		||||
  function testInsert() {
 | 
			
		||||
    $sqlite = new Sqlite(":memory:", [
 | 
			
		||||
      "migrate" => "create table mapping (i integer, s varchar)",
 | 
			
		||||
    ]);
 | 
			
		||||
    $sqlite->exec(["insert into mapping", "values" => ["i" => 1, "s" => "un"]]);
 | 
			
		||||
    $sqlite->exec(["insert mapping", "values" => ["i" => 2, "s" => "deux"]]);
 | 
			
		||||
    $sqlite->exec(["insert into", "into" => "mapping", "values" => ["i" => 3, "s" => "trois"]]);
 | 
			
		||||
    $sqlite->exec(["insert", "into" => "mapping", "values" => ["i" => 4, "s" => "quatre"]]);
 | 
			
		||||
    $sqlite->exec(["insert into mapping(i)", "values" => ["i" => 5, "s" => "cinq"]]);
 | 
			
		||||
    $sqlite->exec(["insert into (i)", "into" => "mapping", "values" => ["i" => 6, "s" => "six"]]);
 | 
			
		||||
    $sqlite->exec(["insert into mapping(i) values ()", "values" => ["i" => 7, "s" => "sept"]]);
 | 
			
		||||
    $sqlite->exec(["insert into mapping(i) values (8)", "values" => ["i" => 42, "s" => "whatever"]]);
 | 
			
		||||
    $sqlite->exec(["insert into mapping(i, s) values (9, 'neuf')", "values" => ["i" => 43, "s" => "garbage"]]);
 | 
			
		||||
    $sqlite->exec(["insert into mapping", "cols" => ["i"], "values" => ["i" => 10, "s" => "dix"]]);
 | 
			
		||||
 | 
			
		||||
    self::assertSame([
 | 
			
		||||
      ["i" => 1, "s" => "un"],
 | 
			
		||||
      ["i" => 2, "s" => "deux"],
 | 
			
		||||
      ["i" => 3, "s" => "trois"],
 | 
			
		||||
      ["i" => 4, "s" => "quatre"],
 | 
			
		||||
      ["i" => 5, "s" => null/*"cinq"*/],
 | 
			
		||||
      ["i" => 6, "s" => null/*"six"*/],
 | 
			
		||||
      ["i" => 7, "s" => null/*"sept"*/],
 | 
			
		||||
      ["i" => 8, "s" => null/*"huit"*/],
 | 
			
		||||
      ["i" => 9, "s" => "neuf"],
 | 
			
		||||
      ["i" => 10, "s" => null/*"dix"*/],
 | 
			
		||||
    ], iterator_to_array($sqlite->all("select * from mapping")));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testSelect() {
 | 
			
		||||
    $sqlite = new Sqlite(":memory:", [
 | 
			
		||||
      "migrate" => "create table user (name varchar, amount integer)",
 | 
			
		||||
    ]);
 | 
			
		||||
    $sqlite->exec(["insert into user", "values" => ["name" => "jclain1", "amount" => 1]]);
 | 
			
		||||
    $sqlite->exec(["insert into user", "values" => ["name" => "jclain2", "amount" => 2]]);
 | 
			
		||||
    $sqlite->exec(["insert into user", "values" => ["name" => "jclain5", "amount" => 5]]);
 | 
			
		||||
    $sqlite->exec(["insert into user", "values" => ["name" => "fclain7", "amount" => 7]]);
 | 
			
		||||
    $sqlite->exec(["insert into user", "values" => ["name" => "fclain9", "amount" => 9]]);
 | 
			
		||||
    $sqlite->exec(["insert into user", "values" => ["name" => "fclain10", "amount" => 10]]);
 | 
			
		||||
    self::assertSame([
 | 
			
		||||
      "name" => "jclain1",
 | 
			
		||||
      "amount" => 1,
 | 
			
		||||
    ], $sqlite->one("select * from user where name = 'jclain1'"));
 | 
			
		||||
    self::assertSame([
 | 
			
		||||
      "name" => "jclain1",
 | 
			
		||||
      "amount" => 1,
 | 
			
		||||
    ], $sqlite->one(["select * from user where name = 'jclain1'"]));
 | 
			
		||||
    self::assertSame([
 | 
			
		||||
      "name" => "jclain1",
 | 
			
		||||
      "amount" => 1,
 | 
			
		||||
    ], $sqlite->one(["select from user where name = 'jclain1'"]));
 | 
			
		||||
    self::assertSame([
 | 
			
		||||
      "name" => "jclain1",
 | 
			
		||||
      "amount" => 1,
 | 
			
		||||
    ], $sqlite->one(["select from user where", "where" => ["name = 'jclain1'"]]));
 | 
			
		||||
    self::assertSame([
 | 
			
		||||
      "name" => "jclain1",
 | 
			
		||||
      "amount" => 1,
 | 
			
		||||
    ], $sqlite->one(["select from user", "where" => ["name = 'jclain1'"]]));
 | 
			
		||||
    self::assertSame([
 | 
			
		||||
      "name" => "jclain1",
 | 
			
		||||
      "amount" => 1,
 | 
			
		||||
    ], $sqlite->one(["select", "from" => "user", "where" => ["name = 'jclain1'"]]));
 | 
			
		||||
    self::assertSame([
 | 
			
		||||
      "name" => "jclain1",
 | 
			
		||||
      "amount" => 1,
 | 
			
		||||
    ], $sqlite->one(["select", "from" => "user", "where" => ["name" => "jclain1"]]));
 | 
			
		||||
    self::assertSame([
 | 
			
		||||
      "name" => "jclain1",
 | 
			
		||||
    ], $sqlite->one(["select name", "from" => "user", "where" => ["name" => "jclain1"]]));
 | 
			
		||||
    self::assertSame([
 | 
			
		||||
      "name" => "jclain1",
 | 
			
		||||
    ], $sqlite->one(["select", "cols" => "name", "from" => "user", "where" => ["name" => "jclain1"]]));
 | 
			
		||||
    self::assertSame([
 | 
			
		||||
      "name" => "jclain1",
 | 
			
		||||
    ], $sqlite->one(["select", "cols" => ["name"], "from" => "user", "where" => ["name" => "jclain1"]]));
 | 
			
		||||
    self::assertSame([
 | 
			
		||||
      "plouf" => "jclain1",
 | 
			
		||||
    ], $sqlite->one(["select", "cols" => ["plouf" => "name"], "from" => "user", "where" => ["name" => "jclain1"]]));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testSelectGroupBy() {
 | 
			
		||||
    $sqlite = new Sqlite(":memory:", [
 | 
			
		||||
      "migrate" => "create table user (name varchar, amount integer)",
 | 
			
		||||
    ]);
 | 
			
		||||
    $sqlite->exec(["insert into user", "values" => ["name" => "jclain1", "amount" => 1]]);
 | 
			
		||||
    $sqlite->exec(["insert into user", "values" => ["name" => "jclain2", "amount" => 1]]);
 | 
			
		||||
    $sqlite->exec(["insert into user", "values" => ["name" => "jclain5", "amount" => 2]]);
 | 
			
		||||
    $sqlite->exec(["insert into user", "values" => ["name" => "fclain7", "amount" => 2]]);
 | 
			
		||||
    $sqlite->exec(["insert into user", "values" => ["name" => "fclain9", "amount" => 2]]);
 | 
			
		||||
    $sqlite->exec(["insert into user", "values" => ["name" => "fclain10", "amount" => 3]]);
 | 
			
		||||
 | 
			
		||||
    self::assertSame([
 | 
			
		||||
      ["count" => 2],
 | 
			
		||||
    ], iterator_to_array($sqlite->all(["select count(name) as count from user", "group by" => ["amount"], "having" => ["count(name) = 2"]])));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										125
									
								
								tests/db/sqlite/_queryTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								tests/db/sqlite/_queryTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,125 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\db\sqlite;
 | 
			
		||||
 | 
			
		||||
use PHPUnit\Framework\TestCase;
 | 
			
		||||
 | 
			
		||||
class _queryTest extends TestCase {
 | 
			
		||||
  function testParseConds(): void {
 | 
			
		||||
    $sql = $params = null;
 | 
			
		||||
    _query_base::parse_conds(null, $sql, $params);
 | 
			
		||||
    self::assertNull($sql);
 | 
			
		||||
    self::assertNull($params);
 | 
			
		||||
 | 
			
		||||
    $sql = $params = null;
 | 
			
		||||
    _query_base::parse_conds([], $sql, $params);
 | 
			
		||||
    self::assertNull($sql);
 | 
			
		||||
    self::assertNull($params);
 | 
			
		||||
 | 
			
		||||
    $sql = $params = null;
 | 
			
		||||
    _query_base::parse_conds(["col" => null], $sql, $params);
 | 
			
		||||
    self::assertSame(["col is null"], $sql);
 | 
			
		||||
    self::assertNull($params);
 | 
			
		||||
 | 
			
		||||
    $sql = $params = null;
 | 
			
		||||
    _query_base::parse_conds(["col = 'value'"], $sql, $params);
 | 
			
		||||
    self::assertSame(["col = 'value'"], $sql);
 | 
			
		||||
    self::assertNull($params);
 | 
			
		||||
 | 
			
		||||
    $sql = $params = null;
 | 
			
		||||
    _query_base::parse_conds([["col = 'value'"]], $sql, $params);
 | 
			
		||||
    self::assertSame(["col = 'value'"], $sql);
 | 
			
		||||
    self::assertNull($params);
 | 
			
		||||
 | 
			
		||||
    $sql = $params = null;
 | 
			
		||||
    _query_base::parse_conds(["int" => 42, "string" => "value"], $sql, $params);
 | 
			
		||||
    self::assertSame(["(int = :int and string = :string)"], $sql);
 | 
			
		||||
    self::assertSame(["int" => 42, "string" => "value"], $params);
 | 
			
		||||
 | 
			
		||||
    $sql = $params = null;
 | 
			
		||||
    _query_base::parse_conds(["or", "int" => 42, "string" => "value"], $sql, $params);
 | 
			
		||||
    self::assertSame(["(int = :int or string = :string)"], $sql);
 | 
			
		||||
    self::assertSame(["int" => 42, "string" => "value"], $params);
 | 
			
		||||
 | 
			
		||||
    $sql = $params = null;
 | 
			
		||||
    _query_base::parse_conds([["int" => 42, "string" => "value"], ["int" => 24, "string" => "eulav"]], $sql, $params);
 | 
			
		||||
    self::assertSame(["((int = :int and string = :string) and (int = :int2 and string = :string2))"], $sql);
 | 
			
		||||
    self::assertSame(["int" => 42, "string" => "value", "int2" => 24, "string2" => "eulav"], $params);
 | 
			
		||||
 | 
			
		||||
    $sql = $params = null;
 | 
			
		||||
    _query_base::parse_conds(["int" => ["is null"], "string" => ["<>", "value"]], $sql, $params);
 | 
			
		||||
    self::assertSame(["(int is null and string <> :string)"], $sql);
 | 
			
		||||
    self::assertSame(["string" => "value"], $params);
 | 
			
		||||
 | 
			
		||||
    $sql = $params = null;
 | 
			
		||||
    _query_base::parse_conds(["col" => ["between", "lower", "upper"]], $sql, $params);
 | 
			
		||||
    self::assertSame(["col between :col and :col2"], $sql);
 | 
			
		||||
    self::assertSame(["col" => "lower", "col2" => "upper"], $params);
 | 
			
		||||
 | 
			
		||||
    $sql = $params = null;
 | 
			
		||||
    _query_base::parse_conds(["col" => ["in", "one"]], $sql, $params);
 | 
			
		||||
    self::assertSame(["col in (:col)"], $sql);
 | 
			
		||||
    self::assertSame(["col" => "one"], $params);
 | 
			
		||||
 | 
			
		||||
    $sql = $params = null;
 | 
			
		||||
    _query_base::parse_conds(["col" => ["in", ["one", "two"]]], $sql, $params);
 | 
			
		||||
    self::assertSame(["col in (:col, :col2)"], $sql);
 | 
			
		||||
    self::assertSame(["col" => "one", "col2" => "two"], $params);
 | 
			
		||||
 | 
			
		||||
    $sql = $params = null;
 | 
			
		||||
    _query_base::parse_conds(["col" => ["=", ["one", "two"]]], $sql, $params);
 | 
			
		||||
    self::assertSame(["col = :col and col = :col2"], $sql);
 | 
			
		||||
    self::assertSame(["col" => "one", "col2" => "two"], $params);
 | 
			
		||||
 | 
			
		||||
    $sql = $params = null;
 | 
			
		||||
    _query_base::parse_conds(["or", "col" => ["=", ["one", "two"]]], $sql, $params);
 | 
			
		||||
    self::assertSame(["col = :col or col = :col2"], $sql);
 | 
			
		||||
    self::assertSame(["col" => "one", "col2" => "two"], $params);
 | 
			
		||||
 | 
			
		||||
    $sql = $params = null;
 | 
			
		||||
    _query_base::parse_conds(["col" => ["<>", ["one", "two"]]], $sql, $params);
 | 
			
		||||
    self::assertSame(["col <> :col and col <> :col2"], $sql);
 | 
			
		||||
    self::assertSame(["col" => "one", "col2" => "two"], $params);
 | 
			
		||||
 | 
			
		||||
    $sql = $params = null;
 | 
			
		||||
    _query_base::parse_conds(["or", "col" => ["<>", ["one", "two"]]], $sql, $params);
 | 
			
		||||
    self::assertSame(["col <> :col or col <> :col2"], $sql);
 | 
			
		||||
    self::assertSame(["col" => "one", "col2" => "two"], $params);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testParseValues(): void {
 | 
			
		||||
    $sql = $params = null;
 | 
			
		||||
    _query_base::parse_set_values(null, $sql, $params);
 | 
			
		||||
    self::assertNull($sql);
 | 
			
		||||
    self::assertNull($params);
 | 
			
		||||
 | 
			
		||||
    $sql = $params = null;
 | 
			
		||||
    _query_base::parse_set_values([], $sql, $params);
 | 
			
		||||
    self::assertNull($sql);
 | 
			
		||||
    self::assertNull($params);
 | 
			
		||||
 | 
			
		||||
    $sql = $params = null;
 | 
			
		||||
    _query_base::parse_set_values(["col = 'value'"], $sql, $params);
 | 
			
		||||
    self::assertSame(["col = 'value'"], $sql);
 | 
			
		||||
    self::assertNull($params);
 | 
			
		||||
 | 
			
		||||
    $sql = $params = null;
 | 
			
		||||
    _query_base::parse_set_values([["col = 'value'"]], $sql, $params);
 | 
			
		||||
    self::assertSame(["col = 'value'"], $sql);
 | 
			
		||||
    self::assertNull($params);
 | 
			
		||||
 | 
			
		||||
    $sql = $params = null;
 | 
			
		||||
    _query_base::parse_set_values(["int" => 42, "string" => "value"], $sql, $params);
 | 
			
		||||
    self::assertSame(["int = :int", "string = :string"], $sql);
 | 
			
		||||
    self::assertSame(["int" => 42, "string" => "value"], $params);
 | 
			
		||||
 | 
			
		||||
    $sql = $params = null;
 | 
			
		||||
    _query_base::parse_set_values(["int" => 42, "string" => "value"], $sql, $params);
 | 
			
		||||
    self::assertSame(["int = :int", "string = :string"], $sql);
 | 
			
		||||
    self::assertSame(["int" => 42, "string" => "value"], $params);
 | 
			
		||||
 | 
			
		||||
    $sql = $params = null;
 | 
			
		||||
    _query_base::parse_set_values([["int" => 42, "string" => "value"], ["int" => 24, "string" => "eulav"]], $sql, $params);
 | 
			
		||||
    self::assertSame(["int = :int", "string = :string", "int = :int2", "string = :string2"], $sql);
 | 
			
		||||
    self::assertSame(["int" => 42, "string" => "value", "int2" => 24, "string2" => "eulav"], $params);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										63
									
								
								tests/file/base/FileReaderTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								tests/file/base/FileReaderTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,63 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\file\base;
 | 
			
		||||
 | 
			
		||||
use nur\sery\file\FileReader;
 | 
			
		||||
use PHPUnit\Framework\TestCase;
 | 
			
		||||
 | 
			
		||||
class FileReaderTest extends TestCase {
 | 
			
		||||
  function testIgnoreBom() {
 | 
			
		||||
    # la lecture avec et sans BOM doit être identique
 | 
			
		||||
    ## sans BOM
 | 
			
		||||
    $reader = new FileReader(__DIR__ . '/impl/sans_bom.txt');
 | 
			
		||||
    self::assertSame("0123456789", $reader->fread(10));
 | 
			
		||||
    self::assertSame(10, $reader->ftell());
 | 
			
		||||
    $reader->seek(30);
 | 
			
		||||
    self::assertSame("abcdefghij", $reader->fread(10));
 | 
			
		||||
    self::assertSame(40, $reader->ftell());
 | 
			
		||||
    $reader->seek(10);
 | 
			
		||||
    self::assertSame("ABCDEFGHIJ", $reader->fread(10));
 | 
			
		||||
    self::assertSame(20, $reader->ftell());
 | 
			
		||||
    $reader->seek(40);
 | 
			
		||||
    self::assertSame("0123456789\n", $reader->getContents());
 | 
			
		||||
    $reader->close();
 | 
			
		||||
    ## avec BOM
 | 
			
		||||
    $reader = new FileReader(__DIR__ . '/impl/avec_bom.txt');
 | 
			
		||||
    self::assertSame("0123456789", $reader->fread(10));
 | 
			
		||||
    self::assertSame(10, $reader->ftell());
 | 
			
		||||
    $reader->seek(30);
 | 
			
		||||
    self::assertSame("abcdefghij", $reader->fread(10));
 | 
			
		||||
    self::assertSame(40, $reader->ftell());
 | 
			
		||||
    $reader->seek(10);
 | 
			
		||||
    self::assertSame("ABCDEFGHIJ", $reader->fread(10));
 | 
			
		||||
    self::assertSame(20, $reader->ftell());
 | 
			
		||||
    $reader->seek(40);
 | 
			
		||||
    self::assertSame("0123456789\n", $reader->getContents());
 | 
			
		||||
    $reader->close();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testCsvAutoParams() {
 | 
			
		||||
    $reader = new FileReader(__DIR__ . '/impl/msexcel.csv');
 | 
			
		||||
    self::assertSame(["nom", "prenom", "age"], $reader->fgetcsv());
 | 
			
		||||
    self::assertSame(["clain", "jephte", "50"], $reader->fgetcsv());
 | 
			
		||||
    self::assertNull($reader->fgetcsv());
 | 
			
		||||
    $reader->close();
 | 
			
		||||
 | 
			
		||||
    $reader = new FileReader(__DIR__ . '/impl/ooffice.csv');
 | 
			
		||||
    self::assertSame(["nom", "prenom", "age"], $reader->fgetcsv());
 | 
			
		||||
    self::assertSame(["clain", "jephte", "50"], $reader->fgetcsv());
 | 
			
		||||
    self::assertNull($reader->fgetcsv());
 | 
			
		||||
    $reader->close();
 | 
			
		||||
 | 
			
		||||
    $reader = new FileReader(__DIR__ . '/impl/weird.tsv');
 | 
			
		||||
    self::assertSame(["nom", "prenom", "age"], $reader->fgetcsv());
 | 
			
		||||
    self::assertSame(["clain", "jephte", "50"], $reader->fgetcsv());
 | 
			
		||||
    self::assertNull($reader->fgetcsv());
 | 
			
		||||
    $reader->close();
 | 
			
		||||
 | 
			
		||||
    $reader = new FileReader(__DIR__ . '/impl/avec_bom.csv');
 | 
			
		||||
    self::assertSame(["nom", "prenom", "age"], $reader->fgetcsv());
 | 
			
		||||
    self::assertSame(["clain", "jephte", "50"], $reader->fgetcsv());
 | 
			
		||||
    self::assertNull($reader->fgetcsv());
 | 
			
		||||
    $reader->close();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								tests/file/base/impl/avec_bom.csv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests/file/base/impl/avec_bom.csv
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
			
		||||
nom,prenom,age
 | 
			
		||||
clain,jephte,50
 | 
			
		||||
		
		
			
  | 
							
								
								
									
										1
									
								
								tests/file/base/impl/avec_bom.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/file/base/impl/avec_bom.txt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
0123456789ABCDEFGHIJ0123456789abcdefghij0123456789
 | 
			
		||||
							
								
								
									
										2
									
								
								tests/file/base/impl/msexcel.csv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests/file/base/impl/msexcel.csv
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
			
		||||
nom;prenom;age
 | 
			
		||||
clain;jephte;50
 | 
			
		||||
		
		
			
  | 
							
								
								
									
										2
									
								
								tests/file/base/impl/ooffice.csv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests/file/base/impl/ooffice.csv
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
			
		||||
nom,prenom,age
 | 
			
		||||
clain,jephte,50
 | 
			
		||||
		
		
			
  | 
							
								
								
									
										1
									
								
								tests/file/base/impl/sans_bom.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/file/base/impl/sans_bom.txt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
0123456789ABCDEFGHIJ0123456789abcdefghij0123456789
 | 
			
		||||
							
								
								
									
										2
									
								
								tests/file/base/impl/weird.tsv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests/file/base/impl/weird.tsv
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
			
		||||
nom	prenom	age
 | 
			
		||||
clain	jephte	50
 | 
			
		||||
		
		
			
  | 
@ -1,7 +1,8 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\php\access;
 | 
			
		||||
namespace nur\sery\php\access;
 | 
			
		||||
 | 
			
		||||
use nulib\tests\TestCase;
 | 
			
		||||
use nur\sery\wip\php\access\KeyAccess;
 | 
			
		||||
use stdClass;
 | 
			
		||||
 | 
			
		||||
class KeyAccessTest extends TestCase {
 | 
			
		||||
@ -1,7 +1,8 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\php\access;
 | 
			
		||||
namespace nur\sery\php\access;
 | 
			
		||||
 | 
			
		||||
use nulib\tests\TestCase;
 | 
			
		||||
use nur\sery\wip\php\access\ValueAccess;
 | 
			
		||||
use stdClass;
 | 
			
		||||
 | 
			
		||||
class ValueAccessTest extends TestCase {
 | 
			
		||||
@ -1,8 +1,7 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\php\content;
 | 
			
		||||
namespace nur\sery\php\content;
 | 
			
		||||
 | 
			
		||||
use nulib\php\content\c;
 | 
			
		||||
use nur\sery\wip\php\content\impl\html;
 | 
			
		||||
use nur\sery\php\content\impl\html;
 | 
			
		||||
use nur\sery\wip\web\content\v;
 | 
			
		||||
use PHPUnit\Framework\TestCase;
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\php\content\impl;
 | 
			
		||||
namespace nur\sery\php\content\impl;
 | 
			
		||||
 | 
			
		||||
use nulib\php\content\IContent;
 | 
			
		||||
use nur\sery\php\content\IContent;
 | 
			
		||||
 | 
			
		||||
class AContent implements IContent {
 | 
			
		||||
  function getContent(): iterable {
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\php\content\impl;
 | 
			
		||||
namespace nur\sery\php\content\impl;
 | 
			
		||||
 | 
			
		||||
use nulib\php\content\IPrintable;
 | 
			
		||||
use nur\sery\php\content\IPrintable;
 | 
			
		||||
 | 
			
		||||
class APrintable implements IPrintable {
 | 
			
		||||
  function print(): void {
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\php\content\impl;
 | 
			
		||||
namespace nur\sery\php\content\impl;
 | 
			
		||||
 | 
			
		||||
use nulib\php\content\c;
 | 
			
		||||
use nulib\php\content\IContent;
 | 
			
		||||
use nur\sery\php\content\c;
 | 
			
		||||
use nur\sery\php\content\IContent;
 | 
			
		||||
 | 
			
		||||
class ATag implements IContent {
 | 
			
		||||
  function __construct(string $tag, $content=null) {
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\php\content\impl;
 | 
			
		||||
namespace nur\sery\php\content\impl;
 | 
			
		||||
 | 
			
		||||
class html {
 | 
			
		||||
  const H1 = [self::class, "h1"];
 | 
			
		||||
							
								
								
									
										1167
									
								
								tests/php/funcTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1167
									
								
								tests/php/funcTest.php
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										292
									
								
								tests/php/nur_funcTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										292
									
								
								tests/php/nur_funcTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,292 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
  function func36(): int { return 36; }
 | 
			
		||||
  
 | 
			
		||||
  function func_m1($a): array { return [$a]; }
 | 
			
		||||
  function func_o1($b=9): array { return [$b]; }
 | 
			
		||||
  function func_v(...$c): array { return [...$c]; }
 | 
			
		||||
  function func_m1o1($a, $b=9): array { return [$a, $b]; }
 | 
			
		||||
  function func_m1v($a, ...$c): array { return [$a, ...$c]; }
 | 
			
		||||
  function func_m1o1v($a, $b=9, ...$c): array { return [$a, $b, ...$c]; }
 | 
			
		||||
  function func_o1v($b=9, ...$c): array { return [$b, ...$c]; }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace nur\sery\php {
 | 
			
		||||
 | 
			
		||||
  use nulib\tests\TestCase;
 | 
			
		||||
 | 
			
		||||
  class nur_funcTest extends TestCase {
 | 
			
		||||
    function testIs_static() {
 | 
			
		||||
      self::assertFalse(nur_func::is_static(null));
 | 
			
		||||
      self::assertFalse(nur_func::is_static(""));
 | 
			
		||||
      self::assertFalse(nur_func::is_static("::"));
 | 
			
		||||
      self::assertFalse(nur_func::is_static("xxx::"));
 | 
			
		||||
      self::assertFalse(nur_func::is_static([]));
 | 
			
		||||
      self::assertFalse(nur_func::is_static([""]));
 | 
			
		||||
      self::assertFalse(nur_func::is_static([null, ""]));
 | 
			
		||||
      self::assertFalse(nur_func::is_static(["xxx", ""]));
 | 
			
		||||
 | 
			
		||||
      self::assertTrue(nur_func::is_static("::xxx"));
 | 
			
		||||
      self::assertTrue(nur_func::is_static(["xxx"]));
 | 
			
		||||
      self::assertTrue(nur_func::is_static([null, "yyy"]));
 | 
			
		||||
      self::assertTrue(nur_func::is_static(["xxx", "yyy"]));
 | 
			
		||||
      self::assertTrue(nur_func::is_static([null, "yyy", "aaa"]));
 | 
			
		||||
      self::assertTrue(nur_func::is_static(["xxx", "yyy", "aaa"]));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    function testFix_static() {
 | 
			
		||||
      $class = "class";
 | 
			
		||||
      $func = "::xxx";
 | 
			
		||||
        nur_func::fix_static($func, $class);
 | 
			
		||||
        self::assertSame("class::xxx", $func);
 | 
			
		||||
      $func = ["xxx"];
 | 
			
		||||
        nur_func::fix_static($func, $class);
 | 
			
		||||
        self::assertSame(["class", "xxx"], $func);
 | 
			
		||||
      $func = [null, "yyy"];
 | 
			
		||||
        nur_func::fix_static($func, $class);
 | 
			
		||||
        self::assertSame(["class", "yyy"], $func);
 | 
			
		||||
      $func = ["xxx", "yyy"];
 | 
			
		||||
        nur_func::fix_static($func, $class);
 | 
			
		||||
        self::assertSame(["xxx", "yyy"], $func);
 | 
			
		||||
      $func = [null, "yyy", "aaa"];
 | 
			
		||||
        nur_func::fix_static($func, $class);
 | 
			
		||||
        self::assertSame(["class", "yyy", "aaa"], $func);
 | 
			
		||||
      $func = ["xxx", "yyy", "aaa"];
 | 
			
		||||
        nur_func::fix_static($func, $class);
 | 
			
		||||
        self::assertSame(["xxx", "yyy", "aaa"], $func);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testIs_method() {
 | 
			
		||||
      self::assertFalse(nur_func::is_method(null));
 | 
			
		||||
      self::assertFalse(nur_func::is_method(""));
 | 
			
		||||
      self::assertFalse(nur_func::is_method("->"));
 | 
			
		||||
      self::assertFalse(nur_func::is_method([]));
 | 
			
		||||
      self::assertFalse(nur_func::is_method([""]));
 | 
			
		||||
      self::assertFalse(nur_func::is_method([null, "->"]));
 | 
			
		||||
      self::assertFalse(nur_func::is_method(["xxx", "->"]));
 | 
			
		||||
 | 
			
		||||
      self::assertTrue(nur_func::is_method("->xxx"));
 | 
			
		||||
      self::assertTrue(nur_func::is_method(["->xxx"]));
 | 
			
		||||
      self::assertTrue(nur_func::is_method([null, "->yyy"]));
 | 
			
		||||
      self::assertTrue(nur_func::is_method(["xxx", "->yyy"]));
 | 
			
		||||
      self::assertTrue(nur_func::is_method([null, "->yyy", "aaa"]));
 | 
			
		||||
      self::assertTrue(nur_func::is_method(["xxx", "->yyy", "aaa"]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testFix_method() {
 | 
			
		||||
      $object = new \stdClass();
 | 
			
		||||
      $func= "->xxx";
 | 
			
		||||
        nur_func::fix_method($func, $object);
 | 
			
		||||
        self::assertSame([$object, "xxx"], $func);
 | 
			
		||||
      $func= ["->xxx"];
 | 
			
		||||
        nur_func::fix_method($func, $object);
 | 
			
		||||
        self::assertSame([$object, "xxx"], $func);
 | 
			
		||||
      $func= [null, "->yyy"];
 | 
			
		||||
        nur_func::fix_method($func, $object);
 | 
			
		||||
        self::assertSame([$object, "yyy"], $func);
 | 
			
		||||
      $func= ["xxx", "->yyy"];
 | 
			
		||||
        nur_func::fix_method($func, $object);
 | 
			
		||||
        self::assertSame([$object, "yyy"], $func);
 | 
			
		||||
      $func= [null, "->yyy", "aaa"];
 | 
			
		||||
        nur_func::fix_method($func, $object);
 | 
			
		||||
        self::assertSame([$object, "yyy", "aaa"], $func);
 | 
			
		||||
      $func= ["xxx", "->yyy", "aaa"];
 | 
			
		||||
        nur_func::fix_method($func, $object);
 | 
			
		||||
        self::assertSame([$object, "yyy", "aaa"], $func);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testCall() {
 | 
			
		||||
      self::assertSame(36, nur_func::call("func36"));
 | 
			
		||||
      self::assertSame(12, nur_func::call(TC::class."::method"));
 | 
			
		||||
      self::assertSame(12, nur_func::call([TC::class, "method"]));
 | 
			
		||||
      $closure = function() {
 | 
			
		||||
        return 21;
 | 
			
		||||
      };
 | 
			
		||||
      self::assertSame(21, nur_func::call($closure));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function test_prepare_fill() {
 | 
			
		||||
      # vérifier que les arguments sont bien remplis, en fonction du fait qu'ils
 | 
			
		||||
      # soient obligatoires, facultatifs ou variadiques
 | 
			
		||||
      
 | 
			
		||||
      # m1
 | 
			
		||||
      self::assertSame([null], nur_func::call("func_m1"));
 | 
			
		||||
      self::assertSame([null], nur_func::call("func_m1", null));
 | 
			
		||||
      self::assertSame([null], nur_func::call("func_m1", null, null));
 | 
			
		||||
      self::assertSame([null], nur_func::call("func_m1", null, null, null));
 | 
			
		||||
      self::assertSame([null], nur_func::call("func_m1", null, null, null, null));
 | 
			
		||||
      self::assertSame([1], nur_func::call("func_m1", 1));
 | 
			
		||||
      self::assertSame([1], nur_func::call("func_m1", 1, 2));
 | 
			
		||||
      self::assertSame([1], nur_func::call("func_m1", 1, 2, 3));
 | 
			
		||||
      self::assertSame([1], nur_func::call("func_m1", 1, 2, 3, 4));
 | 
			
		||||
      
 | 
			
		||||
      # o1
 | 
			
		||||
      self::assertSame([9], nur_func::call("func_o1"));
 | 
			
		||||
      self::assertSame([null], nur_func::call("func_o1", null));
 | 
			
		||||
      self::assertSame([null], nur_func::call("func_o1", null, null));
 | 
			
		||||
      self::assertSame([null], nur_func::call("func_o1", null, null, null));
 | 
			
		||||
      self::assertSame([null], nur_func::call("func_o1", null, null, null, null));
 | 
			
		||||
      self::assertSame([1], nur_func::call("func_o1", 1));
 | 
			
		||||
      self::assertSame([1], nur_func::call("func_o1", 1, 2));
 | 
			
		||||
      self::assertSame([1], nur_func::call("func_o1", 1, 2, 3));
 | 
			
		||||
      self::assertSame([1], nur_func::call("func_o1", 1, 2, 3, 4));
 | 
			
		||||
      
 | 
			
		||||
      # v
 | 
			
		||||
      self::assertSame([], nur_func::call("func_v"));
 | 
			
		||||
      self::assertSame([null], nur_func::call("func_v", null));
 | 
			
		||||
      self::assertSame([null, null], nur_func::call("func_v", null, null));
 | 
			
		||||
      self::assertSame([null, null, null], nur_func::call("func_v", null, null, null));
 | 
			
		||||
      self::assertSame([null, null, null, null], nur_func::call("func_v", null, null, null, null));
 | 
			
		||||
      self::assertSame([1], nur_func::call("func_v", 1));
 | 
			
		||||
      self::assertSame([1, 2], nur_func::call("func_v", 1, 2));
 | 
			
		||||
      self::assertSame([1, 2, 3], nur_func::call("func_v", 1, 2, 3));
 | 
			
		||||
      self::assertSame([1, 2, 3, 4], nur_func::call("func_v", 1, 2, 3, 4));
 | 
			
		||||
      
 | 
			
		||||
      # m1o1
 | 
			
		||||
      self::assertSame([null, 9], nur_func::call("func_m1o1"));
 | 
			
		||||
      self::assertSame([null, 9], nur_func::call("func_m1o1", null));
 | 
			
		||||
      self::assertSame([null, null], nur_func::call("func_m1o1", null, null));
 | 
			
		||||
      self::assertSame([null, null], nur_func::call("func_m1o1", null, null, null));
 | 
			
		||||
      self::assertSame([null, null], nur_func::call("func_m1o1", null, null, null, null));
 | 
			
		||||
      self::assertSame([1, 9], nur_func::call("func_m1o1", 1));
 | 
			
		||||
      self::assertSame([1, 2], nur_func::call("func_m1o1", 1, 2));
 | 
			
		||||
      self::assertSame([1, 2], nur_func::call("func_m1o1", 1, 2, 3));
 | 
			
		||||
      self::assertSame([1, 2], nur_func::call("func_m1o1", 1, 2, 3, 4));
 | 
			
		||||
      
 | 
			
		||||
      # m1v
 | 
			
		||||
      self::assertSame([null], nur_func::call("func_m1v"));
 | 
			
		||||
      self::assertSame([null], nur_func::call("func_m1v", null));
 | 
			
		||||
      self::assertSame([null, null], nur_func::call("func_m1v", null, null));
 | 
			
		||||
      self::assertSame([null, null, null], nur_func::call("func_m1v", null, null, null));
 | 
			
		||||
      self::assertSame([null, null, null, null], nur_func::call("func_m1v", null, null, null, null));
 | 
			
		||||
      self::assertSame([1], nur_func::call("func_m1v", 1));
 | 
			
		||||
      self::assertSame([1, 2], nur_func::call("func_m1v", 1, 2));
 | 
			
		||||
      self::assertSame([1, 2, 3], nur_func::call("func_m1v", 1, 2, 3));
 | 
			
		||||
      self::assertSame([1, 2, 3, 4], nur_func::call("func_m1v", 1, 2, 3, 4));
 | 
			
		||||
      
 | 
			
		||||
      # m1o1v
 | 
			
		||||
      self::assertSame([null, 9], nur_func::call("func_m1o1v"));
 | 
			
		||||
      self::assertSame([null, 9], nur_func::call("func_m1o1v", null));
 | 
			
		||||
      self::assertSame([null, null], nur_func::call("func_m1o1v", null, null));
 | 
			
		||||
      self::assertSame([null, null, null], nur_func::call("func_m1o1v", null, null, null));
 | 
			
		||||
      self::assertSame([null, null, null, null], nur_func::call("func_m1o1v", null, null, null, null));
 | 
			
		||||
      self::assertSame([1, 9], nur_func::call("func_m1o1v", 1));
 | 
			
		||||
      self::assertSame([1, 2], nur_func::call("func_m1o1v", 1, 2));
 | 
			
		||||
      self::assertSame([1, 2, 3], nur_func::call("func_m1o1v", 1, 2, 3));
 | 
			
		||||
      self::assertSame([1, 2, 3, 4], nur_func::call("func_m1o1v", 1, 2, 3, 4));
 | 
			
		||||
      
 | 
			
		||||
      # o1v
 | 
			
		||||
      self::assertSame([9], nur_func::call("func_o1v"));
 | 
			
		||||
      self::assertSame([null], nur_func::call("func_o1v", null));
 | 
			
		||||
      self::assertSame([null, null], nur_func::call("func_o1v", null, null));
 | 
			
		||||
      self::assertSame([null, null, null], nur_func::call("func_o1v", null, null, null));
 | 
			
		||||
      self::assertSame([null, null, null, null], nur_func::call("func_o1v", null, null, null, null));
 | 
			
		||||
      self::assertSame([1], nur_func::call("func_o1v", 1));
 | 
			
		||||
      self::assertSame([1, 2], nur_func::call("func_o1v", 1, 2));
 | 
			
		||||
      self::assertSame([1, 2, 3], nur_func::call("func_o1v", 1, 2, 3));
 | 
			
		||||
      self::assertSame([1, 2, 3, 4], nur_func::call("func_o1v", 1, 2, 3, 4));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testCall_all() {
 | 
			
		||||
      $c1 = new C1();
 | 
			
		||||
      $c2 = new C2();
 | 
			
		||||
      $c3 = new C3();
 | 
			
		||||
 | 
			
		||||
      self::assertSameValues([11, 12], nur_func::call_all(C1::class));
 | 
			
		||||
      self::assertSameValues([11, 12, 21, 22], nur_func::call_all($c1));
 | 
			
		||||
      self::assertSameValues([13, 11, 12], nur_func::call_all(C2::class));
 | 
			
		||||
      self::assertSameValues([13, 23, 11, 12, 21, 22], nur_func::call_all($c2));
 | 
			
		||||
      self::assertSameValues([111, 13, 12], nur_func::call_all(C3::class));
 | 
			
		||||
      self::assertSameValues([111, 121, 13, 23, 12, 22], nur_func::call_all($c3));
 | 
			
		||||
 | 
			
		||||
      $options = "conf";
 | 
			
		||||
      self::assertSameValues([11], nur_func::call_all(C1::class, $options));
 | 
			
		||||
      self::assertSameValues([11, 21], nur_func::call_all($c1, $options));
 | 
			
		||||
      self::assertSameValues([11], nur_func::call_all(C2::class, $options));
 | 
			
		||||
      self::assertSameValues([11, 21], nur_func::call_all($c2, $options));
 | 
			
		||||
      self::assertSameValues([111], nur_func::call_all(C3::class, $options));
 | 
			
		||||
      self::assertSameValues([111, 121], nur_func::call_all($c3, $options));
 | 
			
		||||
 | 
			
		||||
      $options = ["prefix" => "conf"];
 | 
			
		||||
      self::assertSameValues([11], nur_func::call_all(C1::class, $options));
 | 
			
		||||
      self::assertSameValues([11, 21], nur_func::call_all($c1, $options));
 | 
			
		||||
      self::assertSameValues([11], nur_func::call_all(C2::class, $options));
 | 
			
		||||
      self::assertSameValues([11, 21], nur_func::call_all($c2, $options));
 | 
			
		||||
      self::assertSameValues([111], nur_func::call_all(C3::class, $options));
 | 
			
		||||
      self::assertSameValues([111, 121], nur_func::call_all($c3, $options));
 | 
			
		||||
 | 
			
		||||
      self::assertSameValues([11, 12], nur_func::call_all($c1, ["include" => "x"]));
 | 
			
		||||
      self::assertSameValues([11, 21], nur_func::call_all($c1, ["include" => "y"]));
 | 
			
		||||
      self::assertSameValues([11, 12, 21], nur_func::call_all($c1, ["include" => ["x", "y"]]));
 | 
			
		||||
 | 
			
		||||
      self::assertSameValues([21, 22], nur_func::call_all($c1, ["exclude" => "x"]));
 | 
			
		||||
      self::assertSameValues([12, 22], nur_func::call_all($c1, ["exclude" => "y"]));
 | 
			
		||||
      self::assertSameValues([22], nur_func::call_all($c1, ["exclude" => ["x", "y"]]));
 | 
			
		||||
 | 
			
		||||
      self::assertSameValues([12], nur_func::call_all($c1, ["include" => "x", "exclude" => "y"]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testCons() {
 | 
			
		||||
      $obj1 = nur_func::cons(WoCons::class, 1, 2, 3);
 | 
			
		||||
      self::assertInstanceOf(WoCons::class, $obj1);
 | 
			
		||||
 | 
			
		||||
      $obj2 = nur_func::cons(WithEmptyCons::class, 1, 2, 3);
 | 
			
		||||
      self::assertInstanceOf(WithEmptyCons::class, $obj2);
 | 
			
		||||
 | 
			
		||||
      $obj3 = nur_func::cons(WithCons::class, 1, 2, 3);
 | 
			
		||||
      self::assertInstanceOf(WithCons::class, $obj3);
 | 
			
		||||
      self::assertSame(1, $obj3->first);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  class WoCons {
 | 
			
		||||
  }
 | 
			
		||||
  class WithEmptyCons {
 | 
			
		||||
    function __construct() {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  class WithCons {
 | 
			
		||||
    public $first;
 | 
			
		||||
    function __construct($first) {
 | 
			
		||||
      $this->first = $first;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  class TC {
 | 
			
		||||
    static function method() {
 | 
			
		||||
      return 12;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  class C1 {
 | 
			
		||||
    static function confps1_xy() {
 | 
			
		||||
      return 11;
 | 
			
		||||
    }
 | 
			
		||||
    static function ps2_x() {
 | 
			
		||||
      return 12;
 | 
			
		||||
    }
 | 
			
		||||
    function confp1_y() {
 | 
			
		||||
      return 21;
 | 
			
		||||
    }
 | 
			
		||||
    function p2() {
 | 
			
		||||
      return 22;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  class C2 extends C1 {
 | 
			
		||||
    static function ps3() {
 | 
			
		||||
      return 13;
 | 
			
		||||
    }
 | 
			
		||||
    function p3() {
 | 
			
		||||
      return 23;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  class C3 extends C2 {
 | 
			
		||||
    static function confps1_xy() {
 | 
			
		||||
      return 111;
 | 
			
		||||
    }
 | 
			
		||||
    function confp1_y() {
 | 
			
		||||
      return 121;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										85
									
								
								tests/php/time/DateTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								tests/php/time/DateTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,85 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\php\time;
 | 
			
		||||
 | 
			
		||||
use DateTimeZone;
 | 
			
		||||
use nulib\tests\TestCase;
 | 
			
		||||
 | 
			
		||||
class DateTest extends TestCase {
 | 
			
		||||
  protected static function dt(string $datetime): Date {
 | 
			
		||||
    return new Date($datetime, new DateTimeZone("Indian/Reunion"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testDate() {
 | 
			
		||||
    $date = self::dt("2024-04-05 09:15:23");
 | 
			
		||||
 | 
			
		||||
    self::assertSame("05/04/2024", $date->format());
 | 
			
		||||
    self::assertSame("05/04/2024", strval($date));
 | 
			
		||||
    self::assertSame(2024, $date->year);
 | 
			
		||||
    self::assertSame(4, $date->month);
 | 
			
		||||
    self::assertSame(5, $date->day);
 | 
			
		||||
    self::assertSame(0, $date->hour);
 | 
			
		||||
    self::assertSame(0, $date->minute);
 | 
			
		||||
    self::assertSame(0, $date->second);
 | 
			
		||||
    self::assertSame(5, $date->wday);
 | 
			
		||||
    self::assertSame(14, $date->wnum);
 | 
			
		||||
    self::assertSame("+04:00", $date->timezone);
 | 
			
		||||
    self::assertSame("05/04/2024 00:00:00", $date->datetime);
 | 
			
		||||
    self::assertSame("05/04/2024", $date->date);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testClone() {
 | 
			
		||||
    $date = self::dt("now");
 | 
			
		||||
    $clone = Date::clone($date);
 | 
			
		||||
    self::assertInstanceOf(DateTime::class, $clone);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testConstruct() {
 | 
			
		||||
    $y = date("Y");
 | 
			
		||||
    self::assertSame("05/04/$y", strval(new Date("5/4")));
 | 
			
		||||
    self::assertSame("05/04/2024", strval(new Date("5/4/24")));
 | 
			
		||||
    self::assertSame("05/04/2024", strval(new Date("5/4/2024")));
 | 
			
		||||
    self::assertSame("05/04/2024", strval(new Date("05/04/2024")));
 | 
			
		||||
    self::assertSame("05/04/2024", strval(new Date("20240405")));
 | 
			
		||||
    self::assertSame("05/04/2024", strval(new Date("240405")));
 | 
			
		||||
    self::assertSame("05/04/2024", strval(new Date("20240405T091523")));
 | 
			
		||||
    self::assertSame("05/04/2024", strval(new Date("20240405T091523Z")));
 | 
			
		||||
    self::assertSame("05/04/2024", strval(new Date("5/4/2024 9:15:23")));
 | 
			
		||||
    self::assertSame("05/04/2024", strval(new Date("5/4/2024 9.15.23")));
 | 
			
		||||
    self::assertSame("05/04/2024", strval(new Date("5/4/2024 9:15")));
 | 
			
		||||
    self::assertSame("05/04/2024", strval(new Date("5/4/2024 9.15")));
 | 
			
		||||
    self::assertSame("05/04/2024", strval(new Date("5/4/2024 9h15")));
 | 
			
		||||
    self::assertSame("05/04/2024", strval(new Date("5/4/2024 09:15:23")));
 | 
			
		||||
    self::assertSame("05/04/2024", strval(new Date("5/4/2024 09:15")));
 | 
			
		||||
    self::assertSame("05/04/2024", strval(new Date("5/4/2024 09h15")));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testCompare() {
 | 
			
		||||
    $a = new Date("10/02/2024");
 | 
			
		||||
    $b = new Date("15/02/2024");
 | 
			
		||||
    $c = new Date("20/02/2024");
 | 
			
		||||
    $a2 = new Date("10/02/2024");
 | 
			
		||||
    $b2 = new Date("15/02/2024");
 | 
			
		||||
    $c2 = new Date("20/02/2024");
 | 
			
		||||
 | 
			
		||||
    self::assertTrue($a == $a2);
 | 
			
		||||
    self::assertFalse($a === $a2);
 | 
			
		||||
    self::assertTrue($b == $b2);
 | 
			
		||||
    self::assertTrue($c == $c2);
 | 
			
		||||
 | 
			
		||||
    self::assertFalse($a < $a);
 | 
			
		||||
    self::assertTrue($a < $b);
 | 
			
		||||
    self::assertTrue($a < $c);
 | 
			
		||||
 | 
			
		||||
    self::assertTrue($a <= $a);
 | 
			
		||||
    self::assertTrue($a <= $b);
 | 
			
		||||
    self::assertTrue($a <= $c);
 | 
			
		||||
 | 
			
		||||
    self::assertFalse($c > $c);
 | 
			
		||||
    self::assertTrue($c > $b);
 | 
			
		||||
    self::assertTrue($c > $a);
 | 
			
		||||
 | 
			
		||||
    self::assertTrue($c >= $c);
 | 
			
		||||
    self::assertTrue($c >= $b);
 | 
			
		||||
    self::assertTrue($c >= $a);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										109
									
								
								tests/php/time/DateTimeTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								tests/php/time/DateTimeTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,109 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\php\time;
 | 
			
		||||
 | 
			
		||||
use DateTimeZone;
 | 
			
		||||
use nulib\tests\TestCase;
 | 
			
		||||
 | 
			
		||||
class DateTimeTest extends TestCase {
 | 
			
		||||
  protected static function dt(string $datetime): DateTime {
 | 
			
		||||
    return new DateTime($datetime, new DateTimeZone("Indian/Reunion"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testDateTime() {
 | 
			
		||||
    $date = self::dt("2024-04-05 09:15:23");
 | 
			
		||||
 | 
			
		||||
    self::assertEquals("05/04/2024 09:15:23", $date->format());
 | 
			
		||||
    self::assertEquals("05/04/2024 09:15:23", strval($date));
 | 
			
		||||
    self::assertSame(2024, $date->year);
 | 
			
		||||
    self::assertSame(4, $date->month);
 | 
			
		||||
    self::assertSame(5, $date->day);
 | 
			
		||||
    self::assertSame(9, $date->hour);
 | 
			
		||||
    self::assertSame(15, $date->minute);
 | 
			
		||||
    self::assertSame(23, $date->second);
 | 
			
		||||
    self::assertSame(5, $date->wday);
 | 
			
		||||
    self::assertSame(14, $date->wnum);
 | 
			
		||||
    self::assertEquals("+04:00", $date->timezone);
 | 
			
		||||
    self::assertSame("05/04/2024 09:15:23", $date->datetime);
 | 
			
		||||
    self::assertSame("05/04/2024", $date->date);
 | 
			
		||||
    self::assertSame("20240405", $date->Ymd);
 | 
			
		||||
    self::assertSame("20240405T091523", $date->YmdHMS);
 | 
			
		||||
    self::assertSame("20240405T091523+04:00", $date->YmdHMSZ);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testDateTimeZ() {
 | 
			
		||||
    $date = new DateTime("20240405T091523Z");
 | 
			
		||||
    self::assertSame("20240405T091523", $date->YmdHMS);
 | 
			
		||||
    self::assertSame("20240405T091523Z", $date->YmdHMSZ);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testClone() {
 | 
			
		||||
    $date = self::dt("now");
 | 
			
		||||
    $clone = DateTime::clone($date);
 | 
			
		||||
    self::assertInstanceOf(DateTime::class, $clone);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testConstruct() {
 | 
			
		||||
    $y = date("Y");
 | 
			
		||||
    self::assertSame("05/04/$y 00:00:00", strval(new DateTime("5/4")));
 | 
			
		||||
    self::assertSame("05/04/2024 00:00:00", strval(new DateTime("5/4/24")));
 | 
			
		||||
    self::assertSame("05/04/2024 00:00:00", strval(new DateTime("5/4/2024")));
 | 
			
		||||
    self::assertSame("05/04/2024 00:00:00", strval(new DateTime("05/04/2024")));
 | 
			
		||||
    self::assertSame("05/04/2024 00:00:00", strval(new DateTime("20240405")));
 | 
			
		||||
    self::assertSame("05/04/2024 00:00:00", strval(new DateTime("240405")));
 | 
			
		||||
    self::assertSame("05/04/2024 09:15:23", strval(new DateTime("20240405T091523")));
 | 
			
		||||
    self::assertSame("05/04/2024 09:15:23", strval(new DateTime("20240405T091523Z")));
 | 
			
		||||
    self::assertSame("05/04/2024 09:15:23", strval(new DateTime("5/4/2024 9:15:23")));
 | 
			
		||||
    self::assertSame("05/04/2024 09:15:23", strval(new DateTime("5/4/2024 9.15.23")));
 | 
			
		||||
    self::assertSame("05/04/2024 09:15:00", strval(new DateTime("5/4/2024 9:15")));
 | 
			
		||||
    self::assertSame("05/04/2024 09:15:00", strval(new DateTime("5/4/2024 9.15")));
 | 
			
		||||
    self::assertSame("05/04/2024 09:15:00", strval(new DateTime("5/4/2024 9h15")));
 | 
			
		||||
    self::assertSame("05/04/2024 09:15:23", strval(new DateTime("5/4/2024 09:15:23")));
 | 
			
		||||
    self::assertSame("05/04/2024 09:15:00", strval(new DateTime("5/4/2024 09:15")));
 | 
			
		||||
    self::assertSame("05/04/2024 09:15:00", strval(new DateTime("5/4/2024 09h15")));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testCompare() {
 | 
			
		||||
    $a = new DateTime("10/02/2024");
 | 
			
		||||
    $a2 = new DateTime("10/02/2024 8:30");
 | 
			
		||||
    $a3 = new DateTime("10/02/2024 15:45");
 | 
			
		||||
    $b = new DateTime("15/02/2024");
 | 
			
		||||
    $b2 = new DateTime("15/02/2024 8:30");
 | 
			
		||||
    $b3 = new DateTime("15/02/2024 15:45");
 | 
			
		||||
    $x = new DateTime("10/02/2024");
 | 
			
		||||
    $x2 = new DateTime("10/02/2024 8:30");
 | 
			
		||||
    $x3 = new DateTime("10/02/2024 15:45");
 | 
			
		||||
 | 
			
		||||
    self::assertTrue($a == $x);
 | 
			
		||||
    self::assertFalse($a === $x);
 | 
			
		||||
    self::assertTrue($a2 == $x2);
 | 
			
		||||
    self::assertTrue($a3 == $x3);
 | 
			
		||||
 | 
			
		||||
    self::assertFalse($a < $a);
 | 
			
		||||
    self::assertTrue($a < $a2);
 | 
			
		||||
    self::assertTrue($a < $a3);
 | 
			
		||||
    self::assertTrue($a < $b);
 | 
			
		||||
    self::assertTrue($a < $b2);
 | 
			
		||||
    self::assertTrue($a < $b3);
 | 
			
		||||
 | 
			
		||||
    self::assertTrue($a <= $a);
 | 
			
		||||
    self::assertTrue($a <= $a2);
 | 
			
		||||
    self::assertTrue($a <= $a3);
 | 
			
		||||
    self::assertTrue($a <= $b);
 | 
			
		||||
    self::assertTrue($a <= $b2);
 | 
			
		||||
    self::assertTrue($a <= $b3);
 | 
			
		||||
 | 
			
		||||
    self::assertTrue($b > $a);
 | 
			
		||||
    self::assertTrue($b > $a2);
 | 
			
		||||
    self::assertTrue($b > $a3);
 | 
			
		||||
    self::assertFalse($b > $b);
 | 
			
		||||
    self::assertFalse($b > $b2);
 | 
			
		||||
    self::assertFalse($b > $b3);
 | 
			
		||||
 | 
			
		||||
    self::assertTrue($b >= $a);
 | 
			
		||||
    self::assertTrue($b >= $a2);
 | 
			
		||||
    self::assertTrue($b >= $a3);
 | 
			
		||||
    self::assertTrue($b >= $b);
 | 
			
		||||
    self::assertFalse($b >= $b2);
 | 
			
		||||
    self::assertFalse($b >= $b3);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										83
									
								
								tests/php/time/DelayTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								tests/php/time/DelayTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,83 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\php\time;
 | 
			
		||||
 | 
			
		||||
use DateTimeZone;
 | 
			
		||||
use nulib\tests\TestCase;
 | 
			
		||||
 | 
			
		||||
class DelayTest extends TestCase {
 | 
			
		||||
  protected static function dt(string $datetime): DateTime {
 | 
			
		||||
    return new DateTime($datetime, new DateTimeZone("Indian/Reunion"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testDelay() {
 | 
			
		||||
    $from = self::dt("2024-04-05 09:15:23");
 | 
			
		||||
 | 
			
		||||
    $delay = new Delay(10, $from);
 | 
			
		||||
    self::assertEquals(self::dt("2024-04-05 09:15:33"), $delay->getDest());
 | 
			
		||||
 | 
			
		||||
    $delay = new Delay("10", $from);
 | 
			
		||||
    self::assertEquals(self::dt("2024-04-05 09:15:33"), $delay->getDest());
 | 
			
		||||
 | 
			
		||||
    $delay = new Delay("10s", $from);
 | 
			
		||||
    self::assertEquals(self::dt("2024-04-05 09:15:33"), $delay->getDest());
 | 
			
		||||
 | 
			
		||||
    $delay = new Delay("s", $from);
 | 
			
		||||
    self::assertEquals(self::dt("2024-04-05 09:15:24"), $delay->getDest());
 | 
			
		||||
 | 
			
		||||
    $delay = new Delay("5m", $from);
 | 
			
		||||
    self::assertEquals(self::dt("2024-04-05 09:20:00"), $delay->getDest());
 | 
			
		||||
 | 
			
		||||
    $delay = new Delay("5m0", $from);
 | 
			
		||||
    self::assertEquals(self::dt("2024-04-05 09:20:00"), $delay->getDest());
 | 
			
		||||
 | 
			
		||||
    $delay = new Delay("5m2", $from);
 | 
			
		||||
    self::assertEquals(self::dt("2024-04-05 09:20:02"), $delay->getDest());
 | 
			
		||||
 | 
			
		||||
    $delay = new Delay("m", $from);
 | 
			
		||||
    self::assertEquals(self::dt("2024-04-05 09:16:00"), $delay->getDest());
 | 
			
		||||
 | 
			
		||||
    $delay = new Delay("5h", $from);
 | 
			
		||||
    self::assertEquals(self::dt("2024-04-05 14:00:00"), $delay->getDest());
 | 
			
		||||
 | 
			
		||||
    $delay = new Delay("5h0", $from);
 | 
			
		||||
    self::assertEquals(self::dt("2024-04-05 14:00:00"), $delay->getDest());
 | 
			
		||||
 | 
			
		||||
    $delay = new Delay("5h2", $from);
 | 
			
		||||
    self::assertEquals(self::dt("2024-04-05 14:02:00"), $delay->getDest());
 | 
			
		||||
 | 
			
		||||
    $delay = new Delay("h", $from);
 | 
			
		||||
    self::assertEquals(self::dt("2024-04-05 10:00:00"), $delay->getDest());
 | 
			
		||||
 | 
			
		||||
    $delay = new Delay("5d", $from);
 | 
			
		||||
    self::assertEquals(self::dt("2024-04-10 05:00:00"), $delay->getDest());
 | 
			
		||||
 | 
			
		||||
    $delay = new Delay("5d2", $from);
 | 
			
		||||
    self::assertEquals(self::dt("2024-04-10 02:00:00"), $delay->getDest());
 | 
			
		||||
 | 
			
		||||
    $delay = new Delay("5d0", $from);
 | 
			
		||||
    self::assertEquals(self::dt("2024-04-10 00:00:00"), $delay->getDest());
 | 
			
		||||
 | 
			
		||||
    $delay = new Delay("d", $from);
 | 
			
		||||
    self::assertEquals(self::dt("2024-04-06 05:00:00"), $delay->getDest());
 | 
			
		||||
 | 
			
		||||
    $delay = new Delay("2w", $from);
 | 
			
		||||
    self::assertEquals(self::dt("2024-04-21 05:00:00"), $delay->getDest());
 | 
			
		||||
 | 
			
		||||
    $delay = new Delay("2w2", $from);
 | 
			
		||||
    self::assertEquals(self::dt("2024-04-21 02:00:00"), $delay->getDest());
 | 
			
		||||
 | 
			
		||||
    $delay = new Delay("2w0", $from);
 | 
			
		||||
    self::assertEquals(self::dt("2024-04-21 00:00:00"), $delay->getDest());
 | 
			
		||||
 | 
			
		||||
    $delay = new Delay("w", $from);
 | 
			
		||||
    self::assertEquals(self::dt("2024-04-07 05:00:00"), $delay->getDest());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testElapsed() {
 | 
			
		||||
    $delay = new Delay(5);
 | 
			
		||||
    sleep(2);
 | 
			
		||||
    self::assertFalse($delay->isElapsed());
 | 
			
		||||
    sleep(5);
 | 
			
		||||
    self::assertTrue($delay->isElapsed());
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,7 +1,8 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\_scalar;
 | 
			
		||||
namespace nur\sery\schema\_scalar;
 | 
			
		||||
 | 
			
		||||
use nulib\tests\TestCase;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarSchema;
 | 
			
		||||
use nur\sery\wip\schema\SchemaException;
 | 
			
		||||
 | 
			
		||||
class ScalarSchemaTest extends TestCase {
 | 
			
		||||
@ -20,7 +21,6 @@ class ScalarSchemaTest extends TestCase {
 | 
			
		||||
    "formatter_func" => null,
 | 
			
		||||
    "format" => null,
 | 
			
		||||
    "" => ["scalar"],
 | 
			
		||||
    "schema" => null,
 | 
			
		||||
    "name" => null,
 | 
			
		||||
    "pkey" => null,
 | 
			
		||||
    "header" => null,
 | 
			
		||||
							
								
								
									
										111
									
								
								tests/schema/types/boolTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								tests/schema/types/boolTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,111 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\schema\types;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
use nulib\tests\TestCase;
 | 
			
		||||
use nur\sery\schema\_scalar\ScalarValue;
 | 
			
		||||
use nur\sery\schema\Schema;
 | 
			
		||||
 | 
			
		||||
class boolTest extends TestCase {
 | 
			
		||||
  function commonTests($destv, &$dest, callable $destvSetter): void {
 | 
			
		||||
    $destv->set(true);
 | 
			
		||||
    self::assertSame(true, $destv->get());
 | 
			
		||||
    self::assertSame(true, $dest);
 | 
			
		||||
    self::assertSame("Oui", $destv->format());
 | 
			
		||||
    self::assertSame("Oui", $destv->format("OuiNonNull"));
 | 
			
		||||
    self::assertSame("O", $destv->format("ON"));
 | 
			
		||||
    self::assertSame("O", $destv->format("ONN"));
 | 
			
		||||
 | 
			
		||||
    $destv->set(false);
 | 
			
		||||
    self::assertSame(false, $destv->get());
 | 
			
		||||
    self::assertSame(false, $dest);
 | 
			
		||||
    self::assertSame("Non", $destv->format());
 | 
			
		||||
    self::assertSame("Non", $destv->format("OuiNonNull"));
 | 
			
		||||
    self::assertSame("N", $destv->format("ON"));
 | 
			
		||||
    self::assertSame("N", $destv->format("ONN"));
 | 
			
		||||
 | 
			
		||||
    $destv->set("yes");
 | 
			
		||||
    self::assertSame(true, $destv->get());
 | 
			
		||||
 | 
			
		||||
    $destv->set(" yes ");
 | 
			
		||||
    self::assertSame(true, $destv->get());
 | 
			
		||||
 | 
			
		||||
    $destv->set("12");
 | 
			
		||||
    self::assertSame(true, $destv->get());
 | 
			
		||||
 | 
			
		||||
    $destv->set(12);
 | 
			
		||||
    self::assertSame(true, $destv->get());
 | 
			
		||||
 | 
			
		||||
    $destv->set("no");
 | 
			
		||||
    self::assertSame(false, $destv->get());
 | 
			
		||||
 | 
			
		||||
    $destv->set(" no ");
 | 
			
		||||
    self::assertSame(false, $destv->get());
 | 
			
		||||
 | 
			
		||||
    $destv->set("0");
 | 
			
		||||
    self::assertSame(false, $destv->get());
 | 
			
		||||
 | 
			
		||||
    $destv->set(0);
 | 
			
		||||
    self::assertSame(false, $destv->get());
 | 
			
		||||
 | 
			
		||||
    $destv->set(12.34);
 | 
			
		||||
    self::assertSame(true, $destv->get());
 | 
			
		||||
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter("a"));
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter([]));
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(["a"]));
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testBool() {
 | 
			
		||||
    /** @var ScalarValue $destv */
 | 
			
		||||
    Schema::nv($destv, $dest, null, $schema, "bool");
 | 
			
		||||
    $destvSetter = function($value) use($destv) {
 | 
			
		||||
      return function() use($destv, $value) {
 | 
			
		||||
        $destv->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(null));
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(""));
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(" "));
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($destv, $dest, $destvSetter);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testNbool() {
 | 
			
		||||
    /** @var ScalarValue $destv */
 | 
			
		||||
    Schema::nv($destv, $dest, null, $schema, "?bool");
 | 
			
		||||
    $destvSetter = function($value) use($destv) {
 | 
			
		||||
      return function() use($destv, $value) {
 | 
			
		||||
        $destv->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    $destv->set(null);
 | 
			
		||||
    self::assertNull($destv->get());
 | 
			
		||||
    self::assertNull($dest);
 | 
			
		||||
    self::assertSame("Non", $destv->format());
 | 
			
		||||
    self::assertSame("", $destv->format("OuiNonNull"));
 | 
			
		||||
    self::assertSame("N", $destv->format("ON"));
 | 
			
		||||
    self::assertSame("", $destv->format("ONN"));
 | 
			
		||||
 | 
			
		||||
    $destv->set("");
 | 
			
		||||
    self::assertNull($destv->get());
 | 
			
		||||
    self::assertNull($dest);
 | 
			
		||||
    self::assertSame("Non", $destv->format());
 | 
			
		||||
    self::assertSame("", $destv->format("OuiNonNull"));
 | 
			
		||||
    self::assertSame("N", $destv->format("ON"));
 | 
			
		||||
    self::assertSame("", $destv->format("ONN"));
 | 
			
		||||
 | 
			
		||||
    $destv->set(" ");
 | 
			
		||||
    self::assertNull($destv->get());
 | 
			
		||||
    self::assertNull($dest);
 | 
			
		||||
    self::assertSame("Non", $destv->format());
 | 
			
		||||
    self::assertSame("", $destv->format("OuiNonNull"));
 | 
			
		||||
    self::assertSame("N", $destv->format("ON"));
 | 
			
		||||
    self::assertSame("", $destv->format("ONN"));
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($destv, $dest, $destvSetter);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										139
									
								
								tests/schema/types/floatTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								tests/schema/types/floatTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,139 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\schema\types;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
use nulib\tests\TestCase;
 | 
			
		||||
use nur\sery\schema\_scalar\ScalarValue;
 | 
			
		||||
use nur\sery\schema\Schema;
 | 
			
		||||
 | 
			
		||||
class floatTest extends TestCase {
 | 
			
		||||
  function commonTests($destv, &$dest, callable $destvSetter): void {
 | 
			
		||||
    $destv->set(12);
 | 
			
		||||
    self::assertSame(12.0, $destv->get());
 | 
			
		||||
    self::assertSame(12.0, $dest);
 | 
			
		||||
    self::assertSame("12", $destv->format());
 | 
			
		||||
    self::assertSame("0012", $destv->format("%04u"));
 | 
			
		||||
 | 
			
		||||
    $destv->set("12");
 | 
			
		||||
    self::assertSame(12.0, $destv->get());
 | 
			
		||||
 | 
			
		||||
    $destv->set(" 12 ");
 | 
			
		||||
    self::assertSame(12.0, $destv->get());
 | 
			
		||||
 | 
			
		||||
    $destv->set(12.34);
 | 
			
		||||
    self::assertSame(12.34, $destv->get());
 | 
			
		||||
 | 
			
		||||
    $destv->set(true);
 | 
			
		||||
    self::assertSame(1.0, $destv->get());
 | 
			
		||||
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter("a"));
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter([]));
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(["a"]));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testFloat() {
 | 
			
		||||
    /** @var ScalarValue $destv */
 | 
			
		||||
    Schema::nv($destv, $dest, null, $schema, "float");
 | 
			
		||||
    $destvSetter = function($value) use($destv) {
 | 
			
		||||
      return function() use($destv, $value) {
 | 
			
		||||
        $destv->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(null));
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(""));
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(" "));
 | 
			
		||||
 | 
			
		||||
    // valeur non requise donc retourne null
 | 
			
		||||
    $destv->set(false);
 | 
			
		||||
    self::assertNull($destv->get());
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($destv, $dest, $destvSetter);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testRequiredFloat() {
 | 
			
		||||
    /** @var ScalarValue $destv */
 | 
			
		||||
    Schema::nv($destv, $dest, null, $schema, [
 | 
			
		||||
      "float", null,
 | 
			
		||||
      "required" => true,
 | 
			
		||||
    ]);
 | 
			
		||||
    $destvSetter = function($value) use($destv) {
 | 
			
		||||
      return function() use($destv, $value) {
 | 
			
		||||
        $destv->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(null));
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(""));
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(" "));
 | 
			
		||||
 | 
			
		||||
    // valeur requise donc lance une exception
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(false));
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($destv, $dest, $destvSetter);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testNfloat() {
 | 
			
		||||
    /** @var ScalarValue $destv */
 | 
			
		||||
    Schema::nv($destv, $dest, null, $schema, "?float");
 | 
			
		||||
    $destvSetter = function($value) use($destv) {
 | 
			
		||||
      return function() use($destv, $value) {
 | 
			
		||||
        $destv->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    $destv->set(null);
 | 
			
		||||
    self::assertNull($destv->get());
 | 
			
		||||
    self::assertNull($dest);
 | 
			
		||||
    self::assertSame("", $destv->format());
 | 
			
		||||
 | 
			
		||||
    $destv->set("");
 | 
			
		||||
    self::assertNull($destv->get());
 | 
			
		||||
    self::assertNull($dest);
 | 
			
		||||
    self::assertSame("", $destv->format());
 | 
			
		||||
 | 
			
		||||
    $destv->set(" ");
 | 
			
		||||
    self::assertNull($destv->get());
 | 
			
		||||
    self::assertNull($dest);
 | 
			
		||||
    self::assertSame("", $destv->format());
 | 
			
		||||
 | 
			
		||||
    // valeur non requise donc retourne null
 | 
			
		||||
    $destv->set(false);
 | 
			
		||||
    self::assertNull($destv->get());
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($destv, $dest, $destvSetter);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testRequiredNfloat() {
 | 
			
		||||
    /** @var ScalarValue $destv */
 | 
			
		||||
    Schema::nv($destv, $dest, null, $schema, [
 | 
			
		||||
      "?float", null,
 | 
			
		||||
      "required" => true,
 | 
			
		||||
    ]);
 | 
			
		||||
    $destvSetter = function($value) use($destv) {
 | 
			
		||||
      return function() use($destv, $value) {
 | 
			
		||||
        $destv->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    $destv->set(null);
 | 
			
		||||
    self::assertNull($destv->get());
 | 
			
		||||
    self::assertNull($dest);
 | 
			
		||||
    self::assertSame("", $destv->format());
 | 
			
		||||
 | 
			
		||||
    $destv->set("");
 | 
			
		||||
    self::assertNull($destv->get());
 | 
			
		||||
    self::assertNull($dest);
 | 
			
		||||
    self::assertSame("", $destv->format());
 | 
			
		||||
 | 
			
		||||
    $destv->set(" ");
 | 
			
		||||
    self::assertNull($destv->get());
 | 
			
		||||
    self::assertNull($dest);
 | 
			
		||||
    self::assertSame("", $destv->format());
 | 
			
		||||
 | 
			
		||||
    // valeur requise donc lance une exception
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(false));
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($destv, $dest, $destvSetter);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										139
									
								
								tests/schema/types/intTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								tests/schema/types/intTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,139 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\schema\types;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
use nulib\tests\TestCase;
 | 
			
		||||
use nur\sery\schema\_scalar\ScalarValue;
 | 
			
		||||
use nur\sery\schema\Schema;
 | 
			
		||||
 | 
			
		||||
class intTest extends TestCase {
 | 
			
		||||
  function commonTests($destv, &$dest, callable $destvSetter): void {
 | 
			
		||||
    $destv->set(12);
 | 
			
		||||
    self::assertSame(12, $destv->get());
 | 
			
		||||
    self::assertSame(12, $dest);
 | 
			
		||||
    self::assertSame("12", $destv->format());
 | 
			
		||||
    self::assertSame("0012", $destv->format("%04u"));
 | 
			
		||||
 | 
			
		||||
    $destv->set("12");
 | 
			
		||||
    self::assertSame(12, $destv->get());
 | 
			
		||||
 | 
			
		||||
    $destv->set(" 12 ");
 | 
			
		||||
    self::assertSame(12, $destv->get());
 | 
			
		||||
 | 
			
		||||
    $destv->set(12.34);
 | 
			
		||||
    self::assertSame(12, $destv->get());
 | 
			
		||||
 | 
			
		||||
    $destv->set(true);
 | 
			
		||||
    self::assertSame(1, $destv->get());
 | 
			
		||||
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter("a"));
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter([]));
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(["a"]));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testInt() {
 | 
			
		||||
    /** @var ScalarValue $destv */
 | 
			
		||||
    Schema::nv($destv, $dest, null, $schema, "int");
 | 
			
		||||
    $destvSetter = function($value) use($destv) {
 | 
			
		||||
      return function() use($destv, $value) {
 | 
			
		||||
        $destv->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(null));
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(""));
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(" "));
 | 
			
		||||
 | 
			
		||||
    // valeur non requise donc retourne null
 | 
			
		||||
    $destv->set(false);
 | 
			
		||||
    self::assertNull($destv->get());
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($destv, $dest, $destvSetter);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testRequiredInt() {
 | 
			
		||||
    /** @var ScalarValue $destv */
 | 
			
		||||
    Schema::nv($destv, $dest, null, $schema, [
 | 
			
		||||
      "int", null,
 | 
			
		||||
      "required" => true,
 | 
			
		||||
    ]);
 | 
			
		||||
    $destvSetter = function($value) use($destv) {
 | 
			
		||||
      return function() use($destv, $value) {
 | 
			
		||||
        $destv->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(null));
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(""));
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(" "));
 | 
			
		||||
 | 
			
		||||
    // valeur requise donc lance une exception
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(false));
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($destv, $dest, $destvSetter);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testNint() {
 | 
			
		||||
    /** @var ScalarValue $destv */
 | 
			
		||||
    Schema::nv($destv, $dest, null, $schema, "?int");
 | 
			
		||||
    $destvSetter = function($value) use($destv) {
 | 
			
		||||
      return function() use($destv, $value) {
 | 
			
		||||
        $destv->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    $destv->set(null);
 | 
			
		||||
    self::assertNull($destv->get());
 | 
			
		||||
    self::assertNull($dest);
 | 
			
		||||
    self::assertSame("", $destv->format());
 | 
			
		||||
 | 
			
		||||
    $destv->set("");
 | 
			
		||||
    self::assertNull($destv->get());
 | 
			
		||||
    self::assertNull($dest);
 | 
			
		||||
    self::assertSame("", $destv->format());
 | 
			
		||||
 | 
			
		||||
    $destv->set(" ");
 | 
			
		||||
    self::assertNull($destv->get());
 | 
			
		||||
    self::assertNull($dest);
 | 
			
		||||
    self::assertSame("", $destv->format());
 | 
			
		||||
 | 
			
		||||
    // valeur non requise donc retourne null
 | 
			
		||||
    $destv->set(false);
 | 
			
		||||
    self::assertNull($destv->get());
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($destv, $dest, $destvSetter);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testRequiredNint() {
 | 
			
		||||
    /** @var ScalarValue $destv */
 | 
			
		||||
    Schema::nv($destv, $dest, null, $schema, [
 | 
			
		||||
      "?int", null,
 | 
			
		||||
      "required" => true,
 | 
			
		||||
    ]);
 | 
			
		||||
    $destvSetter = function($value) use($destv) {
 | 
			
		||||
      return function() use($destv, $value) {
 | 
			
		||||
        $destv->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    $destv->set(null);
 | 
			
		||||
    self::assertNull($destv->get());
 | 
			
		||||
    self::assertNull($dest);
 | 
			
		||||
    self::assertSame("", $destv->format());
 | 
			
		||||
 | 
			
		||||
    $destv->set("");
 | 
			
		||||
    self::assertNull($destv->get());
 | 
			
		||||
    self::assertNull($dest);
 | 
			
		||||
    self::assertSame("", $destv->format());
 | 
			
		||||
 | 
			
		||||
    $destv->set(" ");
 | 
			
		||||
    self::assertNull($destv->get());
 | 
			
		||||
    self::assertNull($dest);
 | 
			
		||||
    self::assertSame("", $destv->format());
 | 
			
		||||
 | 
			
		||||
    // valeur requise donc lance une exception
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(false));
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($destv, $dest, $destvSetter);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										123
									
								
								tests/schema/types/strTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								tests/schema/types/strTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,123 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\schema\types;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
use nulib\tests\TestCase;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarValue;
 | 
			
		||||
use nur\sery\wip\schema\Schema;
 | 
			
		||||
 | 
			
		||||
class strTest extends TestCase {
 | 
			
		||||
  function commonTests($destv, &$dest, callable $destvSetter): void {
 | 
			
		||||
    $destv->set("");
 | 
			
		||||
    self::assertSame("", $destv->get());
 | 
			
		||||
    self::assertSame("", $dest);
 | 
			
		||||
 | 
			
		||||
    $destv->set(" ");
 | 
			
		||||
    self::assertSame(" ", $destv->get());
 | 
			
		||||
    self::assertSame(" ", $dest);
 | 
			
		||||
 | 
			
		||||
    $destv->set("a");
 | 
			
		||||
    self::assertSame("a", $destv->get());
 | 
			
		||||
    self::assertSame("a", $dest);
 | 
			
		||||
 | 
			
		||||
    $destv->set("12");
 | 
			
		||||
    self::assertSame("12", $destv->get());
 | 
			
		||||
 | 
			
		||||
    $destv->set(" 12 ");
 | 
			
		||||
    self::assertSame(" 12 ", $destv->get());
 | 
			
		||||
 | 
			
		||||
    $destv->set(12);
 | 
			
		||||
    self::assertSame("12", $destv->get());
 | 
			
		||||
 | 
			
		||||
    $destv->set(12.34);
 | 
			
		||||
    self::assertSame("12.34", $destv->get());
 | 
			
		||||
 | 
			
		||||
    $destv->set(true);
 | 
			
		||||
    self::assertSame("1", $destv->get());
 | 
			
		||||
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter([]));
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(["a"]));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testStr() {
 | 
			
		||||
    /** @var ScalarValue $destv */
 | 
			
		||||
    Schema::nv($destv, $dest, null, $schema, "string");
 | 
			
		||||
    $destvSetter = function($value) use($destv) {
 | 
			
		||||
      return function() use($destv, $value) {
 | 
			
		||||
        $destv->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(null));
 | 
			
		||||
 | 
			
		||||
    // valeur non requise donc retourne null
 | 
			
		||||
    $destv->set(false);
 | 
			
		||||
    self::assertNull($destv->get());
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($destv, $dest, $destvSetter);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testRequiredStr() {
 | 
			
		||||
    /** @var ScalarValue $destv */
 | 
			
		||||
    Schema::nv($destv, $dest, null, $schema, [
 | 
			
		||||
      "string", null,
 | 
			
		||||
      "required" => true,
 | 
			
		||||
    ]);
 | 
			
		||||
    $destvSetter = function($value) use($destv) {
 | 
			
		||||
      return function() use($destv, $value) {
 | 
			
		||||
        $destv->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(null));
 | 
			
		||||
 | 
			
		||||
    // valeur requise donc lance une exception
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(false));
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($destv, $dest, $destvSetter);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testNstr() {
 | 
			
		||||
    /** @var ScalarValue $destv */
 | 
			
		||||
    Schema::nv($destv, $dest, null, $schema, "?string");
 | 
			
		||||
    $destvSetter = function($value) use($destv) {
 | 
			
		||||
      return function() use($destv, $value) {
 | 
			
		||||
        $destv->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    $destv->set(null);
 | 
			
		||||
    self::assertNull($destv->get());
 | 
			
		||||
    self::assertNull($dest);
 | 
			
		||||
    self::assertSame("", $destv->format());
 | 
			
		||||
 | 
			
		||||
    // valeur non requise donc retourne null
 | 
			
		||||
    $destv->set(false);
 | 
			
		||||
    self::assertNull($destv->get());
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($destv, $dest, $destvSetter);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testRequiredNstr() {
 | 
			
		||||
    /** @var ScalarValue $destv */
 | 
			
		||||
    Schema::nv($destv, $dest, null, $schema, [
 | 
			
		||||
      "?string", null,
 | 
			
		||||
      "required" => true,
 | 
			
		||||
    ]);
 | 
			
		||||
    $destvSetter = function($value) use($destv) {
 | 
			
		||||
      return function() use($destv, $value) {
 | 
			
		||||
        $destv->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    $destv->set(null);
 | 
			
		||||
    self::assertNull($destv->get());
 | 
			
		||||
    self::assertNull($dest);
 | 
			
		||||
    self::assertSame("", $destv->format());
 | 
			
		||||
 | 
			
		||||
    // valeur requise donc lance une exception
 | 
			
		||||
    self::assertException(Exception::class, $destvSetter(false));
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($destv, $dest, $destvSetter);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								tests/schema/types/unionTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								tests/schema/types/unionTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\schema\types;
 | 
			
		||||
 | 
			
		||||
use nulib\tests\TestCase;
 | 
			
		||||
use nur\sery\schema\_scalar\ScalarValue;
 | 
			
		||||
use nur\sery\schema\Schema;
 | 
			
		||||
 | 
			
		||||
class unionTest extends TestCase {
 | 
			
		||||
  function testUnionTypes() {
 | 
			
		||||
    ## l'ordre des types doit être respecté
 | 
			
		||||
    
 | 
			
		||||
    # string puis int
 | 
			
		||||
    /** @var ScalarValue $siv */
 | 
			
		||||
    Schema::nv($siv, $si, null, $sis, "string|int");
 | 
			
		||||
 | 
			
		||||
    $siv->set("12");
 | 
			
		||||
    self::assertSame("12", $si);
 | 
			
		||||
    $siv->set(12);
 | 
			
		||||
    self::assertSame(12, $si);
 | 
			
		||||
 | 
			
		||||
    # int puis string
 | 
			
		||||
    Schema::nv($isv, $is, null, $iss, "int|string");
 | 
			
		||||
 | 
			
		||||
    $isv->set("12");
 | 
			
		||||
    self::assertSame("12", $is);
 | 
			
		||||
    $isv->set(12);
 | 
			
		||||
    self::assertSame(12, $is);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								tests/strTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								tests/strTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace nur\sery;
 | 
			
		||||
 | 
			
		||||
use nulib\tests\TestCase;
 | 
			
		||||
 | 
			
		||||
class strTest extends TestCase {
 | 
			
		||||
  function testCamel2us() {
 | 
			
		||||
    self::assertSame("a", str::camel2us("a"));
 | 
			
		||||
    self::assertSame("aa", str::camel2us("aa"));
 | 
			
		||||
    self::assertSame("aaa", str::camel2us("aaa"));
 | 
			
		||||
    self::assertSame("a", str::camel2us("A"));
 | 
			
		||||
    self::assertSame("aa", str::camel2us("Aa"));
 | 
			
		||||
    self::assertSame("aa", str::camel2us("AA"));
 | 
			
		||||
    self::assertSame("aaa", str::camel2us("Aaa"));
 | 
			
		||||
    self::assertSame("aaa", str::camel2us("AAA"));
 | 
			
		||||
    self::assertSame("a_aa", str::camel2us("AAa"));
 | 
			
		||||
    self::assertSame("a_b", str::camel2us("aB"));
 | 
			
		||||
    self::assertSame("aa_bb", str::camel2us("aaBb"));
 | 
			
		||||
    self::assertSame("aaa_bbb", str::camel2us("aaaBbb"));
 | 
			
		||||
    self::assertSame("aa_bb", str::camel2us("AaBb"));
 | 
			
		||||
    self::assertSame("aaa_bbb", str::camel2us("AaaBbb"));
 | 
			
		||||
 | 
			
		||||
    self::assertSame("_aaa", str::camel2us("_aaa"));
 | 
			
		||||
    self::assertSame("__aaa_bbb", str::camel2us("__aaaBbb"));
 | 
			
		||||
    self::assertSame("___aaa_bbb", str::camel2us("___AaaBbb"));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										200
									
								
								tests/web/uploadsTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										200
									
								
								tests/web/uploadsTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,200 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\web;
 | 
			
		||||
 | 
			
		||||
use PHPUnit\Framework\TestCase;
 | 
			
		||||
 | 
			
		||||
class uploadsTest extends TestCase {
 | 
			
		||||
  const _FILES = [
 | 
			
		||||
    # name="simple"
 | 
			
		||||
    'simple' => [
 | 
			
		||||
      'name' => '',
 | 
			
		||||
      'type' => '',
 | 
			
		||||
      'tmp_name' => '',
 | 
			
		||||
      'error' => 4,
 | 
			
		||||
      'size' => 0,
 | 
			
		||||
    ],
 | 
			
		||||
    # name=multiple[], name=multiple[]
 | 
			
		||||
    'multiple' => [
 | 
			
		||||
      'name' => [
 | 
			
		||||
        0 => '',
 | 
			
		||||
        1 => '',
 | 
			
		||||
      ],
 | 
			
		||||
      'type' => [
 | 
			
		||||
        0 => '',
 | 
			
		||||
        1 => '',
 | 
			
		||||
      ],
 | 
			
		||||
      'tmp_name' => [
 | 
			
		||||
        0 => '',
 | 
			
		||||
        1 => '',
 | 
			
		||||
      ],
 | 
			
		||||
      'error' => [
 | 
			
		||||
        0 => 4,
 | 
			
		||||
        1 => 4,
 | 
			
		||||
      ],
 | 
			
		||||
      'size' => [
 | 
			
		||||
        0 => 0,
 | 
			
		||||
        1 => 0,
 | 
			
		||||
      ],
 | 
			
		||||
    ],
 | 
			
		||||
    # name=onelevel[a], name=onelevel[b]
 | 
			
		||||
    'onelevel' => [
 | 
			
		||||
      'name' => [
 | 
			
		||||
        'a' => '',
 | 
			
		||||
        'b' => '',
 | 
			
		||||
      ],
 | 
			
		||||
      'type' => [
 | 
			
		||||
        'a' => '',
 | 
			
		||||
        'b' => '',
 | 
			
		||||
      ],
 | 
			
		||||
      'tmp_name' => [
 | 
			
		||||
        'a' => '',
 | 
			
		||||
        'b' => '',
 | 
			
		||||
      ],
 | 
			
		||||
      'error' => [
 | 
			
		||||
        'a' => 4,
 | 
			
		||||
        'b' => 4,
 | 
			
		||||
      ],
 | 
			
		||||
      'size' => [
 | 
			
		||||
        'a' => 0,
 | 
			
		||||
        'b' => 0,
 | 
			
		||||
      ],
 | 
			
		||||
    ],
 | 
			
		||||
    # name=multiplelevel[a][], name=multiplelevel[a][], name=multiplelevel[b][], name=multiplelevel[b][]
 | 
			
		||||
    'multiplelevel' => [
 | 
			
		||||
      'name' => [
 | 
			
		||||
        'a' => [
 | 
			
		||||
          0 => '',
 | 
			
		||||
          1 => '',
 | 
			
		||||
        ],
 | 
			
		||||
        'b' => [
 | 
			
		||||
          0 => '',
 | 
			
		||||
          1 => '',
 | 
			
		||||
        ],
 | 
			
		||||
      ],
 | 
			
		||||
      'type' => [
 | 
			
		||||
        'a' => [
 | 
			
		||||
          0 => '',
 | 
			
		||||
          1 => '',
 | 
			
		||||
        ],
 | 
			
		||||
        'b' => [
 | 
			
		||||
          0 => '',
 | 
			
		||||
          1 => '',
 | 
			
		||||
        ],
 | 
			
		||||
      ],
 | 
			
		||||
      'tmp_name' => [
 | 
			
		||||
        'a' => [
 | 
			
		||||
          0 => '',
 | 
			
		||||
          1 => '',
 | 
			
		||||
        ],
 | 
			
		||||
        'b' => [
 | 
			
		||||
          0 => '',
 | 
			
		||||
          1 => '',
 | 
			
		||||
        ],
 | 
			
		||||
      ],
 | 
			
		||||
      'error' => [
 | 
			
		||||
        'a' => [
 | 
			
		||||
          0 => 4,
 | 
			
		||||
          1 => 4,
 | 
			
		||||
        ],
 | 
			
		||||
        'b' => [
 | 
			
		||||
          0 => 4,
 | 
			
		||||
          1 => 4,
 | 
			
		||||
        ],
 | 
			
		||||
      ],
 | 
			
		||||
      'size' => [
 | 
			
		||||
        'a' => [
 | 
			
		||||
          0 => 0,
 | 
			
		||||
          1 => 0,
 | 
			
		||||
        ],
 | 
			
		||||
        'b' => [
 | 
			
		||||
          0 => 0,
 | 
			
		||||
          1 => 0,
 | 
			
		||||
        ],
 | 
			
		||||
      ],
 | 
			
		||||
    ],
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  const PARSED = [
 | 
			
		||||
    # name="simple"
 | 
			
		||||
    'simple' => [
 | 
			
		||||
      'name' => '',
 | 
			
		||||
      'type' => '',
 | 
			
		||||
      'tmp_name' => '',
 | 
			
		||||
      'error' => 4,
 | 
			
		||||
      'size' => 0,
 | 
			
		||||
    ],
 | 
			
		||||
    # name=multiple[], name=multiple[]
 | 
			
		||||
    'multiple' => [
 | 
			
		||||
      0 => [
 | 
			
		||||
        'name' => '',
 | 
			
		||||
        'type' => '',
 | 
			
		||||
        'tmp_name' => '',
 | 
			
		||||
        'error' => 4,
 | 
			
		||||
        'size' => 0,
 | 
			
		||||
      ],
 | 
			
		||||
      1 => [
 | 
			
		||||
        'name' => '',
 | 
			
		||||
        'type' => '',
 | 
			
		||||
        'tmp_name' => '',
 | 
			
		||||
        'error' => 4,
 | 
			
		||||
        'size' => 0,
 | 
			
		||||
      ],
 | 
			
		||||
    ],
 | 
			
		||||
    # name=onelevel[a], name=onelevel[b]
 | 
			
		||||
    'onelevel' => [
 | 
			
		||||
      'a' => [
 | 
			
		||||
        'name' => '',
 | 
			
		||||
        'type' => '',
 | 
			
		||||
        'tmp_name' => '',
 | 
			
		||||
        'error' => 4,
 | 
			
		||||
        'size' => 0,
 | 
			
		||||
      ],
 | 
			
		||||
      'b' => [
 | 
			
		||||
        'name' => '',
 | 
			
		||||
        'type' => '',
 | 
			
		||||
        'tmp_name' => '',
 | 
			
		||||
        'error' => 4,
 | 
			
		||||
        'size' => 0,
 | 
			
		||||
      ],
 | 
			
		||||
    ],
 | 
			
		||||
    # name=multiplelevel[a][], name=multiplelevel[a][], name=multiplelevel[b][], name=multiplelevel[b][]
 | 
			
		||||
    'multiplelevel' => [
 | 
			
		||||
      'a' => [
 | 
			
		||||
        0 => [
 | 
			
		||||
          'name' => '',
 | 
			
		||||
          'type' => '',
 | 
			
		||||
          'tmp_name' => '',
 | 
			
		||||
          'error' => 4,
 | 
			
		||||
          'size' => 0,
 | 
			
		||||
        ],
 | 
			
		||||
        1 => [
 | 
			
		||||
          'name' => '',
 | 
			
		||||
          'type' => '',
 | 
			
		||||
          'tmp_name' => '',
 | 
			
		||||
          'error' => 4,
 | 
			
		||||
          'size' => 0,
 | 
			
		||||
        ],
 | 
			
		||||
      ],
 | 
			
		||||
      'b' => [
 | 
			
		||||
        0 => [
 | 
			
		||||
          'name' => '',
 | 
			
		||||
          'type' => '',
 | 
			
		||||
          'tmp_name' => '',
 | 
			
		||||
          'error' => 4,
 | 
			
		||||
          'size' => 0,
 | 
			
		||||
        ],
 | 
			
		||||
        1 => [
 | 
			
		||||
          'name' => '',
 | 
			
		||||
          'type' => '',
 | 
			
		||||
          'tmp_name' => '',
 | 
			
		||||
          'error' => 4,
 | 
			
		||||
          'size' => 0,
 | 
			
		||||
        ],
 | 
			
		||||
      ],
 | 
			
		||||
    ],
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  function test_files() {
 | 
			
		||||
    self::assertSame(self::PARSED, uploads::_files(self::_FILES));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -13,43 +13,6 @@ class CursorTest extends TestCase {
 | 
			
		||||
    msg::set_messenger(new StdMessenger());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function test_map_row() {
 | 
			
		||||
    $cursor = new class extends Cursor {
 | 
			
		||||
      function mapRow(array $row, ?array $map): array {
 | 
			
		||||
        return self::map_row($row, $map);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    $row = ["a" => 1, "b" => 2, "c" => 3, "x" => 99];
 | 
			
		||||
    $map = ["a", "b" => "x", "c" => function() { return "y"; }, "d" => null];
 | 
			
		||||
    self::assertSame([
 | 
			
		||||
      "a" => $row["a"],
 | 
			
		||||
      "b" => $row["x"],
 | 
			
		||||
      "c" => "y",
 | 
			
		||||
      "d" => null
 | 
			
		||||
    ], $cursor->mapRow($row, $map));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function test_filter_row() {
 | 
			
		||||
    $cursor = new class extends Cursor {
 | 
			
		||||
      function filterRow(array $row, $filter): bool {
 | 
			
		||||
        return self::filter_row($row, $filter);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    $row = ["a" => 1, "b" => 2, "c" => 3, "x" => 99];
 | 
			
		||||
    self::assertTrue($cursor->filterRow($row, "a"));
 | 
			
		||||
    self::assertTrue($cursor->filterRow($row, ["a"]));
 | 
			
		||||
    self::assertTrue($cursor->filterRow($row, ["a" => true]));
 | 
			
		||||
    self::assertFalse($cursor->filterRow($row, ["a" => false]));
 | 
			
		||||
    self::assertTrue($cursor->filterRow($row, ["a" => 1]));
 | 
			
		||||
    self::assertFalse($cursor->filterRow($row, ["a" => 2]));
 | 
			
		||||
 | 
			
		||||
    self::assertFalse($cursor->filterRow($row, "z"));
 | 
			
		||||
    self::assertFalse($cursor->filterRow($row, ["z"]));
 | 
			
		||||
    self::assertFalse($cursor->filterRow($row, ["z" => true]));
 | 
			
		||||
    self::assertTrue($cursor->filterRow($row, ["z" => false]));
 | 
			
		||||
    self::assertFalse($cursor->filterRow($row, ["z" => 1]));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const SCALARS = [0, 1, 2, 3, 4];
 | 
			
		||||
 | 
			
		||||
  function generator() {
 | 
			
		||||
@ -78,15 +41,6 @@ class CursorTest extends TestCase {
 | 
			
		||||
      return cl::all($c);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $c = new Cursor(null, [
 | 
			
		||||
      "rows" => $this->generator(),
 | 
			
		||||
    ]);
 | 
			
		||||
    self::assertSame([[0], [1], [2], [3], [4]], cl::all($c));
 | 
			
		||||
    self::assertException(Exception::class, function() use ($c) {
 | 
			
		||||
      // pas possible de rewind un générateur
 | 
			
		||||
      return cl::all($c);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $c = new Cursor(null, [
 | 
			
		||||
      "rows_func" => function() {
 | 
			
		||||
        return self::SCALARS;
 | 
			
		||||
 | 
			
		||||
@ -1,95 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\_assoc;
 | 
			
		||||
 | 
			
		||||
use nulib\ext\yaml;
 | 
			
		||||
use nulib\tests\TestCase;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarSchemaTest;
 | 
			
		||||
 | 
			
		||||
class AssocSchemaTest extends TestCase {
 | 
			
		||||
  const NULL_SCHEMA = [
 | 
			
		||||
    "" => ["assoc"],
 | 
			
		||||
    "schema" => null,
 | 
			
		||||
    "type" => [null],
 | 
			
		||||
    "default" => null,
 | 
			
		||||
    "title" => null,
 | 
			
		||||
    "required" => false,
 | 
			
		||||
    "nullable" => true,
 | 
			
		||||
    "desc" => null,
 | 
			
		||||
    "analyzer_func" => null,
 | 
			
		||||
    "extractor_func" => null,
 | 
			
		||||
    "parser_func" => null,
 | 
			
		||||
    "normalizer_func" => null,
 | 
			
		||||
    "messages" => null,
 | 
			
		||||
    "formatter_func" => null,
 | 
			
		||||
    "format" => null,
 | 
			
		||||
    "name" => null,
 | 
			
		||||
    "pkey" => null,
 | 
			
		||||
    "header" => null,
 | 
			
		||||
    "composite" => null,
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  static function schema(array $definition, array $keyDefinitions): array {
 | 
			
		||||
    $definition = array_merge(self::NULL_SCHEMA, $definition, ["schema" => []]);
 | 
			
		||||
    foreach ($keyDefinitions as $key => $keydef) {
 | 
			
		||||
      $definition["schema"][$key] = array_merge(ScalarSchemaTest::NULL_SCHEMA, $keydef);
 | 
			
		||||
    }; unset($subdef);
 | 
			
		||||
    return $definition;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testNormalize() {
 | 
			
		||||
    self::assertSame(self::schema([
 | 
			
		||||
      "type" => ["array"], "nullable" => true,
 | 
			
		||||
    ], [
 | 
			
		||||
      "a" => [
 | 
			
		||||
        "type" => ["string"], "nullable" => false,
 | 
			
		||||
        "name" => "a", "pkey" => "a", "header" => "a",
 | 
			
		||||
      ],
 | 
			
		||||
    ]), AssocSchema::normalize(["a" => "string"]));
 | 
			
		||||
 | 
			
		||||
    self::assertSame(self::schema([
 | 
			
		||||
      "type" => ["array"], "nullable" => true,
 | 
			
		||||
    ], [
 | 
			
		||||
      "a" => [
 | 
			
		||||
        "type" => ["string"], "nullable" => false,
 | 
			
		||||
        "name" => "a", "pkey" => "a", "header" => "a",
 | 
			
		||||
      ],
 | 
			
		||||
      "b" => [
 | 
			
		||||
        "type" => ["int"], "nullable" => false,
 | 
			
		||||
        "name" => "b", "pkey" => "b", "header" => "b",
 | 
			
		||||
      ],
 | 
			
		||||
      "c" => [
 | 
			
		||||
        "type" => ["bool"], "nullable" => false,
 | 
			
		||||
        "name" => "c", "pkey" => "c", "header" => "c",
 | 
			
		||||
      ],
 | 
			
		||||
    ]), AssocSchema::normalize([
 | 
			
		||||
      "a" => "string",
 | 
			
		||||
      "b" => "int",
 | 
			
		||||
      "c" => "bool",
 | 
			
		||||
    ]));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testConstructor() {
 | 
			
		||||
    $schema = new AssocSchema([
 | 
			
		||||
      "a" => "string",
 | 
			
		||||
      "b" => "int",
 | 
			
		||||
      "c" => "bool",
 | 
			
		||||
    ]);
 | 
			
		||||
    self::assertSame(self::schema([
 | 
			
		||||
      "type" => ["array"], "nullable" => true,
 | 
			
		||||
    ], [
 | 
			
		||||
      "a" => [
 | 
			
		||||
        "type" => ["string"], "nullable" => false,
 | 
			
		||||
        "name" => "a", "pkey" => "a", "header" => "a",
 | 
			
		||||
      ],
 | 
			
		||||
      "b" => [
 | 
			
		||||
        "type" => ["int"], "nullable" => false,
 | 
			
		||||
        "name" => "b", "pkey" => "b", "header" => "b",
 | 
			
		||||
      ],
 | 
			
		||||
      "c" => [
 | 
			
		||||
        "type" => ["bool"], "nullable" => false,
 | 
			
		||||
        "name" => "c", "pkey" => "c", "header" => "c",
 | 
			
		||||
      ],
 | 
			
		||||
    ]), $schema->getDefinition());
 | 
			
		||||
    yaml::dump($schema->getDefinition());
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,294 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\_scalar;
 | 
			
		||||
 | 
			
		||||
use nulib\tests\TestCase;
 | 
			
		||||
use nulib\ValueException;
 | 
			
		||||
use nur\sery\wip\schema\input\Input;
 | 
			
		||||
use stdClass;
 | 
			
		||||
 | 
			
		||||
class ScalarWrapperTest extends TestCase {
 | 
			
		||||
  function checkValue(ScalarWrapper $wrapper, $value, bool $present, bool $available, bool $valid, bool $normalized): void {
 | 
			
		||||
    self::assertSame($value, $wrapper->get(), "value");
 | 
			
		||||
    self::assertSame($present, $wrapper->isPresent(), "present");
 | 
			
		||||
    self::assertSame($available, $wrapper->isAvailable(), "available");
 | 
			
		||||
    self::assertSame($valid, $wrapper->isValid(), "valid");
 | 
			
		||||
    self::assertSame($normalized, $wrapper->isNormalized(), "normalized");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function checkVerifix(ScalarSchema $schema, $orig, bool $verifix, $value, bool $present, bool $available, bool $valid, bool $normalized, ?array $inputParams=null): void {
 | 
			
		||||
    $wrapper = $schema->getWrapper();
 | 
			
		||||
    if ($inputParams !== null) $input = new Input($orig, $inputParams);
 | 
			
		||||
    else $input = $orig;
 | 
			
		||||
    $wrapper->reset($input, null, $verifix);
 | 
			
		||||
    $this->checkValue($wrapper, $value, $present, $available, $valid, $normalized);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function checkException(ScalarSchema $schema, $orig, bool $verifix, string $exceptionClass, ?array $inputParams=null) {
 | 
			
		||||
    $wrapper = $schema->getWrapper();
 | 
			
		||||
    if ($inputParams !== null) $orig = new Input($orig, $inputParams);
 | 
			
		||||
    self::assertException($exceptionClass, function() use ($wrapper, &$orig, $verifix) {
 | 
			
		||||
      $wrapper->reset($orig, null, $verifix);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testRaw() {
 | 
			
		||||
    $schema = new ScalarSchema();
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, false, false, false, true, true, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, false, true, false, true, true, true, true);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, null, false, null, true, true, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, null, true, null, true, true, true, true);
 | 
			
		||||
 | 
			
		||||
    $obj = new stdClass();
 | 
			
		||||
    $this->checkVerifix($schema, $obj, false, $obj, true, true, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, $obj, true, $obj, true, true, true, true);
 | 
			
		||||
 | 
			
		||||
    $schema = new ScalarSchema("raw");
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, false, false, false, true, true, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, false, true, false, true, true, true, true);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, null, false, null, true, true, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, null, true, null, true, true, true, true);
 | 
			
		||||
 | 
			
		||||
    $obj = new stdClass();
 | 
			
		||||
    $this->checkVerifix($schema, $obj, false, $obj, true, true, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, $obj, true, $obj, true, true, true, true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testMixed() {
 | 
			
		||||
    $schema = new ScalarSchema("mixed");
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, false, false, false, true, true, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, false, true, false, true, true, true, true);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, null, false, null, true, true, false, false);
 | 
			
		||||
    $this->checkException($schema, null, true, ValueException::class);
 | 
			
		||||
 | 
			
		||||
    $obj = new stdClass();
 | 
			
		||||
    $this->checkVerifix($schema, $obj, false, $obj, true, true, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, $obj, true, $obj, true, true, true, true);
 | 
			
		||||
 | 
			
		||||
    $schema = new ScalarSchema("?mixed");
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, false, false, false, true, true, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, false, true, false, true, true, true, true);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, null, false, null, true, true, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, null, true, null, true, true, true, true);
 | 
			
		||||
 | 
			
		||||
    $obj = new stdClass();
 | 
			
		||||
    $this->checkVerifix($schema, $obj, false, $obj, true, true, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, $obj, true, $obj, true, true, true, true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testRawstring() {
 | 
			
		||||
    $schema = new ScalarSchema("rawstring");
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, false, false, null, true, false, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, false, true, null, true, false, true, true);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, null, false, null, true, true, false, false);
 | 
			
		||||
    $this->checkException($schema, null, true, ValueException::class);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, "", false, "", true, true, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, "", true, "", true, true, true, true);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, "   ", false, "   ", true, true, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, "   ", true, "   ", true, true, true, true);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, "text", false, "text", true, true, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, "text", true, "text", true, true, true, true);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, "  text  ", false, "  text  ", true, true, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, "  text  ", true, "  text  ", true, true, true, true);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, true, false, true, true, true, true, false);
 | 
			
		||||
    $this->checkVerifix($schema, true, true, "1", true, true, true, false);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, 42, false, 42, true, true, true, false);
 | 
			
		||||
    $this->checkVerifix($schema, 42, true, "42", true, true, true, false);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, [], false, [], true, true, false, false);
 | 
			
		||||
    $this->checkException($schema, [], true, ValueException::class);
 | 
			
		||||
 | 
			
		||||
    ## Tester valeur par défaut
 | 
			
		||||
    $schema = new ScalarSchema(["rawstring", null]);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, false, false, null, true, false, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, false, true, null, true, false, true, true);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, null, false, null, true, true, false, false);
 | 
			
		||||
    $this->checkException($schema, null, true, ValueException::class);
 | 
			
		||||
 | 
			
		||||
    $schema = new ScalarSchema(["rawstring", "default"]);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, false, false, "default", true, true, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, false, true, "default", true, true, true, true);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, null, false, null, true, true, false, false);
 | 
			
		||||
    $this->checkException($schema, null, true, ValueException::class);
 | 
			
		||||
 | 
			
		||||
    ## Tester nullable
 | 
			
		||||
    $schema = new ScalarSchema("?rawstring");
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, null, false, null, true, true, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, null, true, null, true, true, true, true);
 | 
			
		||||
 | 
			
		||||
    ## Tester required
 | 
			
		||||
    $schema = new ScalarSchema(["rawstring", "required" => true]);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, false, false, null, true, false, false, false);
 | 
			
		||||
    $this->checkException($schema, false, true, ValueException::class);
 | 
			
		||||
 | 
			
		||||
    ## Tester allow_empty === false
 | 
			
		||||
    $inputParams = ["allow_empty" => false];
 | 
			
		||||
    $schema = new ScalarSchema("rawstring");
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, null, false, null, true, true, false, false, $inputParams);
 | 
			
		||||
    $this->checkException($schema, null, true, ValueException::class, $inputParams);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, "", false, null, true, false, true, true, $inputParams);
 | 
			
		||||
    $this->checkVerifix($schema, "", true, null, true, false, true, true, $inputParams);
 | 
			
		||||
 | 
			
		||||
    $schema = new ScalarSchema("?rawstring");
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, null, false, null, true, true, true, true, $inputParams);
 | 
			
		||||
    $this->checkVerifix($schema, null, true, null, true, true, true, true, $inputParams);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, "", false, null, true, false, true, true, $inputParams);
 | 
			
		||||
    $this->checkVerifix($schema, "", true, null, true, false, true, true, $inputParams);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testString() {
 | 
			
		||||
    $schema = new ScalarSchema("string");
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, false, false, null, true, false, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, false, true, null, true, false, true, true);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, null, false, null, true, true, false, false);
 | 
			
		||||
    $this->checkException($schema, null, true, ValueException::class);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, "", false, "", true, true, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, "", true, "", true, true, true, true);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, "   ", false, "", true, true, true, false);
 | 
			
		||||
    $this->checkVerifix($schema, "   ", true, "", true, true, true, false);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, "text", false, "text", true, true, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, "text", true, "text", true, true, true, true);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, "  text  ", false, "text", true, true, true, false);
 | 
			
		||||
    $this->checkVerifix($schema, "  text  ", true, "text", true, true, true, false);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, true, false, true, true, true, true, false);
 | 
			
		||||
    $this->checkVerifix($schema, true, true, "1", true, true, true, false);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, 42, false, 42, true, true, true, false);
 | 
			
		||||
    $this->checkVerifix($schema, 42, true, "42", true, true, true, false);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, [], false, [], true, true, false, false);
 | 
			
		||||
    $this->checkException($schema, [], true, ValueException::class);
 | 
			
		||||
 | 
			
		||||
    ## Tester nullable
 | 
			
		||||
    $schema = new ScalarSchema("?string");
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, null, false, null, true, true, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, null, true, null, true, true, true, true);
 | 
			
		||||
 | 
			
		||||
    ## Tester required
 | 
			
		||||
    $schema = new ScalarSchema(["string", "required" => true]);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, false, false, null, true, false, false, false);
 | 
			
		||||
    $this->checkException($schema, false, true, ValueException::class);
 | 
			
		||||
 | 
			
		||||
    ## Tester allow_empty === false
 | 
			
		||||
    $inputParams = ["allow_empty" => false];
 | 
			
		||||
    $schema = new ScalarSchema("string");
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, null, false, null, true, true, false, false, $inputParams);
 | 
			
		||||
    $this->checkException($schema, null, true, ValueException::class, $inputParams);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, "", false, null, true, false, true, true, $inputParams);
 | 
			
		||||
    $this->checkVerifix($schema, "", true, null, true, false, true, true, $inputParams);
 | 
			
		||||
 | 
			
		||||
    $schema = new ScalarSchema("?string");
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, null, false, null, true, true, true, true, $inputParams);
 | 
			
		||||
    $this->checkVerifix($schema, null, true, null, true, true, true, true, $inputParams);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, "", false, null, true, false, true, true, $inputParams);
 | 
			
		||||
    $this->checkVerifix($schema, "", true, null, true, false, true, true, $inputParams);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testInt() {
 | 
			
		||||
    $schema = new ScalarSchema("int");
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, false, false, null, true, false, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, false, true, null, true, false, true, true);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, null, false, null, true, true, false, false);
 | 
			
		||||
    $this->checkException($schema, null, true, ValueException::class);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, 42, false, 42, true, true, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, 42, true, 42, true, true, true, true);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, "42", false, "42", true, true, true, false);
 | 
			
		||||
    $this->checkVerifix($schema, "42", true, 42, true, true, true, false);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, "42.5", false, "42.5", true, true, true, false);
 | 
			
		||||
    $this->checkVerifix($schema, "42.5", true, 42, true, true, true, false);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, "42,5", false, "42,5", true, true, true, false);
 | 
			
		||||
    $this->checkVerifix($schema, "42,5", true, 42, true, true, true, false);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, "  42  ", false, "42", true, true, true, false);
 | 
			
		||||
    $this->checkVerifix($schema, "  42  ", true, 42, true, true, true, false);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, "", false, "", true, true, false, false);
 | 
			
		||||
    $this->checkException($schema, "", true, ValueException::class);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, "   ", false, "   ", true, true, false, false);
 | 
			
		||||
    $this->checkException($schema, "   ", true, ValueException::class);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, "text", false, "text", true, true, false, false);
 | 
			
		||||
    $this->checkException($schema, "text", true, ValueException::class);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, true, false, true, true, true, true, false);
 | 
			
		||||
    $this->checkVerifix($schema, true, true, 1, true, true, true, false);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, [], false, [], true, true, false, false);
 | 
			
		||||
    $this->checkException($schema, [], true, ValueException::class);
 | 
			
		||||
 | 
			
		||||
    ## Tester nullable
 | 
			
		||||
    $schema = new ScalarSchema("?int");
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, null, false, null, true, true, true, true);
 | 
			
		||||
    $this->checkVerifix($schema, null, true, null, true, true, true, true);
 | 
			
		||||
 | 
			
		||||
    ## Tester required
 | 
			
		||||
    $schema = new ScalarSchema(["int", "required" => true]);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, false, false, null, true, false, false, false);
 | 
			
		||||
    $this->checkException($schema, false, true, ValueException::class);
 | 
			
		||||
 | 
			
		||||
    ## Tester allow_empty === false
 | 
			
		||||
    $inputParams = ["allow_empty" => false];
 | 
			
		||||
    $schema = new ScalarSchema("int");
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, null, false, null, true, true, false, false, $inputParams);
 | 
			
		||||
    $this->checkException($schema, null, true, ValueException::class, $inputParams);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, "", false, null, true, false, true, true, $inputParams);
 | 
			
		||||
    $this->checkVerifix($schema, "", true, null, true, false, true, true, $inputParams);
 | 
			
		||||
 | 
			
		||||
    $schema = new ScalarSchema("?int");
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, null, false, null, true, true, true, true, $inputParams);
 | 
			
		||||
    $this->checkVerifix($schema, null, true, null, true, true, true, true, $inputParams);
 | 
			
		||||
 | 
			
		||||
    $this->checkVerifix($schema, "", false, null, true, false, true, true, $inputParams);
 | 
			
		||||
    $this->checkVerifix($schema, "", true, null, true, false, true, true, $inputParams);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,111 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\types;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
use nulib\tests\TestCase;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarWrapper;
 | 
			
		||||
use nur\sery\wip\schema\Schema;
 | 
			
		||||
 | 
			
		||||
class boolTest extends TestCase {
 | 
			
		||||
  function commonTests($wrapper, &$value, callable $wrapperSetter): void {
 | 
			
		||||
    $wrapper->set(true);
 | 
			
		||||
    self::assertSame(true, $wrapper->get());
 | 
			
		||||
    self::assertSame(true, $value);
 | 
			
		||||
    self::assertSame("Oui", $wrapper->format());
 | 
			
		||||
    self::assertSame("Oui", $wrapper->format("OuiNonNull"));
 | 
			
		||||
    self::assertSame("O", $wrapper->format("ON"));
 | 
			
		||||
    self::assertSame("O", $wrapper->format("ONN"));
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(false);
 | 
			
		||||
    self::assertSame(false, $wrapper->get());
 | 
			
		||||
    self::assertSame(false, $value);
 | 
			
		||||
    self::assertSame("Non", $wrapper->format());
 | 
			
		||||
    self::assertSame("Non", $wrapper->format("OuiNonNull"));
 | 
			
		||||
    self::assertSame("N", $wrapper->format("ON"));
 | 
			
		||||
    self::assertSame("N", $wrapper->format("ONN"));
 | 
			
		||||
 | 
			
		||||
    $wrapper->set("yes");
 | 
			
		||||
    self::assertSame(true, $wrapper->get());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(" yes ");
 | 
			
		||||
    self::assertSame(true, $wrapper->get());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set("12");
 | 
			
		||||
    self::assertSame(true, $wrapper->get());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(12);
 | 
			
		||||
    self::assertSame(true, $wrapper->get());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set("no");
 | 
			
		||||
    self::assertSame(false, $wrapper->get());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(" no ");
 | 
			
		||||
    self::assertSame(false, $wrapper->get());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set("0");
 | 
			
		||||
    self::assertSame(false, $wrapper->get());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(0);
 | 
			
		||||
    self::assertSame(false, $wrapper->get());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(12.34);
 | 
			
		||||
    self::assertSame(true, $wrapper->get());
 | 
			
		||||
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter("a"));
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter([]));
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(["a"]));
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testBool() {
 | 
			
		||||
    /** @var ScalarWrapper $wrapper */
 | 
			
		||||
    Schema::nw($value, null, $schema, "bool", $wrapper);
 | 
			
		||||
    $wrapperSetter = function($value) use($wrapper) {
 | 
			
		||||
      return function() use($wrapper, $value) {
 | 
			
		||||
        $wrapper->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(null));
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(""));
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(" "));
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($wrapper, $value, $wrapperSetter);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testNbool() {
 | 
			
		||||
    /** @var ScalarWrapper $wrapper */
 | 
			
		||||
    Schema::nw($value, null, $schema, "?bool", $wrapper);
 | 
			
		||||
    $wrapperSetter = function($value) use($wrapper) {
 | 
			
		||||
      return function() use($wrapper, $value) {
 | 
			
		||||
        $wrapper->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(null);
 | 
			
		||||
    self::assertNull($wrapper->get());
 | 
			
		||||
    self::assertNull($value);
 | 
			
		||||
    self::assertSame("Non", $wrapper->format());
 | 
			
		||||
    self::assertSame("", $wrapper->format("OuiNonNull"));
 | 
			
		||||
    self::assertSame("N", $wrapper->format("ON"));
 | 
			
		||||
    self::assertSame("", $wrapper->format("ONN"));
 | 
			
		||||
 | 
			
		||||
    $wrapper->set("");
 | 
			
		||||
    self::assertNull($wrapper->get());
 | 
			
		||||
    self::assertNull($value);
 | 
			
		||||
    self::assertSame("Non", $wrapper->format());
 | 
			
		||||
    self::assertSame("", $wrapper->format("OuiNonNull"));
 | 
			
		||||
    self::assertSame("N", $wrapper->format("ON"));
 | 
			
		||||
    self::assertSame("", $wrapper->format("ONN"));
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(" ");
 | 
			
		||||
    self::assertNull($wrapper->get());
 | 
			
		||||
    self::assertNull($value);
 | 
			
		||||
    self::assertSame("Non", $wrapper->format());
 | 
			
		||||
    self::assertSame("", $wrapper->format("OuiNonNull"));
 | 
			
		||||
    self::assertSame("N", $wrapper->format("ON"));
 | 
			
		||||
    self::assertSame("", $wrapper->format("ONN"));
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($wrapper, $value, $wrapperSetter);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,139 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\types;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
use nulib\tests\TestCase;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarWrapper;
 | 
			
		||||
use nur\sery\wip\schema\Schema;
 | 
			
		||||
 | 
			
		||||
class floatTest extends TestCase {
 | 
			
		||||
  function commonTests($wrapper, &$value, callable $wrapperSetter): void {
 | 
			
		||||
    $wrapper->set(12);
 | 
			
		||||
    self::assertSame(12.0, $wrapper->get());
 | 
			
		||||
    self::assertSame(12.0, $value);
 | 
			
		||||
    self::assertSame("12", $wrapper->format());
 | 
			
		||||
    self::assertSame("0012", $wrapper->format("%04u"));
 | 
			
		||||
 | 
			
		||||
    $wrapper->set("12");
 | 
			
		||||
    self::assertSame(12.0, $wrapper->get());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(" 12 ");
 | 
			
		||||
    self::assertSame(12.0, $wrapper->get());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(12.34);
 | 
			
		||||
    self::assertSame(12.34, $wrapper->get());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(true);
 | 
			
		||||
    self::assertSame(1.0, $wrapper->get());
 | 
			
		||||
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter("a"));
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter([]));
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(["a"]));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testFloat() {
 | 
			
		||||
    /** @var ScalarWrapper $wrapper */
 | 
			
		||||
    Schema::nw($value, null, $schema, "float", $wrapper);
 | 
			
		||||
    $wrapperSetter = function($value) use($wrapper) {
 | 
			
		||||
      return function() use($wrapper, $value) {
 | 
			
		||||
        $wrapper->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(null));
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(""));
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(" "));
 | 
			
		||||
 | 
			
		||||
    // valeur non requise donc retourne null
 | 
			
		||||
    $wrapper->set(false);
 | 
			
		||||
    self::assertNull($wrapper->get());
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($wrapper, $value, $wrapperSetter);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testRequiredFloat() {
 | 
			
		||||
    /** @var ScalarWrapper $wrapper */
 | 
			
		||||
    Schema::nw($value, null, $schema, [
 | 
			
		||||
      "float", null,
 | 
			
		||||
      "required" => true,
 | 
			
		||||
    ], $wrapper);
 | 
			
		||||
    $wrapperSetter = function($value) use($wrapper) {
 | 
			
		||||
      return function() use($wrapper, $value) {
 | 
			
		||||
        $wrapper->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(null));
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(""));
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(" "));
 | 
			
		||||
 | 
			
		||||
    // valeur requise donc lance une exception
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(false));
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($wrapper, $value, $wrapperSetter);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testNfloat() {
 | 
			
		||||
    /** @var ScalarWrapper $wrapper */
 | 
			
		||||
    Schema::nw($value, null, $schema, "?float", $wrapper);
 | 
			
		||||
    $wrapperSetter = function($value) use($wrapper) {
 | 
			
		||||
      return function() use($wrapper, $value) {
 | 
			
		||||
        $wrapper->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(null);
 | 
			
		||||
    self::assertNull($wrapper->get());
 | 
			
		||||
    self::assertNull($value);
 | 
			
		||||
    self::assertSame("", $wrapper->format());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set("");
 | 
			
		||||
    self::assertNull($wrapper->get());
 | 
			
		||||
    self::assertNull($value);
 | 
			
		||||
    self::assertSame("", $wrapper->format());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(" ");
 | 
			
		||||
    self::assertNull($wrapper->get());
 | 
			
		||||
    self::assertNull($value);
 | 
			
		||||
    self::assertSame("", $wrapper->format());
 | 
			
		||||
 | 
			
		||||
    // valeur non requise donc retourne null
 | 
			
		||||
    $wrapper->set(false);
 | 
			
		||||
    self::assertNull($wrapper->get());
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($wrapper, $value, $wrapperSetter);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testRequiredNfloat() {
 | 
			
		||||
    /** @var ScalarWrapper $wrapper */
 | 
			
		||||
    Schema::nw($value, null, $schema, [
 | 
			
		||||
      "?float", null,
 | 
			
		||||
      "required" => true,
 | 
			
		||||
    ], $wrapper);
 | 
			
		||||
    $wrapperSetter = function($value) use($wrapper) {
 | 
			
		||||
      return function() use($wrapper, $value) {
 | 
			
		||||
        $wrapper->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(null);
 | 
			
		||||
    self::assertNull($wrapper->get());
 | 
			
		||||
    self::assertNull($value);
 | 
			
		||||
    self::assertSame("", $wrapper->format());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set("");
 | 
			
		||||
    self::assertNull($wrapper->get());
 | 
			
		||||
    self::assertNull($value);
 | 
			
		||||
    self::assertSame("", $wrapper->format());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(" ");
 | 
			
		||||
    self::assertNull($wrapper->get());
 | 
			
		||||
    self::assertNull($value);
 | 
			
		||||
    self::assertSame("", $wrapper->format());
 | 
			
		||||
 | 
			
		||||
    // valeur requise donc lance une exception
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(false));
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($wrapper, $value, $wrapperSetter);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,139 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\types;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
use nulib\tests\TestCase;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarWrapper;
 | 
			
		||||
use nur\sery\wip\schema\Schema;
 | 
			
		||||
 | 
			
		||||
class intTest extends TestCase {
 | 
			
		||||
  function commonTests($wrapper, &$value, callable $wrapperSetter): void {
 | 
			
		||||
    $wrapper->set(12);
 | 
			
		||||
    self::assertSame(12, $wrapper->get());
 | 
			
		||||
    self::assertSame(12, $value);
 | 
			
		||||
    self::assertSame("12", $wrapper->format());
 | 
			
		||||
    self::assertSame("0012", $wrapper->format("%04u"));
 | 
			
		||||
 | 
			
		||||
    $wrapper->set("12");
 | 
			
		||||
    self::assertSame(12, $wrapper->get());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(" 12 ");
 | 
			
		||||
    self::assertSame(12, $wrapper->get());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(12.34);
 | 
			
		||||
    self::assertSame(12, $wrapper->get());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(true);
 | 
			
		||||
    self::assertSame(1, $wrapper->get());
 | 
			
		||||
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter("a"));
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter([]));
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(["a"]));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testInt() {
 | 
			
		||||
    /** @var ScalarWrapper $wrapper */
 | 
			
		||||
    Schema::nw($value, null, $schema, "int", $wrapper);
 | 
			
		||||
    $wrapperSetter = function($value) use($wrapper) {
 | 
			
		||||
      return function() use($wrapper, $value) {
 | 
			
		||||
        $wrapper->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(null));
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(""));
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(" "));
 | 
			
		||||
 | 
			
		||||
    // valeur non requise donc retourne null
 | 
			
		||||
    $wrapper->set(false);
 | 
			
		||||
    self::assertNull($wrapper->get());
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($wrapper, $value, $wrapperSetter);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testRequiredInt() {
 | 
			
		||||
    /** @var ScalarWrapper $wrapper */
 | 
			
		||||
    Schema::nw($value, null, $schema, [
 | 
			
		||||
      "int", null,
 | 
			
		||||
      "required" => true,
 | 
			
		||||
    ], $wrapper);
 | 
			
		||||
    $wrapperSetter = function($value) use($wrapper) {
 | 
			
		||||
      return function() use($wrapper, $value) {
 | 
			
		||||
        $wrapper->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(null));
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(""));
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(" "));
 | 
			
		||||
 | 
			
		||||
    // valeur requise donc lance une exception
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(false));
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($wrapper, $value, $wrapperSetter);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testNint() {
 | 
			
		||||
    /** @var ScalarWrapper $wrapper */
 | 
			
		||||
    Schema::nw($value, null, $schema, "?int", $wrapper);
 | 
			
		||||
    $wrapperSetter = function($value) use($wrapper) {
 | 
			
		||||
      return function() use($wrapper, $value) {
 | 
			
		||||
        $wrapper->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(null);
 | 
			
		||||
    self::assertNull($wrapper->get());
 | 
			
		||||
    self::assertNull($value);
 | 
			
		||||
    self::assertSame("", $wrapper->format());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set("");
 | 
			
		||||
    self::assertNull($wrapper->get());
 | 
			
		||||
    self::assertNull($value);
 | 
			
		||||
    self::assertSame("", $wrapper->format());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(" ");
 | 
			
		||||
    self::assertNull($wrapper->get());
 | 
			
		||||
    self::assertNull($value);
 | 
			
		||||
    self::assertSame("", $wrapper->format());
 | 
			
		||||
 | 
			
		||||
    // valeur non requise donc retourne null
 | 
			
		||||
    $wrapper->set(false);
 | 
			
		||||
    self::assertNull($wrapper->get());
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($wrapper, $value, $wrapperSetter);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testRequiredNint() {
 | 
			
		||||
    /** @var ScalarWrapper $wrapper */
 | 
			
		||||
    Schema::nw($value, null, $schema, [
 | 
			
		||||
      "?int", null,
 | 
			
		||||
      "required" => true,
 | 
			
		||||
    ], $wrapper);
 | 
			
		||||
    $wrapperSetter = function($value) use($wrapper) {
 | 
			
		||||
      return function() use($wrapper, $value) {
 | 
			
		||||
        $wrapper->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(null);
 | 
			
		||||
    self::assertNull($wrapper->get());
 | 
			
		||||
    self::assertNull($value);
 | 
			
		||||
    self::assertSame("", $wrapper->format());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set("");
 | 
			
		||||
    self::assertNull($wrapper->get());
 | 
			
		||||
    self::assertNull($value);
 | 
			
		||||
    self::assertSame("", $wrapper->format());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(" ");
 | 
			
		||||
    self::assertNull($wrapper->get());
 | 
			
		||||
    self::assertNull($value);
 | 
			
		||||
    self::assertSame("", $wrapper->format());
 | 
			
		||||
 | 
			
		||||
    // valeur requise donc lance une exception
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(false));
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($wrapper, $value, $wrapperSetter);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,123 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\types;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
use nulib\tests\TestCase;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarWrapper;
 | 
			
		||||
use nur\sery\wip\schema\Schema;
 | 
			
		||||
 | 
			
		||||
class strTest extends TestCase {
 | 
			
		||||
  function commonTests($wrapper, &$value, callable $wrapperSetter): void {
 | 
			
		||||
    $wrapper->set("");
 | 
			
		||||
    self::assertSame("", $wrapper->get());
 | 
			
		||||
    self::assertSame("", $value);
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(" ");
 | 
			
		||||
    self::assertSame("", $wrapper->get());
 | 
			
		||||
    self::assertSame("", $value);
 | 
			
		||||
 | 
			
		||||
    $wrapper->set("a");
 | 
			
		||||
    self::assertSame("a", $wrapper->get());
 | 
			
		||||
    self::assertSame("a", $value);
 | 
			
		||||
 | 
			
		||||
    $wrapper->set("12");
 | 
			
		||||
    self::assertSame("12", $wrapper->get());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(" 12 ");
 | 
			
		||||
    self::assertSame("12", $wrapper->get());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(12);
 | 
			
		||||
    self::assertSame("12", $wrapper->get());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(12.34);
 | 
			
		||||
    self::assertSame("12.34", $wrapper->get());
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(true);
 | 
			
		||||
    self::assertSame("1", $wrapper->get());
 | 
			
		||||
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter([]));
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(["a"]));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testStr() {
 | 
			
		||||
    /** @var ScalarWrapper $wrapper */
 | 
			
		||||
    Schema::nw($value, null, $schema, "string", $wrapper);
 | 
			
		||||
    $wrapperSetter = function($value) use($wrapper) {
 | 
			
		||||
      return function() use($wrapper, $value) {
 | 
			
		||||
        $wrapper->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(null));
 | 
			
		||||
 | 
			
		||||
    // valeur non requise donc retourne null
 | 
			
		||||
    $wrapper->set(false);
 | 
			
		||||
    self::assertNull($wrapper->get());
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($wrapper, $value, $wrapperSetter);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testRequiredStr() {
 | 
			
		||||
    /** @var ScalarWrapper $wrapper */
 | 
			
		||||
    Schema::nw($value, null, $schema, [
 | 
			
		||||
      "string", null,
 | 
			
		||||
      "required" => true,
 | 
			
		||||
    ], $wrapper);
 | 
			
		||||
    $wrapperSetter = function($value) use($wrapper) {
 | 
			
		||||
      return function() use($wrapper, $value) {
 | 
			
		||||
        $wrapper->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(null));
 | 
			
		||||
 | 
			
		||||
    // valeur requise donc lance une exception
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(false));
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($wrapper, $value, $wrapperSetter);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testNstr() {
 | 
			
		||||
    /** @var ScalarWrapper $wrapper */
 | 
			
		||||
    Schema::nw($value, null, $schema, "?string", $wrapper);
 | 
			
		||||
    $wrapperSetter = function($value) use($wrapper) {
 | 
			
		||||
      return function() use($wrapper, $value) {
 | 
			
		||||
        $wrapper->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(null);
 | 
			
		||||
    self::assertNull($wrapper->get());
 | 
			
		||||
    self::assertNull($value);
 | 
			
		||||
    self::assertSame("", $wrapper->format());
 | 
			
		||||
 | 
			
		||||
    // valeur non requise donc retourne null
 | 
			
		||||
    $wrapper->set(false);
 | 
			
		||||
    self::assertNull($wrapper->get());
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($wrapper, $value, $wrapperSetter);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testRequiredNstr() {
 | 
			
		||||
    /** @var ScalarWrapper $wrapper */
 | 
			
		||||
    Schema::nw($value, null, $schema, [
 | 
			
		||||
      "?string", null,
 | 
			
		||||
      "required" => true,
 | 
			
		||||
    ], $wrapper);
 | 
			
		||||
    $wrapperSetter = function($value) use($wrapper) {
 | 
			
		||||
      return function() use($wrapper, $value) {
 | 
			
		||||
        $wrapper->set($value);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    $wrapper->set(null);
 | 
			
		||||
    self::assertNull($wrapper->get());
 | 
			
		||||
    self::assertNull($value);
 | 
			
		||||
    self::assertSame("", $wrapper->format());
 | 
			
		||||
 | 
			
		||||
    // valeur requise donc lance une exception
 | 
			
		||||
    self::assertException(Exception::class, $wrapperSetter(false));
 | 
			
		||||
 | 
			
		||||
    $this->commonTests($wrapper, $value, $wrapperSetter);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,30 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\schema\types;
 | 
			
		||||
 | 
			
		||||
use nulib\tests\TestCase;
 | 
			
		||||
use nur\sery\wip\schema\_scalar\ScalarWrapper;
 | 
			
		||||
use nur\sery\wip\schema\Schema;
 | 
			
		||||
 | 
			
		||||
class unionTest extends TestCase {
 | 
			
		||||
  function testUnionTypes() {
 | 
			
		||||
    ## l'ordre des types doit être respecté
 | 
			
		||||
    
 | 
			
		||||
    # string puis int
 | 
			
		||||
    /** @var ScalarWrapper $siw */
 | 
			
		||||
    Schema::nw($si, null, $sis, "string|int", $siw);
 | 
			
		||||
 | 
			
		||||
    $siw->set("12");
 | 
			
		||||
    self::assertSame("12", $si);
 | 
			
		||||
    $siw->set(12);
 | 
			
		||||
    self::assertSame(12, $si);
 | 
			
		||||
 | 
			
		||||
    # int puis string
 | 
			
		||||
    /** @var ScalarWrapper $isw */
 | 
			
		||||
    Schema::nw($is, null, $iss, "int|string", $isw);
 | 
			
		||||
 | 
			
		||||
    $isw->set("12");
 | 
			
		||||
    self::assertSame("12", $is);
 | 
			
		||||
    $isw->set(12);
 | 
			
		||||
    self::assertSame(12, $is);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user