Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
85df50de07 | |||
8080dfae5a | |||
5b3d915a2b | |||
34ef2b7bf5 | |||
df7cd5b127 | |||
cadce02b2c | |||
6b4a3530b6 | |||
0d6892220c | |||
1917607086 |
1
.idea/nulib-base.iml
generated
1
.idea/nulib-base.iml
generated
@ -4,7 +4,6 @@
|
|||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<sourceFolder url="file://$MODULE_DIR$/php/src" isTestSource="false" packagePrefix="nulib\" />
|
<sourceFolder url="file://$MODULE_DIR$/php/src" isTestSource="false" packagePrefix="nulib\" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/php/tests" isTestSource="true" packagePrefix="nulib\" />
|
<sourceFolder url="file://$MODULE_DIR$/php/tests" isTestSource="true" packagePrefix="nulib\" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/php/vendor" />
|
<excludeFolder url="file://$MODULE_DIR$/php/vendor" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
|
14
.idea/php-test-framework.xml
generated
14
.idea/php-test-framework.xml
generated
@ -1,14 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="PhpTestFrameworkVersionCache">
|
|
||||||
<tools_cache>
|
|
||||||
<tool tool_name="PHPUnit">
|
|
||||||
<cache>
|
|
||||||
<versions>
|
|
||||||
<info id="Local/php/vendor/autoload.php" version="9.6.23" />
|
|
||||||
</versions>
|
|
||||||
</cache>
|
|
||||||
</tool>
|
|
||||||
</tools_cache>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
12
.idea/php.xml
generated
12
.idea/php.xml
generated
@ -1,10 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="MessDetector">
|
|
||||||
<phpmd_settings>
|
|
||||||
<phpmd_by_interpreter asDefaultInterpreter="true" interpreter_id="846389f7-9fb5-4173-a868-1dc6b8fbb3fa" timeout="30000" />
|
|
||||||
</phpmd_settings>
|
|
||||||
</component>
|
|
||||||
<component name="MessDetectorOptionsConfiguration">
|
<component name="MessDetectorOptionsConfiguration">
|
||||||
<option name="transferred" value="true" />
|
<option name="transferred" value="true" />
|
||||||
</component>
|
</component>
|
||||||
@ -15,11 +10,6 @@
|
|||||||
<option name="highlightLevel" value="WARNING" />
|
<option name="highlightLevel" value="WARNING" />
|
||||||
<option name="transferred" value="true" />
|
<option name="transferred" value="true" />
|
||||||
</component>
|
</component>
|
||||||
<component name="PhpCodeSniffer">
|
|
||||||
<phpcs_settings>
|
|
||||||
<phpcs_by_interpreter asDefaultInterpreter="true" interpreter_id="846389f7-9fb5-4173-a868-1dc6b8fbb3fa" timeout="30000" />
|
|
||||||
</phpcs_settings>
|
|
||||||
</component>
|
|
||||||
<component name="PhpIncludePathManager">
|
<component name="PhpIncludePathManager">
|
||||||
<include_path>
|
<include_path>
|
||||||
<path value="$PROJECT_DIR$/php/vendor/symfony/polyfill-ctype" />
|
<path value="$PROJECT_DIR$/php/vendor/symfony/polyfill-ctype" />
|
||||||
@ -65,7 +55,7 @@
|
|||||||
</component>
|
</component>
|
||||||
<component name="PhpUnit">
|
<component name="PhpUnit">
|
||||||
<phpunit_settings>
|
<phpunit_settings>
|
||||||
<PhpUnitSettings custom_loader_path="$PROJECT_DIR$/php/vendor/autoload.php" phpunit_phar_path="" />
|
<PhpUnitSettings configuration_file_path="$PROJECT_DIR$/php/vendor/sebastian/object-enumerator/phpunit.xml" custom_loader_path="$PROJECT_DIR$/vendor/autoload.php" use_configuration_file="true" />
|
||||||
</phpunit_settings>
|
</phpunit_settings>
|
||||||
</component>
|
</component>
|
||||||
<component name="PsalmOptionsConfiguration">
|
<component name="PsalmOptionsConfiguration">
|
||||||
|
10
.idea/phpunit.xml
generated
10
.idea/phpunit.xml
generated
@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="PHPUnit">
|
|
||||||
<option name="directories">
|
|
||||||
<list>
|
|
||||||
<option value="$PROJECT_DIR$/tests" />
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
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
|
||||||
|
2
.udir
2
.udir
@ -9,7 +9,7 @@ uinc_options=()
|
|||||||
uinc_args=()
|
uinc_args=()
|
||||||
preconfig_scripts=()
|
preconfig_scripts=()
|
||||||
configure_variables=(dest)
|
configure_variables=(dest)
|
||||||
configure_dest_for=(lib/profile.d/nulib)
|
configure_dest_for=(lib/profile.d/nulib-base)
|
||||||
config_scripts=(lib/uinst/conf)
|
config_scripts=(lib/uinst/conf)
|
||||||
install_profiles=true
|
install_profiles=true
|
||||||
profiledir=lib/profile.d
|
profiledir=lib/profile.d
|
||||||
|
@ -38,8 +38,6 @@ echo "commit=$commit"
|
|||||||
# reprendre la valeur affichée par la précédente commande
|
# reprendre la valeur affichée par la précédente commande
|
||||||
commit=XXX
|
commit=XXX
|
||||||
|
|
||||||
pu
|
|
||||||
|
|
||||||
git checkout dev74
|
git checkout dev74
|
||||||
|
|
||||||
git cherry-pick "$commit"
|
git cherry-pick "$commit"
|
||||||
|
@ -18,12 +18,12 @@
|
|||||||
"nulib/php": "*"
|
"nulib/php": "*"
|
||||||
},
|
},
|
||||||
"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": "*",
|
||||||
|
@ -138,9 +138,9 @@ class Capacitor implements ITransactor {
|
|||||||
$this->storage->_reset($this->channel, $recreate);
|
$this->storage->_reset($this->channel, $recreate);
|
||||||
}
|
}
|
||||||
|
|
||||||
function charge($item, $func=null, ?array $args=null, ?array &$row=null): int {
|
function charge($item, $func=null, ?array $args=null, ?array &$values=null): int {
|
||||||
if ($this->subChannels !== null) $this->beginTransaction();
|
if ($this->subChannels !== null) $this->beginTransaction();
|
||||||
return $this->storage->_charge($this->channel, $item, $func, $args, $row);
|
return $this->storage->_charge($this->channel, $item, $func, $args, $values);
|
||||||
}
|
}
|
||||||
|
|
||||||
function discharge(bool $reset=true): Traversable {
|
function discharge(bool $reset=true): Traversable {
|
||||||
|
@ -25,6 +25,8 @@ class CapacitorChannel implements ITransactor {
|
|||||||
|
|
||||||
const EACH_COMMIT_THRESHOLD = 100;
|
const EACH_COMMIT_THRESHOLD = 100;
|
||||||
|
|
||||||
|
const USE_CACHE = false;
|
||||||
|
|
||||||
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);
|
||||||
@ -58,6 +60,7 @@ class CapacitorChannel implements ITransactor {
|
|||||||
$this->tableName = $tableName;
|
$this->tableName = $tableName;
|
||||||
$this->manageTransactions = $manageTransactions ?? static::MANAGE_TRANSACTIONS;
|
$this->manageTransactions = $manageTransactions ?? static::MANAGE_TRANSACTIONS;
|
||||||
$this->eachCommitThreshold = self::verifix_eachCommitThreshold($eachCommitThreshold);
|
$this->eachCommitThreshold = self::verifix_eachCommitThreshold($eachCommitThreshold);
|
||||||
|
$this->useCache = static::USE_CACHE;
|
||||||
$this->setup = false;
|
$this->setup = false;
|
||||||
$this->created = false;
|
$this->created = false;
|
||||||
$columnDefinitions = $this->COLUMN_DEFINITIONS();
|
$columnDefinitions = $this->COLUMN_DEFINITIONS();
|
||||||
@ -108,8 +111,6 @@ class CapacitorChannel implements ITransactor {
|
|||||||
$def = strval($def);
|
$def = strval($def);
|
||||||
if (preg_match('/\bprimary\s+key\b/i', $def)) {
|
if (preg_match('/\bprimary\s+key\b/i', $def)) {
|
||||||
$primaryKeys[] = $col;
|
$primaryKeys[] = $col;
|
||||||
} elseif ($def === "genserial") {
|
|
||||||
$primaryKeys[] = $col;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -165,6 +166,23 @@ class CapacitorChannel implements ITransactor {
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool faut-il passer par le cache pour les requêtes de all(), each()
|
||||||
|
* et delete()?
|
||||||
|
* ça peut être nécessaire avec MySQL/MariaDB si on utilise les requêtes non
|
||||||
|
* bufférisées, et que la fonction manipule la base de données
|
||||||
|
*/
|
||||||
|
protected bool $useCache;
|
||||||
|
|
||||||
|
function isUseCache(): bool {
|
||||||
|
return $this->useCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setUseCache(bool $useCache=true): self {
|
||||||
|
$this->useCache = $useCache;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* initialiser ce channel avant sa première utilisation.
|
* initialiser ce channel avant sa première utilisation.
|
||||||
*/
|
*/
|
||||||
@ -237,10 +255,6 @@ class CapacitorChannel implements ITransactor {
|
|||||||
* Retourner la clé primaire par cette méthode est l'unique moyen de
|
* Retourner la clé primaire par cette méthode est l'unique moyen de
|
||||||
* déclencher une mise à jour plutôt qu'une nouvelle création.
|
* déclencher une mise à jour plutôt qu'une nouvelle création.
|
||||||
*
|
*
|
||||||
* Bien que ce ne soit pas prévu à la base, si on veut modifier $item dans
|
|
||||||
* cette méthode pour des raisons pratiques, il suffit de retournerla valeur
|
|
||||||
* modifiée avec la clé "item"
|
|
||||||
*
|
|
||||||
* Retourner [false] pour annuler le chargement
|
* Retourner [false] pour annuler le chargement
|
||||||
*/
|
*/
|
||||||
function getItemValues($item): ?array {
|
function getItemValues($item): ?array {
|
||||||
@ -263,8 +277,8 @@ class CapacitorChannel implements ITransactor {
|
|||||||
*
|
*
|
||||||
* cette méthode doit être utilisée dans {@link self::onUpdate()}
|
* cette méthode doit être utilisée dans {@link self::onUpdate()}
|
||||||
*/
|
*/
|
||||||
function wasRowModified(array $row, array $prow): bool {
|
function wasRowModified(array $values, array $pvalues): bool {
|
||||||
return $row["item__sum_"] !== $prow["item__sum_"];
|
return $values["item__sum_"] !== $pvalues["item__sum_"];
|
||||||
}
|
}
|
||||||
|
|
||||||
final function serialize($item): ?string {
|
final function serialize($item): ?string {
|
||||||
@ -295,17 +309,17 @@ class CapacitorChannel implements ITransactor {
|
|||||||
return array_combine($sumCols, [$serial, $sum]);
|
return array_combine($sumCols, [$serial, $sum]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function wasSumModified(string $key, $value, array $prow): bool {
|
function wasSumModified(string $key, $value, array $pvalues): bool {
|
||||||
$sumCol = $this->getSumCols($key)[1];
|
$sumCol = $this->getSumCols($key)[1];
|
||||||
$sum = $this->sum(null, $value);
|
$sum = $this->sum(null, $value);
|
||||||
$psum = $prow[$sumCol] ?? $this->sum(null, $prow[$key] ?? null);
|
$psum = $pvalues[$sumCol] ?? $this->sum(null, $pvalues[$key] ?? null);
|
||||||
return $sum !== $psum;
|
return $sum !== $psum;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _wasSumModified(string $key, array $raw, array $praw): bool {
|
function _wasSumModified(string $key, array $row, array $prow): bool {
|
||||||
$sumCol = $this->getSumCols($key)[1];
|
$sumCol = $this->getSumCols($key)[1];
|
||||||
$sum = $raw[$sumCol] ?? null;
|
$sum = $row[$sumCol] ?? null;
|
||||||
$psum = $praw[$sumCol] ?? null;
|
$psum = $prow[$sumCol] ?? null;
|
||||||
return $sum !== $psum;
|
return $sum !== $psum;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,21 +328,21 @@ class CapacitorChannel implements ITransactor {
|
|||||||
* créer un nouvel élément
|
* créer un nouvel élément
|
||||||
*
|
*
|
||||||
* @param mixed $item l'élément à charger
|
* @param mixed $item l'élément à charger
|
||||||
* @param array $row la ligne à créer, calculée à partir de $item et des
|
* @param array $values la ligne à créer, calculée à partir de $item et des
|
||||||
* valeurs retournées par {@link getItemValues()}
|
* valeurs retournées par {@link getItemValues()}
|
||||||
* @return ?array le cas échéant, un tableau non null à merger dans $row et
|
* @return ?array le cas échéant, un tableau non null à merger dans $values et
|
||||||
* utilisé pour provisionner la ligne nouvellement créée.
|
* utilisé pour provisionner la ligne nouvellement créée.
|
||||||
* Retourner [false] pour annuler le chargement (la ligne n'est pas créée)
|
* Retourner [false] pour annuler le chargement (la ligne n'est pas créée)
|
||||||
*
|
*
|
||||||
* Si $item est modifié dans cette méthode, il est possible de le retourner
|
* Si $item est modifié dans cette méthode, il est possible de le retourner
|
||||||
* avec la clé "item" pour mettre à jour la colonne correspondante.
|
* avec la clé "item" pour mettre à jour la ligne correspondante.
|
||||||
*
|
*
|
||||||
* la création ou la mise à jour est uniquement décidée en fonction des
|
* la création ou la mise à jour est uniquement décidée en fonction des
|
||||||
* valeurs calculées par {@link self::getItemValues()}. Bien que cette méthode
|
* valeurs calculées par {@link self::getItemValues()}. Bien que cette méthode
|
||||||
* peut techniquement retourner de nouvelles valeurs pour la clé primaire, ça
|
* peut techniquement retourner de nouvelles valeurs pour la clé primaire, ça
|
||||||
* risque de créer des doublons
|
* risque de créer des doublons
|
||||||
*/
|
*/
|
||||||
function onCreate($item, array $row, ?array $alwaysNull): ?array {
|
function onCreate($item, array $values, ?array $alwaysNull): ?array {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,12 +351,12 @@ class CapacitorChannel implements ITransactor {
|
|||||||
* mettre à jour un élément existant
|
* mettre à jour un élément existant
|
||||||
*
|
*
|
||||||
* @param mixed $item l'élément à charger
|
* @param mixed $item l'élément à charger
|
||||||
* @param array $row la nouvelle ligne, calculée à partir de $item et
|
* @param array $values la nouvelle ligne, calculée à partir de $item et
|
||||||
* des valeurs retournées par {@link getItemValues()}
|
* des valeurs retournées par {@link getItemValues()}
|
||||||
* @param array $prow la précédente ligne, chargée depuis la base de
|
* @param array $pvalues la précédente ligne, chargée depuis la base de
|
||||||
* données
|
* données
|
||||||
* @return ?array null s'il ne faut pas mettre à jour la ligne. sinon, ce
|
* @return ?array null s'il ne faut pas mettre à jour la ligne. sinon, ce
|
||||||
* tableau est mergé dans $row puis utilisé pour mettre à jour la ligne
|
* tableau est mergé dans $values puis utilisé pour mettre à jour la ligne
|
||||||
* existante
|
* existante
|
||||||
* Retourner [false] pour annuler le chargement (la ligne n'est pas mise à
|
* Retourner [false] pour annuler le chargement (la ligne n'est pas mise à
|
||||||
* jour)
|
* jour)
|
||||||
@ -351,7 +365,7 @@ class CapacitorChannel implements ITransactor {
|
|||||||
* - La clé primaire (il s'agit généralement de "id_") ne peut pas être
|
* - La clé primaire (il s'agit généralement de "id_") ne peut pas être
|
||||||
* modifiée. si elle est retournée, elle est ignorée
|
* modifiée. si elle est retournée, elle est ignorée
|
||||||
*/
|
*/
|
||||||
function onUpdate($item, array $row, array $prow): ?array {
|
function onUpdate($item, array $values, array $pvalues): ?array {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,8 +373,8 @@ class CapacitorChannel implements ITransactor {
|
|||||||
* méthode appelée lors du parcours des éléments avec
|
* méthode appelée lors du parcours des éléments avec
|
||||||
* {@link Capacitor::each()}
|
* {@link Capacitor::each()}
|
||||||
*
|
*
|
||||||
* @param ?array $row la ligne courante. l'élément courant est accessible via
|
* @param mixed $item l'élément courant
|
||||||
* $row["item"]
|
* @param ?array $values la ligne courante
|
||||||
* @return ?array le cas échéant, un tableau non null utilisé pour mettre à
|
* @return ?array le cas échéant, un tableau non null utilisé pour mettre à
|
||||||
* jour la ligne courante
|
* jour la ligne courante
|
||||||
*
|
*
|
||||||
@ -368,7 +382,7 @@ class CapacitorChannel implements ITransactor {
|
|||||||
* - La clé primaire (il s'agit généralement de "id_") ne peut pas être
|
* - La clé primaire (il s'agit généralement de "id_") ne peut pas être
|
||||||
* modifiée. si elle est retournée, elle est ignorée
|
* modifiée. si elle est retournée, elle est ignorée
|
||||||
*/
|
*/
|
||||||
function onEach(array $row): ?array {
|
function onEach($item, array $values): ?array {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const onEach = "->".[self::class, "onEach"][1];
|
const onEach = "->".[self::class, "onEach"][1];
|
||||||
@ -377,11 +391,11 @@ class CapacitorChannel implements ITransactor {
|
|||||||
* méthode appelée lors du parcours des éléments avec
|
* méthode appelée lors du parcours des éléments avec
|
||||||
* {@link Capacitor::delete()}
|
* {@link Capacitor::delete()}
|
||||||
*
|
*
|
||||||
* @param ?array $row la ligne courante. l'élément courant est accessible via
|
* @param mixed $item l'élément courant
|
||||||
* $row["item"]
|
* @param ?array $values la ligne courante
|
||||||
* @return bool true s'il faut supprimer la ligne, false sinon
|
* @return bool true s'il faut supprimer la ligne, false sinon
|
||||||
*/
|
*/
|
||||||
function onDelete(array $row): bool {
|
function onDelete($item, array $values): bool {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const onDelete = "->".[self::class, "onDelete"][1];
|
const onDelete = "->".[self::class, "onDelete"][1];
|
||||||
@ -440,8 +454,8 @@ class CapacitorChannel implements ITransactor {
|
|||||||
$this->capacitor->reset($recreate);
|
$this->capacitor->reset($recreate);
|
||||||
}
|
}
|
||||||
|
|
||||||
function charge($item, $func=null, ?array $args=null, ?array &$row=null): int {
|
function charge($item, $func=null, ?array $args=null, ?array &$values=null): int {
|
||||||
return $this->capacitor->charge($item, $func, $args, $row);
|
return $this->capacitor->charge($item, $func, $args, $values);
|
||||||
}
|
}
|
||||||
|
|
||||||
function discharge(bool $reset=true): Traversable {
|
function discharge(bool $reset=true): Traversable {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace nulib\db;
|
namespace nulib\db;
|
||||||
|
|
||||||
use nulib\A;
|
|
||||||
use nulib\cl;
|
use nulib\cl;
|
||||||
use nulib\db\_private\_migration;
|
use nulib\db\_private\_migration;
|
||||||
use nulib\php\func;
|
use nulib\php\func;
|
||||||
@ -33,43 +32,21 @@ abstract class CapacitorStorage {
|
|||||||
return $channel;
|
return $channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PRIMARY_KEY_DEFINITION = [
|
/** DOIT être défini dans les classes dérivées */
|
||||||
"id_" => "genserial",
|
const PRIMARY_KEY_DEFINITION = null;
|
||||||
];
|
|
||||||
|
|
||||||
# les définitions sont par défaut pour MariaDB/MySQL
|
|
||||||
const SERDATA_DEFINITION = "mediumtext";
|
const SERDATA_DEFINITION = "mediumtext";
|
||||||
const SERSUM_DEFINITION = "varchar(40)";
|
const SERSUM_DEFINITION = "varchar(40)";
|
||||||
const SERTS_DEFINITION = "datetime";
|
const SERTS_DEFINITION = "datetime";
|
||||||
const GENSERIAL_DEFINITION = "integer primary key auto_increment";
|
|
||||||
const GENLIC_DEFINITION = "varchar(80)";
|
|
||||||
const GENLIB_DEFINITION = "varchar(255)";
|
|
||||||
const GENTEXT_DEFINITION = "mediumtext";
|
|
||||||
const GENBOOL_DEFINITION = "integer(1)";
|
|
||||||
const GENUUID_DEFINITION = "varchar(36)";
|
|
||||||
|
|
||||||
protected static function gencol($def): string {
|
protected static function sercol($def): string {
|
||||||
if (!is_string($def)) $def = strval($def);
|
if (!is_string($def)) $def = strval($def);
|
||||||
$def = trim($def);
|
|
||||||
$parts = preg_split('/\s+/', $def, 2);
|
|
||||||
if (count($parts) == 2) {
|
|
||||||
$def = $parts[0];
|
|
||||||
$rest = " $parts[1]";
|
|
||||||
} else {
|
|
||||||
$rest = null;
|
|
||||||
}
|
|
||||||
switch ($def) {
|
switch ($def) {
|
||||||
case "serdata": $def = static::SERDATA_DEFINITION; break;
|
case "serdata": $def = static::SERDATA_DEFINITION; break;
|
||||||
case "sersum": $def = static::SERSUM_DEFINITION; break;
|
case "sersum": $def = static::SERSUM_DEFINITION; break;
|
||||||
case "serts": $def = static::SERTS_DEFINITION; break;
|
case "serts": $def = static::SERTS_DEFINITION; break;
|
||||||
case "genserial": $def = static::GENSERIAL_DEFINITION; break;
|
|
||||||
case "genlic": $def = static::GENLIC_DEFINITION; break;
|
|
||||||
case "genlib": $def = static::GENLIB_DEFINITION; break;
|
|
||||||
case "gentext": $def = static::GENTEXT_DEFINITION; break;
|
|
||||||
case "genbool": $def = static::GENBOOL_DEFINITION; break;
|
|
||||||
case "genuuid": $def = static::GENUUID_DEFINITION; break;
|
|
||||||
}
|
}
|
||||||
return "$def$rest";
|
return $def;
|
||||||
}
|
}
|
||||||
|
|
||||||
const COLUMN_DEFINITIONS = [
|
const COLUMN_DEFINITIONS = [
|
||||||
@ -104,7 +81,7 @@ abstract class CapacitorStorage {
|
|||||||
$mindex++;
|
$mindex++;
|
||||||
} else {
|
} else {
|
||||||
if ($mdef) {
|
if ($mdef) {
|
||||||
$definitions[$mcol] = self::gencol($mdef);
|
$definitions[$mcol] = self::sercol($mdef);
|
||||||
} else {
|
} else {
|
||||||
unset($definitions[$mcol]);
|
unset($definitions[$mcol]);
|
||||||
}
|
}
|
||||||
@ -115,7 +92,7 @@ abstract class CapacitorStorage {
|
|||||||
$constraints[] = $def;
|
$constraints[] = $def;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$definitions[$col] = self::gencol($def);
|
$definitions[$col] = self::sercol($def);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cl::merge($definitions, $constraints);
|
return cl::merge($definitions, $constraints);
|
||||||
@ -125,35 +102,9 @@ abstract class CapacitorStorage {
|
|||||||
return $channel->getMigration();
|
return $channel->getMigration();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** sérialiser les valeurs qui doivent l'être dans $row */
|
/** sérialiser les valeurs qui doivent l'être dans $values */
|
||||||
protected function serialize(CapacitorChannel $channel, ?array $row): ?array {
|
protected function serialize(CapacitorChannel $channel, ?array $values): ?array {
|
||||||
if ($row === null) return null;
|
if ($values === null) return null;
|
||||||
$cols = $this->ColumnDefinitions($channel);
|
|
||||||
$index = 0;
|
|
||||||
$raw = [];
|
|
||||||
foreach (array_keys($cols) as $col) {
|
|
||||||
$key = $col;
|
|
||||||
if ($key === $index) {
|
|
||||||
$index++;
|
|
||||||
} elseif ($channel->isSerialCol($key)) {
|
|
||||||
[$serialCol, $sumCol] = $channel->getSumCols($key);
|
|
||||||
if (array_key_exists($key, $row)) {
|
|
||||||
$sum = $channel->getSum($key, $row[$key]);
|
|
||||||
$raw[$serialCol] = $sum[$serialCol];
|
|
||||||
if (array_key_exists($sumCol, $cols)) {
|
|
||||||
$raw[$sumCol] = $sum[$sumCol];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} elseif (array_key_exists($key, $row)) {
|
|
||||||
$raw[$col] = $row[$key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $raw;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** désérialiser les valeurs qui doivent l'être dans $values */
|
|
||||||
protected function unserialize(CapacitorChannel $channel, ?array $raw): ?array {
|
|
||||||
if ($raw === null) return null;
|
|
||||||
$cols = $this->ColumnDefinitions($channel);
|
$cols = $this->ColumnDefinitions($channel);
|
||||||
$index = 0;
|
$index = 0;
|
||||||
$row = [];
|
$row = [];
|
||||||
@ -161,18 +112,44 @@ abstract class CapacitorStorage {
|
|||||||
$key = $col;
|
$key = $col;
|
||||||
if ($key === $index) {
|
if ($key === $index) {
|
||||||
$index++;
|
$index++;
|
||||||
} elseif (!array_key_exists($col, $raw)) {
|
|
||||||
} elseif ($channel->isSerialCol($key)) {
|
} elseif ($channel->isSerialCol($key)) {
|
||||||
$value = $raw[$col];
|
[$serialCol, $sumCol] = $channel->getSumCols($key);
|
||||||
if ($value !== null) $value = $channel->unserialize($value);
|
if (array_key_exists($key, $values)) {
|
||||||
$row[$key] = $value;
|
$sum = $channel->getSum($key, $values[$key]);
|
||||||
} else {
|
$row[$serialCol] = $sum[$serialCol];
|
||||||
$row[$key] = $raw[$col];
|
if (array_key_exists($sumCol, $cols)) {
|
||||||
|
$row[$sumCol] = $sum[$sumCol];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif (array_key_exists($key, $values)) {
|
||||||
|
$row[$col] = $values[$key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $row;
|
return $row;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** désérialiser les valeurs qui doivent l'être dans $values */
|
||||||
|
protected function unserialize(CapacitorChannel $channel, ?array $row): ?array {
|
||||||
|
if ($row === null) return null;
|
||||||
|
$cols = $this->ColumnDefinitions($channel);
|
||||||
|
$index = 0;
|
||||||
|
$values = [];
|
||||||
|
foreach (array_keys($cols) as $col) {
|
||||||
|
$key = $col;
|
||||||
|
if ($key === $index) {
|
||||||
|
$index++;
|
||||||
|
} elseif (!array_key_exists($col, $row)) {
|
||||||
|
} elseif ($channel->isSerialCol($key)) {
|
||||||
|
$value = $row[$col];
|
||||||
|
if ($value !== null) $value = $channel->unserialize($value);
|
||||||
|
$values[$key] = $value;
|
||||||
|
} else {
|
||||||
|
$values[$key] = $row[$col];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $values;
|
||||||
|
}
|
||||||
|
|
||||||
function getPrimaryKeys(CapacitorChannel $channel): array {
|
function getPrimaryKeys(CapacitorChannel $channel): array {
|
||||||
$primaryKeys = $channel->getPrimaryKeys();
|
$primaryKeys = $channel->getPrimaryKeys();
|
||||||
if ($primaryKeys === null) $primaryKeys = ["id_"];
|
if ($primaryKeys === null) $primaryKeys = ["id_"];
|
||||||
@ -238,22 +215,6 @@ abstract class CapacitorStorage {
|
|||||||
"class_name" => "varchar",
|
"class_name" => "varchar",
|
||||||
];
|
];
|
||||||
|
|
||||||
function channelExists(string $name, ?array &$raw=null): bool {
|
|
||||||
$raw = $this->db()->one([
|
|
||||||
"select",
|
|
||||||
"from" => static::CHANNELS_TABLE,
|
|
||||||
"where" => ["name" => $name],
|
|
||||||
]);
|
|
||||||
return $raw !== null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getChannels(): iterable {
|
|
||||||
return $this->db()->all([
|
|
||||||
"select",
|
|
||||||
"from" => static::CHANNELS_TABLE,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function _createChannelsSql(): array {
|
protected function _createChannelsSql(): array {
|
||||||
return [
|
return [
|
||||||
"create table if not exists",
|
"create table if not exists",
|
||||||
@ -355,7 +316,7 @@ abstract class CapacitorStorage {
|
|||||||
* en fonction du type d'opération: création ou mise à jour
|
* en fonction du type d'opération: création ou mise à jour
|
||||||
*
|
*
|
||||||
* Dans les deux cas, si la fonction retourne un tableau, il est utilisé pour
|
* Dans les deux cas, si la fonction retourne un tableau, il est utilisé pour
|
||||||
* modifier les valeurs insérées/mises à jour. De plus, $row obtient la
|
* modifier les valeurs insérées/mises à jour. De plus, $values obtient la
|
||||||
* valeur finale des données insérées/mises à jour
|
* valeur finale des données insérées/mises à jour
|
||||||
*
|
*
|
||||||
* Si $args est renseigné, il est ajouté aux arguments utilisés pour appeler
|
* Si $args est renseigné, il est ajouté aux arguments utilisés pour appeler
|
||||||
@ -366,27 +327,23 @@ abstract class CapacitorStorage {
|
|||||||
* @return int 1 si l'objet a été chargé ou mis à jour, 0 s'il existait
|
* @return int 1 si l'objet a été chargé ou mis à jour, 0 s'il existait
|
||||||
* déjà à l'identique dans le canal
|
* déjà à l'identique dans le canal
|
||||||
*/
|
*/
|
||||||
function _charge(CapacitorChannel $channel, $item, $func, ?array $args, ?array &$row=null): int {
|
function _charge(CapacitorChannel $channel, $item, $func, ?array $args, ?array &$values=null): int {
|
||||||
$this->_create($channel);
|
$this->_create($channel);
|
||||||
$tableName = $channel->getTableName();
|
$tableName = $channel->getTableName();
|
||||||
$db = $this->db();
|
$db = $this->db();
|
||||||
$args ??= [];
|
$args ??= [];
|
||||||
|
|
||||||
$row = func::call([$channel, "getItemValues"], $item, ...$args);
|
$values = func::call([$channel, "getItemValues"], $item, ...$args);
|
||||||
if ($row === [false]) return 0;
|
if ($values === [false]) return 0;
|
||||||
|
|
||||||
if ($row !== null && array_key_exists("item", $row)) {
|
$row = cl::merge(
|
||||||
$item = A::pop($row, "item");
|
|
||||||
}
|
|
||||||
|
|
||||||
$raw = cl::merge(
|
|
||||||
$channel->getSum("item", $item),
|
$channel->getSum("item", $item),
|
||||||
$this->serialize($channel, $row));
|
$this->serialize($channel, $values));
|
||||||
$praw = null;
|
$prow = null;
|
||||||
$rowIds = $this->getRowIds($channel, $raw, $primaryKeys);
|
$rowIds = $this->getRowIds($channel, $row, $primaryKeys);
|
||||||
if ($rowIds !== null) {
|
if ($rowIds !== null) {
|
||||||
# modification
|
# modification
|
||||||
$praw = $db->one([
|
$prow = $db->one([
|
||||||
"select",
|
"select",
|
||||||
"from" => $tableName,
|
"from" => $tableName,
|
||||||
"where" => $rowIds,
|
"where" => $rowIds,
|
||||||
@ -395,47 +352,47 @@ abstract class CapacitorStorage {
|
|||||||
|
|
||||||
$now = date("Y-m-d H:i:s");
|
$now = date("Y-m-d H:i:s");
|
||||||
$insert = null;
|
$insert = null;
|
||||||
if ($praw === null) {
|
if ($prow === null) {
|
||||||
# création
|
# création
|
||||||
$raw = cl::merge($raw, [
|
$row = cl::merge($row, [
|
||||||
"created_" => $now,
|
"created_" => $now,
|
||||||
"modified_" => $now,
|
"modified_" => $now,
|
||||||
]);
|
]);
|
||||||
$insert = true;
|
$insert = true;
|
||||||
$initFunc = func::with([$channel, "onCreate"], $args);
|
$initFunc = func::with([$channel, "onCreate"], $args);
|
||||||
$row = $this->unserialize($channel, $raw);
|
$values = $this->unserialize($channel, $row);
|
||||||
$prow = null;
|
$pvalues = null;
|
||||||
} else {
|
} else {
|
||||||
# modification
|
# modification
|
||||||
# intégrer autant que possible les valeurs de praw dans raw, de façon que
|
# intégrer autant que possible les valeurs de prow dans row, de façon que
|
||||||
# l'utilisateur puisse voir clairement ce qui a été modifié
|
# l'utilisateur puisse voir clairement ce qui a été modifié
|
||||||
if ($channel->_wasSumModified("item", $raw, $praw)) {
|
if ($channel->_wasSumModified("item", $row, $prow)) {
|
||||||
$insert = false;
|
$insert = false;
|
||||||
$raw = cl::merge($praw, $raw, [
|
$row = cl::merge($prow, $row, [
|
||||||
"modified_" => $now,
|
"modified_" => $now,
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
$raw = cl::merge($praw, $raw);
|
$row = cl::merge($prow, $row);
|
||||||
}
|
}
|
||||||
$initFunc = func::with([$channel, "onUpdate"], $args);
|
$initFunc = func::with([$channel, "onUpdate"], $args);
|
||||||
$row = $this->unserialize($channel, $raw);
|
$values = $this->unserialize($channel, $row);
|
||||||
$prow = $this->unserialize($channel, $praw);
|
$pvalues = $this->unserialize($channel, $prow);
|
||||||
}
|
}
|
||||||
|
|
||||||
$updates = $initFunc->prependArgs([$item, $row, $prow])->invoke();
|
$updates = $initFunc->prependArgs([$item, $values, $pvalues])->invoke();
|
||||||
if ($updates === [false]) return 0;
|
if ($updates === [false]) return 0;
|
||||||
if (is_array($updates) && $updates) {
|
if (is_array($updates) && $updates) {
|
||||||
if ($insert === null) $insert = false;
|
if ($insert === null) $insert = false;
|
||||||
if (!array_key_exists("modified_", $updates)) {
|
if (!array_key_exists("modified_", $updates)) {
|
||||||
$updates["modified_"] = $now;
|
$updates["modified_"] = $now;
|
||||||
}
|
}
|
||||||
$row = cl::merge($row, $updates);
|
$values = cl::merge($values, $updates);
|
||||||
$raw = cl::merge($raw, $this->serialize($channel, $updates));
|
$row = cl::merge($row, $this->serialize($channel, $updates));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($func !== null) {
|
if ($func !== null) {
|
||||||
$updates = func::with($func)
|
$updates = func::with($func)
|
||||||
->prependArgs([$item, $row, $prow])
|
->prependArgs([$item, $values, $pvalues])
|
||||||
->bind($channel)
|
->bind($channel)
|
||||||
->invoke();
|
->invoke();
|
||||||
if ($updates === [false]) return 0;
|
if ($updates === [false]) return 0;
|
||||||
@ -444,8 +401,8 @@ abstract class CapacitorStorage {
|
|||||||
if (!array_key_exists("modified_", $updates)) {
|
if (!array_key_exists("modified_", $updates)) {
|
||||||
$updates["modified_"] = $now;
|
$updates["modified_"] = $now;
|
||||||
}
|
}
|
||||||
$row = cl::merge($row, $updates);
|
$values = cl::merge($values, $updates);
|
||||||
$raw = cl::merge($raw, $this->serialize($channel, $updates));
|
$row = cl::merge($row, $this->serialize($channel, $updates));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -464,23 +421,25 @@ abstract class CapacitorStorage {
|
|||||||
$id = $db->exec([
|
$id = $db->exec([
|
||||||
"insert",
|
"insert",
|
||||||
"into" => $tableName,
|
"into" => $tableName,
|
||||||
"values" => $raw,
|
"values" => $row,
|
||||||
]);
|
]);
|
||||||
if (count($primaryKeys) == 1 && $rowIds === null) {
|
if (count($primaryKeys) == 1 && $rowIds === null) {
|
||||||
# mettre à jour avec l'id généré
|
# mettre à jour avec l'id généré
|
||||||
$row[$primaryKeys[0]] = $id;
|
$values[$primaryKeys[0]] = $id;
|
||||||
}
|
}
|
||||||
$nbModified = 1;
|
$nbModified = 1;
|
||||||
} else {
|
} else {
|
||||||
# calculer ce qui a changé pour ne mettre à jour que le nécessaire
|
# calculer ce qui a changé pour ne mettre à jour que le nécessaire
|
||||||
$updates = [];
|
$updates = [];
|
||||||
foreach ($raw as $col => $value) {
|
foreach ($row as $col => $value) {
|
||||||
if (array_key_exists($col, $rowIds)) {
|
if (array_key_exists($col, $rowIds)) {
|
||||||
# ne jamais mettre à jour la clé primaire
|
# ne jamais mettre à jour la clé primaire
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$pvalue = $praw[$col] ?? null;
|
$pvalue = $prow[$col] ?? null;
|
||||||
if ($value !== $pvalue) $updates[$col] = $value;
|
if ($value !== ($pvalue)) {
|
||||||
|
$updates[$col] = $value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (count($updates) == 1 && array_key_first($updates) == "modified_") {
|
if (count($updates) == 1 && array_key_first($updates) == "modified_") {
|
||||||
# si l'unique modification porte sur la date de modification, alors
|
# si l'unique modification porte sur la date de modification, alors
|
||||||
@ -508,22 +467,19 @@ abstract class CapacitorStorage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function charge(?string $channel, $item, $func=null, ?array $args=null, ?array &$row=null): int {
|
function charge(?string $channel, $item, $func=null, ?array $args=null, ?array &$values=null): int {
|
||||||
return $this->_charge($this->getChannel($channel), $item, $func, $args, $row);
|
return $this->_charge($this->getChannel($channel), $item, $func, $args, $values);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** décharger les données du canal spécifié */
|
||||||
* décharger les données du canal spécifié. seul la valeur de $item est
|
|
||||||
* fournie
|
|
||||||
*/
|
|
||||||
function _discharge(CapacitorChannel $channel, bool $reset=true): Traversable {
|
function _discharge(CapacitorChannel $channel, bool $reset=true): Traversable {
|
||||||
$this->_create($channel);
|
$this->_create($channel);
|
||||||
$raws = $this->db()->all([
|
$rows = $this->db()->all([
|
||||||
"select item__",
|
"select item__",
|
||||||
"from" => $channel->getTableName(),
|
"from" => $channel->getTableName(),
|
||||||
]);
|
]);
|
||||||
foreach ($raws as $raw) {
|
foreach ($rows as $row) {
|
||||||
yield unserialize($raw['item__']);
|
yield unserialize($row['item__']);
|
||||||
}
|
}
|
||||||
if ($reset) $this->_reset($channel);
|
if ($reset) $this->_reset($channel);
|
||||||
}
|
}
|
||||||
@ -592,34 +548,45 @@ abstract class CapacitorStorage {
|
|||||||
if ($filter === null) throw ValueException::null("filter");
|
if ($filter === null) throw ValueException::null("filter");
|
||||||
$this->_create($channel);
|
$this->_create($channel);
|
||||||
$this->verifixFilter($channel, $filter);
|
$this->verifixFilter($channel, $filter);
|
||||||
$raw = $this->db()->one(cl::merge([
|
$row = $this->db()->one(cl::merge([
|
||||||
"select",
|
"select",
|
||||||
"from" => $channel->getTableName(),
|
"from" => $channel->getTableName(),
|
||||||
"where" => $filter,
|
"where" => $filter,
|
||||||
], $mergeQuery));
|
], $mergeQuery));
|
||||||
return $this->unserialize($channel, $raw);
|
return $this->unserialize($channel, $row);
|
||||||
}
|
}
|
||||||
|
|
||||||
function one(?string $channel, $filter, ?array $mergeQuery=null): ?array {
|
function one(?string $channel, $filter, ?array $mergeQuery=null): ?array {
|
||||||
return $this->_one($this->getChannel($channel), $filter, $mergeQuery);
|
return $this->_one($this->getChannel($channel), $filter, $mergeQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function _allCached(string $id, CapacitorChannel $channel, $filter, ?array $mergeQuery=null): Traversable {
|
||||||
|
$this->_create($channel);
|
||||||
|
$this->verifixFilter($channel, $filter);
|
||||||
|
$rows = $this->db()->all(cl::merge([
|
||||||
|
"select",
|
||||||
|
"from" => $channel->getTableName(),
|
||||||
|
"where" => $filter,
|
||||||
|
], $mergeQuery), null, $this->getPrimaryKeys($channel));
|
||||||
|
if ($channel->isUseCache()) {
|
||||||
|
$cacheIds = [$id, get_class($channel)];
|
||||||
|
cache::get()->resetCached($cacheIds);
|
||||||
|
$rows = cache::new(null, $cacheIds, function() use ($rows) {
|
||||||
|
yield from $rows;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
foreach ($rows as $key => $row) {
|
||||||
|
yield $key => $this->unserialize($channel, $row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* obtenir les lignes correspondant au filtre sur le canal spécifié
|
* obtenir les lignes correspondant au filtre sur le canal spécifié
|
||||||
*
|
*
|
||||||
* si $filter n'est pas un tableau, il est transformé en ["id_" => $filter]
|
* si $filter n'est pas un tableau, il est transformé en ["id_" => $filter]
|
||||||
*/
|
*/
|
||||||
function _all(CapacitorChannel $channel, $filter, ?array $mergeQuery=null): Traversable {
|
function _all(CapacitorChannel $channel, $filter, ?array $mergeQuery=null): Traversable {
|
||||||
$this->_create($channel);
|
return $this->_allCached("all", $channel, $filter, $mergeQuery);
|
||||||
$this->verifixFilter($channel, $filter);
|
|
||||||
$raws = $this->db()->all(cl::merge([
|
|
||||||
"select",
|
|
||||||
"from" => $channel->getTableName(),
|
|
||||||
"where" => $filter,
|
|
||||||
], $mergeQuery), null, $this->getPrimaryKeys($channel));
|
|
||||||
foreach ($raws as $key => $raw) {
|
|
||||||
yield $key => $this->unserialize($channel, $raw);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function all(?string $channel, $filter, $mergeQuery=null): Traversable {
|
function all(?string $channel, $filter, $mergeQuery=null): Traversable {
|
||||||
@ -655,10 +622,10 @@ abstract class CapacitorStorage {
|
|||||||
$tableName = $channel->getTableName();
|
$tableName = $channel->getTableName();
|
||||||
try {
|
try {
|
||||||
$args ??= [];
|
$args ??= [];
|
||||||
$rows = $this->_all($channel, $filter, $mergeQuery);
|
$all = $this->_allCached("each", $channel, $filter, $mergeQuery);
|
||||||
foreach ($rows as $row) {
|
foreach ($all as $values) {
|
||||||
$rowIds = $this->getRowIds($channel, $row);
|
$rowIds = $this->getRowIds($channel, $values);
|
||||||
$updates = $onEach->invoke([$row, ...$args]);
|
$updates = $onEach->invoke([$values["item"], $values, ...$args]);
|
||||||
if (is_array($updates) && $updates) {
|
if (is_array($updates) && $updates) {
|
||||||
if (!array_key_exists("modified_", $updates)) {
|
if (!array_key_exists("modified_", $updates)) {
|
||||||
$updates["modified_"] = date("Y-m-d H:i:s");
|
$updates["modified_"] = date("Y-m-d H:i:s");
|
||||||
@ -722,10 +689,10 @@ abstract class CapacitorStorage {
|
|||||||
$tableName = $channel->getTableName();
|
$tableName = $channel->getTableName();
|
||||||
try {
|
try {
|
||||||
$args ??= [];
|
$args ??= [];
|
||||||
$rows = $this->_all($channel, $filter);
|
$all = $this->_allCached("delete", $channel, $filter);
|
||||||
foreach ($rows as $row) {
|
foreach ($all as $values) {
|
||||||
$rowIds = $this->getRowIds($channel, $row);
|
$rowIds = $this->getRowIds($channel, $values);
|
||||||
$shouldDelete = boolval($onDelete->invoke([$row, ...$args]));
|
$shouldDelete = boolval($onDelete->invoke([$values["item"], $values, ...$args]));
|
||||||
if ($shouldDelete) {
|
if ($shouldDelete) {
|
||||||
$db->exec([
|
$db->exec([
|
||||||
"delete",
|
"delete",
|
||||||
|
@ -6,6 +6,7 @@ class _update extends _common {
|
|||||||
"prefix" => "?string",
|
"prefix" => "?string",
|
||||||
"table" => "?string",
|
"table" => "?string",
|
||||||
"schema" => "?array",
|
"schema" => "?array",
|
||||||
|
"cols" => "?array",
|
||||||
"values" => "?array",
|
"values" => "?array",
|
||||||
"where" => "?array",
|
"where" => "?array",
|
||||||
"suffix" => "?string",
|
"suffix" => "?string",
|
||||||
|
@ -19,6 +19,10 @@ class MysqlStorage extends CapacitorStorage {
|
|||||||
return $this->db;
|
return $this->db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PRIMARY_KEY_DEFINITION = [
|
||||||
|
"id_" => "integer primary key auto_increment",
|
||||||
|
];
|
||||||
|
|
||||||
protected function tableExists(string $tableName): bool {
|
protected function tableExists(string $tableName): bool {
|
||||||
$db = $this->db;
|
$db = $this->db;
|
||||||
$found = $db->get([
|
$found = $db->get([
|
||||||
|
@ -9,10 +9,6 @@ class PgsqlStorage extends CapacitorStorage {
|
|||||||
const SERDATA_DEFINITION = "text";
|
const SERDATA_DEFINITION = "text";
|
||||||
const SERSUM_DEFINITION = "varchar(40)";
|
const SERSUM_DEFINITION = "varchar(40)";
|
||||||
const SERTS_DEFINITION = "timestamp";
|
const SERTS_DEFINITION = "timestamp";
|
||||||
const GENSERIAL_DEFINITION = "serial primary key";
|
|
||||||
const GENTEXT_DEFINITION = "text";
|
|
||||||
const GENBOOL_DEFINITION = "boolean";
|
|
||||||
const GENUUID_DEFINITION = "uuid";
|
|
||||||
|
|
||||||
function __construct($pgsql) {
|
function __construct($pgsql) {
|
||||||
$this->db = Pgsql::with($pgsql);
|
$this->db = Pgsql::with($pgsql);
|
||||||
@ -24,6 +20,10 @@ class PgsqlStorage extends CapacitorStorage {
|
|||||||
return $this->db;
|
return $this->db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PRIMARY_KEY_DEFINITION = [
|
||||||
|
"id_" => "serial primary key",
|
||||||
|
];
|
||||||
|
|
||||||
protected function tableExists(string $tableName): bool {
|
protected function tableExists(string $tableName): bool {
|
||||||
if (($index = strpos($tableName, ".")) !== false) {
|
if (($index = strpos($tableName, ".")) !== false) {
|
||||||
$schemaName = substr($tableName, 0, $index);
|
$schemaName = substr($tableName, 0, $index);
|
||||||
|
@ -9,8 +9,6 @@ use nulib\db\CapacitorStorage;
|
|||||||
* Class SqliteStorage
|
* Class SqliteStorage
|
||||||
*/
|
*/
|
||||||
class SqliteStorage extends CapacitorStorage {
|
class SqliteStorage extends CapacitorStorage {
|
||||||
const GENSERIAL_DEFINITION = "integer primary key autoincrement";
|
|
||||||
|
|
||||||
function __construct($sqlite) {
|
function __construct($sqlite) {
|
||||||
$this->db = Sqlite::with($sqlite);
|
$this->db = Sqlite::with($sqlite);
|
||||||
}
|
}
|
||||||
@ -21,6 +19,10 @@ class SqliteStorage extends CapacitorStorage {
|
|||||||
return $this->db;
|
return $this->db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PRIMARY_KEY_DEFINITION = [
|
||||||
|
"id_" => "integer primary key autoincrement",
|
||||||
|
];
|
||||||
|
|
||||||
protected function tableExists(string $tableName): bool {
|
protected function tableExists(string $tableName): bool {
|
||||||
$found = $this->db->get([
|
$found = $this->db->get([
|
||||||
# depuis la version 3.33.0 le nom officiel de la table est sqlite_schema,
|
# depuis la version 3.33.0 le nom officiel de la table est sqlite_schema,
|
||||||
@ -38,6 +40,22 @@ class SqliteStorage extends CapacitorStorage {
|
|||||||
return new _sqliteMigration($migrations, $channel->getName());
|
return new _sqliteMigration($migrations, $channel->getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function channelExists(string $name, ?array &$row=null): bool {
|
||||||
|
$row = $this->db->one([
|
||||||
|
"select",
|
||||||
|
"from" => static::CHANNELS_TABLE,
|
||||||
|
"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 {
|
||||||
$sql = parent::_addToChannelsSql($channel);
|
$sql = parent::_addToChannelsSql($channel);
|
||||||
$sql[0] = "insert or ignore";
|
$sql[0] = "insert or ignore";
|
||||||
|
@ -117,18 +117,4 @@ class file {
|
|||||||
}
|
}
|
||||||
return $file;
|
return $file;
|
||||||
}
|
}
|
||||||
|
|
||||||
static function string_reader(string $content, ?callable $func=null): MemoryStream {
|
|
||||||
$file = new MemoryStream();
|
|
||||||
$file->fwrite($content);
|
|
||||||
$file->rewind();
|
|
||||||
if ($func !== null) {
|
|
||||||
try {
|
|
||||||
$func($file);
|
|
||||||
} finally {
|
|
||||||
$file ->close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $file;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,6 @@ abstract class AbstractReader implements IReader {
|
|||||||
$this->headers = $params["headers"] ?? static::HEADERS;
|
$this->headers = $params["headers"] ?? static::HEADERS;
|
||||||
$this->useHeaders = $params["use_headers"] ?? static::USE_HEADERS;
|
$this->useHeaders = $params["use_headers"] ?? static::USE_HEADERS;
|
||||||
$this->input = $params["input"] ?? static::INPUT;
|
$this->input = $params["input"] ?? static::INPUT;
|
||||||
$this->skip = $params["skip"] ?? 0;
|
|
||||||
$this->trim = boolval($params["trim"] ?? static::TRIM);
|
$this->trim = boolval($params["trim"] ?? static::TRIM);
|
||||||
$this->emptyAsNull = boolval($params["empty_as_null"] ?? static::EMPTY_AS_NULL);
|
$this->emptyAsNull = boolval($params["empty_as_null"] ?? static::EMPTY_AS_NULL);
|
||||||
$this->parseNone = boolval($params["parse_none"] ?? static::PARSE_NONE);
|
$this->parseNone = boolval($params["parse_none"] ?? static::PARSE_NONE);
|
||||||
@ -68,8 +67,6 @@ abstract class AbstractReader implements IReader {
|
|||||||
|
|
||||||
protected $input;
|
protected $input;
|
||||||
|
|
||||||
protected int $skip;
|
|
||||||
|
|
||||||
protected bool $trim;
|
protected bool $trim;
|
||||||
|
|
||||||
protected bool $emptyAsNull;
|
protected bool $emptyAsNull;
|
||||||
@ -84,16 +81,15 @@ abstract class AbstractReader implements IReader {
|
|||||||
|
|
||||||
protected function cookRow(array &$row): bool {
|
protected function cookRow(array &$row): bool {
|
||||||
if (!$this->useHeaders) return true;
|
if (!$this->useHeaders) return true;
|
||||||
if ($this->skip > 0) {
|
if ($this->isrc == 0) {
|
||||||
$this->skip--;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ($this->headers === null) {
|
|
||||||
# ligne d'en-tête
|
# ligne d'en-tête
|
||||||
if ($this->schema === null) $headers = null;
|
$headers = $this->headers;
|
||||||
else $headers = array_keys($this->schema);
|
if ($headers === null) {
|
||||||
if ($headers === null) $headers = $row;
|
if ($this->schema === null) $headers = null;
|
||||||
$this->headers = $headers;
|
else $headers = array_keys($this->schema);
|
||||||
|
if ($headers === null) $headers = $row;
|
||||||
|
$this->headers = $headers;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
A::ensure_size($row, count($this->headers));
|
A::ensure_size($row, count($this->headers));
|
||||||
|
124
php/src/tools/BgLauncherApp.php
Normal file
124
php/src/tools/BgLauncherApp.php
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
<?php
|
||||||
|
namespace nulib\tools;
|
||||||
|
|
||||||
|
use nulib\app;
|
||||||
|
use nulib\app\cli\Application;
|
||||||
|
use nulib\app\RunFile;
|
||||||
|
use nulib\ExitError;
|
||||||
|
use nulib\ext\yaml;
|
||||||
|
use nulib\os\path;
|
||||||
|
use nulib\os\proc\Cmd;
|
||||||
|
use nulib\os\sh;
|
||||||
|
use nulib\output\msg;
|
||||||
|
|
||||||
|
class BgLauncherApp extends Application {
|
||||||
|
const ACTION_INFOS = 0, ACTION_START = 1, ACTION_STOP = 2;
|
||||||
|
const ARGS = [
|
||||||
|
"purpose" => "lancer un script en tâche de fond",
|
||||||
|
"usage" => "ApplicationClass args...",
|
||||||
|
|
||||||
|
"sections" => [
|
||||||
|
parent::VERBOSITY_SECTION,
|
||||||
|
],
|
||||||
|
|
||||||
|
["-i", "--infos", "name" => "action", "value" => self::ACTION_INFOS,
|
||||||
|
"help" => "Afficher des informations sur la tâche",
|
||||||
|
],
|
||||||
|
["-s", "--start", "name" => "action", "value" => self::ACTION_START,
|
||||||
|
"help" => "Démarrer la tâche",
|
||||||
|
],
|
||||||
|
["-k", "--stop", "name" => "action", "value" => self::ACTION_STOP,
|
||||||
|
"help" => "Arrêter la tâche",
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
protected int $action = self::ACTION_START;
|
||||||
|
|
||||||
|
protected ?array $args = null;
|
||||||
|
|
||||||
|
static function show_infos(RunFile $runfile, ?int $level=null): void {
|
||||||
|
msg::print($runfile->getDesc(), $level);
|
||||||
|
msg::print(yaml::with(["data" => $runfile->read()]), ($level ?? 0) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
$args = $this->args;
|
||||||
|
|
||||||
|
$appClass = $args[0] ?? null;
|
||||||
|
if ($appClass === null) {
|
||||||
|
self::die("Vous devez spécifier la classe de l'application");
|
||||||
|
}
|
||||||
|
$appClass = $args[0] = str_replace("/", "\\", $appClass);
|
||||||
|
if (!class_exists($appClass)) {
|
||||||
|
self::die("$appClass: classe non trouvée");
|
||||||
|
}
|
||||||
|
|
||||||
|
$useRunfile = constant("$appClass::USE_RUNFILE");
|
||||||
|
if (!$useRunfile) {
|
||||||
|
self::die("Cette application ne supporte le lancement en tâche de fond");
|
||||||
|
}
|
||||||
|
|
||||||
|
$runfile = app::with($appClass)->getRunfile();
|
||||||
|
switch ($this->action) {
|
||||||
|
case self::ACTION_START:
|
||||||
|
$argc = count($args);
|
||||||
|
$appClass::_manage_runfile($argc, $args, $runfile);
|
||||||
|
if ($runfile->warnIfLocked()) self::exit(app::EC_LOCKED);
|
||||||
|
array_splice($args, 0, 0, [
|
||||||
|
PHP_BINARY,
|
||||||
|
path::abspath(NULIB_APP_app_launcher),
|
||||||
|
]);
|
||||||
|
app::params_putenv();
|
||||||
|
self::_start($args, $runfile);
|
||||||
|
break;
|
||||||
|
case self::ACTION_STOP:
|
||||||
|
self::_stop($runfile);
|
||||||
|
self::show_infos($runfile, -1);
|
||||||
|
break;
|
||||||
|
case self::ACTION_INFOS:
|
||||||
|
self::show_infos($runfile);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function _start(array $args, Runfile $runfile): void {
|
||||||
|
$pid = pcntl_fork();
|
||||||
|
if ($pid == -1) {
|
||||||
|
# parent, impossible de forker
|
||||||
|
throw new ExitError(app::EC_FORK_PARENT, "Unable to fork");
|
||||||
|
} elseif (!$pid) {
|
||||||
|
# child, fork ok
|
||||||
|
$runfile->wfPrepare($pid);
|
||||||
|
$outfile = $runfile->getOutfile() ?? "/tmp/NULIB_APP_app_console.out";
|
||||||
|
$exitcode = app::EC_FORK_CHILD;
|
||||||
|
try {
|
||||||
|
# rediriger STDIN, STDOUT et STDERR
|
||||||
|
fclose(fopen($outfile, "wb")); // vider le fichier
|
||||||
|
fclose(STDIN); $in = fopen("/dev/null", "rb");
|
||||||
|
fclose(STDOUT); $out = fopen($outfile, "ab");
|
||||||
|
fclose(STDERR); $err = fopen($outfile, "ab");
|
||||||
|
# puis lancer la commande
|
||||||
|
$cmd = new Cmd($args);
|
||||||
|
$cmd->addSource("/g/init.env");
|
||||||
|
$cmd->addRedir("both", $outfile, true);
|
||||||
|
$cmd->fork_exec($exitcode, false);
|
||||||
|
sh::_waitpid(-$pid, $exitcode);
|
||||||
|
} finally {
|
||||||
|
$runfile->wfReaped($exitcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function _stop(Runfile $runfile): bool {
|
||||||
|
$data = $runfile->read();
|
||||||
|
$pid = $runfile->_getCid($data);
|
||||||
|
msg::action("stop $pid");
|
||||||
|
if ($runfile->wfKill($reason)) {
|
||||||
|
msg::asuccess();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
msg::afailure($reason);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
53
php/src/tools/SteamTrainApp.php
Normal file
53
php/src/tools/SteamTrainApp.php
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
namespace nulib\tools;
|
||||||
|
|
||||||
|
use nulib\app;
|
||||||
|
use nulib\app\cli\Application;
|
||||||
|
use nulib\output\msg;
|
||||||
|
use nulib\php\time\DateTime;
|
||||||
|
use nulib\text\words;
|
||||||
|
|
||||||
|
class SteamTrainApp extends Application {
|
||||||
|
const PROJDIR = __DIR__.'/../..';
|
||||||
|
const TITLE = "Train à vapeur";
|
||||||
|
const USE_LOGFILE = true;
|
||||||
|
const USE_RUNFILE = true;
|
||||||
|
const USE_RUNLOCK = true;
|
||||||
|
|
||||||
|
const ARGS = [
|
||||||
|
"purpose" => self::TITLE,
|
||||||
|
"description" => <<<EOT
|
||||||
|
Cette application peut être utilisée pour tester le lancement des tâches de fond
|
||||||
|
EOT,
|
||||||
|
|
||||||
|
["-c", "--count", "args" => 1,
|
||||||
|
"help" => "spécifier le nombre d'étapes",
|
||||||
|
],
|
||||||
|
["-f", "--force-enabled", "value" => true,
|
||||||
|
"help" => "lancer la commande même si les tâches planifiées sont désactivées",
|
||||||
|
],
|
||||||
|
["-n", "--no-install-signal-handler", "value" => false,
|
||||||
|
"help" => "ne pas installer le gestionnaire de signaux",
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $count = 100;
|
||||||
|
|
||||||
|
protected bool $forceEnabled = false;
|
||||||
|
|
||||||
|
protected bool $installSignalHandler = true;
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
app::check_bgapplication_enabled($this->forceEnabled);
|
||||||
|
if ($this->installSignalHandler) app::install_signal_handler();
|
||||||
|
$count = intval($this->count);
|
||||||
|
msg::info("Starting train for ".words::q($count, "step#s"));
|
||||||
|
app::action("Running train...", $count);
|
||||||
|
for ($i = 1; $i <= $count; $i++) {
|
||||||
|
msg::print("Tchou-tchou! x $i");
|
||||||
|
app::step();
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
msg::info("Stopping train at ".new DateTime());
|
||||||
|
}
|
||||||
|
}
|
39
php/support/copy-templates
Executable file
39
php/support/copy-templates
Executable file
@ -0,0 +1,39 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
source "$(dirname -- "$0")/../../load.sh" || exit 1
|
||||||
|
|
||||||
|
declare -A DESTDIRS=(
|
||||||
|
[template-_bg_launcher.php]=sbin
|
||||||
|
[template-.launcher.php]=_cli
|
||||||
|
[template-_wrapper.sh]=_cli
|
||||||
|
)
|
||||||
|
declare -A MODES=(
|
||||||
|
[template-_bg_launcher.php]=+x
|
||||||
|
[template-.launcher.php]=
|
||||||
|
[template-_wrapper.sh]=+x
|
||||||
|
)
|
||||||
|
|
||||||
|
projdir=
|
||||||
|
args=(
|
||||||
|
"copier les templates dans le projet en cours"
|
||||||
|
#"usage"
|
||||||
|
-d:,--projdir: .
|
||||||
|
)
|
||||||
|
parse_args "$@"; set -- "${args[@]}"
|
||||||
|
|
||||||
|
if [ -n "$projdir" ]; then
|
||||||
|
cd "$projdir" || die
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -f composer.json ] || die "$(basename "$(dirname "$(pwd)")"): n'est pas un projet composer"
|
||||||
|
|
||||||
|
setx -a templates=ls_files "$MYDIR" "template-*"
|
||||||
|
for template in "${templates[@]}"; do
|
||||||
|
destdir="${DESTDIRS[$template]}"
|
||||||
|
[ -n "$destdir" ] || die "$template: la destination n'est pas configurée"
|
||||||
|
mode="${MODES[$template]}"
|
||||||
|
destname="${template#template-}"
|
||||||
|
|
||||||
|
tail -n+4 "$MYDIR/$template" >"$destdir/$destname"
|
||||||
|
[ -n "$mode" ] && chmod "$mode" "$destdir/$destname"
|
||||||
|
done
|
@ -1,12 +1,12 @@
|
|||||||
# TODO Faire une copie de ce script dans un répertoire de l'application web
|
# TODO Faire une copie de ce script dans un répertoire de l'application web
|
||||||
# (dans le répertoire cli_config/ par défaut) et modifier les paramètres si nécessaire
|
# (dans le répertoire _cli/ par défaut) et modifier les paramètres si nécessaire
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
<?php
|
<?php
|
||||||
require __DIR__.'/../vendor/autoload.php';
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
# Lancer une application en ligne de commande
|
# Lancer une application en ligne de commande
|
||||||
|
|
||||||
const NULIB_APP_app_params = [
|
const NULIB_APP_app_params = [
|
||||||
"projdir" => __DIR__.'/..',
|
"projdir" => __DIR__ . '/..',
|
||||||
"appcode" => \app\config\bootstrap::APPCODE,
|
"appcode" => \app\config\bootstrap::APPCODE,
|
||||||
];
|
];
|
||||||
require __DIR__.'/../vendor/nulib/base/php/src/app/cli/include-launcher.php';
|
require __DIR__.'/../vendor/nulib/base/php/src/app/cli/include-launcher.php';
|
@ -6,10 +6,10 @@ require __DIR__.'/../vendor/autoload.php';
|
|||||||
# Lancer une application en tâche de fond
|
# Lancer une application en tâche de fond
|
||||||
|
|
||||||
use nulib\app;
|
use nulib\app;
|
||||||
use nulib\cli\BgLauncherApp;
|
use nulib\tools\BgLauncherApp;
|
||||||
|
|
||||||
# chemin vers le lanceur PHP
|
# chemin vers le lanceur PHP
|
||||||
const NULIB_APP_app_launcher = __DIR__.'/../@@CLI@@/.launcher.php';
|
const NULIB_APP_app_launcher = __DIR__.'/../_cli/.launcher.php';
|
||||||
|
|
||||||
app::init([
|
app::init([
|
||||||
"projdir" => __DIR__.'/..',
|
"projdir" => __DIR__.'/..',
|
@ -1,5 +1,5 @@
|
|||||||
# TODO Faire une copie de ce script dans un répertoire de l'application web
|
# TODO Faire une copie de ce script dans un répertoire de l'application web
|
||||||
# (dans le répertoire cli_config/ par défaut) et modifier les paramétres si nécessaire
|
# (dans le répertoire _cli/ par défaut) et modifier les paramétres si nécessaire
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
#!/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
|
||||||
@ -57,7 +57,7 @@ Vérification des liens..."
|
|||||||
for i in *.php*; do
|
for i in *.php*; do
|
||||||
[ -f "$i" ] || continue
|
[ -f "$i" ] || continue
|
||||||
name="bin/${i%.*}.php"
|
name="bin/${i%.*}.php"
|
||||||
dest="../@@CLI@@/_wrapper.sh"
|
dest="../_cli/_wrapper.sh"
|
||||||
link="../bin/${i%.*}.php"
|
link="../bin/${i%.*}.php"
|
||||||
if [ -L "$link" ]; then
|
if [ -L "$link" ]; then
|
||||||
echo "* $name OK"
|
echo "* $name OK"
|
@ -7,12 +7,6 @@ use nulib\db\Capacitor;
|
|||||||
use nulib\db\CapacitorChannel;
|
use nulib\db\CapacitorChannel;
|
||||||
|
|
||||||
class SqliteStorageTest extends TestCase {
|
class SqliteStorageTest extends TestCase {
|
||||||
static function Txx(...$values): void {
|
|
||||||
foreach ($values as $value) {
|
|
||||||
var_export($value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function _testChargeStrings(SqliteStorage $storage, ?string $channel) {
|
function _testChargeStrings(SqliteStorage $storage, ?string $channel) {
|
||||||
$storage->reset($channel);
|
$storage->reset($channel);
|
||||||
$storage->charge($channel, "first");
|
$storage->charge($channel, "first");
|
||||||
@ -73,8 +67,7 @@ class SqliteStorageTest extends TestCase {
|
|||||||
$capacitor->charge(["name" => "third", "age" => 15]);
|
$capacitor->charge(["name" => "third", "age" => 15]);
|
||||||
$capacitor->charge(["name" => "fourth", "age" => 20]);
|
$capacitor->charge(["name" => "fourth", "age" => 20]);
|
||||||
|
|
||||||
$setDone = function ($row, $suffix=null) {
|
$setDone = function ($item, $row, $suffix=null) {
|
||||||
$item = $row["item"];
|
|
||||||
$updates = ["done" => 1];
|
$updates = ["done" => 1];
|
||||||
if ($suffix !== null) {
|
if ($suffix !== null) {
|
||||||
$item["name"] .= $suffix;
|
$item["name"] .= $suffix;
|
||||||
@ -83,9 +76,9 @@ class SqliteStorageTest extends TestCase {
|
|||||||
return $updates;
|
return $updates;
|
||||||
};
|
};
|
||||||
$capacitor->each(["age" => [">", 10]], $setDone, ["++"]);
|
$capacitor->each(["age" => [">", 10]], $setDone, ["++"]);
|
||||||
$capacitor->each(["done" => 0], $setDone);
|
$capacitor->each(["done" => 0], $setDone, null);
|
||||||
|
|
||||||
self::Txx(cl::all($capacitor->discharge(false)));
|
Txx(cl::all($capacitor->discharge(false)));
|
||||||
$capacitor->close();
|
$capacitor->close();
|
||||||
self::assertTrue(true);
|
self::assertTrue(true);
|
||||||
}
|
}
|
||||||
@ -140,16 +133,16 @@ class SqliteStorageTest extends TestCase {
|
|||||||
$capacitor->charge(["a" => null, "b" => null]);
|
$capacitor->charge(["a" => null, "b" => null]);
|
||||||
$capacitor->charge(["a" => "first", "b" => "second"]);
|
$capacitor->charge(["a" => "first", "b" => "second"]);
|
||||||
|
|
||||||
self::Txx("=== all");
|
Txx("=== all");
|
||||||
/** @var Sqlite $sqlite */
|
/** @var Sqlite $sqlite */
|
||||||
$sqlite = $capacitor->getStorage()->db();
|
$sqlite = $capacitor->getStorage()->db();
|
||||||
self::Txx(cl::all($sqlite->all([
|
Txx(cl::all($sqlite->all([
|
||||||
"select",
|
"select",
|
||||||
"from" => $capacitor->getChannel()->getTableName(),
|
"from" => $capacitor->getChannel()->getTableName(),
|
||||||
])));
|
])));
|
||||||
self::Txx("=== each");
|
Txx("=== each");
|
||||||
$capacitor->each(null, function ($row) {
|
$capacitor->each(null, function ($item, $values) {
|
||||||
self::Txx($row);
|
Txx($values);
|
||||||
});
|
});
|
||||||
|
|
||||||
$capacitor->close();
|
$capacitor->close();
|
||||||
@ -177,100 +170,99 @@ class SqliteStorageTest extends TestCase {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$capacitor->reset();
|
$capacitor->reset();
|
||||||
$capacitor->charge(["name" => "first", "age" => 5], function($item, ?array $row, ?array $prow) {
|
$capacitor->charge(["name" => "first", "age" => 5], function($item, ?array $values, ?array $pvalues) {
|
||||||
self::assertSame("first", $item["name"]);
|
self::assertSame("first", $item["name"]);
|
||||||
self::assertSame(5, $item["age"]);
|
self::assertSame(5, $item["age"]);
|
||||||
self::assertnotnull($row);
|
self::assertnotnull($values);
|
||||||
self::assertSame(["name", "age", "item", "item__sum_", "created_", "modified_"], array_keys($row));
|
self::assertSame(["name", "age", "item", "item__sum_", "created_", "modified_"], array_keys($values));
|
||||||
self::assertSame([
|
self::assertSame([
|
||||||
"name" => "first",
|
"name" => "first",
|
||||||
"age" => 5,
|
"age" => 5,
|
||||||
"item" => $item,
|
"item" => $item,
|
||||||
], cl::select($row, ["name", "age", "item"]));
|
], cl::select($values, ["name", "age", "item"]));
|
||||||
self::assertNull($prow);
|
self::assertNull($pvalues);
|
||||||
});
|
});
|
||||||
$capacitor->charge(["name" => "first", "age" => 10], function($item, ?array $row, ?array $prow) {
|
$capacitor->charge(["name" => "first", "age" => 10], function($item, ?array $values, ?array $pvalues) {
|
||||||
self::assertSame("first", $item["name"]);
|
self::assertSame("first", $item["name"]);
|
||||||
self::assertSame(10, $item["age"]);
|
self::assertSame(10, $item["age"]);
|
||||||
self::assertnotnull($row);
|
self::assertnotnull($values);
|
||||||
self::assertSame(["name", "age", "done", "notes", "item", "item__sum_", "created_", "modified_"], array_keys($row));
|
self::assertSame(["name", "age", "done", "notes", "item", "item__sum_", "created_", "modified_"], array_keys($values));
|
||||||
self::assertSame([
|
self::assertSame([
|
||||||
"name" => "first",
|
"name" => "first",
|
||||||
"age" => 10,
|
"age" => 10,
|
||||||
"done" => 0,
|
"done" => 0,
|
||||||
"notes" => null,
|
"notes" => null,
|
||||||
"item" => $item,
|
"item" => $item,
|
||||||
], cl::select($row, ["name", "age", "done", "notes", "item"]));
|
], cl::select($values, ["name", "age", "done", "notes", "item"]));
|
||||||
self::assertNotNull($prow);
|
self::assertNotNull($pvalues);
|
||||||
self::assertSame([
|
self::assertSame([
|
||||||
"name" => "first",
|
"name" => "first",
|
||||||
"age" => 5,
|
"age" => 5,
|
||||||
"done" => 0,
|
"done" => 0,
|
||||||
"notes" => null,
|
"notes" => null,
|
||||||
"item" => ["name" => "first", "age" => 5],
|
"item" => ["name" => "first", "age" => 5],
|
||||||
], cl::select($prow, ["name", "age", "done", "notes", "item"]));
|
], cl::select($pvalues, ["name", "age", "done", "notes", "item"]));
|
||||||
});
|
});
|
||||||
|
|
||||||
$capacitor->each(null, function(array $row) {
|
$capacitor->each(null, function($item, ?array $values) {
|
||||||
$item = $row["item"];
|
|
||||||
self::assertSame("first", $item["name"]);
|
self::assertSame("first", $item["name"]);
|
||||||
self::assertSame(10, $item["age"]);
|
self::assertSame(10, $item["age"]);
|
||||||
self::assertnotnull($row);
|
self::assertnotnull($values);
|
||||||
self::assertSame(["name", "age", "done", "notes", "item", "item__sum_", "created_", "modified_"], array_keys($row));
|
self::assertSame(["name", "age", "done", "notes", "item", "item__sum_", "created_", "modified_"], array_keys($values));
|
||||||
self::assertSame([
|
self::assertSame([
|
||||||
"name" => "first",
|
"name" => "first",
|
||||||
"age" => 10,
|
"age" => 10,
|
||||||
"done" => 0,
|
"done" => 0,
|
||||||
"notes" => null,
|
"notes" => null,
|
||||||
"item" => $item,
|
"item" => $item,
|
||||||
], cl::select($row, ["name", "age", "done", "notes", "item"]));
|
], cl::select($values, ["name", "age", "done", "notes", "item"]));
|
||||||
return [
|
return [
|
||||||
"done" => 1,
|
"done" => 1,
|
||||||
"notes" => "modified",
|
"notes" => "modified",
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
$capacitor->charge(["name" => "first", "age" => 10], function($item, ?array $row, ?array $prow) {
|
$capacitor->charge(["name" => "first", "age" => 10], function($item, ?array $values, ?array $pvalues) {
|
||||||
self::assertSame("first", $item["name"]);
|
self::assertSame("first", $item["name"]);
|
||||||
self::assertSame(10, $item["age"]);
|
self::assertSame(10, $item["age"]);
|
||||||
self::assertnotnull($row);
|
self::assertnotnull($values);
|
||||||
self::assertSame(["name", "age", "done", "notes", "item", "item__sum_", "created_", "modified_"], array_keys($row));
|
self::assertSame(["name", "age", "done", "notes", "item", "item__sum_", "created_", "modified_"], array_keys($values));
|
||||||
self::assertSame([
|
self::assertSame([
|
||||||
"name" => "first",
|
"name" => "first",
|
||||||
"age" => 10,
|
"age" => 10,
|
||||||
"done" => 1,
|
"done" => 1,
|
||||||
"notes" => "modified",
|
"notes" => "modified",
|
||||||
"item" => $item,
|
"item" => $item,
|
||||||
], cl::select($row, ["name", "age", "done", "notes", "item"]));
|
], cl::select($values, ["name", "age", "done", "notes", "item"]));
|
||||||
self::assertNotNull($prow);
|
self::assertNotNull($pvalues);
|
||||||
self::assertSame([
|
self::assertSame([
|
||||||
"name" => "first",
|
"name" => "first",
|
||||||
"age" => 10,
|
"age" => 10,
|
||||||
"done" => 1,
|
"done" => 1,
|
||||||
"notes" => "modified",
|
"notes" => "modified",
|
||||||
"item" => $item,
|
"item" => $item,
|
||||||
], cl::select($prow, ["name", "age", "done", "notes", "item"]));
|
], cl::select($pvalues, ["name", "age", "done", "notes", "item"]));
|
||||||
});
|
});
|
||||||
|
|
||||||
$capacitor->charge(["name" => "first", "age" => 20], function($item, ?array $row, ?array $prow) {
|
$capacitor->charge(["name" => "first", "age" => 20], function($item, ?array $values, ?array $pvalues) {
|
||||||
self::assertSame("first", $item["name"]);
|
self::assertSame("first", $item["name"]);
|
||||||
self::assertSame(20, $item["age"]);
|
self::assertSame(20, $item["age"]);
|
||||||
self::assertnotnull($row);
|
self::assertnotnull($values);
|
||||||
self::assertSame(["name", "age", "done", "notes", "item", "item__sum_", "created_", "modified_"], array_keys($row));
|
self::assertSame(["name", "age", "done", "notes", "item", "item__sum_", "created_", "modified_"], array_keys($values));
|
||||||
self::assertSame([
|
self::assertSame([
|
||||||
"name" => "first",
|
"name" => "first",
|
||||||
"age" => 20,
|
"age" => 20,
|
||||||
"done" => 1,
|
"done" => 1,
|
||||||
"notes" => "modified",
|
"notes" => "modified",
|
||||||
"item" => $item,
|
"item" => $item,
|
||||||
], cl::select($row, ["name", "age", "done", "notes", "item"]));
|
], cl::select($values, ["name", "age", "done", "notes", "item"]));
|
||||||
self::assertNotNull($prow);
|
self::assertNotNull($pvalues);
|
||||||
self::assertSame([
|
self::assertSame([
|
||||||
"name" => "first",
|
"name" => "first",
|
||||||
"age" => 10,
|
"age" => 10,
|
||||||
"done" => 1,
|
"done" => 1,
|
||||||
"notes" => "modified",
|
"notes" => "modified",
|
||||||
"item" => ["name" => "first", "age" => 10],
|
"item" => ["name" => "first", "age" => 10],
|
||||||
], cl::select($prow, ["name", "age", "done", "notes", "item"]));
|
], cl::select($pvalues, ["name", "age", "done", "notes", "item"]));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,55 +287,55 @@ class SqliteStorageTest extends TestCase {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$capacitor->reset();
|
$capacitor->reset();
|
||||||
$nbModified = $capacitor->charge(["name" => "first", "age" => 5], function ($item, ?array $row, ?array $prow) {
|
$nbModified = $capacitor->charge(["name" => "first", "age" => 5], function ($item, ?array $values, ?array $pvalues) {
|
||||||
self::assertSame([
|
self::assertSame([
|
||||||
"name" => "first", "age" => 5,
|
"name" => "first", "age" => 5,
|
||||||
"item" => $item,
|
"item" => $item,
|
||||||
], cl::select($row, ["name", "age", "item"]));
|
], cl::select($values, ["name", "age", "item"]));
|
||||||
return ["item" => null];
|
return ["item" => null];
|
||||||
});
|
});
|
||||||
self::assertSame(1, $nbModified);
|
self::assertSame(1, $nbModified);
|
||||||
sleep(1);
|
sleep(1);
|
||||||
# nb: on met des sleep() pour que la date de modification soit systématiquement différente
|
# nb: on met des sleep() pour que la date de modification soit systématiquement différente
|
||||||
|
|
||||||
$nbModified = $capacitor->charge(["name" => "first", "age" => 10], function ($item, ?array $row, ?array $prow) {
|
$nbModified = $capacitor->charge(["name" => "first", "age" => 10], function ($item, ?array $values, ?array $pvalues) {
|
||||||
self::assertSame([
|
self::assertSame([
|
||||||
"name" => "first", "age" => 10,
|
"name" => "first", "age" => 10,
|
||||||
"item" => $item, "item__sum_" => "9181336dfca20c86313d6065d89aa2ad5070b0fc",
|
"item" => $item, "item__sum_" => "9181336dfca20c86313d6065d89aa2ad5070b0fc",
|
||||||
], cl::select($row, ["name", "age", "item", "item__sum_"]));
|
], cl::select($values, ["name", "age", "item", "item__sum_"]));
|
||||||
self::assertSame([
|
self::assertSame([
|
||||||
"name" => "first", "age" => 5,
|
"name" => "first", "age" => 5,
|
||||||
"item" => null, "item__sum_" => null,
|
"item" => null, "item__sum_" => null,
|
||||||
], cl::select($prow, ["name", "age", "item", "item__sum_"]));
|
], cl::select($pvalues, ["name", "age", "item", "item__sum_"]));
|
||||||
return ["item" => null];
|
return ["item" => null];
|
||||||
});
|
});
|
||||||
self::assertSame(1, $nbModified);
|
self::assertSame(1, $nbModified);
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
|
||||||
# pas de modification ici
|
# pas de modification ici
|
||||||
$nbModified = $capacitor->charge(["name" => "first", "age" => 10], function ($item, ?array $row, ?array $prow) {
|
$nbModified = $capacitor->charge(["name" => "first", "age" => 10], function ($item, ?array $values, ?array $pvalues) {
|
||||||
self::assertSame([
|
self::assertSame([
|
||||||
"name" => "first", "age" => 10,
|
"name" => "first", "age" => 10,
|
||||||
"item" => $item, "item__sum_" => "9181336dfca20c86313d6065d89aa2ad5070b0fc",
|
"item" => $item, "item__sum_" => "9181336dfca20c86313d6065d89aa2ad5070b0fc",
|
||||||
], cl::select($row, ["name", "age", "item", "item__sum_"]));
|
], cl::select($values, ["name", "age", "item", "item__sum_"]));
|
||||||
self::assertSame([
|
self::assertSame([
|
||||||
"name" => "first", "age" => 10,
|
"name" => "first", "age" => 10,
|
||||||
"item" => null, "item__sum_" => null,
|
"item" => null, "item__sum_" => null,
|
||||||
], cl::select($prow, ["name", "age", "item", "item__sum_"]));
|
], cl::select($pvalues, ["name", "age", "item", "item__sum_"]));
|
||||||
return ["item" => null];
|
return ["item" => null];
|
||||||
});
|
});
|
||||||
self::assertSame(0, $nbModified);
|
self::assertSame(0, $nbModified);
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
|
||||||
$nbModified = $capacitor->charge(["name" => "first", "age" => 20], function ($item, ?array $row, ?array $prow) {
|
$nbModified = $capacitor->charge(["name" => "first", "age" => 20], function ($item, ?array $values, ?array $pvalues) {
|
||||||
self::assertSame([
|
self::assertSame([
|
||||||
"name" => "first", "age" => 20,
|
"name" => "first", "age" => 20,
|
||||||
"item" => $item, "item__sum_" => "001b91982b4e0883b75428c0eb28573a5dc5f7a5",
|
"item" => $item, "item__sum_" => "001b91982b4e0883b75428c0eb28573a5dc5f7a5",
|
||||||
], cl::select($row, ["name", "age", "item", "item__sum_"]));
|
], cl::select($values, ["name", "age", "item", "item__sum_"]));
|
||||||
self::assertSame([
|
self::assertSame([
|
||||||
"name" => "first", "age" => 10,
|
"name" => "first", "age" => 10,
|
||||||
"item" => null, "item__sum_" => null,
|
"item" => null, "item__sum_" => null,
|
||||||
], cl::select($prow, ["name", "age", "item", "item__sum_"]));
|
], cl::select($pvalues, ["name", "age", "item", "item__sum_"]));
|
||||||
return ["item" => null];
|
return ["item" => null];
|
||||||
});
|
});
|
||||||
self::assertSame(1, $nbModified);
|
self::assertSame(1, $nbModified);
|
||||||
|
@ -3,7 +3,6 @@ namespace nulib\db\sqlite;
|
|||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use nulib\tests\TestCase;
|
use nulib\tests\TestCase;
|
||||||
use nulib\ValueException;
|
|
||||||
|
|
||||||
class SqliteTest extends TestCase {
|
class SqliteTest extends TestCase {
|
||||||
const CREATE_PERSON = "create table person(nom varchar, prenom varchar, age integer)";
|
const CREATE_PERSON = "create table person(nom varchar, prenom varchar, age integer)";
|
||||||
@ -13,8 +12,8 @@ class SqliteTest extends TestCase {
|
|||||||
function testMigration() {
|
function testMigration() {
|
||||||
$sqlite = new Sqlite(":memory:", [
|
$sqlite = new Sqlite(":memory:", [
|
||||||
"migration" => [
|
"migration" => [
|
||||||
"create" => self::CREATE_PERSON,
|
self::CREATE_PERSON,
|
||||||
"insert" => self::INSERT_JEPHTE,
|
self::INSERT_JEPHTE,
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
self::assertSame("clain", $sqlite->get("select nom, age from person"));
|
self::assertSame("clain", $sqlite->get("select nom, age from person"));
|
||||||
@ -31,15 +30,15 @@ class SqliteTest extends TestCase {
|
|||||||
], $sqlite->get("select nom, age from person where nom = 'payet'", null, true));
|
], $sqlite->get("select nom, age from person where nom = 'payet'", null, true));
|
||||||
|
|
||||||
self::assertSame([
|
self::assertSame([
|
||||||
["channel" => "", "name" => "create", "done" => 1],
|
["key" => "0", "value" => self::CREATE_PERSON, "done" => 1],
|
||||||
["channel" => "", "name" => "insert", "done" => 1],
|
["key" => "1", "value" => self::INSERT_JEPHTE, "done" => 1],
|
||||||
], iterator_to_array($sqlite->all("select channel, name, done from _migration")));
|
], iterator_to_array($sqlite->all("select key, value, done from _migration")));
|
||||||
}
|
}
|
||||||
|
|
||||||
function testException() {
|
function testException() {
|
||||||
$sqlite = new Sqlite(":memory:");
|
$sqlite = new Sqlite(":memory:");
|
||||||
self::assertException(Exception::class, [$sqlite, "exec"], "prout");
|
self::assertException(Exception::class, [$sqlite, "exec"], "prout");
|
||||||
self::assertException(ValueException::class, [$sqlite, "exec"], ["prout"]);
|
self::assertException(SqliteException::class, [$sqlite, "exec"], ["prout"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function assertInserted(Sqlite $sqlite, array $row, array $query): void {
|
protected function assertInserted(Sqlite $sqlite, array $row, array $query): void {
|
||||||
@ -142,10 +141,6 @@ class SqliteTest extends TestCase {
|
|||||||
|
|
||||||
self::assertSame([
|
self::assertSame([
|
||||||
["count" => 2],
|
["count" => 2],
|
||||||
], iterator_to_array($sqlite->all([
|
], iterator_to_array($sqlite->all(["select count(name) as count from user", "group by" => ["amount"], "having" => ["count(name) = 2"]])));
|
||||||
"select count(name) as count from user",
|
|
||||||
"group by" => ["amount"],
|
|
||||||
"having" => ["count(name) = 2"],
|
|
||||||
])));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ function build_check_env() {
|
|||||||
if template_copy_missing "$PROJDIR/$file"; then
|
if template_copy_missing "$PROJDIR/$file"; then
|
||||||
updated=1
|
updated=1
|
||||||
setx name=basename -- "$file"
|
setx name=basename -- "$file"
|
||||||
name="${name#.}"; name="${name%.*}"
|
name="${name#.}"; name="${name%.}"
|
||||||
setx file=dirname -- "$file"
|
setx file=dirname -- "$file"
|
||||||
file="$file/$name"
|
file="$file/$name"
|
||||||
updatedfiles+=("$file")
|
updatedfiles+=("$file")
|
||||||
@ -86,7 +86,7 @@ function build_check_env() {
|
|||||||
if template_copy_missing "$file"; then
|
if template_copy_missing "$file"; then
|
||||||
updated=1
|
updated=1
|
||||||
setx name=basename -- "$file"
|
setx name=basename -- "$file"
|
||||||
name="${name#.}"; name="${name%.*}"
|
name="${name#.}"; name="${name%.}"
|
||||||
setx file=dirname -- "$file"
|
setx file=dirname -- "$file"
|
||||||
file="$file/$name"
|
file="$file/$name"
|
||||||
updatedfiles+=("${file#$PROJDIR/}")
|
updatedfiles+=("${file#$PROJDIR/}")
|
||||||
|
@ -40,31 +40,11 @@ p == 1 {
|
|||||||
ac_clean "$conf0"
|
ac_clean "$conf0"
|
||||||
}
|
}
|
||||||
|
|
||||||
declare -A PHPWRAPPER_DESTDIRS=(
|
|
||||||
[_bg_launcher.php]=@@SBIN@@
|
|
||||||
[.launcher.php]=@@CLI@@
|
|
||||||
[_wrapper.sh]=@@CLI@@
|
|
||||||
)
|
|
||||||
declare -A PHPWRAPPER_MODES=(
|
|
||||||
[_bg_launcher.php]=+x
|
|
||||||
[.launcher.php]=
|
|
||||||
[_wrapper.sh]=+x
|
|
||||||
)
|
|
||||||
|
|
||||||
projdir=
|
projdir=
|
||||||
install_phpwrappers=auto
|
|
||||||
args=(
|
args=(
|
||||||
"Mettre à jour le script runphp"
|
"Mettre à jour le script runphp"
|
||||||
"[path/to/runphp]"
|
"[path/to/runphp]"
|
||||||
-d:,--projdir:PROJDIR . "\
|
-d:,--projdir:PROJDIR . "Copier les fichiers pour un projet de l'université de la Réunion"
|
||||||
Copier les fichiers pour un projet de l'université de la Réunion:
|
|
||||||
- BUILDENV0 et BUILDENV sont fixés à ..env.dist et .env
|
|
||||||
- les fichiers ..env.dist et .runphp.conf sont créés le cas échéant
|
|
||||||
- le script build est mis à jour
|
|
||||||
- les wrappers PHP pour la gestion des tâches de fond sont mis à jour le cas
|
|
||||||
échéant"
|
|
||||||
-p,--phpwrappers-install install_phpwrappers=1 "forcer l'installation des wrappers PHP"
|
|
||||||
--np,--no-phpwrappers-install install_phpwrappers= "ne pas installer les wrappers PHP"
|
|
||||||
)
|
)
|
||||||
parse_args "$@"; set -- "${args[@]}"
|
parse_args "$@"; set -- "${args[@]}"
|
||||||
|
|
||||||
@ -113,7 +93,6 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# (Re)construire le fichier destination
|
# (Re)construire le fichier destination
|
||||||
estep "$(relpath "$runphp")"
|
|
||||||
(
|
(
|
||||||
cat "$preamble"
|
cat "$preamble"
|
||||||
echo
|
echo
|
||||||
@ -123,81 +102,24 @@ estep "$(relpath "$runphp")"
|
|||||||
) >"$runphp"
|
) >"$runphp"
|
||||||
[ -x "$runphp" ] || chmod +x "$runphp"
|
[ -x "$runphp" ] || chmod +x "$runphp"
|
||||||
|
|
||||||
eval "$(
|
|
||||||
vars=(PROJDIR COMPOSERDIR COMPOSERPHAR VENDORDIR BUILDENV0 BUILDENV BUILD_FLAVOUR DIST IMAGENAME)
|
|
||||||
arrays=(BUILD_IMAGES DISTFILES TEMPLATEFILES VARFILES)
|
|
||||||
for var in "${vars[@]}"; do eval "$var="; done
|
|
||||||
for array in "${arrays[@]}"; do eval "$array=()"; done
|
|
||||||
source "$runphp"
|
|
||||||
for var in "${vars[@]}"; do echo_setv2 "$var"; done
|
|
||||||
for array in "${arrays[@]}"; do echo_seta2 "$array"; done
|
|
||||||
)"
|
|
||||||
|
|
||||||
estep "$(relpath "$rundir/Dockerfile.runphp")"
|
|
||||||
rsync -lpt "$MYDIR/Dockerfile.runphp" "$rundir/"
|
rsync -lpt "$MYDIR/Dockerfile.runphp" "$rundir/"
|
||||||
|
|
||||||
if [ -n "$projdir" ]; then
|
if [ -n "$projdir" ]; then
|
||||||
if testdiff "$rundir/build" "$MYDIR/build"; then
|
if testdiff "$rundir/build" "$MYDIR/build"; then
|
||||||
estep "$(relpath "$rundir/build")"
|
|
||||||
cp "$MYDIR/build" "$rundir/build"
|
cp "$MYDIR/build" "$rundir/build"
|
||||||
chmod +x "$rundir/build"
|
chmod +x "$rundir/build"
|
||||||
fi
|
fi
|
||||||
if [ ! -f "$projdir/..env.dist" ]; then
|
if [ ! -f "$projdir/..env.dist" ]; then
|
||||||
estep "$(relpath "$projdir/..env.dist")"
|
|
||||||
sed <"$MYDIR/dot-build.env.dist" >"$projdir/..env.dist" '
|
sed <"$MYDIR/dot-build.env.dist" >"$projdir/..env.dist" '
|
||||||
/^IMAGENAME=/s/=.*\//='"$(basename -- "$projdir")"'\//
|
/^IMAGENAME=/s/=.*\//='"$(basename -- "$projdir")"'\//
|
||||||
'
|
'
|
||||||
initial_config=1
|
initial_config=1
|
||||||
fi
|
fi
|
||||||
if [ ! -f "$projdir/.runphp.conf" ]; then
|
if [ ! -f "$projdir/.runphp.conf" ]; then
|
||||||
estep "$(relpath "$projdir/.runphp.conf")"
|
|
||||||
sed <"$MYDIR/dot-runphp.conf" >"$projdir/.runphp.conf" '
|
sed <"$MYDIR/dot-runphp.conf" >"$projdir/.runphp.conf" '
|
||||||
/^RUNPHP=/s/=.*/=sbin\/runphp/
|
/^RUNPHP=/s/=.*/=sbin\/runphp/
|
||||||
'
|
'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
sbin_path=sbin
|
|
||||||
cli_path=cli_config
|
|
||||||
if [ "$install_phpwrappers" == auto ]; then
|
|
||||||
if [ ! -f "$PROJDIR/$COMPOSERDIR/composer.json" ]; then
|
|
||||||
# ce doit être un projet PHP
|
|
||||||
install_phpwrappers=
|
|
||||||
elif [ -d "$projdir/cli_config" ]; then
|
|
||||||
install_phpwrappers=1
|
|
||||||
sbin_path=sbin
|
|
||||||
cli_path=cli_config
|
|
||||||
elif [ -d "$projdir/_cli" ]; then
|
|
||||||
install_phpwrappers=1
|
|
||||||
sbin_path=sbin
|
|
||||||
cli_path=_cli
|
|
||||||
else
|
|
||||||
install_phpwrappers=
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$install_phpwrappers" ]; then
|
|
||||||
setx -a phpwrappers=ls_files "$MYDIR" "phpwrapper-*"
|
|
||||||
for phpwrapper in "${phpwrappers[@]}"; do
|
|
||||||
destname="${phpwrapper#phpwrapper-}"
|
|
||||||
destdir="${PHPWRAPPER_DESTDIRS[$destname]}"
|
|
||||||
[ -n "$destdir" ] || die "$phpwrapper: la destination n'est pas configurée"
|
|
||||||
mode="${PHPWRAPPER_MODES[$destname]}"
|
|
||||||
|
|
||||||
case "$destdir" in
|
|
||||||
@@SBIN@@) destdir="$PROJDIR/$sbin_path";;
|
|
||||||
@@CLI@@) destdir="$PROJDIR/$cli_path";;
|
|
||||||
*) destdir="$PROJDIR/$destdir";;
|
|
||||||
esac
|
|
||||||
|
|
||||||
estep "$(relpath "$destdir/$destname")"
|
|
||||||
mkdir -p "$destdir"
|
|
||||||
tail -n+4 "$MYDIR/$phpwrapper" | sed "
|
|
||||||
s|/@@SBIN@@/|/$sbin_path/|
|
|
||||||
s|/@@CLI@@/|/$cli_path/|
|
|
||||||
" >"$destdir/$destname"
|
|
||||||
[ -n "$mode" ] && chmod "$mode" "$destdir/$destname"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[ -n "$initial_config" ]
|
[ -n "$initial_config" ]
|
||||||
|
21
wip/pman.md
21
wip/pman.md
@ -6,22 +6,9 @@ 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.
|
||||||
## scripts de gestion de projet
|
* prel: faire une release.
|
||||||
|
ces outils peuvent agir sur les projets dépendants: faire une release sur un
|
||||||
définir précisément le rôle des scripts
|
projet downstream, ou synchroniser la version depuis un projet upstream
|
||||||
* pdist: créer la branche DIST, basculer dessus, merger MAIN dans DIST
|
|
||||||
* pmain: initialiser la branche MAIN (si nouveau dépôt), basculer dessus, merger DEVELOP dans MAIN
|
|
||||||
(s'occupe aussi de la configuration pman.conf)
|
|
||||||
* pdev: créer la branche DEVELOP, basculer dessus
|
|
||||||
* pwip: créer une branche WIP, basculer dessus si unique (ou laisser le choix), merger WIP dans DEVELOP
|
|
||||||
* PEUT-ETRE: pfix: créer une branche HOTFIX, basculer dessus si unique (ou laisser le choix), merger HOTFIX dans MAIN
|
|
||||||
* prel: faire une release de DEVELOP dans MAIN. à terme, support des branches de hotfix
|
|
||||||
* il s'agit d'une spécialisation de pmain et/ou pfix pour la gestion des releases
|
|
||||||
* à terme, gestion en cascade des projets dépendants: release sur un projet downstream, ou synchroniser la version depuis un projet upstream
|
|
||||||
|
|
||||||
il faudra supprimer
|
|
||||||
* pman: fonctionnalités réparties dans les autres scripts spécialisés
|
|
||||||
* pmer: fonctionnalités réperties dans les autres scripts spécialisés
|
|
||||||
|
|
||||||
-*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary
|
-*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary
|
Loading…
x
Reference in New Issue
Block a user