199 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			199 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
namespace nur\sery\wip\schema\_scalar;
 | 
						|
 | 
						|
use nur\sery\ref\schema\ref_analyze;
 | 
						|
use nur\sery\ValueException;
 | 
						|
use nur\sery\wip\schema\input\Input;
 | 
						|
use nur\sery\wip\schema\types;
 | 
						|
use nur\sery\wip\schema\types\IType;
 | 
						|
use nur\sery\wip\schema\Value;
 | 
						|
 | 
						|
class ScalarValue extends Value {
 | 
						|
  function __construct(ScalarSchema $schema, &$dest=null, $destKey=null, bool $defaultVerifix=true, ?bool $defaultThrow=null) {
 | 
						|
    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;
 | 
						|
    }
 | 
						|
    $this->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);
 | 
						|
  }
 | 
						|
}
 |