2023-11-09 10:03:35 +04:00
|
|
|
<?php
|
|
|
|
namespace nur\sery\schema;
|
|
|
|
|
2023-11-09 10:34:36 +04:00
|
|
|
use nur\sery\schema\input\Input;
|
2023-11-09 10:03:35 +04:00
|
|
|
use nur\sery\schema\values\AssocValue;
|
|
|
|
use nur\sery\schema\values\IValue;
|
|
|
|
use nur\sery\schema\values\ScalarValue;
|
|
|
|
use nur\sery\schema\values\SeqValue;
|
2023-11-09 10:34:36 +04:00
|
|
|
use nulib\StateException;
|
|
|
|
|
|
|
|
#XXX
|
|
|
|
# analyze() et [analyzer_func] --> indique ce qu'est la valeur qu'on vérifixe
|
|
|
|
# retourne MISSING (la valeur n'existe pas)
|
|
|
|
# NULL (la valeur existe mais est nulle)
|
|
|
|
# STRING (la valeur est une chaine qu'il faut parser)
|
|
|
|
# INVALID (la valeur n'est pas du bon type et il n'est pas possible de la convertir)
|
|
|
|
# VALID (la valeur est dans le bon type)
|
|
|
|
# extract() et [extractor_func] --> si analyze() retourne STRING, extraire la
|
|
|
|
# chaine à parser
|
|
|
|
# parse() et [parser_func] --> parser la chaine et retourner la valeur
|
|
|
|
# format() et [formatter_func] --> formatter la valeur et retourner une chaine
|
2023-11-09 10:03:35 +04:00
|
|
|
|
|
|
|
class Schema {
|
|
|
|
/**
|
2023-11-09 10:34:36 +04:00
|
|
|
* créer une nouvelle instance de cette classe à partir d'un schéma
|
|
|
|
*
|
|
|
|
* @param bool $normalized indique si le schéma est normalisé
|
2023-11-09 10:03:35 +04:00
|
|
|
* normalisé
|
|
|
|
*/
|
2023-11-09 10:34:36 +04:00
|
|
|
static function new(&$md, $schema, bool $normalized=false): self {
|
|
|
|
if ($md === null) $md = new static($schema, !$normalized);
|
2023-11-09 10:03:35 +04:00
|
|
|
return $md;
|
|
|
|
}
|
|
|
|
|
|
|
|
static function normalize($schema): array {
|
|
|
|
if ($schema === null) throw new SchemaException("schema is required");
|
|
|
|
elseif (!is_array($schema)) $schema = [$schema];
|
|
|
|
#XXX
|
|
|
|
return $schema;
|
|
|
|
}
|
|
|
|
|
|
|
|
const SCHEMA = null;
|
|
|
|
|
|
|
|
function __construct($schema=null, bool $normalize=true) {
|
|
|
|
if ($schema === null) $schema = static::SCHEMA;
|
|
|
|
if ($normalize) $schema = self::normalize($schema);
|
|
|
|
$this->schema = $schema;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var array schéma normalisé
|
|
|
|
*
|
|
|
|
* il y a 3 formes pour un schéma:
|
|
|
|
* - schéma valeur scalaire [0 => type, 1 => default, ...]
|
|
|
|
* - schéma tableau séquentiel [schema]
|
|
|
|
* - schéma tableau associatif [key => schema, ...]
|
|
|
|
*/
|
|
|
|
protected $schema;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* retourner true si le schéma est pour une valeur scalaire, false s'il s'agit
|
|
|
|
* du schéma d'un tableau (séquentiel ou associatif)
|
|
|
|
*/
|
|
|
|
function isScalar(): bool {
|
|
|
|
return array_key_exists(0, $this->schema) && array_key_exists(1, $this->schema);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** retourner true si le schéma est pour un tableau séquentiel */
|
|
|
|
function isSeq(): bool {
|
|
|
|
return array_key_exists(0, $this->schema) && !array_key_exists(1, $this->schema);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** retourner true si le schéma est pour un tableau associatif */
|
|
|
|
function isAssoc(): bool {
|
|
|
|
return !array_key_exists(0, $this->schema) && !array_key_exists(1, $this->schema);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var bool true si toutes les clés du schéma doivent exister, avec leur
|
|
|
|
* valeur par défaut le cas échéant
|
|
|
|
*/
|
|
|
|
protected $ppEnsureKeys;
|
|
|
|
|
|
|
|
/** @var bool true si les clés doivent être dans l'ordre du schéma */
|
|
|
|
protected $ppOrderKeys;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var bool true si les valeurs doivent être automatiquement vérifiées et
|
|
|
|
* corrigées
|
|
|
|
*/
|
|
|
|
protected $ppVerifix;
|
|
|
|
|
|
|
|
function ensureSchema(&$value, $key=null, ?array $params=null): void {
|
|
|
|
}
|
|
|
|
|
|
|
|
/** retourner true si la valeur est scalaire */
|
|
|
|
function getScalar(&$value, $key=null, ?ScalarValue &$scalar=null): bool {
|
|
|
|
if (!$this->isScalar()) return false;
|
|
|
|
if ($value instanceof Input) $input = $value;
|
|
|
|
else $input = new Input($value);
|
|
|
|
$scalar = new ScalarValue($input, $this->schema, $key);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** retourner true la valeur est un tableau séquentiel */
|
|
|
|
function getSeq(&$value, $key=null, ?SeqValue &$seq=null): bool {
|
|
|
|
if (!$this->isSeq()) return false;
|
|
|
|
if ($value instanceof Input) $input = $value;
|
|
|
|
else $input = new Input($value);
|
|
|
|
$seq = new SeqValue($input, $this->schema, $key);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** retourner true la valeur est un tableau associatif */
|
|
|
|
function getAssoc(&$value, $key=null, ?AssocValue &$assoc=null): bool {
|
|
|
|
if (!$this->isAssoc()) return false;
|
|
|
|
if ($value instanceof Input) $input = $value;
|
|
|
|
else $input = new Input($value);
|
|
|
|
$assoc = new AssocValue($input, $this->schema, $key);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getValue(&$value, $key=null): IValue {
|
|
|
|
if ($this->getScalar($input, $key, $scalar)) return $scalar;
|
|
|
|
elseif ($this->getSeq($input, $key, $seq)) return $seq;
|
|
|
|
elseif ($this->getAssoc($input, $key, $assoc)) return $assoc;
|
|
|
|
else throw StateException::unexpected_state();
|
|
|
|
}
|
|
|
|
}
|