nur-sery/src/schema/_scalar/ScalarValue.php

200 lines
5.8 KiB
PHP
Raw Normal View History

2023-11-09 10:03:35 +04:00
<?php
2023-11-28 00:20:42 +04:00
namespace nur\sery\schema\_scalar;
2023-11-09 10:03:35 +04:00
2024-04-05 08:31:49 +04:00
use nur\sery\ValueException;
2023-11-27 22:39:35 +04:00
use nur\sery\schema\input\Input;
2023-12-30 14:52:30 +04:00
use nur\sery\ref\schema\ref_analyze;
2023-11-27 22:39:35 +04:00
use nur\sery\schema\Result;
2023-12-28 19:33:13 +04:00
use nur\sery\schema\types;
2023-11-09 10:03:35 +04:00
use nur\sery\schema\types\IType;
2023-11-27 22:39:35 +04:00
use nur\sery\schema\Value;
2023-11-09 10:03:35 +04:00
2023-11-27 22:39:35 +04:00
class ScalarValue extends Value {
2023-12-28 21:07:41 +04:00
function __construct(ScalarSchema $schema, &$dest=null, $destKey=null, bool $defaultVerifix=true, ?bool $defaultThrow=null) {
2023-12-30 14:52:30 +04:00
if ($dest !== null && $defaultThrow = null) {
# Si $dest est null, ne pas lancer d'exception, parce qu'on considère que
# c'est une initialisation sans conséquences
$defaultThrow = true;
}
2023-11-27 22:39:35 +04:00
$this->schema = $schema;
2023-12-28 19:33:13 +04:00
$this->defaultVerifix = $defaultVerifix;
2023-12-28 21:07:41 +04:00
$this->defaultThrow = $defaultThrow !== null? $defaultThrow: false;
2023-11-28 08:20:33 +04:00
$this->result = new ScalarResult();
2023-12-28 19:33:13 +04:00
$this->reset($dest, $destKey);
2023-12-28 21:07:41 +04:00
$this->defaultThrow = $defaultThrow !== null? $defaultThrow: true;
2023-11-27 22:39:35 +04:00
}
function isScalar(?ScalarValue &$scalar=null): bool { $scalar = $this; return true; }
2023-11-09 10:03:35 +04:00
2023-11-25 10:04:24 +04:00
/** @var ScalarSchema schéma de cette valeur */
protected $schema;
2023-11-27 22:39:35 +04:00
/** @var Input source et destination de la valeur */
protected $input;
2023-12-28 19:33:13 +04:00
/** @var string|int|null clé de la valeur dans le tableau destination */
2023-11-28 00:20:42 +04:00
protected $destKey;
2023-11-27 22:39:35 +04:00
2023-12-28 19:33:13 +04:00
/** @var bool */
protected $defaultVerifix;
2023-12-28 19:44:57 +04:00
/** @var bool */
protected $defaultThrow;
2023-12-28 19:33:13 +04:00
/** @var IType type de la valeur après analyse */
2023-11-28 08:20:33 +04:00
protected $type;
/** @var ?ScalarResult résultat de l'analyse de la valeur */
2023-11-25 10:04:24 +04:00
protected $result;
2023-11-09 10:34:36 +04:00
2023-12-28 19:33:13 +04:00
function reset(&$dest, $destKey=null, ?bool $verifix=null): Value {
2023-11-27 22:39:35 +04:00
if ($dest instanceof Input) $input = $dest;
else $input = new Input($dest);
$this->input = $input;
2023-11-28 00:20:42 +04:00
$this->destKey = $destKey;
2023-12-28 19:33:13 +04:00
$this->type = null;
$this->_analyze();
2023-12-28 19:44:57 +04:00
if ($verifix == null) $verifix = $this->defaultVerifix;
2023-11-27 22:39:35 +04:00
if ($verifix) $this->verifix();
return $this;
2023-11-09 10:03:35 +04:00
}
2023-11-28 08:20:33 +04:00
function getKeys(): array {
return [null];
}
2024-01-01 01:01:27 +04:00
function getValue($key=null): ScalarValue {
2023-11-28 08:20:33 +04:00
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();
2023-12-28 19:33:13 +04:00
if (!$input->isPresent($destKey)) return $result->setMissing($schema);
$haveType = false;
2023-12-28 22:48:06 +04:00
$types = [];
$type = $firstType = null;
$haveValue = false;
$value = null;
# d'abord chercher un type pour lequel c'est une valeur normalisée
2023-12-28 19:33:13 +04:00
foreach ($schema->type as $name) {
$type = types::get($name);
if ($firstType === null) $firstType = $type;
2023-12-28 22:48:06 +04:00
$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;
}
2023-12-28 19:33:13 +04:00
}
}
2023-12-28 22:48:06 +04:00
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
2023-12-28 19:33:13 +04:00
if (!$haveType) $type = $this->type = $firstType;
if (!$type->isAvailable($input, $destKey)) return $result->setUnavailable($schema);
2023-11-28 08:53:40 +04:00
$value = $input->get($destKey);
2023-12-28 19:33:13 +04:00
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;
2023-12-28 22:48:06 +04:00
else return $result->setInvalid($value, $schema);
2023-11-28 08:20:33 +04:00
}
2023-12-28 19:44:57 +04:00
function verifix(?bool $throw=null): bool {
if ($throw === null) $throw = $this->defaultThrow;
2023-12-28 22:48:06 +04:00
$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);
2023-12-28 19:33:13 +04:00
return $modified;
2023-11-27 22:39:35 +04:00
}
2023-11-09 10:03:35 +04:00
2024-01-01 01:01:27 +04:00
function getResult(): ScalarResult {
2023-12-28 19:33:13 +04:00
return $this->result;
2023-11-09 10:03:35 +04:00
}
2023-12-28 19:33:13 +04:00
function isPresent(): bool {
return $this->result->present;
2023-11-09 10:03:35 +04:00
}
2023-11-27 22:39:35 +04:00
function getType(): IType {
2023-11-09 10:03:35 +04:00
return $this->type;
}
2023-12-28 19:33:13 +04:00
function isAvailable(): bool {
return $this->result->available;
}
2023-12-03 22:44:29 +04:00
function isValid(): bool {
2023-12-28 19:33:13 +04:00
return $this->result->valid;
2023-11-27 22:39:35 +04:00
}
2023-12-03 22:44:29 +04:00
function isNormalized(): bool {
2023-12-28 19:33:13 +04:00
return $this->result->normalized;
2023-11-09 10:03:35 +04:00
}
2023-12-28 19:33:13 +04:00
function get($default=null) {
if ($this->result->available) return $this->input->get($this->destKey);
else return $default;
}
2024-01-01 01:01:27 +04:00
function set($value, ?bool $verifix=null): ScalarValue {
2023-12-28 19:33:13 +04:00
$this->input->set($value, $this->destKey);
$this->_analyze();
if ($verifix === null) $verifix = $this->defaultVerifix;
if ($verifix) $this->verifix();
return $this;
2023-11-09 10:03:35 +04:00
}
2024-01-01 01:01:27 +04:00
function unset(?bool $verifix=null): ScalarValue {
2023-12-28 19:33:13 +04:00
$this->input->unset($this->destKey);
$this->_analyze();
if ($verifix === null) $verifix = $this->defaultVerifix;
if ($verifix) $this->verifix();
2023-12-28 19:44:57 +04:00
return $this;
2023-11-09 10:03:35 +04:00
}
2023-12-28 19:33:13 +04:00
function format($format=null): string {
2023-12-28 22:48:06 +04:00
return $this->type->format($this->input->get($this->destKey), $format);
2023-11-09 10:03:35 +04:00
}
}