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