intégrer tout nulib
This commit is contained in:
parent
5732020909
commit
e8b7ca91af
4
bbnurse
4
bbnurse
|
@ -123,8 +123,8 @@ args=(
|
||||||
-u[n|m] package|Class [DEST]
|
-u[n|m] package|Class [DEST]
|
||||||
|
|
||||||
Il y a deux types d'évolutions possibles:
|
Il y a deux types d'évolutions possibles:
|
||||||
* mettre en nurserie
|
* mettre en nurserie (-n)
|
||||||
* arriver à maturation
|
* arriver à maturation (-m)
|
||||||
|
|
||||||
Pour chaque type d'évolution, il y a deux actions possibles:
|
Pour chaque type d'évolution, il y a deux actions possibles:
|
||||||
* copier (-c)
|
* copier (-c)
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"nulib/php": "dev-wip",
|
|
||||||
"symfony/yaml": "^5.0",
|
"symfony/yaml": "^5.0",
|
||||||
"php": ">=7.4"
|
"php": ">=7.4"
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
namespace nur\sery;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class AccessException: indiquer que la resource ou l'objet auquel on veut
|
||||||
|
* accéder n'est pas accessible. il s'agit donc d'une erreur de l'utilisateur
|
||||||
|
*/
|
||||||
|
class AccessException extends UserException {
|
||||||
|
static final function read_only(?string $dest=null, ?string $prefix=null): self {
|
||||||
|
if ($prefix) $prefix = "$prefix: ";
|
||||||
|
if ($dest === null) $dest = "this property";
|
||||||
|
$message = "$dest is read-only";
|
||||||
|
return new static($prefix.$message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function immutable_object(?string $dest=null, ?string $prefix=null): self {
|
||||||
|
if ($prefix) $prefix = "$prefix: ";
|
||||||
|
if ($dest === null) $dest = "this object";
|
||||||
|
$message = "$dest is immutable";
|
||||||
|
return new static($prefix.$message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function not_allowed(?string $action=null, ?string $prefix=null): self {
|
||||||
|
if ($prefix) $prefix = "$prefix: ";
|
||||||
|
if ($action === null) $action = "this operation";
|
||||||
|
$message = "$action is not allowed";
|
||||||
|
return new static($prefix.$message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function not_accessible(?string $dest=null, ?string $prefix=null): self {
|
||||||
|
if ($prefix) $prefix = "$prefix: ";
|
||||||
|
if ($dest === null) $dest = "this resource";
|
||||||
|
$message = "$dest is not accessible";
|
||||||
|
return new static($prefix.$message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
namespace nur\sery;
|
||||||
|
|
||||||
|
use RuntimeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class DataException: exception générique concernant l'accès à des données
|
||||||
|
*/
|
||||||
|
class DataException extends RuntimeException {
|
||||||
|
static final function no_more_data(): self {
|
||||||
|
return new self("no more data");
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function ensure_not_eof($data, bool $throw=true, $eof=false) {
|
||||||
|
if (!$throw) return null;
|
||||||
|
elseif ($data !== $eof) return $data;
|
||||||
|
else throw self::no_more_data();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
<?php
|
||||||
|
namespace nur\sery;
|
||||||
|
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ExceptionShadow: une classe qui capture les informations d'une
|
||||||
|
* exception afin de pouvoir les sérialiser
|
||||||
|
*/
|
||||||
|
class ExceptionShadow {
|
||||||
|
protected static function extract_trace(array $trace): array {
|
||||||
|
$frames = [];
|
||||||
|
foreach ($trace as $frame) {
|
||||||
|
$file = cl::get($frame, "file");
|
||||||
|
$line = cl::get($frame, "line");
|
||||||
|
$class = cl::get($frame, "class");
|
||||||
|
$function = cl::get($frame, "function");
|
||||||
|
$type = cl::get($frame, "type");
|
||||||
|
$frames[] = [
|
||||||
|
"file" => $file,
|
||||||
|
"line" => $line,
|
||||||
|
"class" => $class,
|
||||||
|
"object" => null,
|
||||||
|
"type" => $type,
|
||||||
|
"function" => $function,
|
||||||
|
"args" => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return $frames;
|
||||||
|
}
|
||||||
|
|
||||||
|
function __construct(Throwable $exception) {
|
||||||
|
$this->class = get_class($exception);
|
||||||
|
$this->message = $exception->getMessage();
|
||||||
|
$this->code = $exception->getCode();
|
||||||
|
$this->file = $exception->getFile();
|
||||||
|
$this->line = $exception->getLine();
|
||||||
|
$this->trace = self::extract_trace($exception->getTrace());
|
||||||
|
$previous = $exception->getPrevious();
|
||||||
|
if ($previous !== null) $this->previous = new static($previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
protected $class;
|
||||||
|
|
||||||
|
function getClass(): string {
|
||||||
|
return $this->class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
protected $message;
|
||||||
|
|
||||||
|
function getMessage(): string {
|
||||||
|
return $this->message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var mixed */
|
||||||
|
protected $code;
|
||||||
|
|
||||||
|
function getCode() {
|
||||||
|
return $this->code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
protected $file;
|
||||||
|
|
||||||
|
function getFile(): string {
|
||||||
|
return $this->file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
protected $line;
|
||||||
|
|
||||||
|
function getLine(): int {
|
||||||
|
return $this->line;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
protected $trace;
|
||||||
|
|
||||||
|
function getTrace(): array {
|
||||||
|
return $this->trace;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTraceAsString(): string {
|
||||||
|
$lines = [];
|
||||||
|
foreach ($this->trace as $index => $frame) {
|
||||||
|
$lines[] = "#$index $frame[file]($frame[line]): $frame[class]$frame[type]$frame[function]()";
|
||||||
|
}
|
||||||
|
$index++;
|
||||||
|
$lines[] = "#$index {main}";
|
||||||
|
return implode("\n", $lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var ExceptionShadow */
|
||||||
|
protected $previous;
|
||||||
|
|
||||||
|
function getPrevious(): ?ExceptionShadow {
|
||||||
|
return $this->previous;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
namespace nur\sery;
|
||||||
|
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ExitException: une exception qui indique que l'application souhaite
|
||||||
|
* quitter normalement, avec éventuellement un code d'erreur.
|
||||||
|
*/
|
||||||
|
class ExitException extends UserException {
|
||||||
|
function __construct(int $exitcode=0, $user_message=null, Throwable $previous=null) {
|
||||||
|
parent::__construct($user_message, null, $exitcode, $previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isError(): bool {
|
||||||
|
return $this->getCode() !== 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function haveMessage(): bool {
|
||||||
|
return $this->getUserMessage() !== null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
namespace nur\sery;
|
||||||
|
|
||||||
|
use LogicException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class StateException: indiquer que l'état dans lequel on se trouve est
|
||||||
|
* inattendu: il s'agit donc d'un bug
|
||||||
|
*/
|
||||||
|
class StateException extends LogicException {
|
||||||
|
static final function not_implemented(?string $method=null, ?string $prefix=null): self {
|
||||||
|
if ($method === null) $method = "this method";
|
||||||
|
$message = "$method is not implemented";
|
||||||
|
if ($prefix) $prefix = "$prefix: ";
|
||||||
|
return new static($prefix.$message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function unexpected_state(?string $prefix=null): self {
|
||||||
|
$message = "unexpected state";
|
||||||
|
if ($prefix) $prefix = "$prefix: ";
|
||||||
|
return new static($prefix.$message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
namespace nur\sery;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class StopException: une exception qui par convention est envoyée à un
|
||||||
|
* générateur pour indiquer qu'il doit s'arrêter "proprement". cela peut être
|
||||||
|
* utilisé pour implémenter des itérateur "closeable"
|
||||||
|
*/
|
||||||
|
class StopException extends Exception {
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
<?php
|
||||||
|
namespace nur\sery;
|
||||||
|
|
||||||
|
use RuntimeException;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class UserException: une exception qui peut en plus contenir un message
|
||||||
|
* utilisateur
|
||||||
|
*/
|
||||||
|
class UserException extends RuntimeException {
|
||||||
|
/** @param Throwable|ExceptionShadow $e */
|
||||||
|
static function get_user_message($e): ?string {
|
||||||
|
if ($e instanceof self) return $e->getUserMessage();
|
||||||
|
else return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param Throwable|ExceptionShadow $e */
|
||||||
|
static final function get_user_summary($e): string {
|
||||||
|
$parts = [];
|
||||||
|
$first = true;
|
||||||
|
while ($e !== null) {
|
||||||
|
$message = self::get_user_message($e);
|
||||||
|
if (!$message) $message = "(no message)";
|
||||||
|
if ($first) $first = false;
|
||||||
|
else $parts[] = "caused by ";
|
||||||
|
$parts[] = get_class($e) . ": " . $message;
|
||||||
|
$e = $e->getPrevious();
|
||||||
|
}
|
||||||
|
return implode(", ", $parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param Throwable|ExceptionShadow $e */
|
||||||
|
static function get_message($e): ?string {
|
||||||
|
$message = $e->getMessage();
|
||||||
|
if (!$message && $e instanceof self) $message = $e->getUserMessage();
|
||||||
|
return $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param Throwable|ExceptionShadow $e */
|
||||||
|
static final function get_summary($e): string {
|
||||||
|
$parts = [];
|
||||||
|
$first = true;
|
||||||
|
while ($e !== null) {
|
||||||
|
$message = self::get_message($e);
|
||||||
|
if (!$message) $message = "(no message)";
|
||||||
|
if ($first) $first = false;
|
||||||
|
else $parts[] = "caused by ";
|
||||||
|
if ($e instanceof ExceptionShadow) $class = $e->getClass();
|
||||||
|
else $class = get_class($e);
|
||||||
|
$parts[] = "$class: $message";
|
||||||
|
$e = $e->getPrevious();
|
||||||
|
}
|
||||||
|
return implode(", ", $parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param Throwable|ExceptionShadow $e */
|
||||||
|
static final function get_traceback($e): string {
|
||||||
|
$tbs = [];
|
||||||
|
$previous = false;
|
||||||
|
while ($e !== null) {
|
||||||
|
if (!$previous) {
|
||||||
|
$efile = $e->getFile();
|
||||||
|
$eline = $e->getLine();
|
||||||
|
$tbs[] = "at $efile($eline)";
|
||||||
|
} else {
|
||||||
|
$tbs[] = "~~ caused by: " . self::get_summary($e);
|
||||||
|
}
|
||||||
|
$tbs[] = $e->getTraceAsString();
|
||||||
|
$e = $e->getPrevious();
|
||||||
|
$previous = true;
|
||||||
|
#XXX il faudrait ne pas réinclure les lignes communes aux exceptions qui
|
||||||
|
# ont déjà été affichées
|
||||||
|
}
|
||||||
|
return implode("\n", $tbs);
|
||||||
|
}
|
||||||
|
|
||||||
|
function __construct($user_message, $tech_message=null, $code=0, ?Throwable $previous=null) {
|
||||||
|
$this->userMessage = $user_message;
|
||||||
|
if ($tech_message === null) $tech_message = $user_message;
|
||||||
|
parent::__construct($tech_message, $code, $previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected $userMessage;
|
||||||
|
|
||||||
|
function getUserMessage(): ?string {
|
||||||
|
return $this->userMessage;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
<?php
|
||||||
|
namespace nur\sery;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ValueException: indiquer qu'une valeur est invalide
|
||||||
|
*/
|
||||||
|
class ValueException extends UserException {
|
||||||
|
private static function value($value): string {
|
||||||
|
if (is_object($value)) {
|
||||||
|
return "<".get_class($value).">";
|
||||||
|
} elseif (is_array($value)) {
|
||||||
|
$values = $value;
|
||||||
|
$parts = [];
|
||||||
|
foreach ($values as $value) {
|
||||||
|
$parts[] = self::value($value);
|
||||||
|
}
|
||||||
|
return "[" . implode(", ", $parts) . "]";
|
||||||
|
} elseif (is_string($value)) {
|
||||||
|
return $value;
|
||||||
|
} else {
|
||||||
|
return var_export($value, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function message($value, ?string $message, ?string $kind, ?string $prefix, ?string $suffix): string {
|
||||||
|
if ($kind === null) $kind = "value";
|
||||||
|
if ($message === null) $message = "$kind$suffix";
|
||||||
|
if ($value !== null) {
|
||||||
|
$value = self::value($value);
|
||||||
|
if ($prefix) $prefix = "$prefix: $value";
|
||||||
|
else $prefix = $value;
|
||||||
|
}
|
||||||
|
if ($prefix) $prefix = "$prefix: ";
|
||||||
|
return $prefix.$message;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function null(?string $kind=null, ?string $prefix=null, ?string $message=null): self {
|
||||||
|
return new static(self::message(null, $message, $kind, $prefix, " should not be null"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function invalid_kind($value=null, ?string $kind=null, ?string $prefix=null, ?string $message=null): self {
|
||||||
|
return new static(self::message($value, $message, $kind, $prefix, " is invalid"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function invalid_key($value, ?string $prefix=null, ?string $message=null): self {
|
||||||
|
return self::invalid_kind($value, "key", $prefix, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function invalid_value($value, ?string $prefix=null, ?string $message=null): self {
|
||||||
|
return self::invalid_kind($value, "value", $prefix, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function invalid_type($value, string $expected_type): self {
|
||||||
|
return new static(self::message($value, null, "type", null, " is invalid, expected $expected_type"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function invalid_class($class, string $expected_class): self {
|
||||||
|
if (is_object($class)) $class = get_class($class);
|
||||||
|
return new static(self::message($class, null, "class", null, " is invalid, expected $expected_class"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function forbidden($value=null, ?string $kind=null, ?string $prefix=null, ?string $message=null): self {
|
||||||
|
return new static(self::message($value, $message, $kind, $prefix, " is forbidden"));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,509 @@
|
||||||
|
<?php
|
||||||
|
namespace nur\sery;
|
||||||
|
|
||||||
|
use ArrayAccess;
|
||||||
|
use Traversable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class cl: gestion de tableau de valeurs scalaires
|
||||||
|
*/
|
||||||
|
class cl {
|
||||||
|
/** retourner un array non null à partir de $array */
|
||||||
|
static final function with($array): array {
|
||||||
|
if (is_array($array)) return $array;
|
||||||
|
elseif ($array === null || $array === false) return [];
|
||||||
|
elseif ($array instanceof Traversable) return iterator_to_array($array);
|
||||||
|
else return [$array];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** retourner un array à partir de $array, ou null */
|
||||||
|
static final function withn($array): ?array {
|
||||||
|
if (is_array($array)) return $array;
|
||||||
|
elseif ($array === null || $array === false) return null;
|
||||||
|
elseif ($array instanceof Traversable) return iterator_to_array($array);
|
||||||
|
else return [$array];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* s'assurer que $array est un array non null. retourner true si $array n'a
|
||||||
|
* pas été modifié (s'il était déjà un array), false sinon.
|
||||||
|
*/
|
||||||
|
static final function ensure_array(&$array): bool {
|
||||||
|
if (is_array($array)) return true;
|
||||||
|
elseif ($array === null || $array === false) $array = [];
|
||||||
|
elseif ($array instanceof Traversable) $array = iterator_to_array($array);
|
||||||
|
else $array = [$array];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* s'assurer que $array est un array s'il est non null. retourner true si
|
||||||
|
* $array n'a pas été modifié (s'il était déjà un array ou s'il valait null).
|
||||||
|
*/
|
||||||
|
static final function ensure_narray(&$array): bool {
|
||||||
|
if ($array === null || is_array($array)) return true;
|
||||||
|
elseif ($array === false) $array = [];
|
||||||
|
elseif ($array instanceof Traversable) $array = iterator_to_array($array);
|
||||||
|
else $array = [$array];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** tester si $array a au moins une clé numérique */
|
||||||
|
static final function have_num_keys(?array $array): bool {
|
||||||
|
if ($array === null) return false;
|
||||||
|
foreach ($array as $key => $value) {
|
||||||
|
if (is_int($key)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tester si $array est une liste, c'est à dire un tableau non null avec
|
||||||
|
* uniquement des clés numériques séquentielles commençant à zéro
|
||||||
|
*
|
||||||
|
* NB: is_list(null) === false
|
||||||
|
* et is_list([]) === true
|
||||||
|
*/
|
||||||
|
static final function is_list(?array $array): bool {
|
||||||
|
if ($array === null) return false;
|
||||||
|
$index = -1;
|
||||||
|
foreach ($array as $key => $value) {
|
||||||
|
++$index;
|
||||||
|
if ($key !== $index) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tester si $array contient la clé $key
|
||||||
|
*
|
||||||
|
* @param array|ArrayAccess $array
|
||||||
|
*/
|
||||||
|
static final function has($array, $key): bool {
|
||||||
|
if (is_array($array)) {
|
||||||
|
return array_key_exists($key, $array);
|
||||||
|
} elseif ($array instanceof ArrayAccess) {
|
||||||
|
return $array->offsetExists($key);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* retourner $array[$key] ou $default si la clé n'existe pas
|
||||||
|
*
|
||||||
|
* @param array|ArrayAccess $array
|
||||||
|
*/
|
||||||
|
static final function get($array, $key, $default=null) {
|
||||||
|
if (is_array($array)) {
|
||||||
|
if (array_key_exists($key, $array)) return $array[$key];
|
||||||
|
} elseif ($array instanceof ArrayAccess) {
|
||||||
|
if ($array->offsetExists($key)) return $array->offsetGet($key);
|
||||||
|
}
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* si $array est un array ou une instance de ArrayAccess, créer ou modifier
|
||||||
|
* l'élément dont la clé est $key
|
||||||
|
*
|
||||||
|
* @param array|ArrayAccess $array
|
||||||
|
*/
|
||||||
|
static final function set(&$array, $key, $value): void {
|
||||||
|
if (is_array($array) || $array === null) {
|
||||||
|
if ($key === null) $array[] = $value;
|
||||||
|
else $array[$key] = $value;
|
||||||
|
} elseif ($array instanceof ArrayAccess) {
|
||||||
|
$array->offsetSet($key, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* si $array est un array ou une instance de ArrayAccess, supprimer l'élément
|
||||||
|
* dont la clé est $key
|
||||||
|
*
|
||||||
|
* @param array|ArrayAccess $array
|
||||||
|
*/
|
||||||
|
static final function del(&$array, $key): void {
|
||||||
|
if (is_array($array)) {
|
||||||
|
unset($array[$key]);
|
||||||
|
} elseif ($array instanceof ArrayAccess) {
|
||||||
|
$array->offsetUnset($key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** retourner le nombre d'éléments de $array */
|
||||||
|
static final function count(?array $array): int {
|
||||||
|
return $array !== null? count($array): 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** retourner la liste des clés de $array */
|
||||||
|
static final function keys(?array $array): array {
|
||||||
|
return $array !== null? array_keys($array): [];
|
||||||
|
}
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fusionner tous les tableaux spécifiés. Les valeurs null sont ignorées.
|
||||||
|
* Retourner null si aucun tableau n'est fourni ou s'ils étaient tous null.
|
||||||
|
*/
|
||||||
|
static final function merge(...$arrays): ?array {
|
||||||
|
$merges = [];
|
||||||
|
foreach ($arrays as $array) {
|
||||||
|
self::ensure_narray($array);
|
||||||
|
if ($array !== null) $merges[] = $array;
|
||||||
|
}
|
||||||
|
return $merges? array_merge(...$merges): null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vérifier que le chemin $keys existe dans le tableau $array
|
||||||
|
*
|
||||||
|
* si $keys est vide ou null, retourner true
|
||||||
|
*/
|
||||||
|
static final function phas($array, $pkey): bool {
|
||||||
|
# optimisations
|
||||||
|
if ($pkey === null || $pkey === []) {
|
||||||
|
return true;
|
||||||
|
} elseif (is_int($pkey) || (is_string($pkey) && strpos($pkey, ".") === false)) {
|
||||||
|
return self::has($array, $pkey);
|
||||||
|
} elseif (!is_array($pkey)) {
|
||||||
|
$pkey = explode(".", strval($pkey));
|
||||||
|
}
|
||||||
|
# phas
|
||||||
|
$first = true;
|
||||||
|
foreach($pkey as $key) {
|
||||||
|
if ($key === "" && $first) {
|
||||||
|
# une chaine vide en première position est ignorée
|
||||||
|
continue;
|
||||||
|
} elseif (is_array($array)) {
|
||||||
|
if (!array_key_exists($key, $array)) return false;
|
||||||
|
$array = $array[$key];
|
||||||
|
} elseif ($array instanceof ArrayAccess) {
|
||||||
|
if (!$array->offsetExists($key)) return false;
|
||||||
|
$array = $array->offsetGet($key);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$first = false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function each_phas($array, ?array $pkeys): array {
|
||||||
|
$result = [];
|
||||||
|
if ($pkeys !== null) {
|
||||||
|
foreach ($pkeys as $pkey) {
|
||||||
|
$result[] = self::phas($array, $pkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* obtenir la valeur correspondant au chemin $keys dans $array
|
||||||
|
*
|
||||||
|
* si $keys est vide ou null, retourner $default
|
||||||
|
*/
|
||||||
|
static final function pget($array, $pkey, $default=null) {
|
||||||
|
# optimisations
|
||||||
|
if ($pkey === null || $pkey === []) return $default;
|
||||||
|
elseif ($pkey === "") return $array;
|
||||||
|
elseif (is_int($pkey) || (is_string($pkey) && strpos($pkey, ".") === false)) {
|
||||||
|
return self::get($array, $pkey, $default);
|
||||||
|
} elseif (!is_array($pkey)) {
|
||||||
|
$pkey = explode(".", strval($pkey));
|
||||||
|
}
|
||||||
|
# pget
|
||||||
|
$value = $array;
|
||||||
|
$first = true;
|
||||||
|
foreach($pkey as $key) {
|
||||||
|
if ($key === "" && $first) {
|
||||||
|
# une chaine vide en première position est ignorée
|
||||||
|
continue;
|
||||||
|
} elseif (is_array($value)) {
|
||||||
|
if (!array_key_exists($key, $value)) return $default;
|
||||||
|
$value = $value[$key];
|
||||||
|
} elseif ($value instanceof ArrayAccess) {
|
||||||
|
if (!$value->offsetExists($key)) return $default;
|
||||||
|
$value = $value->offsetGet($key);
|
||||||
|
} else {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
$first = false;
|
||||||
|
}
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function each_pget($array, ?array $pkeys): array {
|
||||||
|
$result = [];
|
||||||
|
if ($pkeys !== null) {
|
||||||
|
foreach ($pkeys as $key => $pkey) {
|
||||||
|
$result[$key] = self::pget($array, $pkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* modifier la valeur au chemin de clé $keys dans le tableau $array
|
||||||
|
*
|
||||||
|
* utiliser la clé "" (chaine vide) en dernière position pour rajouter à la fin, e.g
|
||||||
|
* - pset($array, [""], $value) est équivalent à $array[] = $value
|
||||||
|
* - pset($array, ["a", "b", ""], $value) est équivalent à $array["a"]["b"][] = $value
|
||||||
|
* la clé "" n'a pas de propriété particulière quand elle n'est pas en dernière position
|
||||||
|
*
|
||||||
|
* si $keys est vide ou null, $array est remplacé par $value
|
||||||
|
*/
|
||||||
|
static final function pset(&$array, $pkey, $value): void {
|
||||||
|
# optimisations
|
||||||
|
if ($pkey === null || $pkey === []) {
|
||||||
|
$array = $value;
|
||||||
|
return;
|
||||||
|
} elseif ($pkey === "") {
|
||||||
|
$array[] = $value;
|
||||||
|
return;
|
||||||
|
} elseif (is_int($pkey) || (is_string($pkey) && strpos($pkey, ".") === false)) {
|
||||||
|
self::set($array, $pkey, $value);
|
||||||
|
return;
|
||||||
|
} elseif (!is_array($pkey)) {
|
||||||
|
$pkey = explode(".", strval($pkey));
|
||||||
|
}
|
||||||
|
# pset
|
||||||
|
self::ensure_array($array);
|
||||||
|
$current =& $array;
|
||||||
|
$key = null;
|
||||||
|
$last = count($pkey) - 1;
|
||||||
|
$i = 0;
|
||||||
|
foreach ($pkey as $key) {
|
||||||
|
if ($i == $last) break;
|
||||||
|
if ($current instanceof ArrayAccess) {
|
||||||
|
if (!$current->offsetExists($key)) $current->offsetSet($key, []);
|
||||||
|
$current =& $current->offsetGet($key);
|
||||||
|
if ($current === null) {
|
||||||
|
$current = [];
|
||||||
|
} elseif (!is_array($current) && !($current instanceof ArrayAccess)) {
|
||||||
|
$current = [$current];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self::ensure_array($current[$key]);
|
||||||
|
$current =& $current[$key];
|
||||||
|
}
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
if ($key === "") $current[] = $value;
|
||||||
|
else $current[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function each_pset(&$array, ?array $values): void {
|
||||||
|
if ($values !== null) {
|
||||||
|
foreach ($values as $pkey => $value) {
|
||||||
|
self::pset($array, $pkey, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* supprimer la valeur au chemin de clé $keys dans $array
|
||||||
|
*
|
||||||
|
* si $array vaut null ou false, sa valeur est inchangée.
|
||||||
|
* si $keys est vide ou null, $array devient null
|
||||||
|
*/
|
||||||
|
static final function pdel(&$array, $pkey): void {
|
||||||
|
# optimisations
|
||||||
|
if ($array === null || $array === false) {
|
||||||
|
return;
|
||||||
|
} elseif ($pkey === null || $pkey === []) {
|
||||||
|
$array = null;
|
||||||
|
return;
|
||||||
|
} elseif (is_int($pkey) || (is_string($pkey) && strpos($pkey, ".") === false)) {
|
||||||
|
self::del($array, $pkey);
|
||||||
|
return;
|
||||||
|
} elseif (!is_array($pkey)) {
|
||||||
|
$pkey = explode(".", strval($pkey));
|
||||||
|
}
|
||||||
|
# pdel
|
||||||
|
self::ensure_array($array);
|
||||||
|
$current =& $array;
|
||||||
|
$key = null;
|
||||||
|
$last = count($pkey) - 1;
|
||||||
|
$i = 0;
|
||||||
|
foreach ($pkey as $key) {
|
||||||
|
if ($i == $last) break;
|
||||||
|
if ($current instanceof ArrayAccess) {
|
||||||
|
if (!$current->offsetExists($key)) break;
|
||||||
|
} elseif (is_array($current)) {
|
||||||
|
if (!array_key_exists($key, $current)) break;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$current =& $current[$key];
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
if ($i == $last) {
|
||||||
|
if ($current instanceof ArrayAccess) {
|
||||||
|
$current->offsetUnset($key);
|
||||||
|
} elseif (is_array($current)) {
|
||||||
|
unset($current[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function each_pdel(&$array, ?array $pkeys): void {
|
||||||
|
if ($pkeys !== null) {
|
||||||
|
foreach ($pkeys as $pkey) {
|
||||||
|
self::pdel($array, $pkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
/**
|
||||||
|
* retourner le tableau $array en "renommant" les clés selon le tableau
|
||||||
|
* $mappings qui contient des associations de la forme [$from => $to]
|
||||||
|
*/
|
||||||
|
static function rekey(?array $array, ?array $mappings): ?array {
|
||||||
|
if ($array === null || $mappings === null) return $array;
|
||||||
|
$mapped = [];
|
||||||
|
foreach ($array as $key => $value) {
|
||||||
|
if (array_key_exists($key, $mappings)) $key = $mappings[$key];
|
||||||
|
$mapped[$key] = $value;
|
||||||
|
}
|
||||||
|
return $mapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
/** tester si tous les éléments du tableau satisfont la condition */
|
||||||
|
static final function all_if(?array $array, callable $cond): bool {
|
||||||
|
if ($array !== null) {
|
||||||
|
foreach ($array as $value) {
|
||||||
|
if (!$cond($value)) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function all_z(?array $array): bool { return self::all_if($array, [cv::class, "z"]);}
|
||||||
|
static final function all_nz(?array $array): bool { return self::all_if($array, [cv::class, "nz"]);}
|
||||||
|
static final function all_n(?array $array): bool { return self::all_if($array, [cv::class, "n"]);}
|
||||||
|
static final function all_nn(?array $array): bool { return self::all_if($array, [cv::class, "nn"]);}
|
||||||
|
static final function all_t(?array $array): bool { return self::all_if($array, [cv::class, "t"]);}
|
||||||
|
static final function all_f(?array $array): bool { return self::all_if($array, [cv::class, "f"]);}
|
||||||
|
static final function all_pt(?array $array): bool { return self::all_if($array, [cv::class, "pt"]);}
|
||||||
|
static final function all_pf(?array $array): bool { return self::all_if($array, [cv::class, "pf"]);}
|
||||||
|
static final function all_equals(?array $array, $value): bool { return self::all_if($array, cv::equals($value)); }
|
||||||
|
static final function all_not_equals(?array $array, $value): bool { return self::all_if($array, cv::not_equals($value)); }
|
||||||
|
static final function all_same(?array $array, $value): bool { return self::all_if($array, cv::same($value)); }
|
||||||
|
static final function all_not_same(?array $array, $value): bool { return self::all_if($array, cv::not_same($value)); }
|
||||||
|
|
||||||
|
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
/** tester si au moins un élément du tableau satisfait la condition */
|
||||||
|
static final function any_if(?array $array, callable $cond): bool {
|
||||||
|
if ($array !== null) {
|
||||||
|
foreach ($array as $value) {
|
||||||
|
if ($cond($value)) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function any_z(?array $array): bool { return self::any_if($array, [cv::class, "z"]);}
|
||||||
|
static final function any_nz(?array $array): bool { return self::any_if($array, [cv::class, "nz"]);}
|
||||||
|
static final function any_n(?array $array): bool { return self::any_if($array, [cv::class, "n"]);}
|
||||||
|
static final function any_nn(?array $array): bool { return self::any_if($array, [cv::class, "nn"]);}
|
||||||
|
static final function any_t(?array $array): bool { return self::any_if($array, [cv::class, "t"]);}
|
||||||
|
static final function any_f(?array $array): bool { return self::any_if($array, [cv::class, "f"]);}
|
||||||
|
static final function any_pt(?array $array): bool { return self::any_if($array, [cv::class, "pt"]);}
|
||||||
|
static final function any_pf(?array $array): bool { return self::any_if($array, [cv::class, "pf"]);}
|
||||||
|
static final function any_equals(?array $array, $value): bool { return self::any_if($array, cv::equals($value)); }
|
||||||
|
static final function any_not_equals(?array $array, $value): bool { return self::any_if($array, cv::not_equals($value)); }
|
||||||
|
static final function any_same(?array $array, $value): bool { return self::any_if($array, cv::same($value)); }
|
||||||
|
static final function any_not_same(?array $array, $value): bool { return self::any_if($array, cv::not_same($value)); }
|
||||||
|
|
||||||
|
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
static final function filter_if(?array $array, callable $cond): ?array {
|
||||||
|
if ($array === null) return null;
|
||||||
|
$filtered = [];
|
||||||
|
$index = 0;
|
||||||
|
foreach ($array as $key => $value) {
|
||||||
|
if (!$cond($value)) {
|
||||||
|
if ($key === $index) {
|
||||||
|
$index++;
|
||||||
|
$filtered[] = $value;
|
||||||
|
} else {
|
||||||
|
$filtered[$key] = $value;
|
||||||
|
}
|
||||||
|
} elseif ($key === $index) {
|
||||||
|
$index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $filtered;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function filter_z(?array $array): ?array { return self::filter_if($array, [cv::class, "z"]);}
|
||||||
|
static final function filter_nz(?array $array): ?array { return self::filter_if($array, [cv::class, "nz"]);}
|
||||||
|
static final function filter_n(?array $array): ?array { return self::filter_if($array, [cv::class, "n"]);}
|
||||||
|
static final function filter_nn(?array $array): ?array { return self::filter_if($array, [cv::class, "nn"]);}
|
||||||
|
static final function filter_t(?array $array): ?array { return self::filter_if($array, [cv::class, "t"]);}
|
||||||
|
static final function filter_f(?array $array): ?array { return self::filter_if($array, [cv::class, "f"]);}
|
||||||
|
static final function filter_pt(?array $array): ?array { return self::filter_if($array, [cv::class, "pt"]);}
|
||||||
|
static final function filter_pf(?array $array): ?array { return self::filter_if($array, [cv::class, "pf"]);}
|
||||||
|
static final function filter_equals(?array $array, $value): ?array { return self::filter_if($array, cv::equals($value)); }
|
||||||
|
static final function filter_not_equals(?array $array, $value): ?array { return self::filter_if($array, cv::not_equals($value)); }
|
||||||
|
static final function filter_same(?array $array, $value): ?array { return self::filter_if($array, cv::same($value)); }
|
||||||
|
static final function filter_not_same(?array $array, $value): ?array { return self::filter_if($array, cv::not_same($value)); }
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
static final function sorted(?array $array, int $flags=SORT_REGULAR, bool $assoc=false): ?array {
|
||||||
|
if ($array === null) return null;
|
||||||
|
if ($assoc) asort($array, $flags);
|
||||||
|
else sort($array, $flags);
|
||||||
|
return $array;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function ksorted(?array $array, int $flags=SORT_REGULAR): ?array {
|
||||||
|
if ($array === null) return null;
|
||||||
|
ksort($array, $flags);
|
||||||
|
return $array;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* retourner une fonction permettant de trier un tableau sur les clés
|
||||||
|
* spécifiées.
|
||||||
|
*
|
||||||
|
* - les clés ayant le préfixe '+' ou le suffixe '|asc' indiquent un tri
|
||||||
|
* ascendant
|
||||||
|
* - les clés ayant le préfixe '-' ou le suffixe '|desc' indiquent un tri
|
||||||
|
* descendant
|
||||||
|
* - sinon, par défaut, le tri est ascendant
|
||||||
|
*/
|
||||||
|
static final function compare(array $keys): callable {
|
||||||
|
return function ($a, $b) use ($keys) {
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
if (str::del_prefix($key, "+")) $w = 1;
|
||||||
|
elseif (str::del_prefix($key, "-")) $w = -1;
|
||||||
|
elseif (str::del_suffix($key, "|asc")) $w = 1;
|
||||||
|
elseif (str::del_suffix($key, "|desc")) $w = -1;
|
||||||
|
else $w = 1;
|
||||||
|
if ($c = $w * cv::compare(cl::get($a, $key), cl::get($b, $key))) {
|
||||||
|
return $c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function usorted(?array $array, array $keys, bool $assoc=false): ?array {
|
||||||
|
if ($array === null) return null;
|
||||||
|
if ($assoc) uasort($array, self::compare($keys));
|
||||||
|
else usort($array, self::compare($keys));
|
||||||
|
return $array;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,216 @@
|
||||||
|
<?php
|
||||||
|
namespace nur\sery;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class cv: gestion de valeurs scalaires
|
||||||
|
*/
|
||||||
|
class cv {
|
||||||
|
/** tester si $value vaut null ou false */
|
||||||
|
static final function z($value): bool {
|
||||||
|
return $value === false || $value === null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** tester si $value ne vaut ni null ni false */
|
||||||
|
static final function nz($value): bool {
|
||||||
|
return $value !== false && $value !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** tester si $value vaut null */
|
||||||
|
static final function n($value): bool {
|
||||||
|
return $value === null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** tester si $value n'est pas null */
|
||||||
|
static final function nn($value): bool {
|
||||||
|
return $value !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** tester si $value est vraie (y compris la chaine "0") */
|
||||||
|
static final function t($value): bool {
|
||||||
|
return $value || $value === "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
/** tester si $value est fausse (cela n'inclue pas la chaine "0") */
|
||||||
|
static final function f($value): bool {
|
||||||
|
return !$value && $value !== "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
/** tester si $value est vraie selon les règles de PHP. */
|
||||||
|
static final function pt($value): bool {
|
||||||
|
return boolval($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** tester si $value est fausse selon les règles de PHP. */
|
||||||
|
static final function pf($value): bool {
|
||||||
|
return !$value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contruire une fonction qui retourne vrai si on lui passe en argument une
|
||||||
|
* valeur égale à $value
|
||||||
|
*/
|
||||||
|
static final function equals($value): callable {
|
||||||
|
return function ($arg) use($value) { return $arg == $value; };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contruire une fonction qui retourne vrai si on lui passe en argument une
|
||||||
|
* valeur qui n'est pas égale à $value
|
||||||
|
*/
|
||||||
|
static final function not_equals($value): callable {
|
||||||
|
return function ($arg) use($value) { return $arg != $value; };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contruire une fonction qui retourne vrai si on lui passe en argument une
|
||||||
|
* valeur strictement égale à $value
|
||||||
|
*/
|
||||||
|
static final function same($value): callable {
|
||||||
|
return function ($arg) use($value) { return $arg === $value; };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contruire une fonction qui retourne vrai si on lui passe en argument une
|
||||||
|
* valeur qui n'est pas strictement égale à $value
|
||||||
|
*/
|
||||||
|
static final function not_same($value): callable {
|
||||||
|
return function ($arg) use($value) { return $arg !== $value; };
|
||||||
|
}
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
/** mettre à jour $dest avec $value si $cond($value) est vrai */
|
||||||
|
static final function set_if(&$dest, $value, callable $cond) {
|
||||||
|
if ($cond($value)) $dest = $value;
|
||||||
|
return $dest;
|
||||||
|
}
|
||||||
|
static final function set_z(&$dest, $value) { return self::set_if($dest, $value, [self::class, "z"]);}
|
||||||
|
static final function set_nz(&$dest, $value) { return self::set_if($dest, $value, [self::class, "nz"]);}
|
||||||
|
static final function set_n(&$dest, $value) { return self::set_if($dest, $value, [self::class, "n"]);}
|
||||||
|
static final function set_nn(&$dest, $value) { return self::set_if($dest, $value, [self::class, "nn"]);}
|
||||||
|
static final function set_t(&$dest, $value) { return self::set_if($dest, $value, [self::class, "t"]);}
|
||||||
|
static final function set_f(&$dest, $value) { return self::set_if($dest, $value, [self::class, "f"]);}
|
||||||
|
static final function set_pt(&$dest, $value) { return self::set_if($dest, $value, [self::class, "pt"]);}
|
||||||
|
static final function set_pf(&$dest, $value) { return self::set_if($dest, $value, [self::class, "pf"]);}
|
||||||
|
|
||||||
|
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
/** mettre à jour $dest avec $value si $cond($dest) est vrai */
|
||||||
|
static final function update_if(&$dest, $value, callable $cond) {
|
||||||
|
if ($cond($dest)) $dest = $value;
|
||||||
|
return $dest;
|
||||||
|
}
|
||||||
|
static final function update_z(&$dest, $value) { return self::update_if($dest, $value, [self::class, "z"]);}
|
||||||
|
static final function update_nz(&$dest, $value) { return self::update_if($dest, $value, [self::class, "nz"]);}
|
||||||
|
static final function update_n(&$dest, $value) { return self::update_if($dest, $value, [self::class, "n"]);}
|
||||||
|
static final function update_nn(&$dest, $value) { return self::update_if($dest, $value, [self::class, "nn"]);}
|
||||||
|
static final function update_t(&$dest, $value) { return self::update_if($dest, $value, [self::class, "t"]);}
|
||||||
|
static final function update_f(&$dest, $value) { return self::update_if($dest, $value, [self::class, "f"]);}
|
||||||
|
static final function update_pt(&$dest, $value) { return self::update_if($dest, $value, [self::class, "pt"]);}
|
||||||
|
static final function update_pf(&$dest, $value) { return self::update_if($dest, $value, [self::class, "pf"]);}
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
/** retourner $value si elle est vraie (y compris la chaine "0"), false sinon */
|
||||||
|
static final function vf($value) {
|
||||||
|
return $value || $value === "0"? $value: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** retourner $value si elle est vraie (y compris la chaine "0"), null sinon */
|
||||||
|
static final function vn($value) {
|
||||||
|
return $value || $value === "0"? $value: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* retourner la première valeur vraie (y compris la chaine "0")
|
||||||
|
*
|
||||||
|
* si toutes les valeurs sont fausses, retourner la dernière valeur de la
|
||||||
|
* liste, ou null si la liste est vide
|
||||||
|
*/
|
||||||
|
static final function firstv(...$values) {
|
||||||
|
$value = null;
|
||||||
|
foreach ($values as $value) {
|
||||||
|
if ($value || $value === "0") return $value;
|
||||||
|
}
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* retourner la première valeur vraie selon les règles de PHP.
|
||||||
|
*
|
||||||
|
* si toutes les valeurs sont fausses, retourner la dernière valeur de la
|
||||||
|
* liste, ou null si la liste est vide
|
||||||
|
*/
|
||||||
|
static final function firstpv(...$values) {
|
||||||
|
$value = null;
|
||||||
|
foreach ($values as $value) {
|
||||||
|
if ($value) return $value;
|
||||||
|
}
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
/** vérifier si $value est un booléen, sinon retourner null */
|
||||||
|
static final function check_bool($value): ?bool {
|
||||||
|
return is_bool($value)? $value: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** vérifier si $value est un integer, sinon retourner null */
|
||||||
|
static final function check_int($value): ?int {
|
||||||
|
return is_int($value)? $value: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** vérifier si $value est un string, sinon retourner null */
|
||||||
|
static final function check_string($value): ?string {
|
||||||
|
return is_string($value)? $value: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** vérifier si $value est un array, sinon retourner null */
|
||||||
|
static final function check_array($value): ?array {
|
||||||
|
return is_array($value)? $value: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* retourner [$index, $key] initialisés chacun en fonction du type de $value
|
||||||
|
* (index est numérique, key est une chaine)
|
||||||
|
*
|
||||||
|
* lever une exception si $value n'est d'aucun de ces types
|
||||||
|
*/
|
||||||
|
static final function check_key($value, ?string $prefix=null, bool $throw_exception=true): array {
|
||||||
|
$index = is_int($value)? $value : null;
|
||||||
|
$key = is_string($value)? $value : null;
|
||||||
|
if ($index === null && $key === null && $throw_exception) {
|
||||||
|
throw ValueException::invalid_kind($value, "key", $prefix);
|
||||||
|
} else {
|
||||||
|
return [$index, $key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* retourner [$bool, $string, $array] initialisés chacun en fonction du type
|
||||||
|
* de $value.
|
||||||
|
*
|
||||||
|
* @throws ValueException si $value n'est d'aucun de ces types
|
||||||
|
*/
|
||||||
|
static final function check_bsa($value, ?string $prefix=null, bool $throw_exception=true): array {
|
||||||
|
$bool = is_bool($value)? $value : null;
|
||||||
|
$string = is_string($value)? $value : null;
|
||||||
|
$array = is_array($value)? $value : null;
|
||||||
|
if ($bool === null && $string === null && $array === null && $throw_exception) {
|
||||||
|
throw ValueException::invalid_kind($value, "value", $prefix);
|
||||||
|
} else {
|
||||||
|
return [$bool, $string, $array];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
/** retourner -1, 0 ou 1 en fonction de l'ordre relatif entre $a et $b */
|
||||||
|
static final function compare($a, $b): int {
|
||||||
|
if ($a === $b) return 0;
|
||||||
|
if ($a < $b) return -1;
|
||||||
|
if ($a > $b) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
# nulib\os
|
# nur\sery\os
|
||||||
|
|
||||||
Ce package contient des services permettant d'interagir avec le système d'exploitation
|
Ce package contient des services permettant d'interagir avec le système d'exploitation
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\os\file;
|
namespace nur\sery\os\file;
|
||||||
|
|
||||||
use nulib\ValueException;
|
use nur\sery\ValueException;
|
||||||
|
|
||||||
class SharedFile extends FileWriter {
|
class SharedFile extends FileWriter {
|
||||||
const USE_LOCKING = true;
|
const USE_LOCKING = true;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\os\file;
|
namespace nur\sery\os\file;
|
||||||
|
|
||||||
use nulib\str;
|
use nur\sery\str;
|
||||||
use nulib\ValueException;
|
use nur\sery\ValueException;
|
||||||
use nur\sery\os\EOFException;
|
use nur\sery\os\EOFException;
|
||||||
use nur\sery\os\IOException;
|
use nur\sery\os\IOException;
|
||||||
use nur\sery\php\iter\AbstractIterator;
|
use nur\sery\php\iter\AbstractIterator;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php # -*- coding: utf-8 mode: php -*- vim:sw=2:sts=2:et:ai:si:sta:fenc=utf-8
|
<?php # -*- coding: utf-8 mode: php -*- vim:sw=2:sts=2:et:ai:si:sta:fenc=utf-8
|
||||||
namespace nur\sery\os;
|
namespace nur\sery\os;
|
||||||
|
|
||||||
use nulib\str;
|
use nur\sery\str;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class path: manipulation de chemins du système de fichiers
|
* Class path: manipulation de chemins du système de fichiers
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\os;
|
namespace nur\sery\os;
|
||||||
|
|
||||||
use nulib\cl;
|
use nur\sery\cl;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
|
|
||||||
class sh {
|
class sh {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\output;
|
namespace nur\sery\output;
|
||||||
|
|
||||||
use nulib\str;
|
use nur\sery\str;
|
||||||
use nulib\ValueException;
|
use nur\sery\ValueException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class _messenger: classe de base pour say, log et msg
|
* Class _messenger: classe de base pour say, log et msg
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\output;
|
namespace nur\sery\output;
|
||||||
|
|
||||||
use nulib\ValueException;
|
use nur\sery\ValueException;
|
||||||
use nur\sery\output\std\ProxyMessenger;
|
use nur\sery\output\std\ProxyMessenger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\output;
|
namespace nur\sery\output;
|
||||||
|
|
||||||
use nulib\ValueException;
|
use nur\sery\ValueException;
|
||||||
use nur\sery\output\std\ProxyMessenger;
|
use nur\sery\output\std\ProxyMessenger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\output;
|
namespace nur\sery\output;
|
||||||
|
|
||||||
use nulib\ValueException;
|
use nur\sery\ValueException;
|
||||||
use nur\sery\output\std\ProxyMessenger;
|
use nur\sery\output\std\ProxyMessenger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
namespace nur\sery\output\std;
|
namespace nur\sery\output\std;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use nulib\cl;
|
use nur\sery\cl;
|
||||||
use nulib\ExceptionShadow;
|
use nur\sery\ExceptionShadow;
|
||||||
use nulib\UserException;
|
use nur\sery\UserException;
|
||||||
use nur\sery\output\IMessenger;
|
use nur\sery\output\IMessenger;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
namespace nur\sery\output\std;
|
namespace nur\sery\output\std;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use nulib\cl;
|
use nur\sery\cl;
|
||||||
use nur\sery\os\file\Stream;
|
use nur\sery\os\file\Stream;
|
||||||
use nur\sery\php\content\content;
|
use nur\sery\php\content\content;
|
||||||
use nur\sery\php\content\IContent;
|
use nur\sery\php\content\IContent;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# nulib\php
|
# nur\sery\php
|
||||||
|
|
||||||
Ce package contient des services généraux spécifiques à PHP
|
Ce package contient des services généraux spécifiques à PHP
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\php\coll;
|
namespace nur\sery\php\coll;
|
||||||
|
|
||||||
use nulib\cl;
|
use nur\sery\cl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class AutoArray: un tableau dont les éléments peuvent être accédés comme des
|
* Class AutoArray: un tableau dont les éléments peuvent être accédés comme des
|
||||||
|
|
|
@ -4,7 +4,7 @@ namespace nur\sery\php\coll;
|
||||||
use ArrayAccess;
|
use ArrayAccess;
|
||||||
use Countable;
|
use Countable;
|
||||||
use Iterator;
|
use Iterator;
|
||||||
use nulib\cl;
|
use nur\sery\cl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class BaseArray: implémentation de base d'un objet array-like, qui peut aussi
|
* Class BaseArray: implémentation de base d'un objet array-like, qui peut aussi
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\php\content;
|
namespace nur\sery\php\content;
|
||||||
|
|
||||||
use nulib\cl;
|
use nur\sery\cl;
|
||||||
use nur\sery\php\func;
|
use nur\sery\php\func;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
namespace nur\sery\php;
|
namespace nur\sery\php;
|
||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
use nulib\cl;
|
use nur\sery\cl;
|
||||||
use nulib\ValueException;
|
use nur\sery\ValueException;
|
||||||
use nur\sery\ref\php\ref_func;
|
use nur\sery\ref\php\ref_func;
|
||||||
use nur\sery\schema\Schema;
|
use nur\sery\schema\Schema;
|
||||||
use ReflectionClass;
|
use ReflectionClass;
|
||||||
|
|
|
@ -3,7 +3,7 @@ namespace nur\sery\php\iter;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Iterator;
|
use Iterator;
|
||||||
use nulib\DataException;
|
use nur\sery\DataException;
|
||||||
use nur\sery\php\ICloseable;
|
use nur\sery\php\ICloseable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# nulib\schema
|
# nur\sery\schema
|
||||||
|
|
||||||
objet: s'assurer que des données soit dans un type particulier, en les
|
objet: s'assurer que des données soit dans un type particulier, en les
|
||||||
convertissant si nécessaire. la source de ces données peut-être diverse:
|
convertissant si nécessaire. la source de ces données peut-être diverse:
|
||||||
|
|
|
@ -3,8 +3,8 @@ namespace nur\sery\schema;
|
||||||
|
|
||||||
use ArrayAccess;
|
use ArrayAccess;
|
||||||
use LogicException;
|
use LogicException;
|
||||||
use nulib\AccessException;
|
use nur\sery\AccessException;
|
||||||
use nulib\cl;
|
use nur\sery\cl;
|
||||||
use nur\sery\schema\_assoc\AssocSchema;
|
use nur\sery\schema\_assoc\AssocSchema;
|
||||||
use nur\sery\schema\_list\ListSchema;
|
use nur\sery\schema\_list\ListSchema;
|
||||||
use nur\sery\schema\_scalar\ScalarSchema;
|
use nur\sery\schema\_scalar\ScalarSchema;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# nulib\schema
|
# nur\sery\schema
|
||||||
|
|
||||||
* implémenter support `analyzer_func`, `extractor_func`, `parser_func`,
|
* implémenter support `analyzer_func`, `extractor_func`, `parser_func`,
|
||||||
`normalizer_func`, `formatter_func`
|
`normalizer_func`, `formatter_func`
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\schema\_assoc;
|
namespace nur\sery\schema\_assoc;
|
||||||
|
|
||||||
use nulib\cl;
|
use nur\sery\cl;
|
||||||
use nur\sery\ref\schema\ref_schema;
|
use nur\sery\ref\schema\ref_schema;
|
||||||
use nur\sery\schema\_scalar\ScalarValue;
|
use nur\sery\schema\_scalar\ScalarValue;
|
||||||
use nur\sery\schema\input\Input;
|
use nur\sery\schema\input\Input;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\schema\_scalar;
|
namespace nur\sery\schema\_scalar;
|
||||||
|
|
||||||
use nulib\cl;
|
use nur\sery\cl;
|
||||||
use nulib\ValueException;
|
use nur\sery\ValueException;
|
||||||
use nur\sery\ref\schema\ref_analyze;
|
use nur\sery\ref\schema\ref_analyze;
|
||||||
use nur\sery\ref\schema\ref_schema;
|
use nur\sery\ref\schema\ref_schema;
|
||||||
use nur\sery\schema\Result;
|
use nur\sery\schema\Result;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\schema\_scalar;
|
namespace nur\sery\schema\_scalar;
|
||||||
|
|
||||||
use nulib\cl;
|
use nur\sery\cl;
|
||||||
use nur\sery\ref\schema\ref_schema;
|
use nur\sery\ref\schema\ref_schema;
|
||||||
use nur\sery\ref\schema\ref_types;
|
use nur\sery\ref\schema\ref_types;
|
||||||
use nur\sery\schema\Schema;
|
use nur\sery\schema\Schema;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\schema\_scalar;
|
namespace nur\sery\schema\_scalar;
|
||||||
|
|
||||||
use nulib\ValueException;
|
use nur\sery\ValueException;
|
||||||
use nur\sery\schema\input\Input;
|
use nur\sery\schema\input\Input;
|
||||||
use nur\sery\ref\schema\ref_analyze;
|
use nur\sery\ref\schema\ref_analyze;
|
||||||
use nur\sery\schema\Result;
|
use nur\sery\schema\Result;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\schema\input;
|
namespace nur\sery\schema\input;
|
||||||
|
|
||||||
use nulib\cl;
|
use nur\sery\cl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class Input: accès à une valeur
|
* Class Input: accès à une valeur
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\schema\types;
|
namespace nur\sery\schema\types;
|
||||||
|
|
||||||
use nulib\cl;
|
use nur\sery\cl;
|
||||||
|
|
||||||
class Registry {
|
class Registry {
|
||||||
const TYPES = [
|
const TYPES = [
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\schema\types;
|
namespace nur\sery\schema\types;
|
||||||
|
|
||||||
use nulib\cl;
|
use nur\sery\cl;
|
||||||
|
|
||||||
abstract class tarray implements IType {
|
abstract class tarray implements IType {
|
||||||
static function ensure_array(&$array): void {
|
static function ensure_array(&$array): void {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\schema\types;
|
namespace nur\sery\schema\types;
|
||||||
|
|
||||||
use nulib\cl;
|
use nur\sery\cl;
|
||||||
use nulib\ValueException;
|
use nur\sery\ValueException;
|
||||||
use nur\sery\schema\_scalar\ScalarResult;
|
use nur\sery\schema\_scalar\ScalarResult;
|
||||||
use nur\sery\schema\_scalar\ScalarSchema;
|
use nur\sery\schema\_scalar\ScalarSchema;
|
||||||
use nur\sery\schema\input\Input;
|
use nur\sery\schema\input\Input;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\schema\types;
|
namespace nur\sery\schema\types;
|
||||||
|
|
||||||
use nulib\ValueException;
|
use nur\sery\ValueException;
|
||||||
|
|
||||||
abstract class tcallable implements IType {
|
abstract class tcallable implements IType {
|
||||||
static function ensure_callable(&$callable): void {
|
static function ensure_callable(&$callable): void {
|
||||||
|
|
|
@ -0,0 +1,389 @@
|
||||||
|
<?php
|
||||||
|
namespace nur\sery;
|
||||||
|
|
||||||
|
use nur\base;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class str: gestion des chaines de caractère "simples"
|
||||||
|
*/
|
||||||
|
class str {
|
||||||
|
/**
|
||||||
|
* Retourner $s converti en chaine non nulle, ou "" si $s est fausse (cela
|
||||||
|
* n'inclue pas la chaine "0")
|
||||||
|
*/
|
||||||
|
static final function with($s): string {
|
||||||
|
if (!is_string($s)) {
|
||||||
|
if (!$s) return "";
|
||||||
|
else $s = strval($s);
|
||||||
|
}
|
||||||
|
return $s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourner $s converti en chaine non nulle, ou "" si $s est fausse selon les
|
||||||
|
* règles de PHP
|
||||||
|
*/
|
||||||
|
static final function pwith($s): string {
|
||||||
|
if (!is_string($s)) {
|
||||||
|
if (!$s) return "";
|
||||||
|
else $s = strval($s);
|
||||||
|
}
|
||||||
|
return $s?: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tronquer si nécessaire $s à la valeur $length.
|
||||||
|
* la chaine $suffix est rajoutée le cas échéant de façon que la taille
|
||||||
|
* totale n'excède pas $length caractères.
|
||||||
|
*
|
||||||
|
* si $ellips est true et que le troncage est nécessaire, remplacer les 3
|
||||||
|
* derniers caractères par "..."
|
||||||
|
*/
|
||||||
|
static final function trunc(?string $s, int $length, bool $ellips=false, ?string $suffix=null): ?string {
|
||||||
|
if ($s === null) return null;
|
||||||
|
if ($suffix !== null) $length -= strlen($suffix);
|
||||||
|
if (strlen($s) > $length) {
|
||||||
|
if ($ellips && $length > 3) $s = substr($s, 0, $length - 3)."...";
|
||||||
|
else $s = substr($s, 0, $length);
|
||||||
|
}
|
||||||
|
if ($suffix !== null) $s .= $suffix;
|
||||||
|
return $s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** trimmer $s */
|
||||||
|
static final function trim(?string $s): ?string {
|
||||||
|
if ($s === null) return null;
|
||||||
|
else return trim($s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** trimmer $s à gauche */
|
||||||
|
static final function ltrim(?string $s): ?string {
|
||||||
|
if ($s === null) return null;
|
||||||
|
else return ltrim($s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** trimmer $s à droite */
|
||||||
|
static final function rtrim(?string $s): ?string {
|
||||||
|
if ($s === null) return null;
|
||||||
|
else return rtrim($s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function left(?string $s, int $size): ?string {
|
||||||
|
if ($s === null) return null;
|
||||||
|
else return str_pad($s, $size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function right(?string $s, int $size): ?string {
|
||||||
|
if ($s === null) return null;
|
||||||
|
else return str_pad($s, $size, " ", STR_PAD_LEFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function center(?string $s, int $size): ?string {
|
||||||
|
if ($s === null) return null;
|
||||||
|
else return str_pad($s, $size, " ", STR_PAD_BOTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function pad0(?string $s, int $size): ?string {
|
||||||
|
if ($s === null) return null;
|
||||||
|
else return str_pad($s, $size, "0", STR_PAD_LEFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function lower(?string $s): ?string {
|
||||||
|
if ($s === null) return null;
|
||||||
|
else return strtolower($s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function lower1(?string $s): ?string {
|
||||||
|
if ($s === null) return null;
|
||||||
|
else return lcfirst($s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function upper(?string $s): ?string {
|
||||||
|
if ($s === null) return null;
|
||||||
|
else return strtoupper($s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function upper1(?string $s): ?string {
|
||||||
|
if ($s === null) return null;
|
||||||
|
else return ucfirst($s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function upperw(?string $s, ?string $delimiters=null): ?string {
|
||||||
|
if ($s === null) return null;
|
||||||
|
if ($delimiters !== null) return ucwords($s, $delimiters);
|
||||||
|
else return ucwords($s, " _-\t\r\n\f\v");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static final function _starts_with(string $prefix, string $s, ?int $min_len=null): bool {
|
||||||
|
if ($prefix === $s) return true;
|
||||||
|
$len = strlen($prefix);
|
||||||
|
if ($min_len !== null && ($len < $min_len || $len > strlen($s))) return false;
|
||||||
|
return $len == 0 || $prefix === substr($s, 0, $len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tester si $s commence par $prefix
|
||||||
|
* par exemple:
|
||||||
|
* - starts_with("", "whatever") est true
|
||||||
|
* - starts_with("fi", "first") est true
|
||||||
|
* - starts_with("no", "yes") est false
|
||||||
|
*
|
||||||
|
* si $min_len n'est pas null, c'est la longueur minimum requise de $prefix
|
||||||
|
* pour qu'on teste la correspondance. dans le cas contraire, la valeur de
|
||||||
|
* retour est toujours false, sauf s'il y a égalité. e.g
|
||||||
|
* - starts_with("a", "abc", 2) est false
|
||||||
|
* - starts_with("a", "a", 2) est true
|
||||||
|
*/
|
||||||
|
static final function starts_with(?string $prefix, ?string $s, ?int $min_len=null): bool {
|
||||||
|
if ($s === null || $prefix === null) return false;
|
||||||
|
else return self::_starts_with($prefix, $s, $min_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Retourner $s sans le préfixe $prefix s'il existe */
|
||||||
|
static final function without_prefix(?string $prefix, ?string $s): ?string {
|
||||||
|
if ($s === null || $prefix === null) return $s;
|
||||||
|
if (self::_starts_with($prefix, $s)) $s = substr($s, strlen($prefix));
|
||||||
|
return $s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* modifier $s en place pour supprimer le préfixe $prefix s'il existe
|
||||||
|
*
|
||||||
|
* retourner true si le préfixe a été enlevé.
|
||||||
|
*/
|
||||||
|
static final function del_prefix(?string &$s, ?string $prefix): bool {
|
||||||
|
if ($s === null || !self::_starts_with($prefix, $s)) return false;
|
||||||
|
$s = self::without_prefix($prefix, $s);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourner $s avec le préfixe $prefix
|
||||||
|
*
|
||||||
|
* Si $unless_exists, ne pas ajouter le préfixe s'il existe déjà
|
||||||
|
*/
|
||||||
|
static final function with_prefix(?string $prefix, ?string $s, ?string $sep=null, bool $unless_exists=false): ?string {
|
||||||
|
if ($s === null || $prefix === null) return $s;
|
||||||
|
if (!self::_starts_with($prefix, $s) || !$unless_exists) $s = $prefix.$sep.$s;
|
||||||
|
return $s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* modifier $s en place pour ajouter le préfixe $prefix
|
||||||
|
*
|
||||||
|
* retourner true si le préfixe a été ajouté.
|
||||||
|
*/
|
||||||
|
static final function add_prefix(?string &$s, ?string $prefix, bool $unless_exists=true): bool {
|
||||||
|
if (($s === null || self::_starts_with($prefix, $s)) && $unless_exists) return false;
|
||||||
|
$s = self::with_prefix($prefix, $s, null, $unless_exists);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static final function _ends_with(string $suffix, string $s, ?int $min_len=null): bool {
|
||||||
|
if ($suffix === $s) return true;
|
||||||
|
$len = strlen($suffix);
|
||||||
|
if ($min_len !== null && ($len < $min_len || $len > strlen($s))) return false;
|
||||||
|
return $len == 0 || $suffix === substr($s, -$len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tester si $string se termine par $suffix
|
||||||
|
* par exemple:
|
||||||
|
* - ends_with("", "whatever") est true
|
||||||
|
* - ends_with("st", "first") est true
|
||||||
|
* - ends_with("no", "yes") est false
|
||||||
|
*
|
||||||
|
* si $min_len n'est pas null, c'est la longueur minimum requise de $prefix
|
||||||
|
* pour qu'on teste la correspondance. dans le cas contraire, la valeur de
|
||||||
|
* retour est toujours false, sauf s'il y a égalité. e.g
|
||||||
|
* - ends_with("c", "abc", 2) est false
|
||||||
|
* - ends_with("c", "c", 2) est true
|
||||||
|
*/
|
||||||
|
static final function ends_with(?string $suffix, ?string $s, ?int $min_len=null): bool {
|
||||||
|
if ($s === null || $suffix === null) return false;
|
||||||
|
else return self::_ends_with($suffix, $s, $min_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Retourner $s sans le suffixe $suffix s'il existe */
|
||||||
|
static final function without_suffix(?string $suffix, ?string $s): ?string {
|
||||||
|
if ($s === null || $suffix === null) return $s;
|
||||||
|
if (self::_ends_with($suffix, $s)) $s = substr($s, 0, -strlen($suffix));
|
||||||
|
return $s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* modifier $s en place pour supprimer le suffixe $suffix s'il existe
|
||||||
|
*
|
||||||
|
* retourner true si le suffixe a été enlevé.
|
||||||
|
*/
|
||||||
|
static final function del_suffix(?string &$s, ?string $suffix): bool {
|
||||||
|
if ($s === null || !self::_ends_with($suffix, $s)) return false;
|
||||||
|
$s = self::without_suffix($suffix, $s);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourner $s avec le suffixe $suffix
|
||||||
|
*
|
||||||
|
* Si $unless_exists, ne pas ajouter le suffixe s'il existe déjà
|
||||||
|
*/
|
||||||
|
static final function with_suffix(?string $suffix, ?string $s, ?string $sep=null, bool $unless_exists=false): ?string {
|
||||||
|
if ($s === null || $suffix === null) return $s;
|
||||||
|
if (!self::_ends_with($suffix, $s) || !$unless_exists) $s = $s.$sep.$suffix;
|
||||||
|
return $s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* modifier $s en place pour ajouter le suffixe $suffix
|
||||||
|
*
|
||||||
|
* retourner true si le suffixe a été ajouté.
|
||||||
|
*/
|
||||||
|
static final function add_suffix(?string &$s, ?string $suffix, bool $unless_exists=true): bool {
|
||||||
|
if (($s === null || self::_ends_with($suffix, $s)) && $unless_exists) return false;
|
||||||
|
$s = self::with_suffix($suffix, $s, null, $unless_exists);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** splitter $s en deux chaines séparées par $sep */
|
||||||
|
static final function split_pair(?string $s, string $sep=":"): array {
|
||||||
|
if ($s === null) return [null, null];
|
||||||
|
$parts = explode($sep, $s, 2);
|
||||||
|
if ($parts === false) return [null, null];
|
||||||
|
if (count($parts) < 2) $parts[] = null;
|
||||||
|
return $parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** retourner $line sans son caractère de fin de ligne */
|
||||||
|
static final function strip_nl(?string $line): ?string {
|
||||||
|
if ($line === null) return null;
|
||||||
|
if (substr($line, -2) == "\r\n") {
|
||||||
|
$line = substr($line, 0, -2);
|
||||||
|
} elseif (substr($line, -1) == "\n") {
|
||||||
|
$line = substr($line, 0, -1);
|
||||||
|
} elseif (substr($line, -1) == "\r") {
|
||||||
|
$line = substr($line, 0, -1);
|
||||||
|
}
|
||||||
|
return $line;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* normaliser le caractère de fin de ligne: tous les occurrences de [CR]LF et CR sont remplacées par LF
|
||||||
|
*/
|
||||||
|
static final function norm_nl(?string $s): ?string {
|
||||||
|
if ($s === null) return null;
|
||||||
|
$s = str_replace("\r\n", "\n", $s);
|
||||||
|
$s = str_replace("\r", "\n", $s);
|
||||||
|
return $s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* joindre les éléments de $parts comme avec implode(), mais en ignorant les
|
||||||
|
* valeurs fausses (cela n'inclue pas la chaine "0")
|
||||||
|
*
|
||||||
|
* pour chaque valeur du tableau avec une clé associative, c'est la clé qui
|
||||||
|
* est utilisée mais uniquement si la valeur est vraie
|
||||||
|
*/
|
||||||
|
static final function join(string $glue, ?iterable $values): ?string {
|
||||||
|
if ($values === null) return null;
|
||||||
|
$pieces = [];
|
||||||
|
$index = 0;
|
||||||
|
foreach ($values as $key => $value) {
|
||||||
|
if (is_array($value)) $value = self::join($glue, $value);
|
||||||
|
if ($key === $index) {
|
||||||
|
$index++;
|
||||||
|
if (cv::t($value)) $pieces[] = $value;
|
||||||
|
} elseif (cv::t($value)) {
|
||||||
|
$pieces[] = $key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return implode($glue, $pieces);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* comme {@link join()} mais en ignorant les valeurs fausses selon les règles
|
||||||
|
* de PHP
|
||||||
|
*/
|
||||||
|
static final function pjoin(string $glue, ?iterable $values): ?string {
|
||||||
|
if ($values === null) return null;
|
||||||
|
$pieces = [];
|
||||||
|
$index = 0;
|
||||||
|
foreach ($values as $key => $value) {
|
||||||
|
if (is_array($value)) $value = self::join($glue, $value);
|
||||||
|
if ($key === $index) {
|
||||||
|
$index++;
|
||||||
|
if ($value) $pieces[] = $value;
|
||||||
|
} elseif ($value) {
|
||||||
|
$pieces[] = $key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return implode($glue, $pieces);
|
||||||
|
}
|
||||||
|
|
||||||
|
const CAMEL_PATTERN0 = '/([A-Z0-9]+)$/A';
|
||||||
|
const CAMEL_PATTERN1 = '/([A-Z0-9]+)[A-Z]/A';
|
||||||
|
const CAMEL_PATTERN2 = '/([^A-Z]+)/A';
|
||||||
|
const CAMEL_PATTERN3 = '/([A-Z][^A-Z]*)/A';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convertir une chaine de la forme "camelCase" en "under_score". le premier
|
||||||
|
* ensemble de caractères en majuscule est considéré comme étant en minuscule
|
||||||
|
*
|
||||||
|
* par exemple:
|
||||||
|
* - 'myCamelCase' devient 'my_camel_case'
|
||||||
|
* - 'AValue' devient 'a_value'
|
||||||
|
* - 'UPPERValue' devient 'upper_value'
|
||||||
|
* - 'UPPER' devient 'upper'
|
||||||
|
* - 'aXYZ' devient 'a_x_y_z'
|
||||||
|
*
|
||||||
|
* $delimiter est le séparateur en sortie ('_' par défaut)
|
||||||
|
* $upper indique s'il faut transformer le résultat en majuscule
|
||||||
|
*/
|
||||||
|
static final function camel2us(?string $camel, bool $upper=false, string $delimiter="_"): ?string {
|
||||||
|
if ($camel === null || $camel === "") return $camel;
|
||||||
|
$parts = [];
|
||||||
|
if (preg_match(self::CAMEL_PATTERN0, $camel, $vs, PREG_OFFSET_CAPTURE)) {
|
||||||
|
# que des majuscules
|
||||||
|
} elseif (preg_match(self::CAMEL_PATTERN1, $camel, $vs, PREG_OFFSET_CAPTURE)) {
|
||||||
|
# préfixe en majuscule
|
||||||
|
} elseif (preg_match(self::CAMEL_PATTERN2, $camel, $vs, PREG_OFFSET_CAPTURE)) {
|
||||||
|
# préfixe en minuscule
|
||||||
|
} else {
|
||||||
|
throw ValueException::invalid_kind($camel, "camel string");
|
||||||
|
}
|
||||||
|
$parts[] = strtolower($vs[1][0]);
|
||||||
|
$index = intval($vs[1][1]) + strlen($vs[1][0]);
|
||||||
|
while (preg_match(self::CAMEL_PATTERN3, $camel, $vs, PREG_OFFSET_CAPTURE, $index)) {
|
||||||
|
$parts[] = strtolower($vs[1][0]);
|
||||||
|
$index = intval($vs[1][1]) + strlen($vs[1][0]);
|
||||||
|
}
|
||||||
|
$us = implode($delimiter, $parts);
|
||||||
|
if ($upper) $us = strtoupper($us);
|
||||||
|
return $us;
|
||||||
|
}
|
||||||
|
|
||||||
|
const US_PATTERN = '/([ _\-\t\r\n\f\v])/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convertir une chaine de la forme "under_score" en "camelCase"
|
||||||
|
*
|
||||||
|
* par exemple, 'my_camel_case' devient 'myCamelCalse'
|
||||||
|
* et 'UPPER_VALUE' devient 'upperValue'
|
||||||
|
*
|
||||||
|
* si la chaine de départ ne contient pas de delimiter, e.g 'myValue', elle
|
||||||
|
* est retournée inchangée
|
||||||
|
*/
|
||||||
|
static final function us2camel(?string $us, ?string $delimiters=null): ?string {
|
||||||
|
if ($us === null || $us === "") return $us;
|
||||||
|
if ($delimiters === null) $pattern = self::US_PATTERN;
|
||||||
|
else $pattern = '/(['.preg_quote($delimiters).'])/';
|
||||||
|
$parts = preg_split($pattern, $us);
|
||||||
|
$count = count($parts);
|
||||||
|
if ($count == 1) return $us;
|
||||||
|
for ($i = 0; $i < $count; $i++) {
|
||||||
|
$part = strtolower($parts[$i]);
|
||||||
|
if ($i > 0) $part = ucfirst($part);
|
||||||
|
$parts[$i] = $part;
|
||||||
|
}
|
||||||
|
return implode("", $parts);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
namespace nur\sery\values;
|
namespace nur\sery\values;
|
||||||
|
|
||||||
use ArrayAccess;
|
use ArrayAccess;
|
||||||
use nulib\cl;
|
use nur\sery\cl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class akey: accéder aux valeurs d'un tableau
|
* Class akey: accéder aux valeurs d'un tableau
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\values;
|
namespace nur\sery\values;
|
||||||
|
|
||||||
use nulib\cl;
|
use nur\sery\cl;
|
||||||
use nulib\str;
|
use nur\sery\str;
|
||||||
use nur\sery\php\func;
|
use nur\sery\php\func;
|
||||||
use ReflectionClass;
|
use ReflectionClass;
|
||||||
use ReflectionException;
|
use ReflectionException;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\values;
|
namespace nur\sery\values;
|
||||||
|
|
||||||
use nulib\cl;
|
use nur\sery\cl;
|
||||||
use ReflectionClass;
|
use ReflectionClass;
|
||||||
use ReflectionException;
|
use ReflectionException;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
namespace nur\sery\values;
|
namespace nur\sery\values;
|
||||||
|
|
||||||
use ArrayAccess;
|
use ArrayAccess;
|
||||||
use nulib\str;
|
use nur\sery\str;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class valm: frontend pour accéder à une propriété d'un objet (par une méthode
|
* Class valm: frontend pour accéder à une propriété d'un objet (par une méthode
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
namespace nur\sery\values;
|
namespace nur\sery\values;
|
||||||
|
|
||||||
use ArrayAccess;
|
use ArrayAccess;
|
||||||
use nulib\str;
|
use nur\sery\str;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class valx: frontend pour accéder à une propriété d'un objet ou à la clé
|
* Class valx: frontend pour accéder à une propriété d'un objet ou à la clé
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\web\ext;
|
namespace nur\sery\web\ext;
|
||||||
|
|
||||||
use nulib\UserException;
|
use nur\sery\UserException;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
|
||||||
class CurlException extends UserException {
|
class CurlException extends UserException {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\web;
|
namespace nur\sery\web;
|
||||||
|
|
||||||
use nulib\cv;
|
use nur\sery\cv;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class http: des outils pour parler le protocole HTTP dans le cadre de la
|
* Class http: des outils pour parler le protocole HTTP dans le cadre de la
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\web\params;
|
namespace nur\sery\web\params;
|
||||||
|
|
||||||
use nulib\str;
|
use nur\sery\str;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class F: gestion unifiée des paramètres POST + GET
|
* Class F: gestion unifiée des paramètres POST + GET
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\web\params;
|
namespace nur\sery\web\params;
|
||||||
|
|
||||||
use nulib\cl;
|
use nur\sery\cl;
|
||||||
use nulib\str;
|
use nur\sery\str;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class G: gestion des paramètres $_GET
|
* Class G: gestion des paramètres $_GET
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\web\params;
|
namespace nur\sery\web\params;
|
||||||
|
|
||||||
use nulib\cl;
|
use nur\sery\cl;
|
||||||
use nulib\str;
|
use nur\sery\str;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class P: gestion des paramètres $_POST
|
* Class P: gestion des paramètres $_POST
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\web\params;
|
namespace nur\sery\web\params;
|
||||||
|
|
||||||
use nulib\cl;
|
use nur\sery\cl;
|
||||||
use nulib\str;
|
use nur\sery\str;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class R: gestion des paramètres $_REQUEST (GET + POST + COOKIES)
|
* Class R: gestion des paramètres $_REQUEST (GET + POST + COOKIES)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
namespace nur\sery\wip\cli;
|
namespace nur\sery\wip\cli;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use nulib\ExitException;
|
use nur\sery\ExitException;
|
||||||
use nur\sery\output\msg;
|
use nur\sery\output\msg;
|
||||||
use nur\sery\output\std\StdMessenger;
|
use nur\sery\output\std\StdMessenger;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\wip\cli;
|
namespace nur\sery\wip\cli;
|
||||||
|
|
||||||
use nulib\UserException;
|
use nur\sery\UserException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class ArgsException: exception lancée quand il y a une erreur dans l'analyse
|
* Class ArgsException: exception lancée quand il y a une erreur dans l'analyse
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\wip\cli;
|
namespace nur\sery\wip\cli;
|
||||||
|
|
||||||
use nulib\str;
|
use nur\sery\str;
|
||||||
use nur\A;
|
use nur\A;
|
||||||
use nur\sery\php\func;
|
use nur\sery\php\func;
|
||||||
use nur\sery\ref\cli\ref_args;
|
use nur\sery\ref\cli\ref_args;
|
||||||
|
|
Loading…
Reference in New Issue