Compare commits

..

13 Commits

39 changed files with 630 additions and 368 deletions

1
.idea/php.xml generated
View File

@ -70,6 +70,7 @@
<path value="$PROJECT_DIR$/vendor/nulib/spout" />
<path value="$PROJECT_DIR$/vendor/nulib/php" />
<path value="$PROJECT_DIR$/vendor/nulib/spout" />
<path value="$PROJECT_DIR$/vendor/nulib/base" />
</include_path>
</component>
<component name="PhpProjectSharedConfiguration" php_language_level="7.4" />

View File

@ -1,3 +1,5 @@
## Release 0.6.0p82 du 30/05/2025-23:39
## Release 0.6.0p74 du 30/05/2025-23:35
migrer de nulib/php à nulib/base

14
TODO.md
View File

@ -7,5 +7,19 @@
## Vrac
* classe de base `profile_manager` qui permet de gérer des profils
* class Tool permettant d'appliquer un traitement à une valeur scalaire
* ArrayTool permet d'appliquer les traitement à tous les éléments du tableau
* les traitements sont une suite d'opérations à faire, ou de filtres à
appliquer, qui ne sont appliqués que lors du parcours effectif de la liste
* exemple
```php
$result = ArrayTool::with($source)
->filterKey("key")
->filter("value")
->add("value", "key")
->addAll($iterable)
->all();
```
déterminer le genre de traitements que l'on peut offrir
-*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary

View File

@ -2,6 +2,6 @@
<?php
require $_composer_autoload_path?? __DIR__.'/../vendor/autoload.php';
use nulib\tools\Csv2xlsxApp;
use nulib\cli\Csv2xlsxApp;
Csv2xlsxApp::run();

View File

@ -2,6 +2,6 @@
<?php
require $_composer_autoload_path?? __DIR__.'/../vendor/autoload.php';
use nulib\tools\DumpserApp;
use nulib\cli\DumpserApp;
DumpserApp::run();

View File

@ -2,6 +2,6 @@
<?php
require $_composer_autoload_path?? __DIR__.'/../vendor/autoload.php';
use nulib\tools\Json2yamlApp;
use nulib\cli\Json2yamlApp;
Json2yamlApp::run();

View File

@ -2,6 +2,6 @@
<?php
require $_composer_autoload_path?? __DIR__.'/../vendor/autoload.php';
use nulib\tools\SteamTrainApp;
use nulib\cli\MysqlStorageApp;
SteamTrainApp::run();
MysqlStorageApp::run();

View File

@ -2,6 +2,6 @@
<?php
require $_composer_autoload_path?? __DIR__.'/../vendor/autoload.php';
use nulib\tools\NucacheApp;
use nulib\cli\NucacheApp;
NucacheApp::run();

7
bin/pgsql.storage.php Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/php
<?php
require $_composer_autoload_path?? __DIR__.'/../vendor/autoload.php';
use nulib\cli\PgsqlStorageApp;
PgsqlStorageApp::run();

7
bin/sqlite.storage.php Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/php
<?php
require $_composer_autoload_path?? __DIR__.'/../vendor/autoload.php';
use nulib\cli\SqliteStorageApp;
SqliteStorageApp::run();

View File

@ -2,6 +2,6 @@
<?php
require $_composer_autoload_path?? __DIR__.'/../vendor/autoload.php';
use nulib\tools\Yaml2jsonApp;
use nulib\cli\Yaml2jsonApp;
Yaml2jsonApp::run();

View File

@ -3,6 +3,18 @@
"type": "library",
"description": "espace de maturation pour les librairies",
"repositories": [
{
"type": "path",
"url": "../nulib-base"
},
{
"type": "path",
"url": "../nulib-spout"
},
{
"type": "path",
"url": "../nulib-phpss"
},
{
"type": "composer",
"url": "https://repos.univ-reunion.fr/composer"
@ -18,9 +30,9 @@
"php": "^7.4"
},
"require-dev": {
"nulib/base": "^0.6.0p74",
"nulib/spout": "^0.6.0p74",
"nulib/phpss": "^0.6.0p74",
"nulib/base": "^7.4-dev",
"nulib/spout": "^7.4-dev",
"nulib/phpss": "^7.4-dev",
"nulib/tests": "^7.4",
"ext-posix": "*",
"ext-pcntl": "*",
@ -67,9 +79,13 @@
},
"bin": [
"bin/dumpser.php",
"bin/nucache.php",
"bin/csv2xlsx.php",
"bin/json2yml.php",
"bin/yml2json.php",
"bin/sqlite.storage.php",
"bin/mysql.storage.php",
"bin/pgsql.storage.php",
"nur_bin/compctl.php",
"nur_bin/compdep.php",
"nur_bin/datectl.php",
@ -77,9 +93,7 @@
"nur_bin/cachectl.php",
"nur_bin/ldap-delete.php",
"nur_bin/ldap-get-infos.php",
"nur_bin/ldap-search.php",
"nur_bin/storage.sqlite.php",
"nur_bin/storage.mysql.php"
"nur_bin/ldap-search.php"
],
"authors": [
{

54
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "145505a2a855bc2128606baa3df40125",
"content-hash": "2dc79f259fa01ba2a990fbcb8fcec728",
"packages": [],
"packages-dev": [
{
@ -585,11 +585,11 @@
},
{
"name": "nulib/base",
"version": "0.6.0p74",
"source": {
"type": "git",
"url": "https://git.univ-reunion.fr/sda-php/nulib-base.git",
"reference": "ea531c41bcb054250b0efc334c6aaa6f77543070"
"version": "dev-dev74",
"dist": {
"type": "path",
"url": "../nulib-base",
"reference": "a319baec05c4022edc07f738a9f4cbad3e486b82"
},
"require": {
"ext-json": "*",
@ -632,18 +632,20 @@
}
],
"description": "fonctions et classes essentielles",
"time": "2025-05-30T18:35:54+00:00"
"transport-options": {
"relative": true
}
},
{
"name": "nulib/phpss",
"version": "0.6.0p74",
"source": {
"type": "git",
"url": "https://git.univ-reunion.fr/sda-php/nulib-phpss.git",
"reference": "8efedccb6ac52f7f487c503fa820c4749a5aa229"
"version": "dev-dev74",
"dist": {
"type": "path",
"url": "../nulib-phpss",
"reference": "bed69e608189be07e2a5d76940866e340a2264de"
},
"require": {
"nulib/base": "^0.6.0p74",
"nulib/base": "^7.4-dev",
"php": "^7.4",
"phpoffice/phpspreadsheet": "^1.0"
},
@ -674,15 +676,17 @@
}
],
"description": "wrapper pour phpoffice/phpspreadsheet",
"time": "2025-05-30T19:18:29+00:00"
"transport-options": {
"relative": true
}
},
{
"name": "nulib/spout",
"version": "0.6.0p74",
"source": {
"type": "git",
"url": "https://git.univ-reunion.fr/sda-php/nulib-spout.git",
"reference": "042a0a0bb48216898369d612ffc16e25cfea03a1"
"version": "dev-dev74",
"dist": {
"type": "path",
"url": "../nulib-spout",
"reference": "cc2bce3c206bd6b0a0405269db348d3936cf69f3"
},
"require": {
"ext-dom": "*",
@ -690,7 +694,7 @@
"ext-libxml": "*",
"ext-xmlreader": "*",
"ext-zip": "*",
"nulib/base": "^0.6.0p74",
"nulib/base": "^7.4-dev",
"php": "^7.4"
},
"replace": {
@ -728,7 +732,9 @@
}
],
"description": "wrapper pour openspout/openspout",
"time": "2025-05-30T18:54:07+00:00"
"transport-options": {
"relative": true
}
},
{
"name": "nulib/tests",
@ -2951,7 +2957,11 @@
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"stability-flags": {
"nulib/base": 20,
"nulib/spout": 20,
"nulib/phpss": 20
},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {

View File

@ -1,123 +0,0 @@
#!/usr/bin/php
<?php
require $_composer_autoload_path?? __DIR__.'/../vendor/autoload.php';
use nulib\db\Capacitor;
use nulib\db\CapacitorChannel;
use nulib\db\mysql\MysqlStorage;
use nulib\file\Stream;
use nur\cli\Application;
use nur\config;
use nur\yaml;
Application::run(new class extends Application {
const ACTION_QUERY = 0, ACTION_SQL = 1;
const ARGS = [
"merge" => parent::ARGS,
"purpose" => "gestion d'un capacitor mysql",
"usage" => [
"-d DBCONN -c CHANNEL [--query] key=value...",
"-d DBCONN -c CHANNEL --sql-create",
],
["-d", "--dbconn", "args" => 1,
"help" => "nom de la connexion à la base de données",
],
["-t", "--table-name", "args" => 1,
"help" => "nom de la table porteuse du canal de données",
],
["-c", "--channel-class", "args" => 1,
"help" => "nom de la classe dérivée de CapacitorChannel",
],
["--query", "name" => "action", "value" => self::ACTION_QUERY,
"help" => "lister les lignes correspondant aux valeurs spécifiées. c'est l'action par défaut",
],
["-s", "--sql-create", "name" => "action", "value" => self::ACTION_SQL,
"help" => "afficher la requête pour créer la table",
],
];
protected ?string $dbconn = null;
protected ?string $tableName = null;
protected ?string $channelClass = null;
protected int $action = self::ACTION_QUERY;
protected ?array $args = null;
protected static function isa_cond(string $arg, ?array &$ms=null): bool {
return preg_match('/^(.+?)\s*(=|<>|<|>|<=|>=|(?:is\s+)?null|(?:is\s+)?not\s+null)\s*(.*)$/', $arg, $ms);
}
function main() {
$dbconn = $this->dbconn;
if ($dbconn === null) self::die("Vous devez spécifier la base de données");
$tmp = config::db($dbconn);
if ($tmp === null) self::die("$dbconn: base de données invalide");
$dbconn = $tmp;
if ($this->channelClass !== null) {
$channelClass = str_replace("/", "\\", $this->channelClass);
$channel = new $channelClass;
} elseif ($this->tableName !== null) {
$channel = new class($this->tableName) extends CapacitorChannel {
function __construct(?string $name=null) {
parent::__construct($name);
$this->tableName = $name;
}
};
} else {
self::die("Vous devez spécifier le canal de données");
}
$storage = new MysqlStorage($dbconn);
$capacitor = new Capacitor($storage, $channel);
switch ($this->action) {
case self::ACTION_QUERY:
$args = $this->args;
if (!$args) {
# lister les id
$out = new Stream(STDOUT);
$primaryKeys = $storage->getPrimaryKeys($channel);
$rows = $storage->db()->all([
"select",
"cols" => $primaryKeys,
"from" => $channel->getTableName(),
]);
$out->fputcsv($primaryKeys);
foreach ($rows as $row) {
$rowIds = $storage->getRowIds($channel, $row);
$out->fputcsv($rowIds);
}
} else {
# afficher les lignes correspondantes
if (count($args) == 1 && !self::isa_cond($args[0])) {
$filter = $args[0];
} else {
$filter = [];
$ms = null;
foreach ($args as $arg) {
if (self::isa_cond($arg, $ms)) {
$filter[$ms[1]] = [$ms[2], $ms[3]];
} else {
$filter[$arg] = ["not null"];
}
}
}
$first = true;
$capacitor->each($filter, function ($item, $row) use (&$first) {
if ($first) $first = false;
else echo "---\n";
yaml::dump($row);
});
}
break;
case self::ACTION_SQL:
echo $capacitor->getCreateSql()."\n";
break;
}
}
});

View File

@ -8,6 +8,7 @@ use nur\b\ExitError;
use nur\co;
use nur\config;
use nur\func;
use nur\json;
use nur\v\html5\Html5BasicErrorPage;
use nur\v\model\IChildComponent;
use nur\v\model\IComponent;
@ -19,6 +20,7 @@ use nur\v\page;
use nur\v\prefix;
use nur\v\vo;
use Throwable;
use Traversable;
abstract class AbstractPageContainer implements IPageContainer {
protected static function ensure_preparec(IComponent $c, bool $afterPrepare=false): bool {
@ -41,10 +43,10 @@ abstract class AbstractPageContainer implements IPageContainer {
return false;
}
protected static function ensure_setupc(IComponent $c, bool $afterSetup=false): bool {
protected static function ensure_setupc(IComponent $c, bool $afterSetup=false, &$output=null): bool {
if (!$c->didSetup()) {
$c->beforeSetup();
$c->setup();
$output = $c->setup();
if ($afterSetup) $c->afterSetup();
return true;
}
@ -248,6 +250,7 @@ abstract class AbstractPageContainer implements IPageContainer {
function print(): void {
$page = $this->page;
page::set_current_page($page);
$output = null;
try {
$this->phase = self::PREPARE_PHASE;
@ -265,14 +268,43 @@ abstract class AbstractPageContainer implements IPageContainer {
config::configure($this->config["configure_options"]);
$this->phase = self::SETUP_PHASE;
if (self::ensure_setupc($page)) {
if (self::ensure_setupc($page, false, $output)) {
$this->overrideSetup($page);
$page->afterSetup();
}
$this->phase = self::PRINT_PHASE;
$this->overridePrint($page);
if ($output instanceof IComponent) {
self::ensure_phasec($output);
if ($this->beforePrint($output)) {
$this->haveOutput = true;
co::_print([$output]);
}
} elseif (is_callable($output)) {
if ($this->beforePrint(null)) {
$this->haveOutput = true;
$output();
}
} elseif ($output !== null) {
if ($this->beforePrint(null)) {
$this->haveOutput = true;
if (is_iterable($output)) {
header("Content-Type: application/json");
echo "[";
$sep = "";
foreach ($output as $data) {
$line = json::encode($data);
echo "$sep$line\n";
$sep = ",";
}
echo "]";
} else {
co::_print([strval($output)]);
}
}
} else {
$this->overridePrint($page);
}
} catch (Throwable $e) {
if ($e instanceof ExitError && !$e->isError()) {
# NOP
@ -293,6 +325,9 @@ abstract class AbstractPageContainer implements IPageContainer {
}
if ($page->didSetup()) {
$this->phase = self::TEARDOWN_PHASE;
if ($output instanceof IComponent) {
self::ensure_teardownc($output);
}
if (self::ensure_teardownc($page)) {
$this->overrideTeardown($page);
$page->afterTeardown();
@ -310,11 +345,14 @@ abstract class AbstractPageContainer implements IPageContainer {
protected function overrideSetup(IPage $page): void {
}
protected function beforePrint(?IComponent $component): bool {
return $component === null || $component->haveContent();
}
protected function overridePrint(IPage $page): void {
if ($page->haveContent()) {
$this->haveOutput = true;
co::_print([$page]);
}
if (!$this->beforePrint($page)) return;
$this->haveOutput = true;
co::_print([$page]);
}
protected function overrideTeardown(IPage $page): void {

View File

@ -55,7 +55,7 @@ trait TComponent {
protected $setupDone = false;
function beforeSetup(): void {}
function setup(): void {}
function setup() {}
function afterSetup(): void { $this->setupDone = true; }
function didSetup(): bool { return $this->setupDone; }

View File

@ -11,6 +11,7 @@ class Bs3IconManager implements IIconManager {
"warning" => "exclamation-sign",
"error" => "remove-sign",
"pending" => "hourglass",
"refresh",
"config" => "cog",
"save" => "floppy-disk",
@ -83,6 +84,7 @@ EOT;
'success' => 'ok-sign',
'warning' => 'exclamation-sign',
'error' => 'remove-sign',
'pending' => 'hourglass',
'refresh' => 'refresh',
'config' => 'cog',
'save' => 'floppy-disk',
@ -139,6 +141,7 @@ EOT;
'<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>',
];
const ERROR = /*autogen*/['<span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span>'];
const PENDING = /*autogen*/['<span class="glyphicon glyphicon-hourglass" aria-hidden="true"></span>'];
const REFRESH = /*autogen*/['<span class="glyphicon glyphicon-refresh" aria-hidden="true"></span>'];
const CONFIG = /*autogen*/['<span class="glyphicon glyphicon-cog" aria-hidden="true"></span>'];
const SAVE = /*autogen*/['<span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span>'];

View File

@ -6,6 +6,7 @@ use nur\co;
use nur\session;
use nur\v\ly;
use nur\v\model\IBasicPage;
use nur\v\model\IComponent;
use nur\v\model\IPage;
class Html5BasicPageContainer extends Html5VanillaPageContainer {
@ -23,30 +24,31 @@ class Html5BasicPageContainer extends Html5VanillaPageContainer {
function isAutocloseSession(): bool { return $this->config["autoclose_session"]; }
protected function overridePrint(IPage $page): void {
protected function beforePrint(?IComponent $component): bool {
if ($this->isAutocloseSession()) session::close();
return parent::beforePrint($component);
}
protected function overridePrint(IPage $page): void {
if (!$this->beforePrint($page)) return;
if ($page instanceof IBasicPage) {
if ($page->haveContent()) {
$this->doResolveConfig();
$this->haveOutput = true;
$this->printStartHtml();
$this->printStartHead();
$this->printCss();
$this->printJs();
$this->printScript();
$this->printHeadTitle();
$this->printEndHead();
$this->printStartBody();
$this->printContent();
$this->printEndBody();
$this->printEndHtml();
}
$this->doResolveConfig();
$this->haveOutput = true;
$this->printStartHtml();
$this->printStartHead();
$this->printCss();
$this->printJs();
$this->printScript();
$this->printHeadTitle();
$this->printEndHead();
$this->printStartBody();
$this->printContent();
$this->printEndBody();
$this->printEndHtml();
} else {
# si ce n'est pas une instance de IBasicPage, l'imprimer tel quel
if ($page->haveContent()) {
$this->haveOutput = true;
co::_write([$this->page]);
}
$this->haveOutput = true;
co::_write([$page]);
}
}

View File

@ -12,69 +12,65 @@ use nur\v\v;
class Html5NavigablePageContainer extends Html5BasicPageContainer {
protected function overridePrint(IPage $page): void {
if ($this->isAutocloseSession()) session::close();
if (!$this->beforePrint($page)) return;
if ($page instanceof IBasicPage) {
if ($page->haveContent()) {
$this->doResolveConfig();
$this->haveOutput = true;
$this->printStartHtml();
$this->printStartHead();
$this->printCss();
$this->printJs();
$this->printScript();
$this->printHeadTitle();
$this->printEndHead();
$this->printStartBody();
if ($page instanceof INavigablePage) {
$showNavigation = $page->navigationShowNavigation();
$implementsOwnLayout = $page->navigationImplementsOwnLayout();
$containerOptions = $page->CONTAINER_OPTIONS();
} else {
$showNavigation = false;
$containerOptions = null;
}
if ($showNavigation) {
$page->beforePrintStartNavigation();
if ($implementsOwnLayout) $page->printStartNavigation();
else $this->printStartNavigation($page->NAVBAR_OPTIONS());
$page->afterPrintStartNavigation();
$page->beforePrintNavigation();
$page->printNavigation();
$page->afterPrintNavigation();
$page->beforePrintEndNavigation();
if ($implementsOwnLayout) $page->printEndNavigation();
else $this->printEndNavigation();
$page->afterPrintEndNavigation();
$page->beforePrintStartContainer();
if ($implementsOwnLayout) $page->printStartContainer();
else $this->printStartContainer($containerOptions);
$page->afterPrintStartContainer();
} else {
$this->printStartContainer($containerOptions);
}
$this->printContent();
# s'assurer que le layout est correctement fermé
ly::end();
if ($showNavigation) {
$page->beforePrintEndContainer();
if ($implementsOwnLayout) $page->printEndContainer();
else $this->printEndContainer();
$page->afterPrintEndContainer();
} else {
$this->printEndContainer();
}
$this->printEndBody();
$this->printEndHtml();
$this->doResolveConfig();
$this->haveOutput = true;
$this->printStartHtml();
$this->printStartHead();
$this->printCss();
$this->printJs();
$this->printScript();
$this->printHeadTitle();
$this->printEndHead();
$this->printStartBody();
if ($page instanceof INavigablePage) {
$showNavigation = $page->navigationShowNavigation();
$implementsOwnLayout = $page->navigationImplementsOwnLayout();
$containerOptions = $page->CONTAINER_OPTIONS();
} else {
$showNavigation = false;
$containerOptions = null;
}
if ($showNavigation) {
$page->beforePrintStartNavigation();
if ($implementsOwnLayout) $page->printStartNavigation();
else $this->printStartNavigation($page->NAVBAR_OPTIONS());
$page->afterPrintStartNavigation();
$page->beforePrintNavigation();
$page->printNavigation();
$page->afterPrintNavigation();
$page->beforePrintEndNavigation();
if ($implementsOwnLayout) $page->printEndNavigation();
else $this->printEndNavigation();
$page->afterPrintEndNavigation();
$page->beforePrintStartContainer();
if ($implementsOwnLayout) $page->printStartContainer();
else $this->printStartContainer($containerOptions);
$page->afterPrintStartContainer();
} else {
$this->printStartContainer($containerOptions);
}
$this->printContent();
# s'assurer que le layout est correctement fermé
ly::end();
if ($showNavigation) {
$page->beforePrintEndContainer();
if ($implementsOwnLayout) $page->printEndContainer();
else $this->printEndContainer();
$page->afterPrintEndContainer();
} else {
$this->printEndContainer();
}
$this->printEndBody();
$this->printEndHtml();
} else {
# si ce n'est pas une instance de IBasicPage, l'imprimer tel quel
if ($page->haveContent()) {
$this->haveOutput = true;
co::_write([$this->page]);
}
$this->haveOutput = true;
co::_write([$this->page]);
}
}

View File

@ -12,6 +12,7 @@ use nur\v\base\AbstractPageContainer;
use nur\v\base\MenuManager;
use nur\v\fo;
use nur\v\ly;
use nur\v\model\IBasicPage;
use nur\v\model\IComponent;
use nur\v\model\IPage;
use nur\v\model\IPlugin;
@ -46,7 +47,8 @@ class Html5VanillaPageContainer extends AbstractPageContainer {
}
protected function overridePrint(IPage $page): void {
if ($page->haveContent()) {
if (!$this->beforePrint($page)) return;
if ($page instanceof IPage) {
$this->doResolveConfig();
$this->haveOutput = true;
$this->printStartHtml();
@ -62,6 +64,10 @@ class Html5VanillaPageContainer extends AbstractPageContainer {
$this->printContent();
$this->printEndBody();
$this->printEndHtml();
} else {
# si ce n'est pas une instance de IPage, l'imprimer tel quel
$this->haveOutput = true;
co::_write([$page]);
}
}

View File

@ -47,57 +47,58 @@ class icon {
#############################################################################
static final function info(?string $suffix=null, ?string $alt="INFO: "): array { return self::manager()->getIcon("info", $suffix, $alt); }
static final function success(?string $suffix=null, ?string $alt="SUCCESS: "): array { return self::manager()->getIcon("success", $suffix, $alt); }
static final function warning(?string $suffix=null, ?string $alt="WARNING: "): array { return self::manager()->getIcon("warning", $suffix, $alt); }
static final function error(?string $suffix=null, ?string $alt="ERROR: "): array { return self::manager()->getIcon("error", $suffix, $alt); }
static final function info($suffix=null, ?string $alt="INFO: "): array { return self::manager()->getIcon("info", $suffix, $alt); }
static final function success($suffix=null, ?string $alt="SUCCESS: "): array { return self::manager()->getIcon("success", $suffix, $alt); }
static final function warning($suffix=null, ?string $alt="WARNING: "): array { return self::manager()->getIcon("warning", $suffix, $alt); }
static final function error($suffix=null, ?string $alt="ERROR: "): array { return self::manager()->getIcon("error", $suffix, $alt); }
static final function refresh(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("refresh", $suffix, $alt); }
static final function config(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("config", $suffix, $alt); }
static final function save(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("save", $suffix, $alt); }
static final function download(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("download", $suffix, $alt); }
static final function upload(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("upload", $suffix, $alt); }
static final function bin(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("bin", $suffix, $alt); }
static final function mail(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("mail", $suffix, $alt); }
static final function search(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("search", $suffix, $alt); }
static final function user(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("user", $suffix, $alt); }
static final function login(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("login", $suffix, $alt); }
static final function logout(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("logout", $suffix, $alt); }
static final function new_window(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("new_window", $suffix, $alt); }
static final function pending($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("hourglass", $suffix, $alt); }
static final function refresh($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("refresh", $suffix, $alt); }
static final function config($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("config", $suffix, $alt); }
static final function save($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("save", $suffix, $alt); }
static final function download($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("download", $suffix, $alt); }
static final function upload($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("upload", $suffix, $alt); }
static final function bin($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("bin", $suffix, $alt); }
static final function mail($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("mail", $suffix, $alt); }
static final function search($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("search", $suffix, $alt); }
static final function user($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("user", $suffix, $alt); }
static final function login($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("login", $suffix, $alt); }
static final function logout($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("logout", $suffix, $alt); }
static final function new_window($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("new_window", $suffix, $alt); }
static final function ignore(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("fast-forward", $suffix, $alt); }
static final function replace(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("erase", $suffix, $alt); }
static final function delete(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("remove", $suffix, $alt); }
static final function ignore($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("fast-forward", $suffix, $alt); }
static final function replace($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("erase", $suffix, $alt); }
static final function delete($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("remove", $suffix, $alt); }
static final function arrow_up(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("arrow_up", $suffix, $alt); }
static final function arrow_down(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("arrow_down", $suffix, $alt); }
static final function arrow_left(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("arrow_left", $suffix, $alt); }
static final function arrow_right(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("arrow_right", $suffix, $alt); }
static final function chevron_up(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("chevron_up", $suffix, $alt); }
static final function chevron_down(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("chevron_down", $suffix, $alt); }
static final function chevron_left(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("chevron_left", $suffix, $alt); }
static final function chevron_right(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("chevron_right", $suffix, $alt); }
static final function hand_up(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("hand_up", $suffix, $alt); }
static final function hand_down(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("hand_down", $suffix, $alt); }
static final function hand_left(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("hand_left", $suffix, $alt); }
static final function hand_right(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("hand_right", $suffix, $alt); }
static final function menu_up(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("menu_up", $suffix, $alt); }
static final function menu_down(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("menu_down", $suffix, $alt); }
static final function menu_left(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("menu_left", $suffix, $alt); }
static final function menu_right(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("menu_right", $suffix, $alt); }
static final function triangle_up(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("triangle_up", $suffix, $alt); }
static final function triangle_down(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("triangle_down", $suffix, $alt); }
static final function triangle_left(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("triangle_left", $suffix, $alt); }
static final function triangle_right(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("triangle_right", $suffix, $alt); }
static final function arrow_up($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("arrow_up", $suffix, $alt); }
static final function arrow_down($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("arrow_down", $suffix, $alt); }
static final function arrow_left($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("arrow_left", $suffix, $alt); }
static final function arrow_right($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("arrow_right", $suffix, $alt); }
static final function chevron_up($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("chevron_up", $suffix, $alt); }
static final function chevron_down($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("chevron_down", $suffix, $alt); }
static final function chevron_left($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("chevron_left", $suffix, $alt); }
static final function chevron_right($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("chevron_right", $suffix, $alt); }
static final function hand_up($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("hand_up", $suffix, $alt); }
static final function hand_down($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("hand_down", $suffix, $alt); }
static final function hand_left($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("hand_left", $suffix, $alt); }
static final function hand_right($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("hand_right", $suffix, $alt); }
static final function menu_up($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("menu_up", $suffix, $alt); }
static final function menu_down($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("menu_down", $suffix, $alt); }
static final function menu_left($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("menu_left", $suffix, $alt); }
static final function menu_right($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("menu_right", $suffix, $alt); }
static final function triangle_up($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("triangle_up", $suffix, $alt); }
static final function triangle_down($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("triangle_down", $suffix, $alt); }
static final function triangle_left($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("triangle_left", $suffix, $alt); }
static final function triangle_right($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("triangle_right", $suffix, $alt); }
static final function star(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("star", $suffix, $alt); }
static final function star_empty(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("star_empty", $suffix, $alt); }
static final function heart(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("heart", $suffix, $alt); }
static final function heart_empty(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("heart_empty", $suffix, $alt); }
static final function star($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("star", $suffix, $alt); }
static final function star_empty($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("star_empty", $suffix, $alt); }
static final function heart($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("heart", $suffix, $alt); }
static final function heart_empty($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("heart_empty", $suffix, $alt); }
static final function plus(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("plus", $suffix, $alt); }
static final function minus(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("minus", $suffix, $alt); }
static final function plus($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("plus", $suffix, $alt); }
static final function minus($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("minus", $suffix, $alt); }
# template:
#static final function xxx(?string $suffix=null, ?string $alt=null): array { return self::manager()->getIcon("xxx", $suffix, $alt); }
#static final function xxx($suffix=null, ?string $alt=null): array { return self::manager()->getIcon("xxx", $suffix, $alt); }
}

View File

@ -43,7 +43,7 @@ interface IComponent extends IPlugin {
function beforeSetup(): void;
/** initialiser le composant */
function setup(): void;
function setup();
/** marquer le composant comme initialisé */
function afterSetup(): void;

View File

@ -23,7 +23,7 @@ class AppCasauthPage extends AbstractPage {
/** @var string nom de l'utilisateur connecté */
private $user;
function setup(): void {
function setup() {
$destUrl = $retUrl = null;
$user = false;
if ($user === false) $user = A::get($_SERVER, "REMOTE_USER", false);

View File

@ -9,7 +9,7 @@ class AppDevauthPage extends AInitPage {
/** @var string nom de l'utilisateur connecté */
private $user;
function setup(): void {
function setup() {
if (!$this->isDevauthAllowed()) {
page::redirect($this->getLoginUrl());
}

View File

@ -23,7 +23,7 @@ class AppExtauthPage extends AbstractPage {
/** @var string nom de l'utilisateur connecté */
private $user;
function setup(): void {
function setup() {
$destUrl = null;
$user = false;
if ($user === false) $user = A::get($_SERVER, "REMOTE_USER", false);

View File

@ -16,7 +16,7 @@ class AppLogoutPage extends AInitPage {
return static::DEBUG || F::get("d");
}
function setup(): void {
function setup() {
cookie::set("MOD_AUTH_CAS", false);
cookie::set("MOD_AUTH_CAS_S", false);
authz::manager()->resetSession(authz::DISCONNECTED);

View File

@ -63,7 +63,7 @@ class CacheChannel extends CapacitorChannel {
]);
}
function onCreate($item, array $values, ?array $alwaysNull, ?string $duration=null): ?array {
function onCreate($item, array $row, ?array $alwaysNull, ?string $duration=null): ?array {
$now = new DateTime();
$duration ??= $this->duration;
return [
@ -72,7 +72,7 @@ class CacheChannel extends CapacitorChannel {
];
}
function onUpdate($item, array $values, array $pvalues, ?string $duration=null): ?array {
function onUpdate($item, array $row, array $prow, ?string $duration=null): ?array {
$now = new DateTime();
$duration ??= $this->duration;
return [
@ -97,9 +97,9 @@ class CacheChannel extends CapacitorChannel {
$found = false;
$expired = false;
$this->each($cacheIds,
function($item, $values) use (&$found, &$expired) {
function($row) use (&$found, &$expired) {
$found = true;
$expired = $values["duration"]->isElapsed();
$expired = $row["duration"]->isElapsed();
});
return !$found || $expired;
}

View File

@ -1,48 +1,17 @@
#!/usr/bin/php
<?php
require $_composer_autoload_path?? __DIR__.'/../vendor/autoload.php';
namespace nulib\cli;
use nulib\A;
use nulib\app\cli\Application;
use nulib\db\Capacitor;
use nulib\db\CapacitorChannel;
use nulib\db\sqlite\SqliteStorage;
use nulib\db\CapacitorStorage;
use nulib\ext\yaml;
use nulib\file\Stream;
use nur\cli\Application;
use nur\msg;
use nur\yaml;
use nulib\output\msg;
Application::run(new class extends Application {
const ACTION_QUERY = 0, ACTION_SQL = 1;
const ARGS = [
"merge" => parent::ARGS,
"purpose" => "gestion d'un capacitor sqlite",
"usage" => [
"-f DBFILE -n CHANNEL [--query] key=value...",
"-f DBFILE -n CHANNEL --sql-create",
],
["-f", "--dbfile", "args" => 1,
"help" => "chemin vers la base de données",
],
["-n", "--name", "args" => 1,
"help" => "nom du canal de données. table-name et channel-class sont chargés depuis la base de données",
],
["-t", "--table-name", "args" => 1,
"help" => "nom de la table porteuse du canal de données",
],
["-c", "--channel-class", "args" => 1,
"help" => "nom de la classe dérivée de CapacitorChannel",
],
["--query", "name" => "action", "value" => self::ACTION_QUERY,
"help" => "lister les lignes correspondant aux valeurs spécifiées. c'est l'action par défaut",
],
["-s", "--sql-create", "name" => "action", "value" => self::ACTION_SQL,
"help" => "afficher la requête pour créer la table",
],
];
protected ?string $dbfile = null;
protected ?string $name = null;
abstract class AbstractStorageApp extends Application {
const ACTION_RESET = 0, ACTION_QUERY = 1, ACTION_SQL = 2;
protected ?string $tableName = null;
@ -50,28 +19,28 @@ Application::run(new class extends Application {
protected int $action = self::ACTION_QUERY;
protected bool $recreate = true;
protected ?array $args = null;
protected static function isa_cond(string $arg, ?array &$ms=null): bool {
return preg_match('/^(.+?)\s*(=|<>|<|>|<=|>=|(?:is\s+)?null|(?:is\s+)?not\s+null)\s*(.*)$/', $arg, $ms);
}
function main() {
$dbfile = $this->dbfile;
if ($dbfile === null) self::die("Vous devez spécifier la base de données");
if (!file_exists($dbfile)) self::die("$dbfile: fichier introuvable");
$storage = new SqliteStorage($dbfile);
$db = $storage->db();
protected function storageCtl(CapacitorStorage $storage): void {
$args = $this->args;
$name = $this->name;
$channelClass = $this->channelClass;
$tableName = $this->tableName;
if ($name !== null) {
if (!$storage->channelExists($name, $row)) {
self::die("$name: nom de canal de données introuvable");
if ($channelClass === null && $tableName === null) {
$name = A::shift($args);
if ($name !== null) {
if (!$storage->channelExists($name, $row)) {
self::die("$name: nom de canal de données introuvable");
}
if ($row["class_name"] !== "class@anonymous") $channelClass = $row["class_name"];
else $tableName = $row["table_name"];
}
if ($row["class_name"] !== "class@anonymous") $channelClass = $row["class_name"];
else $tableName = $row["table_name"];
}
if ($channelClass !== null) {
$channelClass = str_replace("/", "\\", $channelClass);
@ -95,13 +64,15 @@ Application::run(new class extends Application {
$capacitor = new Capacitor($storage, $channel);
switch ($this->action) {
case self::ACTION_RESET:
$capacitor->reset($this->recreate);
break;
case self::ACTION_QUERY:
$args = $this->args;
if (!$args) {
# lister les id
$out = new Stream(STDOUT);
$primaryKeys = $storage->getPrimaryKeys($channel);
$rows = $db->all([
$rows = $storage->db()->all([
"select",
"cols" => $primaryKeys,
"from" => $channel->getTableName(),
@ -139,4 +110,4 @@ Application::run(new class extends Application {
break;
}
}
});
}

124
src/cli/BgLauncherApp.php Normal file
View File

@ -0,0 +1,124 @@
<?php
namespace nulib\cli;
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;
}
}
}

View File

@ -1,5 +1,5 @@
<?php
namespace nulib\tools;
namespace nulib\cli;
use nulib\app\cli\Application;
use nulib\ext\tab\SsBuilder;

View File

@ -1,5 +1,5 @@
<?php
namespace nulib\tools;
namespace nulib\cli;
use nulib\app\cli\Application;
use nulib\ext\yaml;

View File

@ -1,5 +1,5 @@
<?php
namespace nulib\tools;
namespace nulib\cli;
use nulib\app\cli\Application;
use nulib\ext\json;

View File

@ -0,0 +1,45 @@
<?php
namespace nulib\cli;
use nulib\A;
use nulib\db\mysql\MysqlStorage;
use nur\config;
class MysqlStorageApp extends AbstractStorageApp {
const ARGS = [
"merge" => parent::ARGS,
"purpose" => "gestion d'un capacitor mysql",
"usage" => [
"DBCONN [CHANNEL_NAME | -t TABLE | -c CHANNEL_CLASS] [--query] key=value...",
"DBCONN [CHANNEL_NAME | -t TABLE | -c CHANNEL_CLASS] --sql-create",
],
["-t", "--table-name", "args" => 1,
"help" => "nom de la table porteuse du canal de données",
],
["-c", "--channel-class", "args" => 1,
"help" => "nom de la classe dérivée de CapacitorChannel",
],
["-z", "--reset", "name" => "action", "value" => self::ACTION_RESET,
"help" => "réinitialiser le canal",
],
["-n", "--no-recreate", "name" => "recreate", "value" => false,
"help" => "ne pas recréer la table correspondant au canal"
],
["--query", "name" => "action", "value" => self::ACTION_QUERY,
"help" => "lister les lignes correspondant aux valeurs spécifiées. c'est l'action par défaut",
],
["-s", "--sql-create", "name" => "action", "value" => self::ACTION_SQL,
"help" => "afficher la requête pour créer la table",
],
];
function main() {
$dbconn = A::shift($this->args);
if ($dbconn === null) self::die("Vous devez spécifier la base de données");
$tmp = config::db($dbconn);
if ($tmp === null) self::die("$dbconn: base de données invalide");
$storage = new MysqlStorage($tmp);
$this->storageCtl($storage);
}
}

View File

@ -1,10 +1,10 @@
<?php
namespace nulib\tools;
namespace nulib\cli;
use Exception;
use nulib\app\cli\Application;
use nulib\ext\yaml;
use nulib\cache\CacheFile;
use nulib\ext\yaml;
use nulib\os\path;
use nulib\output\msg;

View File

@ -0,0 +1,45 @@
<?php
namespace nulib\cli;
use nulib\A;
use nulib\db\pgsql\PgsqlStorage;
use nur\config;
class PgsqlStorageApp extends AbstractStorageApp {
const ARGS = [
"merge" => parent::ARGS,
"purpose" => "gestion d'un capacitor pgsql",
"usage" => [
"DBCONN [CHANNEL_NAME | -t TABLE | -c CHANNEL_CLASS] [--query] key=value...",
"DBCONN [CHANNEL_NAME | -t TABLE | -c CHANNEL_CLASS] --sql-create",
],
["-t", "--table-name", "args" => 1,
"help" => "nom de la table porteuse du canal de données",
],
["-c", "--channel-class", "args" => 1,
"help" => "nom de la classe dérivée de CapacitorChannel",
],
["-z", "--reset", "name" => "action", "value" => self::ACTION_RESET,
"help" => "réinitialiser le canal",
],
["-n", "--no-recreate", "name" => "recreate", "value" => false,
"help" => "ne pas recréer la table correspondant au canal"
],
["--query", "name" => "action", "value" => self::ACTION_QUERY,
"help" => "lister les lignes correspondant aux valeurs spécifiées. c'est l'action par défaut",
],
["-s", "--sql-create", "name" => "action", "value" => self::ACTION_SQL,
"help" => "afficher la requête pour créer la table",
],
];
function main() {
$dbconn = A::shift($this->args);
if ($dbconn === null) self::die("Vous devez spécifier la base de données");
$tmp = config::db($dbconn);
if ($tmp === null) self::die("$dbconn: base de données invalide");
$storage = new PgsqlStorage($tmp);
$this->storageCtl($storage);
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace nulib\cli;
use nulib\A;
use nulib\db\sqlite\SqliteStorage;
class SqliteStorageApp extends AbstractStorageApp {
const ARGS = [
"merge" => parent::ARGS,
"purpose" => "gestion d'un capacitor sqlite",
"usage" => [
"DBFILE [CHANNEL_NAME | -t TABLE | -c CHANNEL_CLASS] [--query] key=value...",
"DBFILE [CHANNEL_NAME | -t TABLE | -c CHANNEL_CLASS] --sql-create",
],
["-t", "--table-name", "args" => 1,
"help" => "nom de la table porteuse du canal de données",
],
["-c", "--channel-class", "args" => 1,
"help" => "nom de la classe dérivée de CapacitorChannel",
],
["-z", "--reset", "name" => "action", "value" => self::ACTION_RESET,
"help" => "réinitialiser le canal",
],
["-n", "--no-recreate", "name" => "recreate", "value" => false,
"help" => "ne pas recréer la table correspondant au canal"
],
["--query", "name" => "action", "value" => self::ACTION_QUERY,
"help" => "lister les lignes correspondant aux valeurs spécifiées. c'est l'action par défaut",
],
["-s", "--sql-create", "name" => "action", "value" => self::ACTION_SQL,
"help" => "afficher la requête pour créer la table",
],
];
function main() {
$dbfile = A::shift($this->args);
if ($dbfile === null) self::die("Vous devez spécifier la base de données");
if (!file_exists($dbfile)) self::die("$dbfile: fichier introuvable");
$storage = new SqliteStorage($dbfile);
$this->storageCtl($storage);
}
}

53
src/cli/SteamTrainApp.php Normal file
View File

@ -0,0 +1,53 @@
<?php
namespace nulib\cli;
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());
}
}

View File

@ -1,5 +1,5 @@
<?php
namespace nulib\tools;
namespace nulib\cli;
use nulib\app\cli\Application;
use nulib\ext\json;

View File

@ -3,20 +3,23 @@
* rajouter l'attribut "size" pour spécifier la taille maximale des valeurs
* cela pourrait servir pour générer automatiquement des tables SQL
* ou pour modéliser un schéma FSV
* support `max_size`, qui diffère de `size` en ce qu'on ne spécifie qu'une
taille maximum. sinon, faire `size` à la place de `max_size` et `fixed_size`
à la plage de `size`
* support allowed_values
* support `allowed_values`
* valeurs composite/computed
* analyse / vérification de la valeur complète après calcul du résultat, si
tous les résultats sont bons
* calcul des valeurs composites/computed par une fonction avant/après l'analyse
globale si résultat ok
* fonction getter_func, setter_func, deleter_func pour les propriétés de type
* fonction `getter_func`, `setter_func`, `deleter_func` pour les propriétés de type
computed
* tdate et tdatetime. qu'en est-il des autres classes (delay, etc.)
* parse_format pour spécifier le format d'analyse au lieu de l'auto-détecter
* `parse_format` pour spécifier le format d'analyse au lieu de l'auto-détecter
* ScalarSchema::from_property()
* `ScalarSchema::from_property()`
* l'argument $format de AssocWrapper::format() est un tableau associatif
`[$key => $format]`
@ -68,7 +71,7 @@
la définition de ces "circonstances" est encore à faire: soit un paramètre
lors de la définition du schéma, soit un truc magique du genre "toutes les
valeurs séquentielles sont des clés du schéma", soit un mode automatique
activé par un paramètre où une valeur "val" devient "val"=>true si la clé
activé par un paramètre où une valeur `"val"` devient `"val"=>true` si la clé
"val" existe dans le schéma
-*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary