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); } }