diff --git a/.idea/php.xml b/.idea/php.xml index 3c96682..8f998bb 100644 --- a/.idea/php.xml +++ b/.idea/php.xml @@ -70,6 +70,7 @@ + diff --git a/TODO.md b/TODO.md index 6a61f80..19e0c06 100644 --- a/TODO.md +++ b/TODO.md @@ -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 \ No newline at end of file diff --git a/bin/csv2xlsx.php b/bin/csv2xlsx.php index 0f0bb32..5fb7464 100755 --- a/bin/csv2xlsx.php +++ b/bin/csv2xlsx.php @@ -2,6 +2,6 @@ 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; - } - } -}); diff --git a/nur_src/v/base/AbstractPageContainer.php b/nur_src/v/base/AbstractPageContainer.php index 6c027da..260e607 100644 --- a/nur_src/v/base/AbstractPageContainer.php +++ b/nur_src/v/base/AbstractPageContainer.php @@ -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 { diff --git a/nur_src/v/base/TComponent.php b/nur_src/v/base/TComponent.php index 8d0035d..61dcd46 100644 --- a/nur_src/v/base/TComponent.php +++ b/nur_src/v/base/TComponent.php @@ -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; } diff --git a/nur_src/v/bs3/Bs3IconManager.php b/nur_src/v/bs3/Bs3IconManager.php index 32746ab..f429424 100644 --- a/nur_src/v/bs3/Bs3IconManager.php +++ b/nur_src/v/bs3/Bs3IconManager.php @@ -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; '', ]; const ERROR = /*autogen*/['']; + const PENDING = /*autogen*/['']; const REFRESH = /*autogen*/['']; const CONFIG = /*autogen*/['']; const SAVE = /*autogen*/['']; diff --git a/nur_src/v/html5/Html5BasicPageContainer.php b/nur_src/v/html5/Html5BasicPageContainer.php index ddcd6fd..4ba485b 100644 --- a/nur_src/v/html5/Html5BasicPageContainer.php +++ b/nur_src/v/html5/Html5BasicPageContainer.php @@ -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]); } } diff --git a/nur_src/v/html5/Html5NavigablePageContainer.php b/nur_src/v/html5/Html5NavigablePageContainer.php index ab02ef1..ccc80b7 100644 --- a/nur_src/v/html5/Html5NavigablePageContainer.php +++ b/nur_src/v/html5/Html5NavigablePageContainer.php @@ -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]); } } diff --git a/nur_src/v/html5/Html5VanillaPageContainer.php b/nur_src/v/html5/Html5VanillaPageContainer.php index bad67ac..47a1fbe 100644 --- a/nur_src/v/html5/Html5VanillaPageContainer.php +++ b/nur_src/v/html5/Html5VanillaPageContainer.php @@ -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]); } } diff --git a/nur_src/v/icon.php b/nur_src/v/icon.php index 7308669..1d20ac1 100644 --- a/nur_src/v/icon.php +++ b/nur_src/v/icon.php @@ -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); } } diff --git a/nur_src/v/model/IComponent.php b/nur_src/v/model/IComponent.php index 30ab379..8b2bd2d 100644 --- a/nur_src/v/model/IComponent.php +++ b/nur_src/v/model/IComponent.php @@ -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; diff --git a/nur_src/v/vp/AppCasauthPage.php b/nur_src/v/vp/AppCasauthPage.php index 43da853..b9158df 100644 --- a/nur_src/v/vp/AppCasauthPage.php +++ b/nur_src/v/vp/AppCasauthPage.php @@ -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); diff --git a/nur_src/v/vp/AppDevauthPage.php b/nur_src/v/vp/AppDevauthPage.php index 398f220..7b0c698 100644 --- a/nur_src/v/vp/AppDevauthPage.php +++ b/nur_src/v/vp/AppDevauthPage.php @@ -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()); } diff --git a/nur_src/v/vp/AppExtauthPage.php b/nur_src/v/vp/AppExtauthPage.php index 75a4653..1cebcc2 100644 --- a/nur_src/v/vp/AppExtauthPage.php +++ b/nur_src/v/vp/AppExtauthPage.php @@ -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); diff --git a/nur_src/v/vp/AppLogoutPage.php b/nur_src/v/vp/AppLogoutPage.php index 27b765d..e6afc6c 100644 --- a/nur_src/v/vp/AppLogoutPage.php +++ b/nur_src/v/vp/AppLogoutPage.php @@ -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); diff --git a/src/cache/CacheChannel.php b/src/cache/CacheChannel.php index f222b09..4272a99 100644 --- a/src/cache/CacheChannel.php +++ b/src/cache/CacheChannel.php @@ -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; } diff --git a/nur_bin/storage.sqlite.php b/src/cli/AbstractStorageApp.php old mode 100755 new mode 100644 similarity index 55% rename from nur_bin/storage.sqlite.php rename to src/cli/AbstractStorageApp.php index a636ce3..9526d74 --- a/nur_bin/storage.sqlite.php +++ b/src/cli/AbstractStorageApp.php @@ -1,48 +1,17 @@ -#!/usr/bin/php 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; } } -}); +} diff --git a/src/cli/BgLauncherApp.php b/src/cli/BgLauncherApp.php new file mode 100644 index 0000000..f9d789d --- /dev/null +++ b/src/cli/BgLauncherApp.php @@ -0,0 +1,124 @@ + "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; + } + } +} diff --git a/src/tools/Csv2xlsxApp.php b/src/cli/Csv2xlsxApp.php similarity index 96% rename from src/tools/Csv2xlsxApp.php rename to src/cli/Csv2xlsxApp.php index 7ac9a59..c38a149 100644 --- a/src/tools/Csv2xlsxApp.php +++ b/src/cli/Csv2xlsxApp.php @@ -1,5 +1,5 @@ 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); + } +} diff --git a/src/tools/NucacheApp.php b/src/cli/NucacheApp.php similarity index 99% rename from src/tools/NucacheApp.php rename to src/cli/NucacheApp.php index 583e44e..7248f47 100644 --- a/src/tools/NucacheApp.php +++ b/src/cli/NucacheApp.php @@ -1,10 +1,10 @@ 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); + } +} diff --git a/src/cli/SqliteStorageApp.php b/src/cli/SqliteStorageApp.php new file mode 100644 index 0000000..357099d --- /dev/null +++ b/src/cli/SqliteStorageApp.php @@ -0,0 +1,43 @@ + 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); + } +} diff --git a/src/cli/SteamTrainApp.php b/src/cli/SteamTrainApp.php new file mode 100644 index 0000000..3040883 --- /dev/null +++ b/src/cli/SteamTrainApp.php @@ -0,0 +1,53 @@ + self::TITLE, + "description" => << 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()); + } +} diff --git a/src/tools/Yaml2jsonApp.php b/src/cli/Yaml2jsonApp.php similarity index 94% rename from src/tools/Yaml2jsonApp.php rename to src/cli/Yaml2jsonApp.php index 9eba6ea..0cd4541 100644 --- a/src/tools/Yaml2jsonApp.php +++ b/src/cli/Yaml2jsonApp.php @@ -1,5 +1,5 @@ $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 \ No newline at end of file