nur-ture/src/schema/_assoc/AssocWrapper.php

207 lines
6.6 KiB
PHP

<?php
namespace nulib\schema\_assoc;
use nulib\cl;
use nulib\ref\schema\ref_analyze;
use nulib\schema\_scalar\ScalarWrapper;
use nulib\schema\ConsolidatedResult;
use nulib\schema\input\Input;
use nulib\schema\Result;
use nulib\schema\types\IType;
use nulib\schema\Wrapper;
use nulib\schema\WrapperContext;
use nulib\ValueException;
class AssocWrapper extends Wrapper {
function __construct(AssocSchema $schema, &$value=null, $valueKey=null, ?array $params=null) {
$this->context = $context = new AssocWrapperContext($schema, null, null, $params);
$paramsNoThrow = cl::merge($params, [
"throw" => false,
]);
$keys = $schema->getKeys();
$keyWrappers = [];
foreach ($keys as $key) {
$keyDummy = null;
$keyWrappers[$key] = $schema->getSchema($key)->getWrapper($keyDummy, null, $paramsNoThrow);
}
$context->keys = $keys;
$context->keyWrappers = $keyWrappers;
$arrayDummy = null;
$context->arrayWrapper = new ScalarWrapper($schema, $arrayDummy, null, $paramsNoThrow, $context);
$context->consolidatedResult = new ConsolidatedResult();
if ($value !== null) {
# n'initialiser que si $value n'est pas null
$this->reset($value, $valueKey);
}
}
/** @var AssocWrapperContext */
protected WrapperContext $context;
protected function resetContext(bool $resetSelectedKey): void {
parent::resetContext($resetSelectedKey);
$context = $this->context;
$context->arrayWrapper->getResult()->reset();
foreach ($context->keyWrappers as $wrapper) {
$wrapper->getResult()->reset();
}
if ($resetSelectedKey) $context->selectedKey = null;
}
function reset(&$value, $valueKey=null, ?array $params=null): Wrapper {
$context = $this->context;
if ($value instanceof Input) $input = $value;
else $input = $this->newInput($value);
$context->input = $input;
$context->valueKey = $valueKey;
foreach ($context->keyWrappers as $key => $keyWrapper) {
$keyInput = $input->addKey($valueKey);
$keyWrapper->reset($keyInput, $key, ["analyze" => false]);
}
$this->afterModify($params, true);
return $this;
}
function getKeys(): array {
return $this->context->keys;
}
protected function _getWrapper($key): Wrapper {
$context = $this->context;
if ($key === null || $key === "") return $context->arrayWrapper;
$wrapper = $context->keyWrappers[$key] ?? null;
if ($wrapper === null) throw ValueException::invalid_key($key);
return $wrapper;
}
/** @param string|int|null $key */
function select($key=null): Wrapper {
$wrapper = $this->_getWrapper($key);
$this->context->selectedKey = $key;
return $wrapper;
}
/**
* @param AssocWrapperContext $context
* @param AssocWrapper $wrapper
*/
static function _analyze(WrapperContext $context, Wrapper $wrapper, ?array $params): int {
if ($params["ensure_array"] ?? $context->ensureArray) {
$valueKey = $context->valueKey;
$array = $context->input->get($valueKey);
if ($array === null) $context->input->set([], $valueKey);
}
if ($params["ensure_assoc"] ?? $context->ensureAssoc) {
$context->input->ensureAssoc($context->schema->getKeys());
}
$what = ScalarWrapper::_analyze($context, $wrapper, $params);
if (!$context->result->valid) return $what;
$result = $context->consolidatedResult;
$result->setValid();
foreach ($context->keyWrappers as $key => $keyWrapper) {
$keyWrapper->analyze($params);
if ($keyWrapper->isValid()) continue;
$what = ref_analyze::INVALID;
#XXX pour $prefix, utiliser si possible la description ou une autre valeur
# "user-friendly". possibilité de sélectionner la valeur à utiliser avec
# $params?
$prefix = $key;
if (!$keyWrapper->isPresent()) {
$result->addMissingMessage($keyWrapper, $prefix);
} elseif (!$keyWrapper->isAvailable()) {
$result->addUnavailableMessage($keyWrapper, $prefix);
} elseif ($keyWrapper->isNull()) {
$result->addNullMessage($keyWrapper, $prefix);
} else {
$result->addInvalidMessage($keyWrapper, $prefix);
}
}
return $what;
}
/**
* @param AssocWrapperContext $context
* @param AssocWrapper $wrapper
*/
static function _normalize(WrapperContext $context, Wrapper $wrapper, ?array $params): bool {
$schema = $context->schema;
$keys = $schema->getKeys();
$defaults = [];
$missings = null;
foreach ($keys as $key) {
$type = $wrapper->getType($key);
$default = $schema->getSchema($key)->default;
if ($default === null) $default = $type->getNullValue();
$defaults[$key] = $default;
$missing = $type->getMissingValue($valid);
if ($valid) $missings[$key] = $missing;
}
if ($params["ensure_keys"] ?? $context->ensureKeys) {
$context->input->ensureKeys($defaults, $missings, $params);
} else {
$context->input->deleteMissings($missings, $params);
}
if ($params["ensure_order"] ?? $context->ensureOrder) {
$context->input->ensureOrder($keys, $params);
}
$modified = ScalarWrapper::_normalize($context, $wrapper, $params);
foreach ($context->keyWrappers as $keyWrapper) {
if ($keyWrapper->normalize($params)) $modified = true;
}
return $modified;
}
protected function getConsolidatedResult(): Result {
return $this->context->consolidatedResult;
}
function getResult($key=false): Result {
if ($key === null) return $this->getConsolidatedResult();
if ($key === false) $key = $this->context->selectedKey;
return $this->_getWrapper($key)->getResult();
}
function getType($key=false): IType {
if ($key === false) $key = $this->context->selectedKey;
return $this->_getWrapper($key)->getType();
}
function get($default=null, $key=false) {
$context = $this->context;
if (!$context->arrayWrapper->isAvailable()) return $default;
if ($key === false) $key = $context->selectedKey;
return $this->_getWrapper($key)->get($default);
}
function set($value, ?array $params=null, $key=false): Wrapper {
$context = $this->context;
if ($key === false) $key = $context->selectedKey;
$this->_getWrapper($key)->set($value);
return $this;
}
function unset(?array $params=null, $key=false): Wrapper {
$context = $this->context;
if ($key === false) $key = $context->selectedKey;
$this->_getWrapper($key)->unset();
return $this;
}
function format($format=null, $key=false): string {
$context = $this->context;
if ($key === false) $key = $context->selectedKey;
return $this->_getWrapper($key)->format($format);
}
}