<pman>Intégration de la branche dev74
This commit is contained in:
		
						commit
						467003a7e4
					
				
							
								
								
									
										16
									
								
								TODO.md
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								TODO.md
									
									
									
									
									
								
							| @ -1,5 +1,6 @@ | |||||||
| # nulib | # nulib/bash | ||||||
| 
 | 
 | ||||||
|  | * [nulib/bash](bash/TODO.md) | ||||||
| * runners | * runners | ||||||
|   * [ ] rnlphp -- lancer un programme php avec la bonne version (+docker le cas échéant) |   * [ ] rnlphp -- lancer un programme php avec la bonne version (+docker le cas échéant) | ||||||
|     * [ ] utilisable en shebang |     * [ ] utilisable en shebang | ||||||
| @ -12,4 +13,17 @@ | |||||||
|   * [ ] rnlsh -- lancer un shell avec les librairies bash / lancer un script |   * [ ] rnlsh -- lancer un shell avec les librairies bash / lancer un script | ||||||
| * MYTRUEDIR, MYTRUENAME, MYTRUESELF -- résoudre les liens symboliques | * MYTRUEDIR, MYTRUENAME, MYTRUESELF -- résoudre les liens symboliques | ||||||
| 
 | 
 | ||||||
|  | # nulib/php | ||||||
|  | 
 | ||||||
|  | * [nulib](php/src/TODO.md) | ||||||
|  | * [nulib\app](php/src/app/TODO.md) | ||||||
|  | * [nulib\db](php/src/db/TODO.md) | ||||||
|  | * [nulib\os](php/src/os/TODO.md) | ||||||
|  | * [nulib\output](php/src/output/TODO.md) | ||||||
|  | * [nulib\php\time](php/src/php/time/TODO.md) | ||||||
|  | 
 | ||||||
|  | vrac: | ||||||
|  | * PID dans les logs | ||||||
|  | * build --ci | ||||||
|  | 
 | ||||||
| -*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary | -*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary | ||||||
							
								
								
									
										16
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										16
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							| @ -4,7 +4,7 @@ | |||||||
|         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", |         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", | ||||||
|         "This file is @generated automatically" |         "This file is @generated automatically" | ||||||
|     ], |     ], | ||||||
|     "content-hash": "4569957a35f86d8a4964d01c7358935c", |     "content-hash": "71744d15224f445d1aeefe16ec7d1099", | ||||||
|     "packages": [ |     "packages": [ | ||||||
|         { |         { | ||||||
|             "name": "symfony/deprecation-contracts", |             "name": "symfony/deprecation-contracts", | ||||||
| @ -301,16 +301,16 @@ | |||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|             "name": "myclabs/deep-copy", |             "name": "myclabs/deep-copy", | ||||||
|             "version": "1.13.1", |             "version": "1.13.3", | ||||||
|             "source": { |             "source": { | ||||||
|                 "type": "git", |                 "type": "git", | ||||||
|                 "url": "https://github.com/myclabs/DeepCopy.git", |                 "url": "https://github.com/myclabs/DeepCopy.git", | ||||||
|                 "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c" |                 "reference": "faed855a7b5f4d4637717c2b3863e277116beb36" | ||||||
|             }, |             }, | ||||||
|             "dist": { |             "dist": { | ||||||
|                 "type": "zip", |                 "type": "zip", | ||||||
|                 "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/1720ddd719e16cf0db4eb1c6eca108031636d46c", |                 "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/faed855a7b5f4d4637717c2b3863e277116beb36", | ||||||
|                 "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c", |                 "reference": "faed855a7b5f4d4637717c2b3863e277116beb36", | ||||||
|                 "shasum": "" |                 "shasum": "" | ||||||
|             }, |             }, | ||||||
|             "require": { |             "require": { | ||||||
| @ -349,7 +349,7 @@ | |||||||
|             ], |             ], | ||||||
|             "support": { |             "support": { | ||||||
|                 "issues": "https://github.com/myclabs/DeepCopy/issues", |                 "issues": "https://github.com/myclabs/DeepCopy/issues", | ||||||
|                 "source": "https://github.com/myclabs/DeepCopy/tree/1.13.1" |                 "source": "https://github.com/myclabs/DeepCopy/tree/1.13.3" | ||||||
|             }, |             }, | ||||||
|             "funding": [ |             "funding": [ | ||||||
|                 { |                 { | ||||||
| @ -357,7 +357,7 @@ | |||||||
|                     "type": "tidelift" |                     "type": "tidelift" | ||||||
|                 } |                 } | ||||||
|             ], |             ], | ||||||
|             "time": "2025-04-29T12:36:36+00:00" |             "time": "2025-07-05T12:25:42+00:00" | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|             "name": "nikic/php-parser", |             "name": "nikic/php-parser", | ||||||
| @ -2027,6 +2027,8 @@ | |||||||
|         "php": "^7.4" |         "php": "^7.4" | ||||||
|     }, |     }, | ||||||
|     "platform-dev": { |     "platform-dev": { | ||||||
|  |         "ext-mbstring": "*", | ||||||
|  |         "ext-iconv": "*", | ||||||
|         "ext-posix": "*", |         "ext-posix": "*", | ||||||
|         "ext-pcntl": "*", |         "ext-pcntl": "*", | ||||||
|         "ext-curl": "*", |         "ext-curl": "*", | ||||||
|  | |||||||
							
								
								
									
										5
									
								
								php/src/TODO.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								php/src/TODO.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | # nulib | ||||||
|  | 
 | ||||||
|  | * [ ] support de UserException pour ExceptionShadow: distinguer userMessage et techMessage | ||||||
|  | 
 | ||||||
|  | -*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary | ||||||
| @ -3,5 +3,7 @@ | |||||||
| * [ ] ajouter des méthodes normalisées `app::get_cachedir()` et | * [ ] ajouter des méthodes normalisées `app::get_cachedir()` et | ||||||
|   `app::get_cachefile($name)` avec la valeur par défaut |   `app::get_cachefile($name)` avec la valeur par défaut | ||||||
|   `cachedir = $vardir/cache` |   `cachedir = $vardir/cache` | ||||||
|  | * [ ] `app::action()` et `app::step()` appellent automatiquement | ||||||
|  |   `app::_dispatch_signals()` | ||||||
| 
 | 
 | ||||||
| -*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary | -*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary | ||||||
| @ -2,6 +2,9 @@ | |||||||
| namespace nulib\app; | namespace nulib\app; | ||||||
| 
 | 
 | ||||||
| use nulib\A; | use nulib\A; | ||||||
|  | use nulib\cl; | ||||||
|  | use nulib\cv; | ||||||
|  | use nulib\file; | ||||||
| use nulib\str; | use nulib\str; | ||||||
| 
 | 
 | ||||||
| class args { | class args { | ||||||
| @ -10,7 +13,10 @@ class args { | |||||||
|    * - ["myArg" => $value]  devient  ["--my-arg", "$value"] |    * - ["myArg" => $value]  devient  ["--my-arg", "$value"] | ||||||
|    * - ["myOpt" => true]    devient  ["--my-opt"] |    * - ["myOpt" => true]    devient  ["--my-opt"] | ||||||
|    * - ["myOpt" => false]   est omis |    * - ["myOpt" => false]   est omis | ||||||
|    * - les autres valeurs sont prises telles quelles |    * - les autres valeurs sont transformées en chaines puis ajoutée | ||||||
|  |    * | ||||||
|  |    * ainsi, ["myOpt" => "value", "myArg", "myBool" => true] | ||||||
|  |    * devient ["--my-opt", "value", "myArg", "--my-bool"] | ||||||
|    */ |    */ | ||||||
|   static function from_array(?array $array): array { |   static function from_array(?array $array): array { | ||||||
|     $args = []; |     $args = []; | ||||||
| @ -36,4 +42,205 @@ class args { | |||||||
|     } |     } | ||||||
|     return $args; |     return $args; | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   private static function tint(string $value): int { | ||||||
|  |     return intval($value); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   private static function tbool(string $value): bool { | ||||||
|  |     return boolval($value); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   private static function tarray(string $value): ?array { | ||||||
|  |     if ($value === "") return null; | ||||||
|  |     $tmparray = explode(",", $value); | ||||||
|  |     $array = null; | ||||||
|  |     foreach ($tmparray as $tmpvalue) { | ||||||
|  |       [$tmpkey, $tmpvalue] = str::split_pair($tmpvalue); | ||||||
|  |       if ($tmpvalue === null) cv::swap($tmpkey, $tmpvalue); | ||||||
|  |       if ($tmpkey === null) { | ||||||
|  |         $array[] = $tmpvalue; | ||||||
|  |       } else { | ||||||
|  |         if (str::del_suffix($tmpkey, ":int")) { | ||||||
|  |           $tmpvalue = self::tint($tmpvalue); | ||||||
|  |         } elseif (str::del_suffix($tmpkey, ":bool")) { | ||||||
|  |           $tmpvalue = self::tbool($tmpvalue); | ||||||
|  |         } | ||||||
|  |         $array[$tmpkey] = $tmpvalue; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return $array; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * convertir une liste d'arguments en tableau qui est utilisable comme un | ||||||
|  |    * filtre de base de données ou des données d'une requête REST. les arguments | ||||||
|  |    * peuvent être de la forme: | ||||||
|  |    * - "name=value" | ||||||
|  |    *   qui devient dans le tableau ["name" => "value"] | ||||||
|  |    * - "+arg" ou "arg" | ||||||
|  |    *   qui devient dans le tableau ["arg" => true] | ||||||
|  |    * - "-arg" ou "~arg" | ||||||
|  |    *   qui est stocké dans le tableau $query ["arg" => false] | ||||||
|  |    * | ||||||
|  |    * si $allow_file == true, les formes d'arguments suivantes sont reconnues | ||||||
|  |    * aussi: | ||||||
|  |    * - "name=@file"    (1 argument) OU | ||||||
|  |    *   "name=@" "file" (2 arguments) | ||||||
|  |    *   qui deviennent ["name" => new FileReader(file)] | ||||||
|  |    */ | ||||||
|  |   static function build_query(?array $args, bool $allow_file=true): ?array { | ||||||
|  |     $query = null; | ||||||
|  |     $args ??= []; | ||||||
|  |     $keys = array_keys($args); | ||||||
|  |     $index = 0; | ||||||
|  |     $count = count($keys); | ||||||
|  |     while ($index < $count) { | ||||||
|  |       $arg = $args[$keys[$index++]]; | ||||||
|  |       [$name, $value] = str::split_pair($arg, "="); | ||||||
|  |       $checkType = true; | ||||||
|  |       if ($value === null) { | ||||||
|  |         if (str::del_prefix($name, "+")) { | ||||||
|  |           $value = true; | ||||||
|  |         } elseif (str::del_prefix($name, "-") || str::del_prefix($name, "~")) { | ||||||
|  |           $value = false; | ||||||
|  |         } else { | ||||||
|  |           $value = true; | ||||||
|  |         } | ||||||
|  |       } elseif ($allow_file) { | ||||||
|  |         if ($value === "@") { | ||||||
|  |           $value = $args[$keys[$index++]]; | ||||||
|  |           $value = file::reader($value); | ||||||
|  |           $checkType = false; | ||||||
|  |         } elseif (substr($value, 0, 1) === "@") { | ||||||
|  |           $value = substr($value, 1); | ||||||
|  |           $value = file::reader($value); | ||||||
|  |           $checkType = false; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       if ($checkType) { | ||||||
|  |         if (str::del_suffix($name, ":int")) { | ||||||
|  |           if (str::del_suffix($name, ":array")) { | ||||||
|  |             $value = array_map([self::class, "tint"], self::tarray($value)); | ||||||
|  |           } else { | ||||||
|  |             $value = self::tint($value); | ||||||
|  |           } | ||||||
|  |         } elseif (str::del_suffix($name, ":bool")) { | ||||||
|  |           if (str::del_suffix($name, ":array")) { | ||||||
|  |             $value = array_map([self::class, "tbool"], self::tarray($value)); | ||||||
|  |           } else { | ||||||
|  |             $value = self::tbool($value); | ||||||
|  |           } | ||||||
|  |         } elseif (str::del_suffix($name, ":array")) { | ||||||
|  |           $value = self::tarray($value); | ||||||
|  |           if (str::del_suffix($name, ":int")) { | ||||||
|  |             $value = array_map([self::class, "tint"], $value); | ||||||
|  |           } elseif (str::del_suffix($name, ":bool")) { | ||||||
|  |             $value = array_map([self::class, "tbool"], $value); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       if (cl::has($query, $name)) { | ||||||
|  |         A::ensure_array($query[$name]); | ||||||
|  |         $query[$name][] = $value; | ||||||
|  |       } else { | ||||||
|  |         $query[$name] = $value; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return $query; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * convertir une liste d'arguments de façon qu'ils soient utilisables pour un | ||||||
|  |    * appel de méthode. les arguments peuvent être de la forme: | ||||||
|  |    * - "name=value" | ||||||
|  |    *   qui est stocké dans le tableau $query ["name" => "value"] | ||||||
|  |    *   il est possible de forcer le type de la valeur avec l'un des suffixes | ||||||
|  |    *   :int, :bool ou :array, e.g | ||||||
|  |    *   un entier: "name:int=42" | ||||||
|  |    *   un tableau de chaines: "name:array=a,b,c" | ||||||
|  |    *   un tableau d'entiers: "name:array:int=1,2,3" | ||||||
|  |    * - "+arg" | ||||||
|  |    *   qui est stocké dans le tableau $query ["arg" => true] | ||||||
|  |    * - "-arg" ou "~arg" | ||||||
|  |    *   qui est stocké dans le tableau $query ["arg" => false] | ||||||
|  |    * - "array:sval,key:aval,..." | ||||||
|  |    *   qui devient l'argument ["sval", "key" => "aval", ...] | ||||||
|  |    *   il est possible de forcer le types des éléments avec le préfixe int: ou | ||||||
|  |    *   bool: e.g "array:int:1,2,3" | ||||||
|  |    * - "int:value" | ||||||
|  |    *   qui devient l'argument intval("value") | ||||||
|  |    * - "bool:value" | ||||||
|  |    *   qui devient l'argument boolval("value") | ||||||
|  |    * - "value" | ||||||
|  |    *   qui devient l'argument "value" | ||||||
|  |    * | ||||||
|  |    * à la fin, la liste des arguments est retournée [$arguments...] | ||||||
|  |    * si le tableau $query est renseigné, il est en premier dans la liste des | ||||||
|  |    * arguments e.g [$query, $arguments...] | ||||||
|  |    */ | ||||||
|  |   static function build_method_args(?array $args): ?array { | ||||||
|  |     $query = null; | ||||||
|  |     $margs = []; | ||||||
|  |     $args ??= []; | ||||||
|  |     foreach ($args as $arg) { | ||||||
|  |       [$name, $value] = str::split_pair($arg, "="); | ||||||
|  |       if ($value === null) { | ||||||
|  |         if (str::del_prefix($name, "+")) { | ||||||
|  |           $value = true; | ||||||
|  |         } elseif (str::del_prefix($name, "-") || str::del_prefix($name, "~")) { | ||||||
|  |           $value = false; | ||||||
|  |         } elseif (str::del_prefix($name, "int:")) { | ||||||
|  |           $margs[] = self::tint($name); | ||||||
|  |           continue; | ||||||
|  |         } elseif (str::del_prefix($name, "bool:")) { | ||||||
|  |           $margs[] = self::tbool($name); | ||||||
|  |           continue; | ||||||
|  |         } elseif (str::del_prefix($name, "array:")) { | ||||||
|  |           if (str::del_prefix($name, "int:")) { | ||||||
|  |             $map = [self::class, "tint"]; | ||||||
|  |           } elseif (str::del_prefix($name, "bool:")) { | ||||||
|  |             $map = [self::class, "tbool"]; | ||||||
|  |           } else { | ||||||
|  |             $map = null; | ||||||
|  |           } | ||||||
|  |           $value = self::tarray($name); | ||||||
|  |           if ($map !== null) $value = array_map($map, $value); | ||||||
|  |           $margs[] = $value; | ||||||
|  |           continue; | ||||||
|  |         } else { | ||||||
|  |           $margs[] = $name; | ||||||
|  |           continue; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       if (str::del_suffix($name, ":int")) { | ||||||
|  |         if (str::del_suffix($name, ":array")) { | ||||||
|  |           $value = array_map([self::class, "tint"], self::tarray($value)); | ||||||
|  |         } else { | ||||||
|  |           $value = self::tint($value); | ||||||
|  |         } | ||||||
|  |       } elseif (str::del_suffix($name, ":bool")) { | ||||||
|  |         if (str::del_suffix($name, ":array")) { | ||||||
|  |           $value = array_map([self::class, "tbool"], self::tarray($value)); | ||||||
|  |         } else { | ||||||
|  |           $value = self::tbool($value); | ||||||
|  |         } | ||||||
|  |       } elseif (str::del_suffix($name, ":array")) { | ||||||
|  |         $value = self::tarray($value); | ||||||
|  |         if (str::del_suffix($name, ":int")) { | ||||||
|  |           $value = array_map([self::class, "tint"], $value); | ||||||
|  |         } elseif (str::del_suffix($name, ":bool")) { | ||||||
|  |           $value = array_map([self::class, "tbool"], $value); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       if (cl::has($query, $name)) { | ||||||
|  |         A::ensure_array($query[$name]); | ||||||
|  |         $query[$name][] = $value; | ||||||
|  |       } else { | ||||||
|  |         $query[$name] = $value; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     if ($query !== null) array_unshift($margs, $query); | ||||||
|  |     return $margs; | ||||||
|  |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -134,17 +134,6 @@ class Pdo implements IDatabase { | |||||||
|     return $this; |     return $this; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   const SQL_CHECK_LIVE = "select 1"; |  | ||||||
| 
 |  | ||||||
|   function ensure(): self { |  | ||||||
|     try { |  | ||||||
|       $this->_exec(static::SQL_CHECK_LIVE); |  | ||||||
|     } catch (\PDOException $e) { |  | ||||||
|       $this->open(true); |  | ||||||
|     } |  | ||||||
|     return $this; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   function close(): void { |   function close(): void { | ||||||
|     $this->db = null; |     $this->db = null; | ||||||
|   } |   } | ||||||
| @ -159,6 +148,30 @@ class Pdo implements IDatabase { | |||||||
|     return $this->db()->exec($query); |     return $this->db()->exec($query); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   /** @return array|null */ | ||||||
|  |   function _query(string $query) { | ||||||
|  |     $db = $this->db(); | ||||||
|  |     /** @var \PDOStatement $stmt */ | ||||||
|  |     $stmt = $db->query($query); | ||||||
|  |     if ($stmt === false) return null; | ||||||
|  |     try { | ||||||
|  |       return $stmt->fetchAll(\PDO::FETCH_ASSOC); | ||||||
|  |     } finally { | ||||||
|  |       $stmt->closeCursor(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const SQL_CHECK_LIVE = "select 1"; | ||||||
|  | 
 | ||||||
|  |   function ensure(): self { | ||||||
|  |     try { | ||||||
|  |       $this->_query(static::SQL_CHECK_LIVE); | ||||||
|  |     } catch (\PDOException $e) { | ||||||
|  |       $this->open(true); | ||||||
|  |     } | ||||||
|  |     return $this; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   function exec($query, ?array $params=null) { |   function exec($query, ?array $params=null) { | ||||||
|     $db = $this->db(); |     $db = $this->db(); | ||||||
|     $query = new _pdoQuery($query, $params); |     $query = new _pdoQuery($query, $params); | ||||||
|  | |||||||
| @ -173,17 +173,6 @@ class Pgsql implements IDatabase { | |||||||
|     return $this; |     return $this; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   const SQL_CHECK_LIVE = "select 1"; |  | ||||||
| 
 |  | ||||||
|   function ensure(): self { |  | ||||||
|     try { |  | ||||||
|       $this->_exec(static::SQL_CHECK_LIVE); |  | ||||||
|     } catch (\PDOException $e) { |  | ||||||
|       $this->open(true); |  | ||||||
|     } |  | ||||||
|     return $this; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   function close(): self { |   function close(): self { | ||||||
|     if ($this->db !== null) { |     if ($this->db !== null) { | ||||||
|       pg_close($this->db); |       pg_close($this->db); | ||||||
| @ -204,6 +193,31 @@ class Pgsql implements IDatabase { | |||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   function _query(string $query): ?array { | ||||||
|  |     $result = pg_query($this->db(), $query); | ||||||
|  |     if ($result === false) return null; | ||||||
|  |     try { | ||||||
|  |       $rows = []; | ||||||
|  |       while (($row = pg_fetch_assoc($result)) !== false) { | ||||||
|  |         $rows[] = $row; | ||||||
|  |       } | ||||||
|  |       return $rows; | ||||||
|  |     } finally { | ||||||
|  |       pg_free_result($result); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const SQL_CHECK_LIVE = "select 1"; | ||||||
|  | 
 | ||||||
|  |   function ensure(): self { | ||||||
|  |     try { | ||||||
|  |       $this->_query(static::SQL_CHECK_LIVE); | ||||||
|  |     } catch (\PDOException $e) { | ||||||
|  |       $this->open(true); | ||||||
|  |     } | ||||||
|  |     return $this; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   function getLastSerial() { |   function getLastSerial() { | ||||||
|     $db = $this->db(); |     $db = $this->db(); | ||||||
|     $result = @pg_query($db, "select lastval()"); |     $result = @pg_query($db, "select lastval()"); | ||||||
|  | |||||||
| @ -167,17 +167,6 @@ class Sqlite implements IDatabase { | |||||||
|     return $this; |     return $this; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   const SQL_CHECK_LIVE = "select 1"; |  | ||||||
| 
 |  | ||||||
|   function ensure(): self { |  | ||||||
|     try { |  | ||||||
|       $this->_exec(static::SQL_CHECK_LIVE); |  | ||||||
|     } catch (\PDOException $e) { |  | ||||||
|       $this->open(true); |  | ||||||
|     } |  | ||||||
|     return $this; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   function close(): void { |   function close(): void { | ||||||
|     if ($this->db !== null) { |     if ($this->db !== null) { | ||||||
|       $this->db->close(); |       $this->db->close(); | ||||||
| @ -203,6 +192,31 @@ class Sqlite implements IDatabase { | |||||||
|     return $this->db()->exec($query); |     return $this->db()->exec($query); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   function _query(string $query): ?array { | ||||||
|  |     $result = $this->db()->query($query); | ||||||
|  |     if ($result === false) return null; | ||||||
|  |     try { | ||||||
|  |       $rows = []; | ||||||
|  |       while (($row = $result->fetchArray(SQLITE3_ASSOC)) !== false) { | ||||||
|  |         $rows[] = $row; | ||||||
|  |       } | ||||||
|  |       return $rows; | ||||||
|  |     } finally { | ||||||
|  |       $result->finalize(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const SQL_CHECK_LIVE = "select 1"; | ||||||
|  | 
 | ||||||
|  |   function ensure(): self { | ||||||
|  |     try { | ||||||
|  |       $this->_query(static::SQL_CHECK_LIVE); | ||||||
|  |     } catch (\PDOException $e) { | ||||||
|  |       $this->open(true); | ||||||
|  |     } | ||||||
|  |     return $this; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   function exec($query, ?array $params=null) { |   function exec($query, ?array $params=null) { | ||||||
|     $db = $this->db(); |     $db = $this->db(); | ||||||
|     $query = new _sqliteQuery($query, $params); |     $query = new _sqliteQuery($query, $params); | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| # TOOD | # nulib\output | ||||||
| 
 | 
 | ||||||
| * dans msg::action($m, function() {}), *bloquer* la marque pour empêcher d'aller | * dans msg::action($m, function() {}), *bloquer* la marque pour empêcher d'aller | ||||||
|   plus bas que prévu. comme ça s'il y a plusieurs success ou failure dans la |   plus bas que prévu. comme ça s'il y a plusieurs success ou failure dans la | ||||||
| @ -32,4 +32,10 @@ pour l'UI | |||||||
| peut-être rajouter `ui` (ou `web`?) en plus de say, log, debuglog? | peut-être rajouter `ui` (ou `web`?) en plus de say, log, debuglog? | ||||||
| --> ou renommer `say` en `console`, et `ui` en `say` | --> ou renommer `say` en `console`, et `ui` en `say` | ||||||
| 
 | 
 | ||||||
|  | * [ ] ajouter une option `Application::MSG_SIGNALS` qui fait que | ||||||
|  |   * les méthodes `msg::eXXX()` appellent automatiquement `app::_dispatch_signals()` | ||||||
|  | * [ ] ajouter une option `Application::MSG_ACTIONS` qui fait que | ||||||
|  |   * `msg::section()` et/ou `msg::title()` appellent automatiquement `app::action()` | ||||||
|  |   * `msg::estep()` appelle automatiquement `app::step()` | ||||||
|  | 
 | ||||||
| -*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary | -*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary | ||||||
| @ -23,4 +23,72 @@ class argsTest extends TestCase { | |||||||
| 
 | 
 | ||||||
|     self::assertSame(["x", "1", "2", "3", "y"], args::from_array(["x", [1, 2, 3], "y"])); |     self::assertSame(["x", "1", "2", "3", "y"], args::from_array(["x", [1, 2, 3], "y"])); | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   function testBuild_query() { | ||||||
|  |     self::assertSame(null, args::build_query(null)); | ||||||
|  |     self::assertSame(null, args::build_query([])); | ||||||
|  | 
 | ||||||
|  |     self::assertSame(["a" => true], args::build_query(["a"])); | ||||||
|  |     self::assertSame(["a" => true], args::build_query(["+a"])); | ||||||
|  |     self::assertSame(["a" => false], args::build_query(["-a"])); | ||||||
|  |     self::assertSame(["a" => false], args::build_query(["~a"])); | ||||||
|  |     self::assertSame(["x" => "a"], args::build_query(["x=a"])); | ||||||
|  |     self::assertSame(["x" => 0], args::build_query(["x:int=0"])); | ||||||
|  |     self::assertSame(["x" => 42], args::build_query(["x:int=42"])); | ||||||
|  |     self::assertSame(["x" => false], args::build_query(["x:bool=0"])); | ||||||
|  |     self::assertSame(["x" => true], args::build_query(["x:bool=42"])); | ||||||
|  |     self::assertSame(["x" => ["a", "b"]], args::build_query(["x:array=a,b"])); | ||||||
|  |     self::assertSame(["x" => [0, 42]], args::build_query(["x:array:int=0,42"])); | ||||||
|  |     self::assertSame(["x" => [0, 42]], args::build_query(["x:int:array=0,42"])); | ||||||
|  | 
 | ||||||
|  |     self::assertSame(["x" => "a", "y" => "b"], args::build_query(["x=a", "y=b"])); | ||||||
|  |     self::assertSame(["x" => ["a", "b"]], args::build_query(["x=a", "x=b"])); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function testBuild_method_args() { | ||||||
|  |     self::assertSame([], args::build_method_args(null)); | ||||||
|  |     self::assertSame([], args::build_method_args([])); | ||||||
|  | 
 | ||||||
|  |     self::assertSame(["a"], args::build_method_args(["a"])); | ||||||
|  |     self::assertSame(["a", "b"], args::build_method_args(["a", "b"])); | ||||||
|  | 
 | ||||||
|  |     self::assertSame([0], args::build_method_args(["int:0"])); | ||||||
|  |     self::assertSame([42], args::build_method_args(["int:42"])); | ||||||
|  |     # pour le moment, pas de tint
 | ||||||
|  |     self::assertSame([0], args::build_method_args(["int:"])); | ||||||
|  |     self::assertSame([0], args::build_method_args(["int:truc"])); | ||||||
|  | 
 | ||||||
|  |     self::assertSame([false], args::build_method_args(["bool:0"])); | ||||||
|  |     self::assertSame([true], args::build_method_args(["bool:42"])); | ||||||
|  |     self::assertSame([false], args::build_method_args(["bool:"])); | ||||||
|  |     self::assertSame([true], args::build_method_args(["bool:truc"])); | ||||||
|  |     # pour le moment, pas de tbool
 | ||||||
|  |     self::assertSame([true], args::build_method_args(["bool:false"])); | ||||||
|  |     self::assertSame([true], args::build_method_args(["bool:true"])); | ||||||
|  | 
 | ||||||
|  |     self::assertSame([["a", "b"]], args::build_method_args(["array:a,b"])); | ||||||
|  |     self::assertSame([["x" => "a", "y" => "b"]], args::build_method_args(["array:x:a,y:b"])); | ||||||
|  |     # pour le moment, pas de tint
 | ||||||
|  |     self::assertSame([[0, 42, 0, 0]], args::build_method_args(["array:int:0,42,,truc"])); | ||||||
|  |     self::assertSame([["x" => 0, "y" => 42]], args::build_method_args(["array:int:x:0,y:42"])); | ||||||
|  |     # pour le moment, pas de tbool
 | ||||||
|  |     self::assertSame([[false, true, false, true, true, true]], args::build_method_args(["array:bool:0,42,,truc,false,true"])); | ||||||
|  |     self::assertSame([["x" => false, "y" => true]], args::build_method_args(["array:bool:x:0,y:42"])); | ||||||
|  | 
 | ||||||
|  |     self::assertSame([["a" => true]], args::build_method_args(["+a"])); | ||||||
|  |     self::assertSame([["a" => false]], args::build_method_args(["-a"])); | ||||||
|  |     self::assertSame([["a" => false]], args::build_method_args(["~a"])); | ||||||
|  |     self::assertSame([["x" => "a"]], args::build_method_args(["x=a"])); | ||||||
|  |     self::assertSame([["x" => 0]], args::build_method_args(["x:int=0"])); | ||||||
|  |     self::assertSame([["x" => 42]], args::build_method_args(["x:int=42"])); | ||||||
|  |     self::assertSame([["x" => false]], args::build_method_args(["x:bool=0"])); | ||||||
|  |     self::assertSame([["x" => true]], args::build_method_args(["x:bool=42"])); | ||||||
|  |     self::assertSame([["x" => ["a", "b"]]], args::build_method_args(["x:array=a,b"])); | ||||||
|  |     self::assertSame([["x" => [0, 42]]], args::build_method_args(["x:array:int=0,42"])); | ||||||
|  |     self::assertSame([["x" => [0, 42]]], args::build_method_args(["x:int:array=0,42"])); | ||||||
|  | 
 | ||||||
|  |     self::assertSame([["x" => "a", "y" => "b"], "a", "b"], args::build_method_args(["x=a", "a", "y=b", "b"])); | ||||||
|  | 
 | ||||||
|  |     self::assertSame([["x" => ["a", "b"]]], args::build_method_args(["x=a", "x=b"])); | ||||||
|  |   } | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user