<pman>Intégration de la branche dev74

This commit is contained in:
Jephté Clain 2025-07-07 21:33:14 +04:00
commit 5732c8f4bd
16 changed files with 137 additions and 49 deletions

View File

@ -218,10 +218,10 @@ class A {
static final function filter_f($dest): void { self::filter_if($dest, [cv::class, "f"]);}
static final function filter_pt($dest): void { self::filter_if($dest, [cv::class, "pt"]);}
static final function filter_pf($dest): void { self::filter_if($dest, [cv::class, "pf"]);}
static final function filter_equals($dest, $value): void { self::filter_if($dest, cv::equals($value)); }
static final function filter_not_equals($dest, $value): void { self::filter_if($dest, cv::not_equals($value)); }
static final function filter_same($dest, $value): void { self::filter_if($dest, cv::same($value)); }
static final function filter_not_same($dest, $value): void { self::filter_if($dest, cv::not_same($value)); }
static final function filter_equals($dest, $value): void { self::filter_if($dest, cv::Fequals($value)); }
static final function filter_not_equals($dest, $value): void { self::filter_if($dest, cv::Fnot_equals($value)); }
static final function filter_same($dest, $value): void { self::filter_if($dest, cv::Fsame($value)); }
static final function filter_not_same($dest, $value): void { self::filter_if($dest, cv::Fnot_same($value)); }
#############################################################################

View File

@ -817,10 +817,10 @@ class cl {
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)); }
static final function all_equals(?array $array, $value): bool { return self::all_if($array, cv::Fequals($value)); }
static final function all_not_equals(?array $array, $value): bool { return self::all_if($array, cv::Fnot_equals($value)); }
static final function all_same(?array $array, $value): bool { return self::all_if($array, cv::Fsame($value)); }
static final function all_not_same(?array $array, $value): bool { return self::all_if($array, cv::Fnot_same($value)); }
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -842,10 +842,10 @@ class cl {
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 any_equals(?array $array, $value): bool { return self::any_if($array, cv::Fequals($value)); }
static final function any_not_equals(?array $array, $value): bool { return self::any_if($array, cv::Fnot_equals($value)); }
static final function any_same(?array $array, $value): bool { return self::any_if($array, cv::Fsame($value)); }
static final function any_not_same(?array $array, $value): bool { return self::any_if($array, cv::Fnot_same($value)); }
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -876,10 +876,10 @@ class cl {
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 filter_equals(?array $array, $value): ?array { return self::filter_if($array, cv::Fequals($value)); }
static final function filter_not_equals(?array $array, $value): ?array { return self::filter_if($array, cv::Fnot_equals($value)); }
static final function filter_same(?array $array, $value): ?array { return self::filter_if($array, cv::Fsame($value)); }
static final function filter_not_same(?array $array, $value): ?array { return self::filter_if($array, cv::Fnot_same($value)); }
#############################################################################

View File

@ -49,7 +49,7 @@ class cv {
* contruire une fonction qui retourne vrai si on lui passe en argument une
* valeur égale à $value
*/
static final function equals($value): callable {
static final function Fequals($value): callable {
return function ($arg) use($value) { return $arg == $value; };
}
@ -57,7 +57,7 @@ class cv {
* 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 {
static final function Fnot_equals($value): callable {
return function ($arg) use($value) { return $arg != $value; };
}
@ -65,7 +65,7 @@ class cv {
* contruire une fonction qui retourne vrai si on lui passe en argument une
* valeur strictement égale à $value
*/
static final function same($value): callable {
static final function Fsame($value): callable {
return function ($arg) use($value) { return $arg === $value; };
}
@ -73,7 +73,7 @@ class cv {
* 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 {
static final function Fnot_same($value): callable {
return function ($arg) use($value) { return $arg !== $value; };
}
@ -231,6 +231,24 @@ class cv {
#############################################################################
/**
* tester l'égalité non stricte de deux valeurs, dans le cas leurs types ne
* sont pas forcément cohérents: par exemple eq("1", 1) === true
*
* cette fonction est utile par exemple quand on veut comparer des données
* provenant d'une base de données: PHP a la facheuse tendance de retourner
* les nombres sous forme de chaines
*/
static final function equals($a, $b): bool {
# cette fonction existe parce que le type des valeurs retournées par la BDD
# n'est pas cohérent, "1" au lieu de 1 par exemple
if ($a === null) return $b === null;
elseif ($b === null) return $a === null;
elseif (is_scalar($a)) return strval($a) === strval($b);
# ne pas utiliser l'égalité stricte ici: ce sont des objets
else return $a == $b;
}
/** 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;

View File

@ -182,11 +182,27 @@ class Capacitor implements ITransactor {
return $this->storage->_delete($this->channel, $filter, $func, $args);
}
function dbUpdate(array $update) {
function dbAll(array $query, ?array $params=null): iterable {
$primaryKeys = $this->channel->getPrimaryKeys();
return $this->storage->db()->all(cl::merge([
"select",
"from" => $this->getTableName(),
], $query), $params, $primaryKeys);
}
function dbOne(array $query, ?array $params=null): ?array {
return $this->storage->db()->one(cl::merge([
"select",
"from" => $this->getTableName(),
], $query), $params);
}
/** @return int|false */
function dbUpdate(array $query, ?array $params=null) {
return $this->storage->db()->exec(cl::merge([
"update",
"table" => $this->getTableName(),
], $update));
], $query), $params);
}
function close(): void {

View File

@ -414,6 +414,11 @@ class CapacitorChannel implements ITransactor {
return $this;
}
function initStorage(CapacitorStorage $storage): self {
new Capacitor($storage, $this);
return $this;
}
function willUpdate(...$transactors): ITransactor {
return $this->capacitor->willUpdate(...$transactors);
}
@ -508,8 +513,17 @@ class CapacitorChannel implements ITransactor {
return $this->capacitor->delete($filter, $func, $args);
}
function dbUpdate(array $update) {
return $this->capacitor->dbUpdate($update);
function dbAll(array $query, ?array $params=null): iterable {
return $this->capacitor->dbAll($query, $params);
}
function dbOne(array $query, ?array $params=null): ?array {
return $this->capacitor->dbOne($query, $params);
}
/** @return int|false */
function dbUpdate(array $query, ?array $params=null) {
return $this->capacitor->dbUpdate($query, $params);
}
function close(): void {

View File

@ -3,6 +3,7 @@ namespace nulib\db;
use nulib\A;
use nulib\cl;
use nulib\cv;
use nulib\db\_private\_migration;
use nulib\php\func;
use nulib\ValueException;
@ -479,8 +480,9 @@ abstract class CapacitorStorage {
# ne jamais mettre à jour la clé primaire
continue;
}
$pvalue = $praw[$col] ?? null;
if ($value !== $pvalue) $updates[$col] = $value;
if (!cv::equals($value, $praw[$col] ?? null)) {
$updates[$col] = $value;
}
}
if (count($updates) == 1 && array_key_first($updates) == "modified_") {
# si l'unique modification porte sur la date de modification, alors

12
php/src/ext/utils.php Normal file
View File

@ -0,0 +1,12 @@
<?php
namespace nulib\ext;
class utils {
/** générateur d'UUIDv4 "du pauvre" */
static final function uuidgen(): string {
$data = random_bytes(16);
$data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0100
$data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10
return vsprintf("%s%s-%s-%s-%s-%s%s%s", str_split(bin2hex($data), 4));
}
}

View File

@ -7,10 +7,10 @@ use nulib\php\func;
* Class Printer: wrapper autour d'une instance de {@link IContent} qui affiche
* le contenu au lieu de le retourner
*
* cette classe est conçue pour wrapper des objets complexes dont le contenu est
* contruit au fur et à mesure: ainsi, les objets peuvent être utilisés tels
* quels dans un contenu, ou alors être wrappés si on veut simplement les
* afficher
* cette classe est conçue pour wrapper des objets complexes dont le contenu
* peut être multiple et est contruit au fur et à mesure: ainsi, les objets
* peuvent être utilisés tels quels dans un contenu, ou alors être wrappés si
* on veut simplement les afficher
*/
class Printer implements IPrintable {
function __construct(IContent $content) {
@ -24,6 +24,9 @@ class Printer implements IPrintable {
c::write($content);
}
/**
* afficher le contenu retourné par une méthode spécifique de $content
*/
function __call($name, $args) {
$content = func::call([$this->content, $name], ...$args);
c::write($content);

View File

@ -139,6 +139,12 @@ class DateTime extends \DateTime {
return false;
}
/** retourner le nombre de secondes depuis minuit */
static function _nbsecs_format(\DateTime $datetime): string {
[$h, $m, $s] = explode(",", $datetime->format("H,i,s"));
return $h * 3600 + $m * 60 + $s;
}
static function _YmdHMSZ_format(\DateTime $datetime): string {
$YmdHMS = $datetime->format("Ymd\\THis");
$Z = $datetime->format("P");
@ -156,6 +162,7 @@ class DateTime extends \DateTime {
"second" => "s",
"wday" => "N",
"wnum" => "W",
"nbsecs" => [self::class, "_nbsecs_format"],
];
const STRING_FORMATS = [
"timezone" => "P",
@ -166,14 +173,6 @@ class DateTime extends \DateTime {
"YmdHMSZ" => [self::class, "_YmdHMSZ_format"],
];
static function clone(DateTimeInterface $dateTime): self {
if ($dateTime instanceof static) return clone $dateTime;
$clone = new static();
$clone->setTimestamp($dateTime->getTimestamp());
$clone->setTimezone($dateTime->getTimezone());
return $clone;
}
/**
* corriger une année à deux chiffres qui est située dans le passé et
* retourner l'année à 4 chiffres.
@ -282,7 +281,7 @@ class DateTime extends \DateTime {
if ($Y !== null) {
if ($H === null) $datetime = sprintf("%04d-%02d-%02d", $Y, $m, $d);
else $datetime = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $Y, $m, $d, $H, $M, $S);
if ($Z !== null) $timezone = new DateTimeZone(self::fix_z($Z));
if ($Z !== null) $timezone ??= new DateTimeZone(self::fix_z($Z));
}
parent::__construct($datetime, $timezone);
@ -295,7 +294,7 @@ class DateTime extends \DateTime {
} else {
$datetime = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $Y, $m, $d, $H ?? 0, $M ?? 0, $S ?? 0);
}
if ($Z !== null) $timezone = new DateTimeZone(self::fix_z($Z));
if ($Z !== null) $timezone ??= new DateTimeZone(self::fix_z($Z));
parent::__construct($datetime, $timezone);
} else {
@ -308,6 +307,10 @@ class DateTime extends \DateTime {
}
}
function clone(): self {
return clone $this;
}
function diff($target, $absolute=false): DateInterval {
return new DateInterval(parent::diff($target, $absolute));
}
@ -374,7 +377,7 @@ class DateTime extends \DateTime {
function __get($name) {
if (array_key_exists($name, self::INT_FORMATS)) {
$format = self::INT_FORMATS[$name];
if (is_callable($format)) return $format($this);
if (is_callable($format)) return intval($format($this));
else return intval($this->format($format));
} elseif (array_key_exists($name, self::STRING_FORMATS)) {
$format = self::STRING_FORMATS[$name];

View File

@ -40,8 +40,8 @@ class Delay {
"s" => [1, 0],
];
static function compute_dest(int $x, string $u, ?int $y, DateTime $from): array {
$dest = DateTime::clone($from);
static function compute_dest(int $x, string $u, ?int $y, ?DateTimeInterface $from): array {
$dest = DateTime::with($from)->clone();
$yu = null;
switch ($u) {
case "w":
@ -92,7 +92,7 @@ class Delay {
function __construct($delay, ?DateTimeInterface $from=null) {
if ($from === null) $from = new DateTime();
if ($delay === "INF") {
$dest = DateTime::clone($from);
$dest = DateTime::with($from)->clone();
$dest->add(new DateInterval("P9999Y"));
$repr = "INF";
} elseif (is_int($delay)) {

10
php/src/php/time/TODO.md Normal file
View File

@ -0,0 +1,10 @@
# nulib\php\time
* Date, DateTime sont immutables par défaut. par exemple, add() retourne un nouvel objet.
ajouter une version des méthodes qui modifie les données en place en les
préfixant de `_` e.g `_add()`
en terme d'implémentation, dériver \DateTime pour supporter les modification
en place, bien que ce ne soit pas le fonctionnement par défaut
-*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary

View File

@ -17,6 +17,11 @@ class str {
return $s;
}
/** s'assure que $s est une chaine s'il n'est pas null */
static final function ensure(&$s): void {
if ($s !== null) $s = self::with($s);
}
/**
* Retourner $s converti en chaine non nulle, ou "" si $s est fausse selon les
* règles de PHP

2
php/tests/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.db*
*.cache

View File

@ -1 +0,0 @@
/capacitor.db*

View File

@ -29,7 +29,7 @@ class DateTest extends TestCase {
function testClone() {
$date = self::dt("now");
$clone = Date::clone($date);
$clone = $date->clone();
self::assertInstanceOf(DateTime::class, $clone);
}

View File

@ -32,13 +32,17 @@ class DateTimeTest extends TestCase {
function testDateTimeZ() {
$date = new DateTime("20240405T091523Z");
self::assertSame("20240405T131523", $date->YmdHMS);
self::assertSame("20240405T131523+04:00", $date->YmdHMSZ);
# comme on spécifie la timezone, la valeur Z est ignorée
$date = new DateTime("20240405T091523Z", new DateTimeZone("Indian/Reunion"));
self::assertSame("20240405T091523", $date->YmdHMS);
self::assertSame("20240405T091523Z", $date->YmdHMSZ);
self::assertSame("20240405T091523+04:00", $date->YmdHMSZ);
}
function testClone() {
$date = self::dt("now");
$clone = DateTime::clone($date);
$clone = $date->clone();
self::assertInstanceOf(DateTime::class, $clone);
}
@ -51,7 +55,7 @@ class DateTimeTest extends TestCase {
self::assertSame("05/04/2024 00:00:00", strval(new DateTime("20240405")));
self::assertSame("05/04/2024 00:00:00", strval(new DateTime("240405")));
self::assertSame("05/04/2024 09:15:23", strval(new DateTime("20240405T091523")));
self::assertSame("05/04/2024 09:15:23", strval(new DateTime("20240405T091523Z")));
self::assertSame("05/04/2024 13:15:23", strval(new DateTime("20240405T091523Z")));
self::assertSame("05/04/2024 09:15:23", strval(new DateTime("5/4/2024 9:15:23")));
self::assertSame("05/04/2024 09:15:23", strval(new DateTime("5/4/2024 9.15.23")));
self::assertSame("05/04/2024 09:15:00", strval(new DateTime("5/4/2024 9:15")));