<?php namespace nur\sery\wip\schema\_scalar; 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\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 $type * @property-read mixed $default * @property-read string|null $title * @property-read bool $required * @property-read bool $nullable * @property-read string|array|null $desc * @property-read callable|null $analyzerFunc * @property-read callable|null $extractorFunc * @property-read callable|null $parserFunc * @property-read callable|null $normalizerFunc * @property-read array|null $messages * @property-read callable|null $formatterFunc * @property-read mixed $format * @property-read array $nature * @property-read string|int|null $name * @property-read string|array|null $pkey * @property-read string|null $header * @property-read bool|null $composite */ class ScalarSchema extends Schema { /** @var array meta-schema d'un schéma de nature scalaire */ const METASCHEMA = ref_schema::SCALAR_METASCHEMA; /** * indiquer si $definition est une définition de schéma scalaire que * {@link normalize()} pourrait normaliser */ static function isa_definition($definition): bool { # chaine ou null if ($definition === null) return true; if (is_string($definition)) return true; if (!is_array($definition)) return false; # nature explicitement spécifiée if (array_key_exists("", $definition)) { $nature = $definition[""]; if ($nature === "scalar") return true; if (is_array($nature) && array_key_exists(0, $nature) && $nature[0] === "scalar") { return true; } return false; } # un unique élément chaine à l'index 0 $count = count($definition); $haveIndex0 = array_key_exists(0, $definition); if ($count == 1 && $haveIndex0 && ($definition[0] === null || is_string($definition[0]))) { return true; } # un élément à l'index 0, et d'autres éléments return $haveIndex0 && $count > 1; } static function normalize($definition, $definitionKey=null): array { 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; } function isScalar(?ScalarSchema &$scalar=null): bool { $scalar = $this; return true; } 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)); } ############################################################################# # key & properties const _PROPERTY_PKEYS = [ "analyzerFunc" => "analyzer_func", "extractorFunc" => "extractor_func", "parserFunc" => "parser_func", "normalizerFunc" => "normalizer_func", "formatterFunc" => "formatter_func", "nature" => ["", 0], ]; }