Compare commits
28 Commits
Author | SHA1 | Date | |
---|---|---|---|
9f8b6545e6 | |||
cf20b9aeaf | |||
dd4fae6898 | |||
d75350d614 | |||
89f24d8d90 | |||
2af9b0b8f0 | |||
03338f97f0 | |||
33fab8496a | |||
e8ac4ed8be | |||
6fa07746e8 | |||
795e4cd2e3 | |||
10409febe6 | |||
fd120298a9 | |||
7bcdaef650 | |||
0395f9e629 | |||
630e7aefab | |||
f1f033e0e9 | |||
cb86dd93bd | |||
829caf41a4 | |||
927ee2fb98 | |||
18485c7d3f | |||
c66cc867dc | |||
facb2dc410 | |||
6b0ae5a109 | |||
90dc129018 | |||
0c473384f2 | |||
14c4aaf416 | |||
c91d2f2e85 |
14
.pman.conf
14
.pman.conf
@ -1,11 +1,11 @@
|
|||||||
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
|
||||||
UPSTREAM=
|
UPSTREAM=dev74
|
||||||
DEVELOP=dev74
|
DEVELOP=dev82
|
||||||
FEATURE=wip74/
|
FEATURE=wip82/
|
||||||
RELEASE=rel74-
|
RELEASE=rel82-
|
||||||
MAIN=dist74
|
MAIN=dist82
|
||||||
TAG_SUFFIX=p74
|
TAG_SUFFIX=p82
|
||||||
HOTFIX=hotf74-
|
HOTFIX=hotf82-
|
||||||
DIST=
|
DIST=
|
||||||
NOAUTO=
|
NOAUTO=
|
||||||
|
@ -4,5 +4,5 @@
|
|||||||
RUNPHP=
|
RUNPHP=
|
||||||
|
|
||||||
# Si RUNPHP n'est pas défini, les variables suivantes peuvent être définies
|
# Si RUNPHP n'est pas défini, les variables suivantes peuvent être définies
|
||||||
DIST=d11
|
DIST=d12
|
||||||
#REGISTRY=pubdocker.univ-reunion.fr/dist
|
#REGISTRY=pubdocker.univ-reunion.fr/dist
|
||||||
|
15
CHANGES.md
15
CHANGES.md
@ -1,18 +1,3 @@
|
|||||||
## Release 0.5.1p82 du 12/05/2025-15:31
|
|
||||||
|
|
||||||
## Release 0.5.1p74 du 12/05/2025-15:28
|
|
||||||
|
|
||||||
* `d274a65` améliorer status
|
|
||||||
* `2e026da` l'option -ww affiche la différence
|
|
||||||
* `8e7e59c` intégrer les méthodes de Cursor et KeyAccess
|
|
||||||
* `a587f99` installer completion pour pman
|
|
||||||
* `cc56dc9` renommer pdev en pmer
|
|
||||||
* `0a73ba3` améliorer ergonomie de p
|
|
||||||
* `aef0533` ajout str::split
|
|
||||||
* `87e262c` ajout cl::delv
|
|
||||||
* `a371a68` maj doc
|
|
||||||
* `d706122` ajout infos release
|
|
||||||
|
|
||||||
## Release 0.5.0p82 du 30/04/2025-04:33
|
## Release 0.5.0p82 du 30/04/2025-04:33
|
||||||
|
|
||||||
## Release 0.5.0p74 du 30/04/2025-04:31
|
## Release 0.5.0p74 du 30/04/2025-04:31
|
||||||
|
31
README.md
31
README.md
@ -1,31 +0,0 @@
|
|||||||
# nulib
|
|
||||||
|
|
||||||
|
|
||||||
## Release
|
|
||||||
|
|
||||||
Exemple: release de la version 0.6.0
|
|
||||||
~~~sh
|
|
||||||
version=0.6.0
|
|
||||||
|
|
||||||
## branche dev74
|
|
||||||
git checkout dev74
|
|
||||||
|
|
||||||
prel -v$version
|
|
||||||
|
|
||||||
_merge82
|
|
||||||
|
|
||||||
## branche dev82
|
|
||||||
git checkout dev82
|
|
||||||
|
|
||||||
prel -C
|
|
||||||
|
|
||||||
commit="$(git log --grep="Init changelog . version ${version}p82" --format=%H)" &&
|
|
||||||
echo "commit=$commit"
|
|
||||||
|
|
||||||
git checkout dev74
|
|
||||||
|
|
||||||
git cherry-pick "$commit"
|
|
||||||
pp -a
|
|
||||||
~~~
|
|
||||||
|
|
||||||
-*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary
|
|
@ -1 +1 @@
|
|||||||
0.5.1
|
0.5.0
|
||||||
|
@ -84,12 +84,6 @@ function _list_commits() {
|
|||||||
_filter_rel
|
_filter_rel
|
||||||
}
|
}
|
||||||
|
|
||||||
function _show_diff() {
|
|
||||||
local source="${1:-$SrcBranch}" dest="${2:-$DestBranch}" mergebase
|
|
||||||
setx mergebase=git merge-base "$dest" "$source"
|
|
||||||
git diff ${_sd_COLOR:+--color=$_sd_COLOR} "$mergebase..$source"
|
|
||||||
}
|
|
||||||
|
|
||||||
function _scripte() {
|
function _scripte() {
|
||||||
echo >>"$script"
|
echo >>"$script"
|
||||||
echo "$comment$(qvals "$@")" >>"$script"
|
echo "$comment$(qvals "$@")" >>"$script"
|
||||||
@ -426,7 +420,7 @@ EOF
|
|||||||
$(qvals echo "$(awk <"$changelog" '
|
$(qvals echo "$(awk <"$changelog" '
|
||||||
BEGIN { p = 0 }
|
BEGIN { p = 0 }
|
||||||
p == 0 && $0 == "" { p = 1; next }
|
p == 0 && $0 == "" { p = 1; next }
|
||||||
p == 1 { print }
|
p == 1 { gsub(/\$/, "\\$", $0); print }
|
||||||
')") >CHANGES.md
|
')") >CHANGES.md
|
||||||
git add CHANGES.md
|
git add CHANGES.md
|
||||||
EOF
|
EOF
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
|
||||||
exec "$(dirname -- "$0")/pmer" --tech-merge -Bdev82 dev74 -a "git checkout dev74" "$@"
|
exec "$(dirname -- "$0")/pdev" --tech-merge -Bdev82 dev74 -a "git checkout dev74" "$@"
|
||||||
|
10
bin/p
10
bin/p
@ -29,9 +29,6 @@ function git_statuses() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
# sans arguments, il y a un comportement spécial
|
|
||||||
[ $# -eq 0 ] && NoArgs=1 || NoArgs=
|
|
||||||
|
|
||||||
chdir=
|
chdir=
|
||||||
all=
|
all=
|
||||||
composer=
|
composer=
|
||||||
@ -46,13 +43,6 @@ Si l'option -a est utilisée, ce script accepte comme arguments une liste de pat
|
|||||||
)
|
)
|
||||||
parse_args "$@"; set -- "${args[@]}"
|
parse_args "$@"; set -- "${args[@]}"
|
||||||
|
|
||||||
if [ -n "$NoArgs" ]; then
|
|
||||||
# si aucun argument n'est spécifié et si on n'est pas dans un projet git,
|
|
||||||
# afficher le status de tous les sous répertoires
|
|
||||||
setx toplevel=git_get_toplevel
|
|
||||||
[ -z "$toplevel" ] && all=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
setx OrigCwd=pwd
|
setx OrigCwd=pwd
|
||||||
if [ -n "$chdir" ]; then
|
if [ -n "$chdir" ]; then
|
||||||
cd "$chdir" || die
|
cd "$chdir" || die
|
||||||
|
@ -11,19 +11,8 @@ function show_action() {
|
|||||||
local commits
|
local commits
|
||||||
setx commits=_list_commits
|
setx commits=_list_commits
|
||||||
if [ -n "$commits" ]; then
|
if [ -n "$commits" ]; then
|
||||||
if [ $ShowLevel -ge 2 ]; then
|
einfo "Commits à fusionner $SrcBranch --> $DestBranch"
|
||||||
{
|
eecho "$commits"
|
||||||
echo "\
|
|
||||||
# Commits à fusionner $SrcBranch --> $DestBranch
|
|
||||||
|
|
||||||
$commits
|
|
||||||
"
|
|
||||||
_sd_COLOR=always _show_diff
|
|
||||||
} | less -eRF
|
|
||||||
else
|
|
||||||
einfo "Commits à fusionner $SrcBranch --> $DestBranch"
|
|
||||||
eecho "$commits"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,7 +148,6 @@ ConfigFile=
|
|||||||
_Fake=
|
_Fake=
|
||||||
_KeepScript=
|
_KeepScript=
|
||||||
action=merge
|
action=merge
|
||||||
ShowLevel=0
|
|
||||||
TechMerge=
|
TechMerge=
|
||||||
SquashMsg=
|
SquashMsg=
|
||||||
[ -z "$PMAN_NO_PUSH" ] && Push=1 || Push=
|
[ -z "$PMAN_NO_PUSH" ] && Push=1 || Push=
|
||||||
@ -170,7 +158,6 @@ args=(
|
|||||||
" [source]
|
" [source]
|
||||||
|
|
||||||
CONFIGURATION
|
CONFIGURATION
|
||||||
|
|
||||||
Le fichier .pman.conf contient la configuration des branches. Les variables
|
Le fichier .pman.conf contient la configuration des branches. Les variables
|
||||||
supplémentaires suivantes peuvent être définies:
|
supplémentaires suivantes peuvent être définies:
|
||||||
BEFORE_MERGE_<srcType>
|
BEFORE_MERGE_<srcType>
|
||||||
@ -189,7 +176,7 @@ fichier de configuration des branches. cette option est prioritaire sur --config
|
|||||||
par défaut, utiliser le fichier .pman.conf dans le répertoire du dépôt s'il existe"
|
par défaut, utiliser le fichier .pman.conf dans le répertoire du dépôt s'il existe"
|
||||||
--fake _Fake=1 "++option non documentée"
|
--fake _Fake=1 "++option non documentée"
|
||||||
--keep-script _KeepScript=1 "++option non documentée"
|
--keep-script _KeepScript=1 "++option non documentée"
|
||||||
-w,--show '$action=show; inc@ ShowLevel' "\
|
-w,--show action=show "\
|
||||||
lister les modifications qui seraient fusionnées dans la branche destination"
|
lister les modifications qui seraient fusionnées dans la branche destination"
|
||||||
-b,--rebase action=rebase "\
|
-b,--rebase action=rebase "\
|
||||||
lancer git rebase -i sur la branche source. cela permet de réordonner les
|
lancer git rebase -i sur la branche source. cela permet de réordonner les
|
2
bin/pman
2
bin/pman
@ -78,7 +78,7 @@ function init_repo_action() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function init_config_action() {
|
function init_config_action() {
|
||||||
local -a push_branches; local config
|
local -a push_branches; config
|
||||||
|
|
||||||
[ -f .pman.conf -a -z "$ForceCreate" ] && die "La configuration pman a déjà été initialisée"
|
[ -f .pman.conf -a -z "$ForceCreate" ] && die "La configuration pman a déjà été initialisée"
|
||||||
|
|
||||||
|
18
bin/prel
18
bin/prel
@ -11,19 +11,8 @@ function show_action() {
|
|||||||
local commits
|
local commits
|
||||||
setx commits=_list_commits
|
setx commits=_list_commits
|
||||||
if [ -n "$commits" ]; then
|
if [ -n "$commits" ]; then
|
||||||
if [ $ShowLevel -ge 2 ]; then
|
einfo "Commits à fusionner $SrcBranch --> $DestBranch"
|
||||||
{
|
eecho "$commits"
|
||||||
echo "\
|
|
||||||
# Commits à fusionner $SrcBranch --> $DestBranch
|
|
||||||
|
|
||||||
$commits
|
|
||||||
"
|
|
||||||
_sd_COLOR=always _show_diff
|
|
||||||
} | less -eRF
|
|
||||||
else
|
|
||||||
einfo "Commits à fusionner $SrcBranch --> $DestBranch"
|
|
||||||
eecho "$commits"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,7 +194,6 @@ ConfigFile=
|
|||||||
_Fake=
|
_Fake=
|
||||||
_KeepScript=
|
_KeepScript=
|
||||||
action=release
|
action=release
|
||||||
ShowLevel=0
|
|
||||||
[ -z "$PMAN_NO_MERGE" ] && Merge=1 || Merge=
|
[ -z "$PMAN_NO_MERGE" ] && Merge=1 || Merge=
|
||||||
[ -z "$PMAN_NO_PUSH" ] && Push=1 || Push=
|
[ -z "$PMAN_NO_PUSH" ] && Push=1 || Push=
|
||||||
Version=
|
Version=
|
||||||
@ -234,7 +222,7 @@ fichier de configuration des branches. cette option est prioritaire sur --config
|
|||||||
par défaut, utiliser le fichier .pman.conf dans le répertoire du dépôt s'il existe"
|
par défaut, utiliser le fichier .pman.conf dans le répertoire du dépôt s'il existe"
|
||||||
--fake _Fake=1 "++option non documentée"
|
--fake _Fake=1 "++option non documentée"
|
||||||
--keep-script _KeepScript=1 "++option non documentée"
|
--keep-script _KeepScript=1 "++option non documentée"
|
||||||
-w,--show '$action=show; inc@ ShowLevel' "\
|
-w,--show action=show "\
|
||||||
lister les modifications qui seraient intégrées dans la release"
|
lister les modifications qui seraient intégrées dans la release"
|
||||||
--release action=release "++\
|
--release action=release "++\
|
||||||
créer la release.
|
créer la release.
|
||||||
|
@ -29,7 +29,7 @@ for file in "$@"; do
|
|||||||
estep "Création de $file"
|
estep "Création de $file"
|
||||||
|
|
||||||
cat >"$file" <<EOF
|
cat >"$file" <<EOF
|
||||||
-- -*- coding: utf-8 mode: sql -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
-- -*- coding: utf-8 mode: sql -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=$encoding
|
||||||
-- @database xxx
|
-- @database xxx
|
||||||
|
|
||||||
start transaction;
|
start transaction;
|
||||||
|
@ -15,12 +15,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"symfony/yaml": "^5.0",
|
"symfony/yaml": "^7.1",
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"php": "^7.4"
|
"php": "^8.2"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"nulib/tests": "^7.4",
|
"nulib/tests": "^8.2",
|
||||||
"ext-posix": "*",
|
"ext-posix": "*",
|
||||||
"ext-pcntl": "*",
|
"ext-pcntl": "*",
|
||||||
"ext-curl": "*",
|
"ext-curl": "*",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
|
||||||
function __pman_pmer_branches() {
|
function __pman_pdev_branches() {
|
||||||
local toplevel="$(git rev-parse --show-toplevel 2>/dev/null)"
|
local toplevel="$(git rev-parse --show-toplevel 2>/dev/null)"
|
||||||
[ -n "$toplevel" ] || return 0
|
[ -n "$toplevel" ] || return 0
|
||||||
|
|
||||||
@ -29,9 +29,9 @@ function __pman_pmer_branches() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function __pmer_completion() {
|
function __pdev_completion() {
|
||||||
local cur
|
local cur
|
||||||
_get_comp_words_by_ref cur
|
_get_comp_words_by_ref cur
|
||||||
COMPREPLY=($(compgen -W "$(__pman_pmer_branches)" "$cur"))
|
COMPREPLY=($(compgen -W "$(__pman_pdev_branches)" "$cur"))
|
||||||
}
|
}
|
||||||
complete -F __pmer_completion pmer
|
complete -F __pdev_completion pdev
|
||||||
|
@ -1,20 +1,6 @@
|
|||||||
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
|
||||||
source "$@" || exit 1
|
source "$@" || exit 1
|
||||||
cd "$srcdir"
|
|
||||||
|
|
||||||
# supprimer les fichiers de VCS
|
# supprimer les fichiers de VCS
|
||||||
rm -rf .git
|
rm -rf "$srcdir/.git"
|
||||||
|
|
||||||
# completion
|
|
||||||
fromdir=lib/completion.d
|
|
||||||
todir="$HOME/etc/completion.d"
|
|
||||||
mkdir -p "$todir"
|
|
||||||
for file in pman; do
|
|
||||||
from="$fromdir/$file"
|
|
||||||
to="$todir/$file"
|
|
||||||
if [ -f "$to" ]; then
|
|
||||||
diff -q "$from" "$to" && continue
|
|
||||||
fi
|
|
||||||
cp "$from" "$to"
|
|
||||||
done
|
|
||||||
|
120
php/src/A.php
120
php/src/A.php
@ -1,14 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace nulib;
|
namespace nulib;
|
||||||
|
|
||||||
use nulib\php\func;
|
|
||||||
use Traversable;
|
use Traversable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class A: gestion de tableaux ou d'instances de {@link IArrayWrapper}
|
* Class A: gestion de tableaux ou d'instances de {@link IArrayWrapper}
|
||||||
*
|
*
|
||||||
* cette classe reprend les méthodes de {@link cl} avec la différence que la
|
* contrairement à {@link cl}, les méthodes de cette classes sont plutôt conçues
|
||||||
* modification est faite en place
|
* pour modifier le tableau en place
|
||||||
*/
|
*/
|
||||||
class A {
|
class A {
|
||||||
/**
|
/**
|
||||||
@ -177,14 +176,6 @@ class A {
|
|||||||
return $pvalue;
|
return $pvalue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static final function shift(?array &$dest, int $count=1, $default=null) {
|
|
||||||
if ($dest === null) return null;
|
|
||||||
$values = array_slice($dest, 0, $count);
|
|
||||||
$dest = array_slice($dest, $count);
|
|
||||||
if ($values === []) return $default;
|
|
||||||
else return $count == 1? $values[0]: $values;
|
|
||||||
}
|
|
||||||
|
|
||||||
static final function pop(&$dest, $key, $default=null) {
|
static final function pop(&$dest, $key, $default=null) {
|
||||||
if ($dest === null) return $default;
|
if ($dest === null) return $default;
|
||||||
self::ensure_narray($dest);
|
self::ensure_narray($dest);
|
||||||
@ -241,111 +232,4 @@ class A {
|
|||||||
if ($assoc) uasort($array, cl::compare($keys));
|
if ($assoc) uasort($array, cl::compare($keys));
|
||||||
else usort($array, cl::compare($keys));
|
else usort($array, cl::compare($keys));
|
||||||
}
|
}
|
||||||
|
|
||||||
#############################################################################
|
|
||||||
|
|
||||||
/**
|
|
||||||
* s'assurer que $array est un tableau associatif, en remplaçant toutes les
|
|
||||||
* clés numériques par la clé correspondante dans $key
|
|
||||||
* <code>
|
|
||||||
* $array = ["first", "second"]
|
|
||||||
* A::ensure_assoc($array, ["a", "b"]);
|
|
||||||
* // returns ["a" => "first", "b" => "second"]
|
|
||||||
* </code>
|
|
||||||
*/
|
|
||||||
static final function ensure_assoc(?array &$array, array $keys, ?array $params=null): void {
|
|
||||||
$prefix = $params["key_prefix"] ?? null;
|
|
||||||
$suffix = $params["key_suffix"] ?? null;
|
|
||||||
$index = 0;
|
|
||||||
foreach ($keys as $key) {
|
|
||||||
if ($prefix !== null || $suffix !== null) {
|
|
||||||
$destKey = "$prefix$key$suffix";
|
|
||||||
} else {
|
|
||||||
# préserver les clés numériques
|
|
||||||
$destKey = $key;
|
|
||||||
}
|
|
||||||
if ($array !== null && array_key_exists($destKey, $array)) continue;
|
|
||||||
while (in_array($index, $keys, true)) {
|
|
||||||
$index++;
|
|
||||||
}
|
|
||||||
if ($array !== null && array_key_exists($index, $array)) {
|
|
||||||
$array[$destKey] = $array[$index];
|
|
||||||
unset($array[$index]);
|
|
||||||
$index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* s'assurer que $array contient toutes les clés de $defaults, avec la valeur
|
|
||||||
* par défaut le cas échéant
|
|
||||||
*
|
|
||||||
* $missings est un tableau indiquant des valeurs qui si elles sont dans
|
|
||||||
* $array, signifie que la clé correspondante doit être considérée comme
|
|
||||||
* inexistante (et donc remplacée par la valeur de $defaults)
|
|
||||||
*/
|
|
||||||
static final function ensure_keys(?array &$array, array $defaults, ?array $missings=null, ?array $params=null): void {
|
|
||||||
$keys = array_keys($defaults);
|
|
||||||
$prefix = $params["key_prefix"] ?? null;
|
|
||||||
$suffix = $params["key_suffix"] ?? null;
|
|
||||||
foreach ($keys as $key) {
|
|
||||||
$destKey = "$prefix$key$suffix";
|
|
||||||
$haveMissing = $missings !== null && array_key_exists($key, $missings);
|
|
||||||
if ($array === null || !array_key_exists($destKey, $array)) {
|
|
||||||
$array[$destKey] = $defaults[$key];
|
|
||||||
} elseif ($haveMissing && $array[$destKey] === $missings[$key]) {
|
|
||||||
$array[$destKey] = $defaults[$key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* supprimer dans $array les clés dont les valeurs correspondent au tableau
|
|
||||||
* $missings
|
|
||||||
*/
|
|
||||||
static final function delete_missings(?array &$array, array $missings, ?array $params=null): void {
|
|
||||||
$prefix = $params["key_prefix"] ?? null;
|
|
||||||
$suffix = $params["key_suffix"] ?? null;
|
|
||||||
foreach ($missings as $key => $missing) {
|
|
||||||
$destKey = "$prefix$key$suffix";
|
|
||||||
if (array_key_exists($destKey, $array) && $array[$destKey] === $missing) {
|
|
||||||
unset($array[$destKey]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* s'assurer que les clés dans $array sont dans le même ordre que dans $keys
|
|
||||||
*
|
|
||||||
* les clés supplémentaires sont poussées à la fin du tableau
|
|
||||||
*/
|
|
||||||
static final function ensure_order(?array &$array, array $keys, ?array $params=null): void {
|
|
||||||
if ($array === null) return;
|
|
||||||
|
|
||||||
$prefix = $params["key_prefix"] ?? null;
|
|
||||||
$suffix = $params["key_suffix"] ?? null;
|
|
||||||
if ($prefix !== null || $suffix !== null) {
|
|
||||||
foreach ($keys as &$key) {
|
|
||||||
$key = "$prefix$key$suffix";
|
|
||||||
}; unset($key);
|
|
||||||
}
|
|
||||||
|
|
||||||
$destKeys = array_keys($array);
|
|
||||||
$keyCount = count($keys);
|
|
||||||
if (array_slice($destKeys, 0, $keyCount) === $keys) {
|
|
||||||
# si le tableau a déjà les bonnes clés dans le bon ordre, rien à faire
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$ordered = [];
|
|
||||||
foreach ($keys as $key) {
|
|
||||||
if (array_key_exists($key, $array)) {
|
|
||||||
$ordered[$key] = $array[$key];
|
|
||||||
unset($array[$key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$preserveKeys = $params["preserve_keys"] ?? false;
|
|
||||||
if ($preserveKeys) $array = cl::merge2($ordered, $array);
|
|
||||||
else $array = array_merge($ordered, $array);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -460,7 +460,7 @@ class RunFile {
|
|||||||
$exitcode = null;
|
$exitcode = null;
|
||||||
$message = [
|
$message = [
|
||||||
"status" => "$desc: EN COURS pid $data[pid]",
|
"status" => "$desc: EN COURS pid $data[pid]",
|
||||||
"started" => "Démarrée $sinceStart le $dateStart",
|
"started" => "Démarrée depuis $dateStart ($sinceStart)",
|
||||||
"action" => $action,
|
"action" => $action,
|
||||||
];
|
];
|
||||||
} elseif ($this->isStopped($data)) {
|
} elseif ($this->isStopped($data)) {
|
||||||
@ -471,9 +471,8 @@ class RunFile {
|
|||||||
elseif ($exitcode === 0) $type = "success";
|
elseif ($exitcode === 0) $type = "success";
|
||||||
else $type = "danger";
|
else $type = "danger";
|
||||||
$message = [
|
$message = [
|
||||||
"status" => "$desc: TERMINEE",
|
"status" => "$desc: TERMINEE$duration",
|
||||||
"stopped" => "Arrêtée $sinceStop le $dateStop",
|
"stopped" => "Arrêtée $sinceStop le $dateStop",
|
||||||
"duration" => $duration,
|
|
||||||
"result" => $result,
|
"result" => $result,
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
|
137
php/src/cl.php
137
php/src/cl.php
@ -60,35 +60,6 @@ class cl {
|
|||||||
return $default;
|
return $default;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* retourner la valeur à l'index $index, ou $default si le tableau est null
|
|
||||||
* ou vide, ou si l'index n'existe pas
|
|
||||||
*
|
|
||||||
* ici, l'index est le rang de la clé: 0 pour la première clé du tableau, 1
|
|
||||||
* pour la deuxième, etc.
|
|
||||||
*
|
|
||||||
* si $index est négatif, il est compté à partir de la fin du tableau
|
|
||||||
*/
|
|
||||||
static final function nth(?iterable $iterable, int $index, $default=null) {
|
|
||||||
if ($iterable === null) return $default;
|
|
||||||
if ($index < 0 && !is_array($iterable)) {
|
|
||||||
$iterable = iterator_to_array($iterable, false);
|
|
||||||
}
|
|
||||||
if (is_array($iterable)) {
|
|
||||||
$keys = array_keys($iterable);
|
|
||||||
$count = count($keys);
|
|
||||||
while ($index < 0) $index += $count;
|
|
||||||
$key = $keys[$index] ?? null;
|
|
||||||
if ($key === null) return $default;
|
|
||||||
return $iterable[$key];
|
|
||||||
}
|
|
||||||
foreach ($iterable as $value) {
|
|
||||||
if ($index === 0) return $value;
|
|
||||||
$index--;
|
|
||||||
}
|
|
||||||
return $default;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* retourner la dernière valeur de $array ou $default si le tableau est null
|
* retourner la dernière valeur de $array ou $default si le tableau est null
|
||||||
* ou vide
|
* ou vide
|
||||||
@ -241,7 +212,7 @@ class cl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* obtenir la liste des clés qui seraient finalement obtenues après l'appel à
|
* obtenir la liste des clés finalement obtenues après l'appel à
|
||||||
* {@link self::select()} avec le mapping spécifié
|
* {@link self::select()} avec le mapping spécifié
|
||||||
*/
|
*/
|
||||||
static final function selected_keys(?array $mappings): array {
|
static final function selected_keys(?array $mappings): array {
|
||||||
@ -284,7 +255,7 @@ class cl {
|
|||||||
* $includes qui ne sont pas mentionnées dans $excludes.
|
* $includes qui ne sont pas mentionnées dans $excludes.
|
||||||
*
|
*
|
||||||
* - si $includes===null && $excludes===null, retourner le tableau inchangé
|
* - si $includes===null && $excludes===null, retourner le tableau inchangé
|
||||||
* - si $includes vaut null, c'est comme si toutes les clés étaient incluses
|
* - si $includes vaut null, prendre toutes les clés
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static final function xselect($array, ?array $includes, ?array $excludes=null): ?array {
|
static final function xselect($array, ?array $includes, ?array $excludes=null): ?array {
|
||||||
@ -331,27 +302,6 @@ class cl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* si $array est un array ou une instance de ArrayAccess&Traversable,
|
|
||||||
* supprimer le premier élément dont la valeur est $value
|
|
||||||
*
|
|
||||||
* @param array|ArrayAccess $array
|
|
||||||
*/
|
|
||||||
static final function delv(&$array, $value, bool $strict=false): void {
|
|
||||||
if (is_array($array)) {
|
|
||||||
$key = array_search($value, $array, $strict);
|
|
||||||
if ($key !== false) unset($array[$key]);
|
|
||||||
} elseif ($array instanceof ArrayAccess && $array instanceof Traversable) {
|
|
||||||
$found = false;
|
|
||||||
foreach ($array as $key => $val) {
|
|
||||||
if ($strict) $found = $val === $value;
|
|
||||||
else $found = $val == $value;
|
|
||||||
if ($found) break;
|
|
||||||
}
|
|
||||||
if ($found) $array->offsetUnset($key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** retourner le nombre d'éléments de $array */
|
/** retourner le nombre d'éléments de $array */
|
||||||
static final function count(?array $array): int {
|
static final function count(?array $array): int {
|
||||||
return $array !== null? count($array): 0;
|
return $array !== null? count($array): 0;
|
||||||
@ -398,86 +348,15 @@ class cl {
|
|||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
|
||||||
/**
|
static final function map($func, ?iterable $array): array {
|
||||||
* tester si $array satisfait les conditions de $filter
|
$result = [];
|
||||||
* - $filter est un scalaire, le transformer en [$filter]
|
if ($array !== null) {
|
||||||
* - sinon $filter doit être un tableau de scalaires
|
|
||||||
*
|
|
||||||
* les règles des conditions sont les suivantes:
|
|
||||||
* - une valeur séquentielle $key est équivalente à la valeur associative
|
|
||||||
* $key => true
|
|
||||||
* - une valeur associative $key => bool indique que la clé correspondante ne
|
|
||||||
* doit pas (resp. doit) exister selon que bool vaut false (resp. true)
|
|
||||||
* - une valeur associative $key => $value indique que la clé correspondante
|
|
||||||
* doit exiter avec la valeur spécifiée
|
|
||||||
*/
|
|
||||||
static final function filter(?array $array, $filter): bool {
|
|
||||||
if ($filter === null) return false;
|
|
||||||
if (!is_array($filter)) $filter = [$filter];
|
|
||||||
if (!$filter) return false;
|
|
||||||
|
|
||||||
$index = 0;
|
|
||||||
foreach ($filter as $key => $value) {
|
|
||||||
if ($key === $index) {
|
|
||||||
$index++;
|
|
||||||
if ($array === null) return false;
|
|
||||||
if (!array_key_exists($value, $array)) return false;
|
|
||||||
} elseif (is_bool($value)) {
|
|
||||||
if ($value) {
|
|
||||||
if ($array === null || !array_key_exists($key, $array)) return false;
|
|
||||||
} else {
|
|
||||||
if ($array !== null && array_key_exists($key, $array)) return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ($array === null) return false;
|
|
||||||
if (!array_key_exists($key, $array)) return false;
|
|
||||||
if ($array[$key] !== $value) return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* mapper le tableau source $array selon les règles suivantes illustrées dans
|
|
||||||
* l'exemple suivant:
|
|
||||||
* si
|
|
||||||
* $map = ["a", "b" => "x", "c" => function() { return "y"; }, "d" => null]
|
|
||||||
* alors retourner le tableau
|
|
||||||
* ["a" => $array["a"], "b" => $array["x"], "c" => "y", "d" => null]
|
|
||||||
*
|
|
||||||
* si une fonction est utilisée, sa signature est
|
|
||||||
* <code>function(mixed $value, string|int $key, ?array $array)</code>
|
|
||||||
*/
|
|
||||||
static function map(?array $array, ?array $map): ?array {
|
|
||||||
if ($map === null) return $array;
|
|
||||||
$index = 0;
|
|
||||||
$mapped = [];
|
|
||||||
foreach ($map as $key => $value) {
|
|
||||||
if ($key === $index) {
|
|
||||||
$index++;
|
|
||||||
if ($value === null) $mapped[] = null;
|
|
||||||
else $mapped[$value] = cl::get($array, $value);
|
|
||||||
} elseif (is_callable($value)) {
|
|
||||||
$func = func::with($value);
|
|
||||||
$value = cl::get($array, $key);
|
|
||||||
$mapped[$key] = $func->invoke([$value, $key, $array]);
|
|
||||||
} else {
|
|
||||||
if ($value === null) $mapped[$key] = null;
|
|
||||||
else $mapped[$key] = cl::get($array, $value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $mapped;
|
|
||||||
}
|
|
||||||
|
|
||||||
static final function mapf(?iterable $items, $func): array {
|
|
||||||
$mapped = [];
|
|
||||||
if ($items !== null) {
|
|
||||||
$func = func::with($func);
|
$func = func::with($func);
|
||||||
foreach ($items as $key => $item) {
|
foreach ($array as $key => $value) {
|
||||||
$mapped[$key] = $func->invoke([$item, $key, $items]);
|
$result[$key] = $func->invoke([$value, $key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $mapped;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
@ -86,12 +86,6 @@ class cv {
|
|||||||
$b = $tmp;
|
$b = $tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** cloner une valeur */
|
|
||||||
static final function clone($value) {
|
|
||||||
if (is_object($value)) $value = clone $value;
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
|
||||||
/** mettre à jour $dest avec $value si $cond($value) est vrai */
|
/** mettre à jour $dest avec $value si $cond($value) est vrai */
|
||||||
@ -203,29 +197,19 @@ class cv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* retourner [$bool, $scalar, $array] initialisés chacun en fonction du type
|
* retourner [$bool, $string, $array] initialisés chacun en fonction du type
|
||||||
* de $value.
|
* de $value.
|
||||||
*
|
*
|
||||||
* @throws ValueException si $value n'est d'aucun de ces types
|
* @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 {
|
static final function check_bsa($value, ?string $prefix=null, bool $throw_exception=true): array {
|
||||||
$bool = is_bool($value)? $value : null;
|
$bool = is_bool($value)? $value : null;
|
||||||
$scalar = !is_bool($value) && is_scalar($value)? $value : null;
|
$string = is_string($value)? $value : null;
|
||||||
$array = is_array($value)? $value : null;
|
$array = is_array($value)? $value : null;
|
||||||
if ($bool === null && $scalar === null && $array === null && $throw_exception) {
|
if ($bool === null && $string === null && $array === null && $throw_exception) {
|
||||||
throw ValueException::invalid_kind($value, "value", $prefix);
|
throw ValueException::invalid_kind($value, "value", $prefix);
|
||||||
} else {
|
} else {
|
||||||
return [$bool, $scalar, $array];
|
return [$bool, $string, $array];
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static final function subclass_of($value, $class): bool {
|
|
||||||
if (is_string($value)) {
|
|
||||||
return $value === $class || is_subclass_of($value, $class);
|
|
||||||
} elseif (is_object($value)) {
|
|
||||||
return $value instanceof $class;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace nulib\db;
|
namespace nulib\db;
|
||||||
|
|
||||||
use nulib\cl;
|
|
||||||
use nulib\php\func;
|
use nulib\php\func;
|
||||||
use nulib\ValueException;
|
use nulib\ValueException;
|
||||||
use Traversable;
|
use Traversable;
|
||||||
@ -169,13 +168,6 @@ class Capacitor implements ITransactor {
|
|||||||
return $this->storage->_delete($this->channel, $filter, $func, $args);
|
return $this->storage->_delete($this->channel, $filter, $func, $args);
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbUpdate(array $update) {
|
|
||||||
return $this->storage->db()->exec(cl::merge([
|
|
||||||
"update",
|
|
||||||
"table" => $this->getTableName(),
|
|
||||||
], $update));
|
|
||||||
}
|
|
||||||
|
|
||||||
function close(): void {
|
function close(): void {
|
||||||
$this->storage->close();
|
$this->storage->close();
|
||||||
}
|
}
|
||||||
|
@ -13,9 +13,7 @@ class CapacitorChannel implements ITransactor {
|
|||||||
|
|
||||||
const TABLE_NAME = null;
|
const TABLE_NAME = null;
|
||||||
|
|
||||||
protected function COLUMN_DEFINITIONS(): ?array {
|
const COLUMN_DEFINITIONS = null;
|
||||||
return static::COLUMN_DEFINITIONS;
|
|
||||||
} const COLUMN_DEFINITIONS = null;
|
|
||||||
|
|
||||||
const PRIMARY_KEYS = null;
|
const PRIMARY_KEYS = null;
|
||||||
|
|
||||||
@ -30,17 +28,19 @@ class CapacitorChannel implements ITransactor {
|
|||||||
static function verifix_name(?string &$name, ?string &$tableName=null): void {
|
static function verifix_name(?string &$name, ?string &$tableName=null): void {
|
||||||
if ($name !== null) {
|
if ($name !== null) {
|
||||||
$name = strtolower($name);
|
$name = strtolower($name);
|
||||||
$tableName ??= str_replace("-", "_", $name) . "_channel";
|
if ($tableName === null) {
|
||||||
|
$tableName = str_replace("-", "_", $name) . "_channel";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$name = static::class;
|
$name = static::class;
|
||||||
if ($name === self::class) {
|
if ($name === self::class) {
|
||||||
$name = "default";
|
$name = "default";
|
||||||
$tableName ??= "default_channel";
|
if ($tableName === null) $tableName = "default_channel";
|
||||||
} else {
|
} else {
|
||||||
$name = preg_replace('/^.*\\\\/', "", $name);
|
$name = preg_replace('/^.*\\\\/', "", $name);
|
||||||
$name = preg_replace('/Channel$/', "", $name);
|
$name = preg_replace('/Channel$/', "", $name);
|
||||||
$name = lcfirst($name);
|
$name = lcfirst($name);
|
||||||
$tableName ??= str::camel2us($name);
|
if ($tableName === null) $tableName = str::camel2us($name);
|
||||||
$name = strtolower($name);
|
$name = strtolower($name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,7 +63,7 @@ class CapacitorChannel implements ITransactor {
|
|||||||
$this->useCache = static::USE_CACHE;
|
$this->useCache = static::USE_CACHE;
|
||||||
$this->setup = false;
|
$this->setup = false;
|
||||||
$this->created = false;
|
$this->created = false;
|
||||||
$columnDefinitions = $this->COLUMN_DEFINITIONS();
|
$columnDefinitions = cl::withn(static::COLUMN_DEFINITIONS);
|
||||||
$primaryKeys = cl::withn(static::PRIMARY_KEYS);
|
$primaryKeys = cl::withn(static::PRIMARY_KEYS);
|
||||||
$migration = cl::withn(static::MIGRATION);
|
$migration = cl::withn(static::MIGRATION);
|
||||||
$lastMkey = 1;
|
$lastMkey = 1;
|
||||||
@ -482,10 +482,6 @@ class CapacitorChannel implements ITransactor {
|
|||||||
return $this->capacitor->delete($filter, $func, $args);
|
return $this->capacitor->delete($filter, $func, $args);
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbUpdate(array $update) {
|
|
||||||
return $this->capacitor->dbUpdate($update);
|
|
||||||
}
|
|
||||||
|
|
||||||
function close(): void {
|
function close(): void {
|
||||||
$this->capacitor->close();
|
$this->capacitor->close();
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ namespace nulib\db;
|
|||||||
|
|
||||||
use nulib\cl;
|
use nulib\cl;
|
||||||
use nulib\db\_private\_migration;
|
use nulib\db\_private\_migration;
|
||||||
|
use nulib\db\cache\cache;
|
||||||
use nulib\php\func;
|
use nulib\php\func;
|
||||||
use nulib\ValueException;
|
use nulib\ValueException;
|
||||||
use Traversable;
|
use Traversable;
|
||||||
@ -676,7 +677,7 @@ abstract class CapacitorStorage {
|
|||||||
function _delete(CapacitorChannel $channel, $filter, $func, ?array $args): int {
|
function _delete(CapacitorChannel $channel, $filter, $func, ?array $args): int {
|
||||||
$this->_create($channel);
|
$this->_create($channel);
|
||||||
if ($func === null) $func = CapacitorChannel::onDelete;
|
if ($func === null) $func = CapacitorChannel::onDelete;
|
||||||
$onDelete = func::with($func)->bind($channel);
|
$onEach = func::with($func)->bind($channel);
|
||||||
$db = $this->db();
|
$db = $this->db();
|
||||||
# si on est déjà dans une transaction, désactiver la gestion des transactions
|
# si on est déjà dans une transaction, désactiver la gestion des transactions
|
||||||
$manageTransactions = $channel->isManageTransactions() && !$db->inTransaction();
|
$manageTransactions = $channel->isManageTransactions() && !$db->inTransaction();
|
||||||
@ -692,8 +693,8 @@ abstract class CapacitorStorage {
|
|||||||
$all = $this->_allCached("delete", $channel, $filter);
|
$all = $this->_allCached("delete", $channel, $filter);
|
||||||
foreach ($all as $values) {
|
foreach ($all as $values) {
|
||||||
$rowIds = $this->getRowIds($channel, $values);
|
$rowIds = $this->getRowIds($channel, $values);
|
||||||
$shouldDelete = boolval($onDelete->invoke([$values["item"], $values, ...$args]));
|
$delete = boolval($onEach->invoke([$values["item"], $values, ...$args]));
|
||||||
if ($shouldDelete) {
|
if ($delete) {
|
||||||
$db->exec([
|
$db->exec([
|
||||||
"delete",
|
"delete",
|
||||||
"from" => $tableName,
|
"from" => $tableName,
|
||||||
|
@ -23,8 +23,7 @@ class _select extends _common {
|
|||||||
return preg_match("/^select\b/i", $sql);
|
return preg_match("/^select\b/i", $sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function add_prefix(?string $col, ?string $prefix): string {
|
private static function add_prefix(string $col, ?string $prefix): string {
|
||||||
$col ??= "null";
|
|
||||||
if ($prefix === null) return $col;
|
if ($prefix === null) return $col;
|
||||||
if (strpos($col, ".") !== false) return $col;
|
if (strpos($col, ".") !== false) return $col;
|
||||||
return "$prefix$col";
|
return "$prefix$col";
|
||||||
|
116
php/src/db/cache/CacheChannel.php
vendored
Normal file
116
php/src/db/cache/CacheChannel.php
vendored
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
<?php
|
||||||
|
namespace nulib\db\cache;
|
||||||
|
|
||||||
|
use nulib\cl;
|
||||||
|
use nulib\db\CapacitorChannel;
|
||||||
|
use nulib\php\time\DateTime;
|
||||||
|
use nulib\php\time\Delay;
|
||||||
|
|
||||||
|
class CacheChannel extends CapacitorChannel {
|
||||||
|
/** @var int durée de vie par défaut du cache */
|
||||||
|
const DURATION = "1D"; // jusqu'au lendemain
|
||||||
|
|
||||||
|
const INCLUDES = null;
|
||||||
|
|
||||||
|
const EXCLUDES = null;
|
||||||
|
|
||||||
|
const COLUMN_DEFINITIONS = [
|
||||||
|
"group_id" => "varchar(64) not null",
|
||||||
|
"id" => "varchar(64) not null",
|
||||||
|
"date_start" => "datetime",
|
||||||
|
"duration_" => "text",
|
||||||
|
"primary key (group_id, id)",
|
||||||
|
];
|
||||||
|
|
||||||
|
static function get_cache_ids($id): array {
|
||||||
|
if (is_array($id)) {
|
||||||
|
$keys = array_keys($id);
|
||||||
|
if (array_key_exists("group_id", $id)) $groupIdKey = "group_id";
|
||||||
|
else $groupIdKey = $keys[1] ?? null;
|
||||||
|
$groupId = $id[$groupIdKey] ?? "";
|
||||||
|
if (array_key_exists("id", $id)) $idKey = "id";
|
||||||
|
else $idKey = $keys[0] ?? null;
|
||||||
|
$id = $id[$idKey] ?? "";
|
||||||
|
} else {
|
||||||
|
$groupId = "";
|
||||||
|
}
|
||||||
|
if (preg_match('/^(.*\\\\)?([^\\\\]+)$/', $groupId, $ms)) {
|
||||||
|
# si le groupe est une classe, faire un hash du package pour limiter la
|
||||||
|
# longueur du groupe
|
||||||
|
[$package, $groupId] = [$ms[1], $ms[2]];
|
||||||
|
$package = substr(md5($package), 0, 4);
|
||||||
|
$groupId = "${groupId}_$package";
|
||||||
|
}
|
||||||
|
return ["group_id" => $groupId, "id" => $id];
|
||||||
|
}
|
||||||
|
|
||||||
|
function __construct(?string $duration=null, ?string $name=null) {
|
||||||
|
parent::__construct($name);
|
||||||
|
$this->duration = $duration ?? static::DURATION;
|
||||||
|
$this->includes = static::INCLUDES;
|
||||||
|
$this->excludes = static::EXCLUDES;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected string $duration;
|
||||||
|
|
||||||
|
protected ?array $includes;
|
||||||
|
|
||||||
|
protected ?array $excludes;
|
||||||
|
|
||||||
|
function getItemValues($item): ?array {
|
||||||
|
return cl::merge(self::get_cache_ids($item), [
|
||||||
|
"item" => null,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCreate($item, array $values, ?array $alwaysNull, ?string $duration=null): ?array {
|
||||||
|
$now = new DateTime();
|
||||||
|
$duration ??= $this->duration;
|
||||||
|
return [
|
||||||
|
"date_start" => $now,
|
||||||
|
"duration" => new Delay($duration, $now),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function onUpdate($item, array $values, array $pvalues, ?string $duration=null): ?array {
|
||||||
|
$now = new DateTime();
|
||||||
|
$duration ??= $this->duration;
|
||||||
|
return [
|
||||||
|
"date_start" => $now,
|
||||||
|
"duration" => new Delay($duration, $now),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldUpdate($id, bool $noCache=false): bool {
|
||||||
|
if ($noCache) return true;
|
||||||
|
|
||||||
|
$cacheIds = self::get_cache_ids($id);
|
||||||
|
$groupId = $cacheIds["group_id"];
|
||||||
|
if ($groupId) {
|
||||||
|
$includes = $this->includes;
|
||||||
|
$shouldInclude = $includes !== null && in_array($groupId, $includes);
|
||||||
|
$excludes = $this->excludes;
|
||||||
|
$shouldExclude = $excludes !== null && in_array($groupId, $excludes);
|
||||||
|
if (!$shouldInclude || $shouldExclude) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$found = false;
|
||||||
|
$expired = false;
|
||||||
|
$this->each($cacheIds,
|
||||||
|
function($item, $values) use (&$found, &$expired) {
|
||||||
|
$found = true;
|
||||||
|
$expired = $values["duration"]->isElapsed();
|
||||||
|
});
|
||||||
|
return !$found || $expired;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setCached($id, ?string $duration=null): void {
|
||||||
|
$cacheIds = self::get_cache_ids($id);
|
||||||
|
$this->charge($cacheIds, null, [$duration]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetCached($id) {
|
||||||
|
$cacheIds = self::get_cache_ids($id);
|
||||||
|
$this->delete($cacheIds);
|
||||||
|
}
|
||||||
|
}
|
51
php/src/db/cache/RowsChannel.php
vendored
Normal file
51
php/src/db/cache/RowsChannel.php
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
namespace nulib\db\cache;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use IteratorAggregate;
|
||||||
|
use nulib\cl;
|
||||||
|
use nulib\db\CapacitorChannel;
|
||||||
|
use Traversable;
|
||||||
|
|
||||||
|
class RowsChannel extends CapacitorChannel implements IteratorAggregate {
|
||||||
|
const COLUMN_DEFINITIONS = [
|
||||||
|
"key" => "varchar(128) primary key not null",
|
||||||
|
"all_values" => "mediumtext",
|
||||||
|
];
|
||||||
|
|
||||||
|
function __construct($id, callable $builder, ?string $duration=null) {
|
||||||
|
$this->cacheIds = $cacheIds = CacheChannel::get_cache_ids($id);
|
||||||
|
$this->builder = Closure::fromCallable($builder);
|
||||||
|
$this->duration = $duration;
|
||||||
|
$name = "{$cacheIds["group_id"]}-{$cacheIds["id"]}";
|
||||||
|
parent::__construct($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected array $cacheIds;
|
||||||
|
|
||||||
|
protected Closure $builder;
|
||||||
|
|
||||||
|
protected ?string $duration = null;
|
||||||
|
|
||||||
|
function getItemValues($item): ?array {
|
||||||
|
$key = array_keys($item)[0];
|
||||||
|
$row = $item[$key];
|
||||||
|
return [
|
||||||
|
"key" => $key,
|
||||||
|
"item" => $row,
|
||||||
|
"all_values" => implode(" ", cl::filter_n(cl::with($row))),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getIterator(): Traversable {
|
||||||
|
$cm = cache::get();
|
||||||
|
if ($cm->shouldUpdate($this->cacheIds)) {
|
||||||
|
$this->capacitor->reset();
|
||||||
|
foreach (($this->builder)() as $key => $row) {
|
||||||
|
$this->charge([$key => $row]);
|
||||||
|
}
|
||||||
|
$cm->setCached($this->cacheIds, $this->duration);
|
||||||
|
}
|
||||||
|
return $this->discharge(false);
|
||||||
|
}
|
||||||
|
}
|
37
php/src/db/cache/cache.php
vendored
Normal file
37
php/src/db/cache/cache.php
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
namespace nulib\db\cache;
|
||||||
|
|
||||||
|
use nulib\db\Capacitor;
|
||||||
|
use nulib\db\CapacitorStorage;
|
||||||
|
use nulib\db\sqlite\SqliteStorage;
|
||||||
|
|
||||||
|
class cache {
|
||||||
|
protected static ?CapacitorStorage $storage = null;
|
||||||
|
|
||||||
|
static function set_storage(CapacitorStorage $storage): CapacitorStorage {
|
||||||
|
return self::$storage = $storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function get_storage(): CapacitorStorage {
|
||||||
|
return self::$storage ??= new SqliteStorage("");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static ?CacheChannel $channel = null;
|
||||||
|
|
||||||
|
static function set(?CacheChannel $channel): CacheChannel {
|
||||||
|
$channel ??= new CacheChannel();
|
||||||
|
new Capacitor(self::get_storage(), $channel);
|
||||||
|
return self::$channel = $channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function get(): CacheChannel {
|
||||||
|
if (self::$channel !== null) return self::$channel;
|
||||||
|
else return self::set(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
static function new(?RowsChannel $channel, $id=null, ?callable $builder=null): RowsChannel {
|
||||||
|
$channel ??= new RowsChannel($id, $builder);
|
||||||
|
new Capacitor(self::get_storage(), $channel);
|
||||||
|
return $channel;
|
||||||
|
}
|
||||||
|
}
|
@ -30,11 +30,7 @@ class Pgsql implements IDatabase {
|
|||||||
|
|
||||||
|
|
||||||
protected const OPTIONS = [
|
protected const OPTIONS = [
|
||||||
# XXX désactiver les connexions persistantes par défaut
|
"persistent" => true,
|
||||||
# pour réactiver par défaut, il faudrait vérifier la connexion à chaque fois
|
|
||||||
# qu'elle est ouverte avec un "select 1". en effet, l'expérience jusqu'ici
|
|
||||||
# est que la première connexion après un long timeout échoue
|
|
||||||
"persistent" => false,
|
|
||||||
"force_new" => false,
|
"force_new" => false,
|
||||||
"serial_support" => true,
|
"serial_support" => true,
|
||||||
];
|
];
|
||||||
@ -85,12 +81,6 @@ class Pgsql implements IDatabase {
|
|||||||
#if ($tmp !== null) $dbconn = $tmp;
|
#if ($tmp !== null) $dbconn = $tmp;
|
||||||
#else $dbconn = ["" => $dbconn];
|
#else $dbconn = ["" => $dbconn];
|
||||||
}
|
}
|
||||||
unset($dbconn["type"]);
|
|
||||||
$name = $dbconn["name"] ?? null;
|
|
||||||
if ($name !== null) {
|
|
||||||
$dbconn[""] = $name;
|
|
||||||
unset($dbconn["name"]);
|
|
||||||
}
|
|
||||||
$params["dbconn"] = $dbconn;
|
$params["dbconn"] = $dbconn;
|
||||||
}
|
}
|
||||||
# dbconn
|
# dbconn
|
||||||
|
@ -40,20 +40,12 @@ class SqliteStorage extends CapacitorStorage {
|
|||||||
return new _sqliteMigration($migrations, $channel->getName());
|
return new _sqliteMigration($migrations, $channel->getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
function channelExists(string $name, ?array &$row=null): bool {
|
function channelExists(string $name): bool {
|
||||||
$row = $this->db->one([
|
return null !== $this->db->get([
|
||||||
"select",
|
"select name",
|
||||||
"from" => static::CHANNELS_TABLE,
|
"from" => static::CHANNELS_TABLE,
|
||||||
"where" => ["name" => $name],
|
"where" => ["name" => $name],
|
||||||
]);
|
]);
|
||||||
return $row !== null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getChannels(): iterable {
|
|
||||||
return $this->db->all([
|
|
||||||
"select",
|
|
||||||
"from" => static::CHANNELS_TABLE,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function _addToChannelsSql(CapacitorChannel $channel): array {
|
protected function _addToChannelsSql(CapacitorChannel $channel): array {
|
||||||
|
@ -40,6 +40,4 @@ interface IReader extends _IFile {
|
|||||||
function unserialize(?array $options=null, bool $close=true, bool $alreadyLocked=false);
|
function unserialize(?array $options=null, bool $close=true, bool $alreadyLocked=false);
|
||||||
|
|
||||||
function copyTo(IWriter $dest, bool $closeWriter=false, bool $closeReader=true): void;
|
function copyTo(IWriter $dest, bool $closeWriter=false, bool $closeReader=true): void;
|
||||||
|
|
||||||
function setCsvFlavour(?string $flavour): void;
|
|
||||||
}
|
}
|
||||||
|
@ -299,8 +299,8 @@ class Stream extends AbstractIterator implements IReader, IWriter {
|
|||||||
|
|
||||||
/** retourner le contenu du fichier sous forme de chaine */
|
/** retourner le contenu du fichier sous forme de chaine */
|
||||||
function getContents(bool $close=true, bool $alreadyLocked=false): string {
|
function getContents(bool $close=true, bool $alreadyLocked=false): string {
|
||||||
$useLocking = $this->useLocking && !$alreadyLocked;
|
$useLocking = $this->useLocking;
|
||||||
if ($useLocking) $this->lock(LOCK_SH);
|
if ($useLocking && !$alreadyLocked) $this->lock(LOCK_SH);
|
||||||
try {
|
try {
|
||||||
return IOException::ensure_valid(stream_get_contents($this->fd), $this->throwOnError);
|
return IOException::ensure_valid(stream_get_contents($this->fd), $this->throwOnError);
|
||||||
} finally {
|
} finally {
|
||||||
@ -380,9 +380,7 @@ class Stream extends AbstractIterator implements IReader, IWriter {
|
|||||||
/** @throws IOException */
|
/** @throws IOException */
|
||||||
function ftruncate(int $size=0, bool $rewind=true): self {
|
function ftruncate(int $size=0, bool $rewind=true): self {
|
||||||
$fd = $this->getResource();
|
$fd = $this->getResource();
|
||||||
$r = ftruncate($fd, $size);
|
IOException::ensure_valid(ftruncate($fd, $size), $this->throwOnError);
|
||||||
$this->stat = null;
|
|
||||||
IOException::ensure_valid($r, $this->throwOnError);
|
|
||||||
if ($rewind) rewind($fd);
|
if ($rewind) rewind($fd);
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@ -392,7 +390,6 @@ class Stream extends AbstractIterator implements IReader, IWriter {
|
|||||||
$fd = $this->getResource();
|
$fd = $this->getResource();
|
||||||
if ($length === null) $r = fwrite($fd, $data);
|
if ($length === null) $r = fwrite($fd, $data);
|
||||||
else $r = fwrite($fd, $data, $length);
|
else $r = fwrite($fd, $data, $length);
|
||||||
$this->stat = null;
|
|
||||||
return IOException::ensure_valid($r, $this->throwOnError);
|
return IOException::ensure_valid($r, $this->throwOnError);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,13 +403,9 @@ class Stream extends AbstractIterator implements IReader, IWriter {
|
|||||||
$line[] = strval($col);
|
$line[] = strval($col);
|
||||||
}
|
}
|
||||||
$line = implode($sep, $line);
|
$line = implode($sep, $line);
|
||||||
$r = fwrite($fd, "$line\n");
|
IOException::ensure_valid(fwrite($fd, "$line\n"), $this->throwOnError);
|
||||||
$this->stat = null;
|
|
||||||
IOException::ensure_valid($r, $this->throwOnError);
|
|
||||||
} else {
|
} else {
|
||||||
$r = fputcsv($fd, $row, $params[0], $params[1], $params[2]);
|
IOException::ensure_valid(fputcsv($fd, $row, $params[0], $params[1], $params[2]), $this->throwOnError);
|
||||||
$this->stat = null;
|
|
||||||
IOException::ensure_valid($r, $this->throwOnError);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,8 +471,8 @@ class Stream extends AbstractIterator implements IReader, IWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function putContents(string $contents, bool $close=true, bool $alreadyLocked=false): void {
|
function putContents(string $contents, bool $close=true, bool $alreadyLocked=false): void {
|
||||||
$useLocking = $this->useLocking && !$alreadyLocked;
|
$useLocking = $this->useLocking;
|
||||||
if ($useLocking) $this->lock(LOCK_EX);
|
if ($useLocking && !$alreadyLocked) $this->lock(LOCK_EX);
|
||||||
try {
|
try {
|
||||||
$this->fwrite($contents);
|
$this->fwrite($contents);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -2,9 +2,7 @@
|
|||||||
namespace nulib\file\csv;
|
namespace nulib\file\csv;
|
||||||
|
|
||||||
use nulib\file;
|
use nulib\file;
|
||||||
use nulib\file\_IFile;
|
|
||||||
use nulib\file\FileReader;
|
use nulib\file\FileReader;
|
||||||
use nulib\file\IReader;
|
|
||||||
use nulib\file\tab\AbstractReader;
|
use nulib\file\tab\AbstractReader;
|
||||||
use nulib\file\tab\TAbstractReader;
|
use nulib\file\tab\TAbstractReader;
|
||||||
|
|
||||||
@ -22,12 +20,7 @@ class CsvReader extends AbstractReader {
|
|||||||
protected ?string $inputEncoding;
|
protected ?string $inputEncoding;
|
||||||
|
|
||||||
function getIterator() {
|
function getIterator() {
|
||||||
$input = $this->input;
|
$reader = new FileReader(file::fix_dash($this->input));
|
||||||
if ($input instanceof IReader) {
|
|
||||||
$reader = $input;
|
|
||||||
} else {
|
|
||||||
$reader = new FileReader(file::fix_dash($input));
|
|
||||||
}
|
|
||||||
$inputEncoding = $this->inputEncoding;
|
$inputEncoding = $this->inputEncoding;
|
||||||
if ($inputEncoding !== null) {
|
if ($inputEncoding !== null) {
|
||||||
$reader->appendFilter("convert.iconv.$inputEncoding.utf-8");
|
$reader->appendFilter("convert.iconv.$inputEncoding.utf-8");
|
||||||
|
@ -59,10 +59,9 @@ class func {
|
|||||||
* @param bool $strict vérifier l'inexistence de la classe et l'existence de
|
* @param bool $strict vérifier l'inexistence de la classe et l'existence de
|
||||||
* la fonction (ne pas uniquement faire une vérification syntaxique)
|
* la fonction (ne pas uniquement faire une vérification syntaxique)
|
||||||
*/
|
*/
|
||||||
static function verifix_function(&$func, ?array &$args=null, bool $strict=true, ?string &$reason=null): bool {
|
static function verifix_function(&$func, bool $strict=true, ?string &$reason=null): bool {
|
||||||
if ($strict) $reason = null;
|
if ($strict) $reason = null;
|
||||||
if ($func instanceof ReflectionFunction) return true;
|
if ($func instanceof ReflectionFunction) return true;
|
||||||
$rargs = null;
|
|
||||||
if (is_string($func)) {
|
if (is_string($func)) {
|
||||||
$c = false;
|
$c = false;
|
||||||
$f = $func;
|
$f = $func;
|
||||||
@ -71,7 +70,6 @@ class func {
|
|||||||
$c = $func[0];
|
$c = $func[0];
|
||||||
if (!array_key_exists(1, $func)) return false;
|
if (!array_key_exists(1, $func)) return false;
|
||||||
$f = $func[1];
|
$f = $func[1];
|
||||||
$rargs = array_slice($func, 2);
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -92,7 +90,6 @@ class func {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$func = [false, $f];
|
$func = [false, $f];
|
||||||
if ($rargs) $args = cl::merge($rargs, $args);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +98,7 @@ class func {
|
|||||||
* {@link self::verifix_function()}
|
* {@link self::verifix_function()}
|
||||||
*/
|
*/
|
||||||
static function is_function($func, bool $strict=true, ?string &$reason=null): bool {
|
static function is_function($func, bool $strict=true, ?string &$reason=null): bool {
|
||||||
return self::verifix_function($func, $args, $strict, $reason);
|
return self::verifix_function($func, $strict, $reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
@ -118,10 +115,9 @@ class func {
|
|||||||
* @param bool $strict vérifier l'existence de la classe (ne pas uniquement
|
* @param bool $strict vérifier l'existence de la classe (ne pas uniquement
|
||||||
* faire une vérification syntaxique)
|
* faire une vérification syntaxique)
|
||||||
*/
|
*/
|
||||||
static function verifix_class(&$func, ?array &$args=null, bool $strict=true, ?string &$reason=null): bool {
|
static function verifix_class(&$func, bool $strict=true, ?string &$reason=null): bool {
|
||||||
if ($strict) $reason = null;
|
if ($strict) $reason = null;
|
||||||
if ($func instanceof ReflectionClass) return true;
|
if ($func instanceof ReflectionClass) return true;
|
||||||
$rargs = null;
|
|
||||||
if (is_string($func)) {
|
if (is_string($func)) {
|
||||||
$c = $func;
|
$c = $func;
|
||||||
$f = false;
|
$f = false;
|
||||||
@ -130,7 +126,6 @@ class func {
|
|||||||
$c = $func[0];
|
$c = $func[0];
|
||||||
if (!array_key_exists(1, $func)) return false;
|
if (!array_key_exists(1, $func)) return false;
|
||||||
$f = $func[1];
|
$f = $func[1];
|
||||||
$rargs = array_slice($func, 2);
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -144,7 +139,6 @@ class func {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$func = [$c, false];
|
$func = [$c, false];
|
||||||
if ($rargs) $args = cl::merge($rargs, $args);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +147,7 @@ class func {
|
|||||||
* {@link self::verifix_class()}
|
* {@link self::verifix_class()}
|
||||||
*/
|
*/
|
||||||
static function is_class($func, bool $strict=true, ?string &$reason=null): bool {
|
static function is_class($func, bool $strict=true, ?string &$reason=null): bool {
|
||||||
return self::verifix_class($func, $args, $strict, $reason);
|
return self::verifix_class($func, $strict, $reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
@ -204,16 +198,14 @@ class func {
|
|||||||
* liée à une classe avant d'être utilisée
|
* liée à une classe avant d'être utilisée
|
||||||
*
|
*
|
||||||
* @param bool $strict vérifier l'existence de la classe et de la méthode si
|
* @param bool $strict vérifier l'existence de la classe et de la méthode si
|
||||||
* @param array|null &$args
|
|
||||||
* la méthode est liée (ne pas uniquement faire une vérification syntaxique)
|
* la méthode est liée (ne pas uniquement faire une vérification syntaxique)
|
||||||
*/
|
*/
|
||||||
static function verifix_static(&$func, ?array &$args = null, bool $strict=true, ?bool &$bound=null, ?string &$reason=null): bool {
|
static function verifix_static(&$func, bool $strict=true, ?bool &$bound=null, ?string &$reason=null): bool {
|
||||||
if ($strict) $reason = null;
|
if ($strict) $reason = null;
|
||||||
if ($func instanceof ReflectionMethod) {
|
if ($func instanceof ReflectionMethod) {
|
||||||
$bound = false;
|
$bound = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
$rargs = null;
|
|
||||||
if (is_string($func)) {
|
if (is_string($func)) {
|
||||||
if (!self::_parse_c_static($func, $c, $f, $bound)) return false;
|
if (!self::_parse_c_static($func, $c, $f, $bound)) return false;
|
||||||
$cf = [$c, $f];
|
$cf = [$c, $f];
|
||||||
@ -260,7 +252,6 @@ class func {
|
|||||||
self::_parse_static($f);
|
self::_parse_static($f);
|
||||||
}
|
}
|
||||||
$cf[1] = $f;
|
$cf[1] = $f;
|
||||||
$rargs = array_slice($func, 2);
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -283,7 +274,6 @@ class func {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$func = $cf;
|
$func = $cf;
|
||||||
if ($rargs) $args = cl::merge($rargs, $args);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,7 +282,7 @@ class func {
|
|||||||
* {@link self::verifix_static()}
|
* {@link self::verifix_static()}
|
||||||
*/
|
*/
|
||||||
static function is_static($func, bool $strict=true, ?bool &$bound=null, ?string &$reason=null): bool {
|
static function is_static($func, bool $strict=true, ?bool &$bound=null, ?string &$reason=null): bool {
|
||||||
return self::verifix_static($func, $args, $strict, $bound, $reason);
|
return self::verifix_static($func, $strict, $bound, $reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
@ -345,13 +335,12 @@ class func {
|
|||||||
* @param bool $strict vérifier l'existence de la classe et de la méthode si
|
* @param bool $strict vérifier l'existence de la classe et de la méthode si
|
||||||
* la méthode est liée (ne pas uniquement faire une vérification syntaxique)
|
* la méthode est liée (ne pas uniquement faire une vérification syntaxique)
|
||||||
*/
|
*/
|
||||||
static function verifix_method(&$func, ?array &$args=null, bool $strict=true, ?bool &$bound=null, ?string &$reason=null): bool {
|
static function verifix_method(&$func, bool $strict=true, ?bool &$bound=null, ?string &$reason=null): bool {
|
||||||
if ($strict) $reason = null;
|
if ($strict) $reason = null;
|
||||||
if ($func instanceof ReflectionMethod) {
|
if ($func instanceof ReflectionMethod) {
|
||||||
$bound = false;
|
$bound = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
$rargs = null;
|
|
||||||
if (is_string($func)) {
|
if (is_string($func)) {
|
||||||
if (!self::_parse_c_method($func, $c, $f, $bound)) return false;
|
if (!self::_parse_c_method($func, $c, $f, $bound)) return false;
|
||||||
$cf = [$c, $f];
|
$cf = [$c, $f];
|
||||||
@ -399,7 +388,6 @@ class func {
|
|||||||
self::_parse_method($f);
|
self::_parse_method($f);
|
||||||
}
|
}
|
||||||
$cf[1] = $f;
|
$cf[1] = $f;
|
||||||
$rargs = array_slice($func, 2);
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -422,7 +410,6 @@ class func {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$func = $cf;
|
$func = $cf;
|
||||||
if ($rargs) $args = cl::merge($rargs, $args);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -431,7 +418,7 @@ class func {
|
|||||||
* {@link self::verifix_method()}
|
* {@link self::verifix_method()}
|
||||||
*/
|
*/
|
||||||
static function is_method($func, bool $strict=true, ?bool &$bound=null, ?string &$reason=null): bool {
|
static function is_method($func, bool $strict=true, ?bool &$bound=null, ?string &$reason=null): bool {
|
||||||
return self::verifix_method($func, $args, $strict, $bound, $reason);
|
return self::verifix_method($func, $strict, $bound, $reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
@ -465,30 +452,24 @@ class func {
|
|||||||
return new self(self::TYPE_METHOD, $func, $args, false);
|
return new self(self::TYPE_METHOD, $func, $args, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (self::verifix_function($func, $args, $strict, $reason)) {
|
if (self::verifix_function($func, $strict, $reason)) {
|
||||||
return new self(self::TYPE_FUNCTION, $func, $args, false, $reason);
|
return new self(self::TYPE_FUNCTION, $func, $args, false, $reason);
|
||||||
} elseif (self::verifix_class($func, $args, $strict, $reason)) {
|
} elseif (self::verifix_class($func, $strict, $reason)) {
|
||||||
return new self(self::TYPE_CLASS, $func, $args, false, $reason);
|
return new self(self::TYPE_CLASS, $func, $args, false, $reason);
|
||||||
} elseif (self::verifix_method($func, $args, $strict, $bound, $reason)) {
|
} elseif (self::verifix_method($func, $strict, $bound, $reason)) {
|
||||||
return new self(self::TYPE_METHOD, $func, $args, $bound, $reason);
|
return new self(self::TYPE_METHOD, $func, $args, $bound, $reason);
|
||||||
} elseif (self::verifix_static($func, $args, $strict, $bound, $reason)) {
|
} elseif (self::verifix_static($func, $strict, $bound, $reason)) {
|
||||||
return new self(self::TYPE_STATIC, $func, $args, $bound, $reason);
|
return new self(self::TYPE_STATIC, $func, $args, $bound, $reason);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static function with($func, ?array $args=null, bool $strict=true): self {
|
static function with($func, ?array $args=null, bool $strict=true): self {
|
||||||
if ($func instanceof self) return $func;
|
|
||||||
$func = self::_with($func, $args, $strict, $reason);
|
$func = self::_with($func, $args, $strict, $reason);
|
||||||
if ($func !== null) return $func;
|
if ($func !== null) return $func;
|
||||||
throw self::not_a_callable($func, $reason);
|
throw self::not_a_callable($func, $reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
static function withn($func, ?array $args=null, bool $strict=true): ?self {
|
|
||||||
if ($func === null) return null;
|
|
||||||
else return self::with($func, $args, $strict);
|
|
||||||
}
|
|
||||||
|
|
||||||
static function ensure($func, ?array $args=null, bool $strict=true): self {
|
static function ensure($func, ?array $args=null, bool $strict=true): self {
|
||||||
$func = self::with($func, $args, $strict);
|
$func = self::with($func, $args, $strict);
|
||||||
if (!$func->isBound()) {
|
if (!$func->isBound()) {
|
||||||
|
@ -29,7 +29,7 @@ class DateInterval extends \DateInterval {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function __construct($duration) {
|
function __construct($duration) {
|
||||||
if (is_numeric($duration)) $duration = "PT${duration}S";
|
if (is_int($duration)) $duration = "PT${duration}S";
|
||||||
if ($duration instanceof \DateInterval) {
|
if ($duration instanceof \DateInterval) {
|
||||||
$this->y = $duration->y;
|
$this->y = $duration->y;
|
||||||
$this->m = $duration->m;
|
$this->m = $duration->m;
|
||||||
|
@ -3,7 +3,6 @@ namespace nulib\php\time;
|
|||||||
|
|
||||||
use DateTimeInterface;
|
use DateTimeInterface;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use nulib\ValueException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class Delay: une durée jusqu'à un moment destination. le moment destination
|
* Class Delay: une durée jusqu'à un moment destination. le moment destination
|
||||||
@ -116,10 +115,6 @@ class Delay {
|
|||||||
$this->repr = $repr;
|
$this->repr = $repr;
|
||||||
}
|
}
|
||||||
|
|
||||||
function __clone() {
|
|
||||||
$this->dest = clone $this->dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
function __serialize(): array {
|
function __serialize(): array {
|
||||||
return [$this->dest, $this->repr];
|
return [$this->dest, $this->repr];
|
||||||
}
|
}
|
||||||
@ -135,7 +130,7 @@ class Delay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addDuration($duration) {
|
function addDuration($duration) {
|
||||||
if (is_numeric($duration) && $duration < 0) {
|
if (is_int($duration) && $duration < 0) {
|
||||||
$this->dest->sub(DateInterval::with(-$duration));
|
$this->dest->sub(DateInterval::with(-$duration));
|
||||||
} else {
|
} else {
|
||||||
$this->dest->add(DateInterval::with($duration));
|
$this->dest->add(DateInterval::with($duration));
|
||||||
@ -143,7 +138,7 @@ class Delay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function subDuration($duration) {
|
function subDuration($duration) {
|
||||||
if (is_numeric($duration) && $duration < 0) {
|
if (is_int($duration) && $duration < 0) {
|
||||||
$this->dest->add(DateInterval::with(-$duration));
|
$this->dest->add(DateInterval::with(-$duration));
|
||||||
} else {
|
} else {
|
||||||
$this->dest->sub(DateInterval::with($duration));
|
$this->dest->sub(DateInterval::with($duration));
|
||||||
|
@ -328,22 +328,6 @@ class str {
|
|||||||
else return preg_split('/\s+/', $s);
|
else return preg_split('/\s+/', $s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* découper la chaine:
|
|
||||||
* - avec preg_split si $sep est une expression régulière /re/
|
|
||||||
* - avec explode sinon
|
|
||||||
*/
|
|
||||||
static final function split(string $sep, ?string $s): ?array {
|
|
||||||
if ($s === null) return null;
|
|
||||||
if ($sep === "") {
|
|
||||||
return [$s];
|
|
||||||
} elseif (substr($sep, 0, 1) === "/") {
|
|
||||||
return preg_split($sep, $s);
|
|
||||||
} else {
|
|
||||||
return explode($sep, $s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* joindre les éléments de $parts comme avec implode(), mais en ignorant les
|
* joindre les éléments de $parts comme avec implode(), mais en ignorant les
|
||||||
* valeurs fausses (cela n'inclue pas la chaine "0")
|
* valeurs fausses (cela n'inclue pas la chaine "0")
|
||||||
|
@ -12,10 +12,10 @@ class clTest extends TestCase {
|
|||||||
}
|
}
|
||||||
function test_same_keys() {
|
function test_same_keys() {
|
||||||
$array = ["a" => 42, "b" => "tesxt"]; $arrayKeys = array_keys($array);
|
$array = ["a" => 42, "b" => "tesxt"]; $arrayKeys = array_keys($array);
|
||||||
$missingArray = ["c" => true]; $missingArrayKeys = array_keys($missingArray);
|
$xarray = ["parasite0", "a" => 42, "parasite1", "b" => "tesxt"]; $xarrayKeys = array_keys($array);
|
||||||
$ref = ["a" => "int", "b" => "text"]; $refKeys = array_keys($ref);
|
$ref = ["a" => "int", "b" => "text"]; $refKeys = array_keys($ref);
|
||||||
$missingRef = ["c" => "bool"]; $missingRefKeys = array_keys($missingRef);
|
$missingArray = ["c" => true]; $missingKeys = array_keys($missingArray);
|
||||||
$xarray = ["parasite0", "a" => 42, "parasite1", "b" => "tesxt"];
|
$missingRef = ["c" => "bool"]; $missingKeys = array_keys($missingRef);
|
||||||
|
|
||||||
$this->checkKeys(null, null, true, [], [], []);
|
$this->checkKeys(null, null, true, [], [], []);
|
||||||
$this->checkKeys(null, [], true, [], [], []);
|
$this->checkKeys(null, [], true, [], [], []);
|
||||||
@ -29,8 +29,8 @@ class clTest extends TestCase {
|
|||||||
$this->checkKeys($array, [], true, [], $arrayKeys, []);
|
$this->checkKeys($array, [], true, [], $arrayKeys, []);
|
||||||
|
|
||||||
$this->checkKeys($array, $ref, true, $arrayKeys, [], []);
|
$this->checkKeys($array, $ref, true, $arrayKeys, [], []);
|
||||||
$this->checkKeys(cl::merge($array, $missingArray), $ref, true, $arrayKeys, $missingArrayKeys, []);
|
$this->checkKeys(cl::merge($array, $missingArray), $ref, true, $arrayKeys, $missingKeys, []);
|
||||||
$this->checkKeys($array, cl::merge($ref, $missingRef), false, $arrayKeys, [], $missingRefKeys);
|
$this->checkKeys($array, cl::merge($ref, $missingRef), false, $arrayKeys, [], $missingKeys);
|
||||||
|
|
||||||
$this->checkKeys($xarray, $ref, false, $arrayKeys, [0, 1], []);
|
$this->checkKeys($xarray, $ref, false, $arrayKeys, [0, 1], []);
|
||||||
}
|
}
|
||||||
|
@ -295,14 +295,14 @@ namespace nulib\php {
|
|||||||
|
|
||||||
$workf = $func;
|
$workf = $func;
|
||||||
$msg = var_export($func, true)." (strict)";
|
$msg = var_export($func, true)." (strict)";
|
||||||
self::assertSame($verifix1, func::verifix_function($workf, $args, true), "$msg --> verifix");
|
self::assertSame($verifix1, func::verifix_function($workf, true), "$msg --> verifix");
|
||||||
if ($verifix1) {
|
if ($verifix1) {
|
||||||
self::assertSame($func1, $workf, "$msg --> func");
|
self::assertSame($func1, $workf, "$msg --> func");
|
||||||
}
|
}
|
||||||
|
|
||||||
$workf = $func;
|
$workf = $func;
|
||||||
$msg = var_export($func, true)." (lenient)";
|
$msg = var_export($func, true)." (lenient)";
|
||||||
self::assertSame($verifix2, func::verifix_function($workf, $args, false), "$msg --> verifix");
|
self::assertSame($verifix2, func::verifix_function($workf, false), "$msg --> verifix");
|
||||||
if ($verifix2) {
|
if ($verifix2) {
|
||||||
self::assertSame($func2, $workf, "$msg --> func");
|
self::assertSame($func2, $workf, "$msg --> func");
|
||||||
}
|
}
|
||||||
@ -595,7 +595,7 @@ namespace nulib\php {
|
|||||||
|
|
||||||
$workf = $func;
|
$workf = $func;
|
||||||
$msg = var_export($func, true)." (strict)";
|
$msg = var_export($func, true)." (strict)";
|
||||||
self::assertSame($verifix1, func::verifix_static($workf, $args, true, $bound), "$msg --> verifix");
|
self::assertSame($verifix1, func::verifix_static($workf, true, $bound), "$msg --> verifix");
|
||||||
if ($verifix1) {
|
if ($verifix1) {
|
||||||
self::assertSame($bound1, $bound, "$msg --> bound");
|
self::assertSame($bound1, $bound, "$msg --> bound");
|
||||||
self::assertSame($func1, $workf, "$msg --> func");
|
self::assertSame($func1, $workf, "$msg --> func");
|
||||||
@ -603,7 +603,7 @@ namespace nulib\php {
|
|||||||
|
|
||||||
$workf = $func;
|
$workf = $func;
|
||||||
$msg = var_export($func, true)." (lenient)";
|
$msg = var_export($func, true)." (lenient)";
|
||||||
self::assertSame($verifix2, func::verifix_static($workf, $args, false, $bound), "$msg --> verifix");
|
self::assertSame($verifix2, func::verifix_static($workf, false, $bound), "$msg --> verifix");
|
||||||
if ($verifix2) {
|
if ($verifix2) {
|
||||||
self::assertSame($bound2, $bound, "$msg --> bound");
|
self::assertSame($bound2, $bound, "$msg --> bound");
|
||||||
self::assertSame($func2, $workf, "$msg --> func");
|
self::assertSame($func2, $workf, "$msg --> func");
|
||||||
@ -894,7 +894,7 @@ namespace nulib\php {
|
|||||||
|
|
||||||
$workf = $func;
|
$workf = $func;
|
||||||
$msg = var_export($func, true)." (strict)";
|
$msg = var_export($func, true)." (strict)";
|
||||||
self::assertSame($verifix1, func::verifix_method($workf, $args, true, $bound), "$msg --> verifix");
|
self::assertSame($verifix1, func::verifix_method($workf, true, $bound), "$msg --> verifix");
|
||||||
if ($verifix1) {
|
if ($verifix1) {
|
||||||
self::assertSame($bound1, $bound, "$msg --> bound");
|
self::assertSame($bound1, $bound, "$msg --> bound");
|
||||||
self::assertSame($func1, $workf, "$msg --> func");
|
self::assertSame($func1, $workf, "$msg --> func");
|
||||||
@ -902,7 +902,7 @@ namespace nulib\php {
|
|||||||
|
|
||||||
$workf = $func;
|
$workf = $func;
|
||||||
$msg = var_export($func, true)." (lenient)";
|
$msg = var_export($func, true)." (lenient)";
|
||||||
self::assertSame($verifix2, func::verifix_method($workf, $args, false, $bound), "$msg --> verifix");
|
self::assertSame($verifix2, func::verifix_method($workf, false, $bound), "$msg --> verifix");
|
||||||
if ($verifix2) {
|
if ($verifix2) {
|
||||||
self::assertSame($bound2, $bound, "$msg --> bound");
|
self::assertSame($bound2, $bound, "$msg --> bound");
|
||||||
self::assertSame($func2, $workf, "$msg --> func");
|
self::assertSame($func2, $workf, "$msg --> func");
|
||||||
|
@ -6,7 +6,7 @@ outil pour gérer les projets PHP
|
|||||||
projets dépendants du projet courant
|
projets dépendants du projet courant
|
||||||
* pver: gestion des versions.
|
* pver: gestion des versions.
|
||||||
calculer la prochaine version en respectant semver
|
calculer la prochaine version en respectant semver
|
||||||
* pmer: gérer les branches de features et hotfixes.
|
* pdev: gérer les branches de features et hotfixes.
|
||||||
* prel: faire une release.
|
* prel: faire une release.
|
||||||
ces outils peuvent agir sur les projets dépendants: faire une release sur un
|
ces outils peuvent agir sur les projets dépendants: faire une release sur un
|
||||||
projet downstream, ou synchroniser la version depuis un projet upstream
|
projet downstream, ou synchroniser la version depuis un projet upstream
|
||||||
|
Loading…
x
Reference in New Issue
Block a user