modifs.mineures sans commentaires

This commit is contained in:
Jephté Clain 2025-03-19 16:10:26 +04:00
parent ef7e8551aa
commit 1fc4e7637b
20 changed files with 288 additions and 123 deletions

View File

@ -8,6 +8,16 @@ use nulib\cl;
* de {@link IAccess}
*/
abstract class AbstractAccess implements IAccess {
function __construct(?array $params=null) {
$this->allowEmpty = $params["allow_empty"] ?? true;
}
protected bool $allowEmpty;
function isAllowEmpty(): bool {
return $this->allowEmpty;
}
function inc(): int {
$value = (int)$this->get();
$this->set(++$value);

View File

@ -0,0 +1,57 @@
<?php
namespace nur\sery\wip\php\access;
use nulib\cl;
class ChainAccess extends AbstractAccess {
function __construct(IAccess $access, $key) {
parent::__construct();
$this->access = $access;
$this->key = $key;
}
protected IAccess $access;
/** @var int|string|array */
protected $key;
function isAllowEmpty(): bool {
return $this->access->isAllowEmpty();
}
function exists(): bool {
$key = $this->key;
if ($key === null) return false;
if (!$this->access->exists()) return false;
return cl::phas($this->access->get(), $key);
}
function available(): bool {
$key = $this->key;
if ($key === null) return false;
if (!$this->access->available()) return false;
$array = $this->access->get();
if (!cl::phas($array, $key)) return false;
return $this->isAllowEmpty() || cl::pget($array, $key) !== "";
}
function get($default=null) {
return cl::pget($this->access->get($default), $this->key);
}
function set($value): void {
$array = $this->access->get();
cl::pset($array, $this->key, $value);
$this->access->set($array);
}
function del(): void {
$array = $this->access->get();
cl::pdel($array, $this->key);
$this->access->set($array);
}
function addKey($key): IAccess {
return new ChainAccess($this->access, cl::merge($this->key, $key));
}
}

View File

@ -8,66 +8,88 @@ use nulib\cl;
*/
class FormAccess extends AbstractAccess {
function __construct($key, ?array $params=null) {
parent::__construct($params);
$this->key = $key;
$this->allowEmpty = $params["allow_empty"] ?? false;
}
/** @var int|string */
/** @var int|string|array */
protected $key;
protected bool $allowEmpty;
function exists(): bool {
protected function _exists(array $first, ?array $second=null): bool {
$key = $this->key;
if ($key === null) return false;
return array_key_exists($key, $_POST) || array_key_exists($key, $_GET);
if (cl::phas($first, $key)) return true;
return $second !== null && cl::phas($second, $key);
}
public function available(): bool {
function exists(): bool {
return $this->_exists($_POST, $_GET);
}
protected function _available(array $first, ?array $second=null): bool {
$key = $this->key;
if ($key === null) return false;
if (array_key_exists($key, $_POST)) {
return $this->allowEmpty || $_POST[$key] !== "";
} elseif (array_key_exists($key, $_GET)) {
return $this->allowEmpty || $_GET[$key] !== "";
if (cl::phas($first, $key)) {
return $this->allowEmpty || cl::pget($first, $key) !== "";
} elseif ($second !== null && cl::phas($second, $key)) {
return $this->allowEmpty || cl::pget($second, $key) !== "";
} else {
return false;
}
}
function get($default=null) {
public function available(): bool {
return $this->_available($_POST, $_GET);
}
protected function _get($default, array $first, ?array $second=null) {
$key = $this->key;
if ($key === null) return $default;
if (array_key_exists($key, $_POST)) {
$value = $_POST[$key];
if ($value === "" && !$this->allowEmpty) return $default;
return $value;
} elseif (array_key_exists($key, $_GET)) {
$value = $_GET[$key];
if ($value === "" && !$this->allowEmpty) return $default;
return $value;
if (cl::phas($first, $key)) {
$value = cl::pget($first, $key);
if ($value !== "" || $this->allowEmpty) return $value;
} elseif ($second !== null && cl::phas($second, $key)) {
$value = cl::pget($second, $key);
if ($value !== "" || $this->allowEmpty) return $value;
}
return $default;
}
function get($default=null) {
return $this->_get($default, $_POST, $_GET);
}
function _set($value, array &$first, ?array &$second=null): void {
$key = $this->key;
if ($key === null) return;
if ($second !== null && !cl::phas($first, $key) && cl::phas($second, $key)) {
cl::pset($second, $key, $value);
} else {
return $default;
cl::pset($first, $key, $value);
}
}
function set($value): void {
$this->_set($value, $_POST, $_GET);
}
function _del(array &$first, ?array &$second=null): void {
$key = $this->key;
if ($key === null) return;
if (!array_key_exists($key, $_POST) && array_key_exists($key, $_GET)) {
cl::set($_GET, $key, $value);
if ($second !== null && !cl::phas($first, $key) && cl::phas($second, $key)) {
cl::pdel($second, $key);
} else {
cl::set($_POST, $key, $value);
cl::pdel($first, $key);
}
}
function del(): void {
$key = $this->key;
if ($key === null) return;
if (!array_key_exists($key, $_POST) && array_key_exists($key, $_GET)) {
cl::del($_GET, $key);
} else {
cl::del($_POST, $key);
}
$this->_del($_POST, $_GET);
}
function addKey($key): self {
return new static(cl::merge($this->key, $key), [
"allow_empty" => $this->allowEmpty
]);
}
}

View File

@ -8,42 +8,22 @@ use nulib\cl;
*/
class GetAccess extends FormAccess {
function exists(): bool {
$key = $this->key;
if ($key === null) return false;
return array_key_exists($key, $_GET);
return $this->_exists($_GET);
}
public function available(): bool {
$key = $this->key;
if ($key === null) return false;
if (array_key_exists($key, $_GET)) {
return $this->allowEmpty || $_GET[$key] !== "";
} else {
return false;
}
return $this->_available($_GET);
}
function get($default=null) {
$key = $this->key;
if ($key === null) return $default;
if (array_key_exists($key, $_GET)) {
$value = $_GET[$key];
if ($value === "" && !$this->allowEmpty) return $default;
return $value;
} else {
return $default;
}
return $this->_get($default, $_GET);
}
function set($value): void {
$key = $this->key;
if ($key === null) return;
cl::set($_GET, $key, $value);
$this->_set($value, $_GET);
}
function del(): void {
$key = $this->key;
if ($key === null) return;
cl::del($_GET, $key);
$this->_del($_GET);
}
}

View File

@ -25,4 +25,7 @@ interface IAccess extends IGetter, ISetter, IDeleter {
* tableau si $key===null
*/
function append($value, $key=null): void;
/** retourner une instance permettant d'accéder à $value[$key] */
function addKey($key): IAccess;
}

View File

@ -11,6 +11,12 @@ interface IGetter {
*/
function exists(): bool;
/**
* @return bool true si cet objet autorise les chaines vides. si c'est le cas,
* {@link exists()} et {@link available()} sont fonctionnellement identiques
*/
function isAllowEmpty(): bool;
/** @return bool true si la valeur existe et est utilisable, false sinon */
function available(): bool;

View File

@ -9,61 +9,67 @@ use nulib\cl;
*/
class KeyAccess extends AbstractAccess {
function __construct(&$array, $key, ?array $params=null) {
parent::__construct($params);
$this->array =& $array;
$this->key = $key;
$this->allowNull = $params["allow_null"] ?? true;
$this->allowFalse = $params["allow_false"] ?? false;
$this->allowEmpty = $params["allow_empty"] ?? true;
}
/** @var array|ArrayAccess */
protected $array;
function reset(&$array): self {
$this->array =& $array;
return $this;
}
/** @var int|string */
/** @var int|string|array */
protected $key;
protected bool $allowNull;
protected bool $allowFalse;
protected bool $allowEmpty;
function reset(&$array): self {
$this->array =& $array;
return $this;
}
function exists(): bool {
$key = $this->key;
if ($key === null) return false;
return cl::has($this->array, $key);
return cl::phas($this->array, $key);
}
function available(): bool {
if (!$this->exists()) return false;
$value = cl::get($this->array, $this->key);
$value = cl::pget($this->array, $this->key);
if ($value === "") return $this->allowEmpty;
if ($value === null) return $this->allowNull;
if ($value === false) return $this->allowFalse;
if ($value === "") return $this->allowEmpty;
return true;
}
function get($default=null) {
if ($this->key === null) return $default;
$value = cl::get($this->array, $this->key, $default);
$value = cl::pget($this->array, $this->key, $default);
if ($value === "" && !$this->allowEmpty) return $default;
if ($value === null && !$this->allowNull) return $default;
if ($value === false && !$this->allowFalse) return $default;
if ($value === "" && !$this->allowEmpty) return $default;
return $value;
}
function set($value): void {
if ($this->key === null) return;
cl::set($this->array, $this->key, $value);
cl::pset($this->array, $this->key, $value);
}
function del(): void {
if ($this->key === null) return;
cl::del($this->array, $this->key);
cl::pdel($this->array, $this->key);
}
function addKey($key): self {
return new KeyAccess($this->array, cl::merge($this->key, $key), [
"allow_empty" => $this->allowEmpty,
"allow_null" => $this->allowNull,
"allow_false" => $this->allowFalse,
]);
}
}

View File

@ -8,42 +8,22 @@ use nulib\cl;
*/
class PostAccess extends FormAccess {
function exists(): bool {
$key = $this->key;
if ($key === null) return false;
return array_key_exists($key, $_POST);
return $this->_exists($_POST);
}
public function available(): bool {
$key = $this->key;
if ($key === null) return false;
if (array_key_exists($key, $_POST)) {
return $this->allowEmpty || $_POST[$key] !== "";
} else {
return false;
}
return $this->_available($_POST);
}
function get($default=null) {
$key = $this->key;
if ($key === null) return $default;
if (array_key_exists($key, $_POST)) {
$value = $_POST[$key];
if ($value === "" && !$this->allowEmpty) return $default;
return $value;
} else {
return $default;
}
return $this->_get($default, $_POST);
}
function set($value): void {
$key = $this->key;
if ($key === null) return;
cl::set($_POST, $key, $value);
$this->_set($value, $_POST);
}
function del(): void {
$key = $this->key;
if ($key === null) return;
cl::del($_POST, $key);
$this->_del($_POST);
}
}

View File

@ -16,6 +16,7 @@ namespace nur\sery\wip\php\access;
*/
class ShadowAccess extends AbstractAccess {
function __construct(IAccess $reader, IAccess $writer) {
parent::__construct();
$this->reader = $reader;
$this->writer = $writer;
$this->getter = $reader;
@ -27,6 +28,10 @@ class ShadowAccess extends AbstractAccess {
protected IGetter $getter;
public function isAllowEmpty(): bool {
return $this->getter->isAllowEmpty();
}
function exists(): bool {
return $this->getter->exists();
}
@ -48,4 +53,8 @@ class ShadowAccess extends AbstractAccess {
$this->writer->del();
$this->getter = $this->reader;
}
function addKey($key): IAccess {
return new ChainAccess($this, $key);
}
}

View File

@ -6,25 +6,23 @@ namespace nur\sery\wip\php\access;
*/
class ValueAccess extends AbstractAccess {
function __construct(&$value, ?array $params=null) {
parent::__construct($params);
$this->value =& $value;
$this->allowNull = $params["allow_null"] ?? false;
$this->allowFalse = $params["allow_false"] ?? true;
$this->allowEmpty = $params["allow_empty"] ?? true;
}
/** @var mixed */
protected $value;
function reset(&$value): self {
$this->value =& $value;
return $this;
}
protected bool $allowNull;
protected bool $allowFalse;
protected bool $allowEmpty;
function reset(&$value): self {
$this->value =& $value;
return $this;
}
function exists(): bool {
return $this->allowNull || $this->value !== null;
@ -53,4 +51,12 @@ class ValueAccess extends AbstractAccess {
function del(): void {
$this->value = null;
}
function addKey($key): KeyAccess {
return new KeyAccess($this->value, $key, [
"allow_empty" => $this->allowEmpty,
"allow_null" => $this->allowNull,
"allow_false" => $this->allowFalse,
]);
}
}

View File

@ -65,20 +65,20 @@ abstract class Wrapper implements ArrayAccess, IteratorAggregate {
}
/** analyser la valeur */
abstract static function _analyze(?array $params, WrapperContext $context, Wrapper $wrapper): int;
abstract static function _analyze(WrapperContext $context, Wrapper $wrapper, ?array $params): int;
function analyze(?array $params=null): bool {
$context = $this->context;
$reanalyze = $params["reanalyze"] ?? false;
if ($context->analyzed && !$reanalyze) return false;
static::_analyze($params, $context, $this);
static::_analyze($context, $this, $params);
$context->analyzed = true;
return true;
}
/** normaliser la valeur */
abstract static function _normalize(?array $params, WrapperContext $context, Wrapper $wrapper): bool;
abstract static function _normalize(WrapperContext $context, Wrapper $wrapper, ?array $params): bool;
function normalize(?array $params=null): bool {
$context = $this->context;
@ -89,7 +89,7 @@ abstract class Wrapper implements ArrayAccess, IteratorAggregate {
$renormalize = $params["renormalize"] ?? false;
if ($renormalize || !$context->normalized) {
$modified = static::_normalize($params, $context, $this);
$modified = static::_normalize($context, $this, $params);
$context->normalized = true;
} else {
$modified = false;

View File

@ -5,6 +5,10 @@ use nur\sery\wip\schema\input\Input;
use nur\sery\wip\schema\types\IType;
class WrapperContext {
const DEFAULT_ANALYZE = true;
const DEFAULT_NORMALIZE = true;
const DEFAULT_THROW = true;
function __construct(Schema $schema, ?Input $input, $valueKey, ?array $params) {
$this->resetParams($params);
$this->schema = $schema;
@ -19,9 +23,9 @@ class WrapperContext {
function resetParams(?array $params): void {
$this->params = $params;
$this->analyze = $params["analyze"] ?? true;
$this->normalize = $params["normalize"] ?? true;
$this->throw = $params["throw"] ?? true;
$this->analyze = $params["analyze"] ?? self::DEFAULT_ANALYZE;
$this->normalize = $params["normalize"] ?? self::DEFAULT_NORMALIZE;
$this->throw = $params["throw"] ?? self::DEFAULT_THROW;
}
/** schéma de la valeur */

View File

@ -1,9 +1,11 @@
<?php
namespace nur\sery\wip\schema\_assoc;
use nulib\ref\schema\ref_analyze;
use nulib\ValueException;
use nur\sery\wip\schema\_scalar\ScalarResult;
use nur\sery\wip\schema\_scalar\ScalarWrapper;
use nur\sery\wip\schema\input\Input;
use nur\sery\wip\schema\Result;
use nur\sery\wip\schema\types\IType;
use nur\sery\wip\schema\Wrapper;
@ -49,6 +51,19 @@ class AssocWrapper extends Wrapper {
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 => $wrapper) {
$wrapper->reset($input->subInput($valueKey), $key);
}
$this->afterModify($params, true);
return $this;
}
function getKeys(): array {
return $this->context->keys;
}
@ -71,28 +86,27 @@ class AssocWrapper extends Wrapper {
* @param AssocWrapperContext $context
* @param AssocWrapper $wrapper
*/
static function _analyze(?array $params, WrapperContext $context, Wrapper $wrapper): int {
static function _analyze(WrapperContext $context, Wrapper $wrapper, ?array $params): int {
if ($context->ensureArray) {
$array = $context->input->get();
if ($array === null) $context->input->set([]);
}
$what = ScalarWrapper::_analyze($params, $context, $wrapper);
$what = ScalarWrapper::_analyze($context, $wrapper, $params);
/** @var ScalarResult $result */
$result = $context->result;
if (!$result->valid) return $what;
foreach ($context->keyWrappers as $wrapper) {
$wrapper->analyze($params);
if (!$wrapper->isValid()) {
$result->setInvalid(null, $context->schema, $wrapper->getResult()->exception);
break;
#XXX
$what = ref_analyze::INVALID;
$result->addInvalidMessage($wrapper);
}
}
return $what;
}
static function _normalize(?array $params, WrapperContext $context, Wrapper $wrapper): bool {
return ScalarWrapper::_normalize($params, $context, $wrapper);
static function _normalize(WrapperContext $context, Wrapper $wrapper, ?array $params): bool {
return ScalarWrapper::_normalize($context, $wrapper, $params);
}
function getResult($key=false): Result {

View File

@ -8,11 +8,15 @@ use nur\sery\wip\schema\Wrapper;
use nur\sery\wip\schema\WrapperContext;
class AssocWrapperContext extends WrapperContext {
const DEFAULT_ENSURE_ARRAY = false;
const DEFAULT_ENSURE_KEYS = true;
const DEFAULT_ENSURE_ORDER = true;
function __construct(Schema $schema, ?Input $input, $valueKey, ?array $params) {
parent::__construct($schema, $input, $valueKey, $params);
$this->ensureArray = $params["ensure_array"] ?? false;
$this->ensureKeys = $params["ensure_keys"] ?? true;
$this->ensureOrder = $params["ensure_order"] ?? true;
$this->ensureArray = $params["ensure_array"] ?? self::DEFAULT_ENSURE_ARRAY;
$this->ensureKeys = $params["ensure_keys"] ?? self::DEFAULT_ENSURE_KEYS;
$this->ensureOrder = $params["ensure_order"] ?? self::DEFAULT_ENSURE_ORDER;
}
public bool $ensureArray;

View File

@ -7,6 +7,7 @@ use nulib\ref\schema\ref_schema;
use nulib\ValueException;
use nur\sery\wip\schema\Result;
use nur\sery\wip\schema\Schema;
use nur\sery\wip\schema\Wrapper;
use Throwable;
/**
@ -118,6 +119,29 @@ class ScalarResult extends Result {
return ref_analyze::INVALID;
}
function addInvalidMessage(Wrapper $wrapper): void {
$this->resultAvailable = true;
$this->present = true;
$this->available = true;
$this->null = false;
$this->valid = false;
$this->messageKey = "invalid";
$result = $wrapper->getResult();
$resultException = $result->exception;
$resultMessage = $result->message;
if ($resultException !== null) {
$tmessage = ValueException::get_message($resultException);
if ($tmessage) {
if ($resultMessage !== null) $resultMessage .= ": ";
$resultMessage .= $tmessage;
}
}
$message = $this->message;
if ($message) $message .= "\n";
$message .= $resultMessage;
$this->message = $message;
}
function setValid($normalizedValue=null): int {
$this->resultAvailable = true;
$this->present = true;

View File

@ -147,7 +147,7 @@ class ScalarWrapper extends Wrapper {
/**
* @param ScalarWrapper $wrapper
*/
static function _analyze(?array $params, WrapperContext $context, Wrapper $wrapper): int {
static function _analyze(WrapperContext $context, Wrapper $wrapper, ?array $params): int {
/** @var ScalarSchema $schema */
$schema = $context->schema;
$input = $context->input;
@ -196,7 +196,7 @@ class ScalarWrapper extends Wrapper {
/**
* @param ScalarWrapper $wrapper
*/
static function _normalize(?array $params, WrapperContext $context, Wrapper $wrapper): bool {
static function _normalize(WrapperContext $context, Wrapper $wrapper, ?array $params): bool {
/** @var ScalarSchema $schema */
$schema = $context->schema;
$input = $context->input;

View File

@ -0,0 +1,5 @@
<?php
namespace nur\sery\wip\schema\input;
class ChainInput implements IInput {
}

View File

@ -0,0 +1,18 @@
<?php
namespace nur\sery\wip\schema\input;
interface IInput {
/** tester si la valeur existe sans tenir compte de $allowEmpty */
function isPresent($key=null): bool;
/** tester si la valeur est disponible en tenant compte de $allowEmpty */
function isAvailable($key=null): bool;
function get($key=null);
function set($value, $key=null): void;
function unset($key=null): void;
function addKey($key): IInput;
}

View File

@ -10,7 +10,7 @@ use nur\sery\wip\php\access\ValueAccess;
*
* cette implémentation lit depuis et écrit dans une référence
*/
class Input {
class Input implements IInput {
const ALLOW_EMPTY = true;
function __construct(&$value=null, ?array $params=null) {
@ -63,4 +63,8 @@ class Input {
function unset($key=null): void {
$this->access($key)->del();
}
function addKey($key): IInput {
return new ChainInput($this, $key);
}
}

View File

@ -101,6 +101,19 @@ class AssocSchemaTest extends TestCase {
}
function testWrapper() {
$schema = new AssocSchema([
"a" => "?string",
"b" => "?int",
"c" => "?bool",
]);
$array = ["a" => " string ", "b" => " 42 ", "c" => false];
$schema->getWrapper($array);
self::assertSame([
"a" => "string",
"b" => 42,
"c" => false,
], $array);
$schema = new AssocSchema([
"a" => "string",
"b" => "int",