getWrapper($value, $valueKey, null, $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(&$definition, $definitionKey=null, ?array $natureMetaschema=null): void { if (!is_array($definition)) $definition = [$definition]; # s'assurer que toutes les clés existent avec leur valeur par défaut $index = 0; foreach (array_keys(ref_schema::VALUE_METASCHEMA) as $key) { if (!array_key_exists($key, $definition)) { if (array_key_exists($index, $definition)) { $definition[$key] = $definition[$index]; unset($definition[$index]); $index++; } else { $definition[$key] = ref_schema::VALUE_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); $natureMetaschema ??= ref_schema::NATURE_METASCHEMA; foreach (array_keys($natureMetaschema) as $key) { if (!array_key_exists($key, $nature)) { $nature[$key] = $natureMetaschema[$key][1]; } } $definition[""] = $nature; # name, pkey, header $name = $definition["name"]; $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"]); tfunc::ensure_nfunc($definition["analyzer_func"]); tfunc::ensure_nfunc($definition["extractor_func"]); tfunc::ensure_nfunc($definition["parser_func"]); tfunc::ensure_nfunc($definition["normalizer_func"]); tarray::ensure_narray($definition["messages"]); tfunc::ensure_nfunc($definition["formatter_func"]); tbool::ensure_nbool($definition["computed"]); switch ($nature[0] ?? null) { case "assoc": foreach ($definition["schema"] as $key => &$keydef) { self::_normalize_definition($keydef, $key); }; unset($keydef); break; case "list": self::_normalize_definition($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(null, null, $keydef, false); }; unset($keydef); break; case "list": Schema::ns(null, null, $definition["schema"], false); break; } } /** * @var array définition du schéma, à redéfinir le cas échéant dans une classe * dérivée */ const SCHEMA = null; protected array $_definition; protected array $definition; function getDefinition(): array { return $this->_definition; } /** * retourner la liste des clés valides pour l'accès aux valeurs et résultats */ abstract function getKeys(): array; abstract function getSchema($key=false): Schema; abstract protected function newWrapper(): Wrapper; abstract function getWrapper(&$value=null, $valueKey=null, ?array $params=null, ?Wrapper &$wrapper=null): Wrapper; ############################################################################# # key & properties function offsetExists($offset): bool { return array_key_exists($offset, $this->definition); } function offsetGet($offset) { if (!array_key_exists($offset, $this->definition)) return null; else return $this->definition[$offset]; } function offsetSet($offset, $value): void { throw AccessException::read_only(null, $offset); } function offsetUnset($offset): void { throw AccessException::read_only(null, $offset); } const _PROPERTY_PKEYS = [ "analyzerFunc" => "analyzer_func", "extractorFunc" => "extractor_func", "parserFunc" => "parser_func", "normalizerFunc" => "normalizer_func", "formatterFunc" => "formatter_func", "nature" => ["", 0], ]; function __get($name) { $pkey = cl::get(static::_PROPERTY_PKEYS, $name, $name); return cl::pget($this->definition, $pkey); } }