<pman>Intégration de la branche rel82-0.7.0
This commit is contained in:
		
						commit
						9ccc9d984f
					
				
							
								
								
									
										10
									
								
								CHANGES.md
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								CHANGES.md
									
									
									
									
									
								
							| @ -1,3 +1,13 @@ | |||||||
|  | ## Release 0.7.0p82 du 22/10/2025-18:36 | ||||||
|  | 
 | ||||||
|  | ## Release 0.7.0p74 du 22/10/2025-18:33 | ||||||
|  | 
 | ||||||
|  | * `5e41e7d` gestion simplifiée des schéma | ||||||
|  | * `efb4f03` importation Hour et Time et d'autres vclasses | ||||||
|  | * `4f0d6d4` function isa() pour les vclasses | ||||||
|  | * `cfb8f0d` corriger la prise en compte des configurations de branche | ||||||
|  | * nombreuses autres modifications non documentées ici | ||||||
|  | 
 | ||||||
| ## Release 0.6.1p82 du 03/06/2025-10:22 | ## Release 0.6.1p82 du 03/06/2025-10:22 | ||||||
| 
 | 
 | ||||||
| ## Release 0.6.1p74 du 03/06/2025-10:21 | ## Release 0.6.1p74 du 03/06/2025-10:21 | ||||||
|  | |||||||
| @ -1 +1 @@ | |||||||
| 0.6.1 | 0.7.0 | ||||||
|  | |||||||
| @ -366,7 +366,8 @@ function load_config() { | |||||||
|             ac_set_tmpfile config |             ac_set_tmpfile config | ||||||
|             git show "$ConfigBranch:.pman.conf" >"$config" 2>/dev/null |             git show "$ConfigBranch:.pman.conf" >"$config" 2>/dev/null | ||||||
|             [ -s "$config" ] || die "$ConfigBranch: aucune configuration trouvée sur cette branche" || return |             [ -s "$config" ] || die "$ConfigBranch: aucune configuration trouvée sur cette branche" || return | ||||||
|             source "$config" |             ConfigFile="$config" | ||||||
|  |             source "$ConfigFile" | ||||||
|         fi |         fi | ||||||
|     elif [ -f .pman.conf ]; then |     elif [ -f .pman.conf ]; then | ||||||
|         ConfigFile="$(pwd)/.pman.conf" |         ConfigFile="$(pwd)/.pman.conf" | ||||||
| @ -681,9 +682,7 @@ function _create_upstream_action() { | |||||||
| 
 | 
 | ||||||
|     # faire une copie de la configuration actuelle |     # faire une copie de la configuration actuelle | ||||||
|     local config; ac_set_tmpfile config |     local config; ac_set_tmpfile config | ||||||
|     set -x; ls -l "$ConfigFile" #XXX |  | ||||||
|     cp "$ConfigFile" "$config" |     cp "$ConfigFile" "$config" | ||||||
|     set +x #XXX |  | ||||||
| 
 | 
 | ||||||
|     einfo "Création de la branche $RefBranch" |     einfo "Création de la branche $RefBranch" | ||||||
|     git checkout --orphan "$RefBranch" || die |     git checkout --orphan "$RefBranch" || die | ||||||
|  | |||||||
| @ -9,4 +9,4 @@ args=( | |||||||
| ) | ) | ||||||
| parse_args "$@"; set -- "${args[@]}" | parse_args "$@"; set -- "${args[@]}" | ||||||
| 
 | 
 | ||||||
| exec "$MYDIR/ptool" -fupstream -Bdev82 -m --tech-merge ${dev74:+-a "git checkout dev74"} "$@" | exec "$MYDIR/ptool" -fupstream -Bdev82 --tech-merge ${dev74:+-a "git checkout dev74"} "$@" | ||||||
|  | |||||||
| @ -221,6 +221,9 @@ if check_gitdir; then | |||||||
|     set_pman_vars "$merge_dir" |     set_pman_vars "$merge_dir" | ||||||
|     load_branches current |     load_branches current | ||||||
|     loaded_config=1 |     loaded_config=1 | ||||||
|  |     # remettre à zéro ConfigFile pour ne pas influencer le rechargement plus bas | ||||||
|  |     oConfigFile="$ConfigFile" | ||||||
|  |     ConfigFile= | ||||||
| else | else | ||||||
|     set_pman_vars "$merge_dir" |     set_pman_vars "$merge_dir" | ||||||
| fi | fi | ||||||
| @ -377,6 +380,9 @@ if [ -z "$loaded_config" -o -n "$chdir" -o -n "$ConfigFile" -o -n "$ConfigBranch | |||||||
|     load_config |     load_config | ||||||
|     set_pman_vars "$merge_dir" |     set_pman_vars "$merge_dir" | ||||||
|     load_branches current |     load_branches current | ||||||
|  | else | ||||||
|  |     # restaurer ConfigFile précédent | ||||||
|  |     ConfigFile="$oConfigFile" | ||||||
| fi | fi | ||||||
| resolve_should_push quiet | resolve_should_push quiet | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -6,38 +6,26 @@ use nulib\cl; | |||||||
| use nulib\cv; | use nulib\cv; | ||||||
| use nulib\exceptions; | use nulib\exceptions; | ||||||
| use nulib\output\msg; | use nulib\output\msg; | ||||||
|  | use nulib\php\types\vbool; | ||||||
| use nulib\str; | use nulib\str; | ||||||
| use PHPMailer\PHPMailer\PHPMailer; | use PHPMailer\PHPMailer\PHPMailer; | ||||||
| use PHPMailer\PHPMailer\SMTP; | use PHPMailer\PHPMailer\SMTP; | ||||||
| 
 | 
 | ||||||
| class mailer { | class mailer { | ||||||
|   private static function is_bool(&$value): bool { |   private static function is_bool(&$value): bool { | ||||||
|     if ($value === null) { |     if ($value === null) return false; | ||||||
|       return false; |     elseif (is_bool($value)) return true; | ||||||
|     } elseif (is_bool($value)) { |     elseif (is_numeric($value)) { | ||||||
|  |       $value = $value != 0; | ||||||
|       return true; |       return true; | ||||||
|     } elseif (is_int($value)) { |     } elseif (vbool::is_yes($value)) { | ||||||
|       $value = boolval($value); |       $value = true; | ||||||
|  |       return true; | ||||||
|  |     } elseif ($value === "" || vbool::is_no($value)) { | ||||||
|  |       $value = false; | ||||||
|       return true; |       return true; | ||||||
|     } else { |  | ||||||
|       switch (strval($value)) { |  | ||||||
|       case "": |  | ||||||
|       case "0": |  | ||||||
|       case "no": |  | ||||||
|       case "off": |  | ||||||
|       case "false": |  | ||||||
|         $value = false; |  | ||||||
|         return true; |  | ||||||
|       case "1": |  | ||||||
|       case "yes": |  | ||||||
|       case "on": |  | ||||||
|       case "true": |  | ||||||
|         $value = true; |  | ||||||
|         return true; |  | ||||||
|       default: |  | ||||||
|         return false; |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|  |     return false; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private static function get_bool($value): bool { |   private static function get_bool($value): bool { | ||||||
| @ -120,19 +108,14 @@ class mailer { | |||||||
|     $mailer->SMTPDebug = $debug; |     $mailer->SMTPDebug = $debug; | ||||||
|     # auth, username, password
 |     # auth, username, password
 | ||||||
|     $username = $params["username"] ?? null; |     $username = $params["username"] ?? null; | ||||||
|     $username ??= cv::vn(getenv("NULIB_MAIL_USERNAME")); |  | ||||||
|     $password = $params["password"] ?? null; |     $password = $params["password"] ?? null; | ||||||
|     $password ??= cv::vn(getenv("NULIB_MAIL_PASSWORD")); |  | ||||||
|     $auth = $params["auth"] ?? null; |     $auth = $params["auth"] ?? null; | ||||||
|     $auth ??= cv::vn(getenv("NULIB_MAIL_AUTH")); |  | ||||||
|     $auth ??= $username !== null && $password !== null; |     $auth ??= $username !== null && $password !== null; | ||||||
|     $mailer->SMTPAuth = self::get_bool($auth); |     $mailer->SMTPAuth = self::get_bool($auth); | ||||||
|     $mailer->Username = $username; |     $mailer->Username = $username; | ||||||
|     $mailer->Password = $password; |     $mailer->Password = $password; | ||||||
|     # secure
 |     # secure
 | ||||||
|     $secure = $params["secure"] ?? null; |     $secure = $params["secure"] ?? false; | ||||||
|     $secure ??= cv::vn(getenv("NULIB_MAIL_SECURE")); |  | ||||||
|     $secure ??= false; |  | ||||||
|     if (self::is_bool($secure)) { |     if (self::is_bool($secure)) { | ||||||
|       if (!$secure) { |       if (!$secure) { | ||||||
|         $mailer->SMTPSecure = ""; |         $mailer->SMTPSecure = ""; | ||||||
|  | |||||||
							
								
								
									
										16
									
								
								php/src/php/time/Hour.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								php/src/php/time/Hour.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | <?php | ||||||
|  | namespace nulib\php\time; | ||||||
|  | 
 | ||||||
|  | class Hour extends Time { | ||||||
|  |   const UNIT = self::UNIT_MINUTES; | ||||||
|  | 
 | ||||||
|  |   const FORMAT = "%hh%M"; | ||||||
|  | 
 | ||||||
|  |   function format(?string $format=null): string { | ||||||
|  |     $string = parent::format($format); | ||||||
|  |     if (substr($string, -3) == "h00") { | ||||||
|  |       $string = substr($string, 0, -2); | ||||||
|  |     } | ||||||
|  |     return $string; | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										288
									
								
								php/src/php/time/Time.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										288
									
								
								php/src/php/time/Time.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,288 @@ | |||||||
|  | <?php | ||||||
|  | namespace nulib\php\time; | ||||||
|  | 
 | ||||||
|  | use DateTimeInterface; | ||||||
|  | use nulib\exceptions; | ||||||
|  | use nulib\php\types\vbool; | ||||||
|  | use nulib\php\types\vint; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Class Time: une heure allant de 0h à 24h inclus. | ||||||
|  |  * | ||||||
|  |  * la seule utilisation autorisée de "24h" est comme borne supérieure pour une | ||||||
|  |  * plage horaire. | ||||||
|  |  */ | ||||||
|  | class Time { | ||||||
|  |   const UNIT_HOURS = 3600; | ||||||
|  |   const UNIT_MINUTES = 60; | ||||||
|  |   const UNIT_SECONDS = 1; | ||||||
|  | 
 | ||||||
|  |   const PATTERNS = [ | ||||||
|  |     '/^(\d+)[:.h](\d+)(?:[:.](\d+))?$/', | ||||||
|  |     '/^(\d+)h(?:(\d+)(?:[:.](\d+))?)?$/' | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   /** @var string format par défaut pour l'affichage */ | ||||||
|  |   const FORMAT = "%H:%M:%S"; | ||||||
|  | 
 | ||||||
|  |   static function with($time): self { | ||||||
|  |     if ($time instanceof static) return $time; | ||||||
|  |     else return new static($time); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function withn($time): ?self { | ||||||
|  |     if ($time === null) return null; | ||||||
|  |     elseif ($time instanceof static) return $time; | ||||||
|  |     else return new static($time); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function isa_time($time): bool { | ||||||
|  |     if ($time === null) return false; | ||||||
|  |     if ($time instanceof self) return true; | ||||||
|  |     if (is_int($time)) return true; | ||||||
|  |     if (is_string($time)) { | ||||||
|  |       foreach (self::PATTERNS as $pattern) { | ||||||
|  |         if (preg_match($pattern, $time)) return true; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     if ($time instanceof DateTimeInterface) return true; | ||||||
|  |     if (is_array($time) && count($time) == 3) return true; | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   protected static function s_now(): int { | ||||||
|  |     $hms = date('His'); | ||||||
|  |     return intval(substr($hms, 0, 2)) * 3600 | ||||||
|  |       + intval(substr($hms, 2, 2)) * 60 | ||||||
|  |       + intval(substr($hms, 4, 2)); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   protected static function s_get($time, int $unit=self::UNIT_SECONDS): int { | ||||||
|  |     if ($time === null) { | ||||||
|  |       return 0; | ||||||
|  |     } elseif ($time instanceof self) { | ||||||
|  |       return $time->getSeconds(); | ||||||
|  |     } elseif (is_int($time)) { | ||||||
|  |       return $time * $unit; | ||||||
|  |     } elseif (is_string($time)) { | ||||||
|  |       $matched = false; | ||||||
|  |       foreach (self::PATTERNS as $pattern) { | ||||||
|  |         if (preg_match($pattern, $time, $ms)) { | ||||||
|  |           $matched = true; | ||||||
|  |           break; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       if ($matched) { | ||||||
|  |         $h = $ms[1]; | ||||||
|  |         $m = $ms[2] ?? 0; | ||||||
|  |         $s = $ms[3] ?? 0; | ||||||
|  |         return intval($h) * 3600 + intval($m) * 60 + intval($s); | ||||||
|  |       } | ||||||
|  |     } elseif ($time instanceof DateTimeInterface) { | ||||||
|  |       $hms = $time->format('His'); | ||||||
|  |       return intval(substr($hms, 0, 2)) * 3600 | ||||||
|  |         + intval(substr($hms, 2, 2)) * 60 | ||||||
|  |         + intval(substr($hms, 4, 2)); | ||||||
|  |     } elseif (is_array($time) && count($time) == 3) { | ||||||
|  |       [$h, $m, $s] = $time; | ||||||
|  |       return $h * 3600 + $m * 60 + $s; | ||||||
|  |     } | ||||||
|  |     throw exceptions::invalid_value($time, "time"); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   protected static function s_adjust(int &$seconds, int $unit=self::UNIT_SECONDS, ?int $step=null): int { | ||||||
|  |     if ($step !== null) $unit *= $step; | ||||||
|  |     $adjust = $seconds % $unit; | ||||||
|  |     if ($seconds < 0) $adjust = -$adjust; | ||||||
|  |     $seconds -= $adjust; | ||||||
|  |     return $seconds; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   protected static function s_wrap_start(int &$seconds): int { | ||||||
|  |     while ($seconds < 0) $seconds += 86400; | ||||||
|  |     if ($seconds >= 86400) $seconds %= 86400; | ||||||
|  |     return $seconds; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   protected static function s_wrap_end(int &$seconds): int { | ||||||
|  |     while ($seconds < 0) $seconds += 86400; | ||||||
|  |     if ($seconds > 86400) $seconds %= 86400; | ||||||
|  |     return $seconds; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * @var int la valeur de l'unité en secondes, pour le constructeur et les | ||||||
|  |    * méthodes {@link setu()}, {@link addu()} et {@link subu()} | ||||||
|  |    */ | ||||||
|  |   const UNIT = self::UNIT_SECONDS; | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * @var int|null un nombre d'unité dont l'heure doit être multiple. par | ||||||
|  |    * exemple, si l'unité est la minute, une valeur 5 permet d'avoir des heures | ||||||
|  |    * qui vont de 5 en 5 minutes (0h00, 0h05, 0h10, etc.) | ||||||
|  |    */ | ||||||
|  |   const STEP = null; | ||||||
|  | 
 | ||||||
|  |   /** @var bool s'il faut garder les heures dans la plage [0, 24h] */ | ||||||
|  |   const WRAP = true; | ||||||
|  | 
 | ||||||
|  |   function __construct($time=null, ?array $params=null) { | ||||||
|  |     $this->unit = vint::with($params["unit"] ?? static::UNIT); | ||||||
|  |     $this->step = vint::withn($params["step"] ?? self::STEP); | ||||||
|  |     $this->wrap = vbool::with($params["wrap"] ?? self::WRAP); | ||||||
|  |     if ($time === null) $seconds = self::s_now(); | ||||||
|  |     else $seconds = self::s_get($time, $this->unit); | ||||||
|  |     $this->setSeconds($seconds); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   protected int $unit; | ||||||
|  | 
 | ||||||
|  |   protected ?int $step; | ||||||
|  | 
 | ||||||
|  |   protected bool $wrap; | ||||||
|  | 
 | ||||||
|  |   protected int $seconds; | ||||||
|  | 
 | ||||||
|  |   function getSeconds(): int { | ||||||
|  |     return $this->seconds; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * mettre à jour cet objet avec le nombre de secondes spécifié | ||||||
|  |    * | ||||||
|  |    * le nombre effectif de secondes est calculé en tenant compte de l'unité | ||||||
|  |    * actuelle | ||||||
|  |    * | ||||||
|  |    * @return int le nombre de seconde effectif, après correction | ||||||
|  |    */ | ||||||
|  |   protected function setSeconds(?int $seconds): int { | ||||||
|  |     $this->seconds = $seconds ?? self::s_now(); | ||||||
|  |     return $this->afterUpdate(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   protected function afterUpdate(): int { | ||||||
|  |     self::s_adjust($this->seconds, $this->unit, $this->step); | ||||||
|  |     if ($this->wrap) $this->wrapEnd(); | ||||||
|  |     return $this->seconds; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * wrapper l'heure pour la garder dans la plage [0h, 24h[ ce qui la rend | ||||||
|  |    * propice à l'utilisation comme borne inférieure d'une période | ||||||
|  |    */ | ||||||
|  |   function wrapStart(): self { | ||||||
|  |     self::s_wrap_start($this->seconds); | ||||||
|  |     return $this; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * wrapper l'heure pour la garder dans la plage [0h, 24h] ce qui la rend | ||||||
|  |    * propice à l'utilisation comme borne supérieure d'une période | ||||||
|  |    */ | ||||||
|  |   function wrapEnd(): self { | ||||||
|  |     self::s_wrap_end($this->seconds); | ||||||
|  |     return $this; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** formatter cette heure pour affichage */ | ||||||
|  |   function format(?string $format=null): string { | ||||||
|  |     if ($format === null) $format = static::FORMAT; | ||||||
|  |     $v = $this->seconds; | ||||||
|  |     $h = intdiv($v, 3600); $v = $v % 3600; | ||||||
|  |     $m = intdiv($v, 60); | ||||||
|  |     $s = $v % 60; | ||||||
|  |     $searches = [ | ||||||
|  |       "%H", "%h", | ||||||
|  |       "%M", "%m", | ||||||
|  |       "%S", "%s", | ||||||
|  |       "%%", | ||||||
|  |     ]; | ||||||
|  |     $replaces = [ | ||||||
|  |       sprintf("%02u", $h), strval($h), | ||||||
|  |       sprintf("%02u", $m), strval($m), | ||||||
|  |       sprintf("%02u", $s), strval($s), | ||||||
|  |       "%", | ||||||
|  |     ]; | ||||||
|  |     return str_replace($searches, $replaces, $format); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function __toString(): string { | ||||||
|  |     return $this->format(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** @return int le nombre d'unités */ | ||||||
|  |   function getu(): int { | ||||||
|  |     return intdiv($this->seconds, $this->unit); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** créer une nouvelle heure avec le nombre d'unités spécifiées */ | ||||||
|  |   function setu(int $count): self { | ||||||
|  |     $this->setSeconds($count * $this->unit); | ||||||
|  |     return $this; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** créer une nouvelle heure en ajoutant à cette heure le nombre d'unités spécifiées */ | ||||||
|  |   function addu(int $count=1): self { | ||||||
|  |     $count *= $this->unit; | ||||||
|  |     if ($this->step !== null) $count *= $this->step; | ||||||
|  |     $this->setSeconds($this->seconds + $count); | ||||||
|  |     return $this; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** créer une nouvelle heure en soustrayant à cette heure le nombre d'unités spécifiées */ | ||||||
|  |   function subu(int $count=1): self { | ||||||
|  |     $count *= $this->unit; | ||||||
|  |     if ($this->step !== null) $count *= $this->step; | ||||||
|  |     $this->setSeconds($this->seconds - $count); | ||||||
|  |     return $this; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** forcer cette heure à l'heure spécifiée */ | ||||||
|  |   function set($time): self { | ||||||
|  |     if ($time === null) $seconds = self::s_now(); | ||||||
|  |     else $seconds = self::with($time)->getSeconds(); | ||||||
|  |     $this->setSeconds($seconds); | ||||||
|  |     return $this; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** ajouter à cette heure l'heure spécifiée */ | ||||||
|  |   function add($time): self { | ||||||
|  |     if ($time !== null) { | ||||||
|  |       $this->setSeconds($this->seconds + self::with($time)->getSeconds()); | ||||||
|  |     } | ||||||
|  |     return $this; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** soustraire à cette heure l'heure spécifiée */ | ||||||
|  |   function sub($time): self { | ||||||
|  |     if ($time !== null) { | ||||||
|  |       $this->setSeconds($this->seconds - self::with($time)->getSeconds()); | ||||||
|  |     } | ||||||
|  |     return $this; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * comparer avec l'heure spécifiée. retourner une valeur négative, égale à | ||||||
|  |    * zéro ou positive suivant le résultat de la comparaison | ||||||
|  |    */ | ||||||
|  |   function compare($time): int { | ||||||
|  |     if ($time === null) return 1; | ||||||
|  |     else return $this->seconds - self::with($time)->getSeconds(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * tester si cette heure est avant ou égale à l'heure spécifiée | ||||||
|  |    */ | ||||||
|  |   function before($other): bool { | ||||||
|  |     if ($other === null) return false; | ||||||
|  |     else return $this->seconds <= self::with($other)->getSeconds(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * tester si cette heure est après ou égale à l'heure spécifiée | ||||||
|  |    */ | ||||||
|  |   function after($other): bool { | ||||||
|  |     if ($other === null) return true; | ||||||
|  |     else return $this->seconds >= self::with($other)->getSeconds(); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										58
									
								
								php/src/php/types/_schema.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								php/src/php/types/_schema.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,58 @@ | |||||||
|  | <?php | ||||||
|  | namespace nulib\php\types; | ||||||
|  | 
 | ||||||
|  | use nulib\exceptions; | ||||||
|  | use nulib\str; | ||||||
|  | 
 | ||||||
|  | class _schema { | ||||||
|  |   /** @var array association type simple / vclass */ | ||||||
|  |   const VCLASSES = [ | ||||||
|  |     "rawstring" => vrawstring::class, | ||||||
|  |     "string" => vstring::class, | ||||||
|  |     "text" => vtext::class, | ||||||
|  |     "bool" => vbool::class, | ||||||
|  |     "int" => vint::class, | ||||||
|  |     "float" => vfloat::class, | ||||||
|  |     "array" => varray::class, | ||||||
|  |     "func" => vfunc::class, | ||||||
|  |     "raw" => vraw::class, | ||||||
|  |     "mixed" => vmixed::class, | ||||||
|  |     "key" => vkey::class, | ||||||
|  |     "pkey" => vpkey::class, | ||||||
|  |     "content" => vcontent::class, | ||||||
|  |     "datetime" => vdatetime::class, | ||||||
|  |     "date" => vdate::class, | ||||||
|  |     "time" => vtime::class, | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   static function get_types($schema, &$default = null, ?bool &$required = null): array { | ||||||
|  |     if (is_array($schema)) { | ||||||
|  |       $types = $schema["type"] ?? $schema[0] ?? null; | ||||||
|  |       $default = $schema["default"] ?? $schema[1] ?? null; | ||||||
|  |       $required = vbool::with($schema["required"] ?? false); | ||||||
|  |     } elseif (is_string($schema)) { | ||||||
|  |       $types = $schema; | ||||||
|  |       $default = null; | ||||||
|  |       $required = false; | ||||||
|  |     } else { | ||||||
|  |       throw exceptions::invalid_value($schema, "schema"); | ||||||
|  |     } | ||||||
|  |     if (is_string($types)) { | ||||||
|  |       $types = explode(",", $types); | ||||||
|  |     } elseif (!is_array($types)) { | ||||||
|  |       throw exceptions::invalid_value($types, "types"); | ||||||
|  |     } | ||||||
|  |     return $types; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function get_vclass(array $types, ?bool &$nullable): ?string { | ||||||
|  |     foreach ($types as $type) { | ||||||
|  |       $vclass = self::VCLASSES[$type] ?? null; | ||||||
|  |       if ($vclass !== null) { | ||||||
|  |         $nullable = str::del_prefix($type, "?"); | ||||||
|  |         return $vclass; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										75
									
								
								php/src/php/types/assoc.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								php/src/php/types/assoc.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,75 @@ | |||||||
|  | <?php | ||||||
|  | namespace nulib\php\types; | ||||||
|  | 
 | ||||||
|  | use nulib\exceptions; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Class assoc: gestion simplifiée de schémas associatifs | ||||||
|  |  * | ||||||
|  |  * seuls les types simples sont reconnus | ||||||
|  |  */ | ||||||
|  | class assoc { | ||||||
|  |   /** indiquer si $array est conforme au schéma */ | ||||||
|  |   public static function check_schema(?array $array, array $schema, bool $strict = false): bool { | ||||||
|  |     foreach ($schema as $key => $kschema) { | ||||||
|  |       $types = _schema::get_types($kschema, $default, $required); | ||||||
|  |       $exists = array_key_exists($key, $array); | ||||||
|  |       if (!$exists) { | ||||||
|  |         if ($required) return false; | ||||||
|  |         else continue; | ||||||
|  |       } | ||||||
|  |       $vclass = _schema::get_vclass($types, $nullable); | ||||||
|  |       # le test échoue si le type n'est pas supporté
 | ||||||
|  |       if ($vclass === null) return false; | ||||||
|  |       $value = $array[$key]; | ||||||
|  |       if ($value === null) { | ||||||
|  |         if (!$nullable) return false; | ||||||
|  |       } else { | ||||||
|  |         if (!$vclass::isa($value, $strict)) return false; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * s'assurer que $array est conforme au schéma | ||||||
|  |    * - les clés ne sont pas créées si elles n'existent pas, sauf si la valeur | ||||||
|  |    * est requise ou si une valeur par défaut non nulle est fournie | ||||||
|  |    */ | ||||||
|  |   public static function ensure_schema(&$array, array $schema): bool { | ||||||
|  |     $ensured = true; | ||||||
|  |     foreach ($schema as $key => $kschema) { | ||||||
|  |       $types = _schema::get_types($kschema, $default, $required); | ||||||
|  | 
 | ||||||
|  |       $exists = array_key_exists($key, $array); | ||||||
|  |       if (!$exists) { | ||||||
|  |         if ($required) { | ||||||
|  |           if ($default !== null) { | ||||||
|  |             $array[$key] = $default; | ||||||
|  |           } else { | ||||||
|  |             throw exceptions::missing_value(null, "array", "$key est obligatoire"); | ||||||
|  |           } | ||||||
|  |         } elseif ($default !== null) { | ||||||
|  |           $array[$key] = $default; | ||||||
|  |         } | ||||||
|  |         continue; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $vclass = _schema::get_vclass($types, $nullable); | ||||||
|  |       # le test échoue si le type n'est pas supporté
 | ||||||
|  |       if ($vclass === null) { | ||||||
|  |         $ensured = false; | ||||||
|  |         continue; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $value = $array[$key]; | ||||||
|  |       if ($nullable) { | ||||||
|  |         $array[$key] = $vclass::withn($value); | ||||||
|  |       } else { | ||||||
|  |         if ($value === null) $value = $default; | ||||||
|  |         $array[$key] = $vclass::with($value); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return $ensured; | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										34
									
								
								php/src/php/types/scalar.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								php/src/php/types/scalar.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | |||||||
|  | <?php | ||||||
|  | namespace nulib\php\types; | ||||||
|  | 
 | ||||||
|  | use nulib\exceptions; | ||||||
|  | use nulib\str; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Class scalar: gestion simplifiée de schémas de valeurs simples | ||||||
|  |  */ | ||||||
|  | class scalar { | ||||||
|  |   /** indiquer si $value est conforme au schéma */ | ||||||
|  |   static function check_schema($value, $schema, bool $strict=false): bool { | ||||||
|  |     $types = _schema::get_types($schema); | ||||||
|  |     $vclass = _schema::get_vclass($types, $nullable); | ||||||
|  |     # le test échoue si le type n'est pas supporté
 | ||||||
|  |     if ($vclass === null) return false; | ||||||
|  |     if ($value === null) return $nullable; | ||||||
|  |     return $vclass::isa($value, $strict); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function ensure_schema(&$value, $schema): bool { | ||||||
|  |     $types = _schema::get_types($schema, $default); | ||||||
|  |     $vclass = _schema::get_vclass($types, $nullable); | ||||||
|  |     # la conversion échoue si le type n'est pas supporté
 | ||||||
|  |     if ($vclass === null) return false; | ||||||
|  |     if ($nullable) { | ||||||
|  |       $value = $vclass::withn($value); | ||||||
|  |     } else { | ||||||
|  |       if ($value === null) $value = $default; | ||||||
|  |       $value = $vclass::with($value); | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -2,10 +2,19 @@ | |||||||
| namespace nulib\php\types; | namespace nulib\php\types; | ||||||
| 
 | 
 | ||||||
| use nulib\cl; | use nulib\cl; | ||||||
|  | use nulib\exceptions; | ||||||
| 
 | 
 | ||||||
| class varray { | class varray { | ||||||
|  |   static function isa($value, bool $strict=false) : bool { | ||||||
|  |     if ($strict) return is_array($value); | ||||||
|  |     else return is_scalar($value); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   static function ensure(&$array): void { |   static function ensure(&$array): void { | ||||||
|     if (!is_array($array)) $array = cl::with($array); |     if (is_array($array)) return; | ||||||
|  |     if ($array === null || $array === false) $array = []; | ||||||
|  |     elseif (is_scalar($array)) $array = cl::with($array); | ||||||
|  |     else throw exceptions::invalid_value($array, "array"); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   static function ensuren(&$array): void { |   static function ensuren(&$array): void { | ||||||
|  | |||||||
| @ -1,6 +1,8 @@ | |||||||
| <?php | <?php | ||||||
| namespace nulib\php\types; | namespace nulib\php\types; | ||||||
| 
 | 
 | ||||||
|  | use nulib\exceptions; | ||||||
|  | 
 | ||||||
| class vbool { | class vbool { | ||||||
|   /** liste de valeurs chaines à considérer comme 'OUI' */ |   /** liste de valeurs chaines à considérer comme 'OUI' */ | ||||||
|   public const YES_VALUES = [ |   public const YES_VALUES = [ | ||||||
| @ -30,12 +32,25 @@ class vbool { | |||||||
|     return in_array($value, self::NO_VALUES, true); |     return in_array($value, self::NO_VALUES, true); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   static function isa($value, bool $strict=false) : bool { | ||||||
|  |     if ($strict) return is_bool($value); | ||||||
|  |     elseif (is_string($value)) return self::is_yes($value) || self::is_no($value); | ||||||
|  |     else return is_scalar($value); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   static function ensure(&$bool): void { |   static function ensure(&$bool): void { | ||||||
|     if (is_string($bool)) { |     if (is_bool($bool)) return; | ||||||
|  |     if ($bool === null) { | ||||||
|  |       $bool = false; | ||||||
|  |     } elseif (is_string($bool)) { | ||||||
|       if (self::is_yes($bool)) $bool = true; |       if (self::is_yes($bool)) $bool = true; | ||||||
|       elseif (self::is_no($bool)) $bool = false; |       elseif (self::is_no($bool)) $bool = false; | ||||||
|  |       else throw exceptions::invalid_value($bool, "boolean"); | ||||||
|  |     } elseif (is_scalar($bool)) { | ||||||
|  |       $bool = boolval($bool); | ||||||
|  |     } else { | ||||||
|  |       throw exceptions::invalid_value($bool, "boolean"); | ||||||
|     } |     } | ||||||
|     if (!is_bool($bool)) $bool = boolval($bool); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   static function ensuren(&$bool): void { |   static function ensuren(&$bool): void { | ||||||
|  | |||||||
| @ -1,10 +1,28 @@ | |||||||
| <?php | <?php | ||||||
| namespace nulib\php\types; | namespace nulib\php\types; | ||||||
| 
 | 
 | ||||||
|  | use nulib\exceptions; | ||||||
|  | use nulib\php\content\IContent; | ||||||
|  | use nulib\php\content\IPrintable; | ||||||
|  | 
 | ||||||
| class vcontent { | class vcontent { | ||||||
|  |   static function isa($value, bool $strict=false) : bool { | ||||||
|  |     if ($strict) return is_array($value) || is_string($value); | ||||||
|  |     return is_array($value) || is_scalar($value) || | ||||||
|  |       $value instanceof IContent || $value instanceof IPrintable; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   static function ensure(&$content): void { |   static function ensure(&$content): void { | ||||||
|     if ($content === null || $content === false) $content = []; |     if (is_array($content) || is_string($content)) return; | ||||||
|     elseif (!is_string($content) && !is_array($content)) $content = strval($content); |     if ($content === null || $content === false) { | ||||||
|  |       $content = []; | ||||||
|  |     } elseif (is_scalar($content)) { | ||||||
|  |       $content = [$content]; | ||||||
|  |     } elseif ($content instanceof IContent || $content instanceof IPrintable) { | ||||||
|  |       $content = [$content]; | ||||||
|  |     } else { | ||||||
|  |       throw exceptions::invalid_value($content, "content"); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   static function ensuren(&$content): void { |   static function ensuren(&$content): void { | ||||||
|  | |||||||
							
								
								
									
										29
									
								
								php/src/php/types/vdate.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								php/src/php/types/vdate.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | |||||||
|  | <?php | ||||||
|  | namespace nulib\php\types; | ||||||
|  | 
 | ||||||
|  | use nulib\php\time\Date; | ||||||
|  | 
 | ||||||
|  | class vdate { | ||||||
|  |   static function isa($value, bool $strict=false) : bool { | ||||||
|  |     if ($strict) return $value instanceof Date; | ||||||
|  |     else return Date::isa_date($value); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function ensure(&$date): void { | ||||||
|  |     $date = Date::with($date); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function ensuren(&$date): void { | ||||||
|  |     $date = Date::withn($date); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function with($value): Date { | ||||||
|  |     self::ensure($value); | ||||||
|  |     return $value; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function withn($value): ?Date { | ||||||
|  |     self::ensuren($value); | ||||||
|  |     return $value; | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								php/src/php/types/vdatetime.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								php/src/php/types/vdatetime.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | |||||||
|  | <?php | ||||||
|  | namespace nulib\php\types; | ||||||
|  | 
 | ||||||
|  | use nulib\php\time\DateTime; | ||||||
|  | 
 | ||||||
|  | class vdatetime { | ||||||
|  |   static function isa($value, bool $strict=false) : bool { | ||||||
|  |     if ($strict) return $value instanceof DateTime; | ||||||
|  |     else return DateTime::isa_datetime($value); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function ensure(&$datetime): void { | ||||||
|  |     $datetime = DateTime::with($datetime); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function ensuren(&$datetime): void { | ||||||
|  |     $datetime = DateTime::withn($datetime); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function with($value): DateTime { | ||||||
|  |     self::ensure($value); | ||||||
|  |     return $value; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function withn($value): ?DateTime { | ||||||
|  |     self::ensuren($value); | ||||||
|  |     return $value; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -1,9 +1,19 @@ | |||||||
| <?php | <?php | ||||||
| namespace nulib\php\types; | namespace nulib\php\types; | ||||||
| 
 | 
 | ||||||
|  | use nulib\exceptions; | ||||||
|  | 
 | ||||||
| class vfloat { | class vfloat { | ||||||
|  |   static function isa($value, bool $strict=false) : bool { | ||||||
|  |     if ($strict) return is_float($value); | ||||||
|  |     else return is_numeric($value); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   static function ensure(&$float): void { |   static function ensure(&$float): void { | ||||||
|     if (!is_float($float)) $float = floatval($float); |     if (is_float($float)) return; | ||||||
|  |     if ($float === null || $float === false) $float = 0.0; | ||||||
|  |     elseif (is_numeric($float)) $float = floatval($float); | ||||||
|  |     else throw exceptions::invalid_value($float, "float"); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   static function ensuren(&$float): void { |   static function ensuren(&$float): void { | ||||||
|  | |||||||
| @ -4,6 +4,11 @@ namespace nulib\php\types; | |||||||
| use nulib\php\func; | use nulib\php\func; | ||||||
| 
 | 
 | ||||||
| class vfunc { | class vfunc { | ||||||
|  |   static function isa($value, bool $strict=false) : bool { | ||||||
|  |     if ($strict) return $value instanceof func; | ||||||
|  |     else return func::is_callable($value); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   static function ensure(&$func): void { |   static function ensure(&$func): void { | ||||||
|     $func = func::ensure($func); |     $func = func::ensure($func); | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -1,9 +1,19 @@ | |||||||
| <?php | <?php | ||||||
| namespace nulib\php\types; | namespace nulib\php\types; | ||||||
| 
 | 
 | ||||||
|  | use nulib\exceptions; | ||||||
|  | 
 | ||||||
| class vint { | class vint { | ||||||
|  |   static function isa($value, bool $strict=false) : bool { | ||||||
|  |     if ($strict) return is_int($value); | ||||||
|  |     else return is_numeric($value); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   static function ensure(&$int): void { |   static function ensure(&$int): void { | ||||||
|     if (!is_int($int)) $int = intval($int); |     if (is_int($int)) return; | ||||||
|  |     if ($int === null || $int === false) $int = 0.0; | ||||||
|  |     elseif (is_numeric($int)) $int = intval($int); | ||||||
|  |     else throw exceptions::invalid_value($int, "int"); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   static function ensuren(&$int): void { |   static function ensuren(&$int): void { | ||||||
|  | |||||||
| @ -1,11 +1,20 @@ | |||||||
| <?php | <?php | ||||||
| namespace nulib\php\types; | namespace nulib\php\types; | ||||||
| 
 | 
 | ||||||
|  | use nulib\exceptions; | ||||||
|  | 
 | ||||||
| class vkey { | class vkey { | ||||||
|  |   static function isa($value, bool $strict=false) : bool { | ||||||
|  |     if ($strict) return is_int($value) || is_string($value); | ||||||
|  |     else return is_scalar($value); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   static function ensure(&$key): void { |   static function ensure(&$key): void { | ||||||
|  |     if (is_int($key) || is_string($key)) return; | ||||||
|     if ($key === null) $key = ""; |     if ($key === null) $key = ""; | ||||||
|     elseif ($key === false) $key = 0; |     elseif ($key === false) $key = 0; | ||||||
|     elseif (!is_string($key) && !is_int($key)) $key = strval($key); |     elseif (is_scalar($key)) $key = strval($key); | ||||||
|  |     else throw exceptions::invalid_value($key, "key"); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   static function ensuren(&$key): void { |   static function ensuren(&$key): void { | ||||||
|  | |||||||
							
								
								
									
										22
									
								
								php/src/php/types/vmixed.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								php/src/php/types/vmixed.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | |||||||
|  | <?php | ||||||
|  | namespace nulib\php\types; | ||||||
|  | 
 | ||||||
|  | class vmixed { | ||||||
|  |   static function isa($value, bool $strict=false) : bool { | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function ensure(&$mixed): void { | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function ensuren(&$mixed): void { | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function with($value) { | ||||||
|  |     return $value; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function withn($value) { | ||||||
|  |     return $value; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -1,17 +1,28 @@ | |||||||
| <?php | <?php | ||||||
| namespace nulib\php\types; | namespace nulib\php\types; | ||||||
| 
 | 
 | ||||||
|  | use nulib\exceptions; | ||||||
|  | 
 | ||||||
| class vpkey { | class vpkey { | ||||||
|  |   static function isa($value, bool $strict=false) : bool { | ||||||
|  |     if ($strict) return is_array($value) || is_int($value) || is_string($value); | ||||||
|  |     else return is_array($value) || is_scalar($value); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   static function ensure(&$pkey): void { |   static function ensure(&$pkey): void { | ||||||
|     if ($pkey === null) $pkey = ""; |  | ||||||
|     elseif ($pkey === false) $pkey = 0; |  | ||||||
|     elseif (!is_string($pkey) && !is_int($pkey) && !is_array($pkey)) $pkey = strval($pkey); |  | ||||||
|     if (is_array($pkey)) { |     if (is_array($pkey)) { | ||||||
|       foreach ($pkey as &$key) { |       foreach ($pkey as &$key) { | ||||||
|         vkey::ensure($key); |         vkey::ensure($key); | ||||||
|       }; |       }; | ||||||
|       unset($key); |       unset($key); | ||||||
|  |       return; | ||||||
|  |     } elseif (is_int($pkey) || is_string($pkey)) { | ||||||
|  |       return; | ||||||
|     } |     } | ||||||
|  |     if ($pkey === null) $pkey = ""; | ||||||
|  |     elseif ($pkey === false) $pkey = 0; | ||||||
|  |     elseif (is_scalar($pkey)) $pkey = strval($pkey); | ||||||
|  |     else throw exceptions::invalid_value($pkey, "pkey"); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   static function ensuren(&$pkey): void { |   static function ensuren(&$pkey): void { | ||||||
|  | |||||||
							
								
								
									
										22
									
								
								php/src/php/types/vraw.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								php/src/php/types/vraw.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | |||||||
|  | <?php | ||||||
|  | namespace nulib\php\types; | ||||||
|  | 
 | ||||||
|  | class vraw { | ||||||
|  |   static function isa($value, bool $strict=false) : bool { | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function ensure(&$raw): void { | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function ensuren(&$raw): void { | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function with($value) { | ||||||
|  |     return $value; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function withn($value) { | ||||||
|  |     return $value; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -1,6 +1,7 @@ | |||||||
| <?php | <?php | ||||||
| namespace nulib\php\types; | namespace nulib\php\types; | ||||||
| 
 | 
 | ||||||
|  | use nulib\exceptions; | ||||||
| use nulib\str; | use nulib\str; | ||||||
| 
 | 
 | ||||||
| class vrawstring { | class vrawstring { | ||||||
| @ -9,8 +10,19 @@ class vrawstring { | |||||||
|   /** @var bool faut-il normaliser les caractères fin de ligne */ |   /** @var bool faut-il normaliser les caractères fin de ligne */ | ||||||
|   const NORM_NL = false; |   const NORM_NL = false; | ||||||
| 
 | 
 | ||||||
|  |   static function isa($value, bool $strict=false) : bool { | ||||||
|  |     if ($strict) return is_string($value); | ||||||
|  |     else return is_scalar($value); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   static function ensure(&$string): void { |   static function ensure(&$string): void { | ||||||
|     if (!is_string($string)) $string = strval($string); |     if (!is_string($string)) { | ||||||
|  |       if (is_scalar($string)) { | ||||||
|  |         $string = strval($string); | ||||||
|  |       } else { | ||||||
|  |         throw exceptions::invalid_value($string, "string"); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|     if (static::TRIM) $string = trim($string); |     if (static::TRIM) $string = trim($string); | ||||||
|     if (static::NORM_NL) $string = str::norm_nl($string); |     if (static::NORM_NL) $string = str::norm_nl($string); | ||||||
|   } |   } | ||||||
|  | |||||||
							
								
								
									
										30
									
								
								php/src/php/types/vtime.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								php/src/php/types/vtime.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | <?php | ||||||
|  | namespace nulib\php\types; | ||||||
|  | 
 | ||||||
|  | use nulib\php\time\DateTime; | ||||||
|  | use nulib\php\time\Time; | ||||||
|  | 
 | ||||||
|  | class vtime { | ||||||
|  |   static function isa($value, bool $strict=false) : bool { | ||||||
|  |     if ($strict) return $value instanceof Time; | ||||||
|  |     else return Time::isa_time($value); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function ensure(&$time): void { | ||||||
|  |     $time = Time::with($time); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function ensuren(&$time): void { | ||||||
|  |     $time = Time::withn($time); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function with($value): Time { | ||||||
|  |     self::ensure($value); | ||||||
|  |     return $value; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function withn($value): ?Time { | ||||||
|  |     self::ensuren($value); | ||||||
|  |     return $value; | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										60
									
								
								php/tests/php/time/HourTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								php/tests/php/time/HourTest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,60 @@ | |||||||
|  | <?php | ||||||
|  | namespace nulib\php\time; | ||||||
|  | 
 | ||||||
|  | use nulib\tests\TestCase; | ||||||
|  | use nulib\ValueException; | ||||||
|  | 
 | ||||||
|  | class HourTest extends TestCase { | ||||||
|  |   function testParse() { | ||||||
|  |     self::assertSame("8h", strval(new Hour("08:00:00"))); | ||||||
|  |     self::assertSame("8h", strval(new Hour("8:0"))); | ||||||
|  |     self::assertSame("8h", strval(new Hour("8.0"))); | ||||||
|  |     self::assertSame("8h", strval(new Hour("8h"))); | ||||||
|  | 
 | ||||||
|  |     self::assertSame("8h15", strval(new Hour("08:15:00"))); | ||||||
|  |     self::assertSame("8h15", strval(new Hour("8:15"))); | ||||||
|  |     self::assertSame("8h15", strval(new Hour("8.15"))); | ||||||
|  |     self::assertSame("8h15", strval(new Hour("8h15"))); | ||||||
|  | 
 | ||||||
|  |     self::assertSame("8h15", strval(new Hour("08:15:23"))); | ||||||
|  |     self::assertSame("8h15", strval(new Hour("8:15.23"))); | ||||||
|  |     self::assertSame("8h15", strval(new Hour("8.15.23"))); | ||||||
|  |     self::assertSame("8h15", strval(new Hour("8h15.23"))); | ||||||
|  | 
 | ||||||
|  |     self::assertSame("31h11", strval(new Hour("30:70:80", [ | ||||||
|  |       "wrap" => false, | ||||||
|  |     ]))); | ||||||
|  |     self::assertSame("7h11", strval(new Hour("30:70:80"))); | ||||||
|  | 
 | ||||||
|  |     self::assertException(ValueException::class, function() { | ||||||
|  |       return strval(new Hour("bad format")); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function testFormat() { | ||||||
|  |     self::assertSame("0h", (new Hour(0))->format()); | ||||||
|  |     self::assertSame("0h56", (new Hour(56))->format()); | ||||||
|  |     self::assertSame("2h", (new Hour(120))->format()); | ||||||
|  |     self::assertSame("23h59", (new Hour(1439))->format()); | ||||||
|  |     self::assertSame("24h", (new Hour(1440))->format()); | ||||||
|  |     self::assertSame("0h01", (new Hour(1441))->format()); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function testStep() { | ||||||
|  |     $h = new Hour(null, [ | ||||||
|  |       "step" => 5, | ||||||
|  |     ]); | ||||||
|  |     $h->setu(10); self::assertSame("0h10", strval($h)); | ||||||
|  |     $h->setu(12); self::assertSame("0h10", strval($h)); | ||||||
|  |     $h->setu(15); self::assertSame("0h15", strval($h)); | ||||||
|  |     $h->setu(17); self::assertSame("0h15", strval($h)); | ||||||
|  | 
 | ||||||
|  |     $h->set("8h"); | ||||||
|  |     $h->addu(); self::assertSame("8h05", strval($h)); | ||||||
|  |     $h->addu(); self::assertSame("8h10", strval($h)); | ||||||
|  |     $h->addu(); self::assertSame("8h15", strval($h)); | ||||||
|  |     $h->subu(); self::assertSame("8h10", strval($h)); | ||||||
|  |     $h->subu(); self::assertSame("8h05", strval($h)); | ||||||
|  |     $h->subu(); self::assertSame("8h", strval($h)); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										74
									
								
								php/tests/php/time/TimeTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								php/tests/php/time/TimeTest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,74 @@ | |||||||
|  | <?php | ||||||
|  | namespace nulib\php\time; | ||||||
|  | 
 | ||||||
|  | use nulib\tests\TestCase; | ||||||
|  | use nulib\ValueException; | ||||||
|  | 
 | ||||||
|  | class TimeTest extends TestCase { | ||||||
|  |   function testParse() { | ||||||
|  |     self::assertSame("08:00:00", strval(new Time("08:00:00"))); | ||||||
|  |     self::assertSame("08:00:00", strval(new Time("8:0"))); | ||||||
|  |     self::assertSame("08:00:00", strval(new Time("8.0"))); | ||||||
|  |     self::assertSame("08:00:00", strval(new Time("8h"))); | ||||||
|  | 
 | ||||||
|  |     self::assertSame("08:15:00", strval(new Time("08:15:00"))); | ||||||
|  |     self::assertSame("08:15:00", strval(new Time("8:15"))); | ||||||
|  |     self::assertSame("08:15:00", strval(new Time("8.15"))); | ||||||
|  |     self::assertSame("08:15:00", strval(new Time("8h15"))); | ||||||
|  | 
 | ||||||
|  |     self::assertSame("08:15:23", strval(new Time("08:15:23"))); | ||||||
|  |     self::assertSame("08:15:23", strval(new Time("8:15.23"))); | ||||||
|  |     self::assertSame("08:15:23", strval(new Time("8.15.23"))); | ||||||
|  |     self::assertSame("08:15:23", strval(new Time("8h15.23"))); | ||||||
|  | 
 | ||||||
|  |     self::assertSame("31:11:20", strval(new Time("30:70:80", [ | ||||||
|  |       "wrap" => false, | ||||||
|  |     ]))); | ||||||
|  |     self::assertSame("07:11:20", strval(new Time("30:70:80"))); | ||||||
|  | 
 | ||||||
|  |     self::assertException(ValueException::class, function() { | ||||||
|  |       return strval(new Time("bad format")); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function testGetu() { | ||||||
|  |     self::assertSame(0, (new Time(0))->getu()); | ||||||
|  |     self::assertSame(86399, (new Time(-1))->getu()); | ||||||
|  |     self::assertSame(1, (new Time(1))->getu()); | ||||||
|  |     self::assertSame(120, (new Time(120))->getu()); | ||||||
|  |     self::assertSame(86400, (new Time(86400))->getu()); | ||||||
|  |     self::assertSame(0, (new Time(-86400))->getu()); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function testAddu() { | ||||||
|  |     $t = new Time(0); | ||||||
|  |     $t->addu(0); self::assertSame(0, $t->getu()); | ||||||
|  |     $t->addu(10); self::assertSame(10, $t->getu()); | ||||||
|  |     $t->addu(10); self::assertSame(20, $t->getu()); | ||||||
|  |     $t->addu(100); self::assertSame(120, $t->getu()); | ||||||
|  |     $t->addu(86280); self::assertSame(86400, $t->getu()); | ||||||
|  |     $t->addu(86400); self::assertSame(0, $t->getu()); | ||||||
|  |     $t->addu(-86400); self::assertSame(0, $t->getu()); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function testSubu() { | ||||||
|  |     $t = new Time(0); | ||||||
|  |     $t->subu(-86400); self::assertSame(86400, $t->getu()); | ||||||
|  |     $t->subu(86400); self::assertSame(0, $t->getu()); | ||||||
|  |      | ||||||
|  |     $t = new Time(120); | ||||||
|  |     $t->subu(100); self::assertSame(20, $t->getu()); | ||||||
|  |     $t->subu(10); self::assertSame(10, $t->getu()); | ||||||
|  |     $t->subu(10); self::assertSame(0, $t->getu()); | ||||||
|  |     $t->subu(0); self::assertSame(0, $t->getu()); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function testFormat() { | ||||||
|  |     self::assertSame("00:00:00", (new Time(0))->format()); | ||||||
|  |     self::assertSame("00:00:56", (new Time(56))->format()); | ||||||
|  |     self::assertSame("00:02:00", (new Time(120))->format()); | ||||||
|  |     self::assertSame("23:59:59", (new Time(86399))->format()); | ||||||
|  |     self::assertSame("24:00:00", (new Time(86400))->format()); | ||||||
|  |     self::assertSame("00:00:01", (new Time(86401))->format()); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										88
									
								
								php/tests/php/types/assocTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								php/tests/php/types/assocTest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,88 @@ | |||||||
|  | <?php | ||||||
|  | namespace nulib\php\types; | ||||||
|  | 
 | ||||||
|  | use nulib\tests\TestCase; | ||||||
|  | use nulib\ValueException; | ||||||
|  | 
 | ||||||
|  | class assocTest extends TestCase { | ||||||
|  |   static function assertEnsureOk(array $schema, ?array $input, ?array $output) { | ||||||
|  |     assoc::ensure_schema($input, $schema); | ||||||
|  |     self::assertSame($output, $input); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static function assertEnsureFail(array $schema, ?array $input, ?array $output) { | ||||||
|  |     self::assertException(ValueException::class, function() use ($input, $schema) { | ||||||
|  |       assoc::ensure_schema($input, $schema); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function testEnsureSchema() { | ||||||
|  |     self::assertEnsureOk([ | ||||||
|  |       "string" => "string", | ||||||
|  |       "int" => "int", | ||||||
|  |     ], [ | ||||||
|  |       "string" => 5, | ||||||
|  |       "int" => "42", | ||||||
|  |     ], [ | ||||||
|  |       "string" => "5", | ||||||
|  |       "int" => 42, | ||||||
|  |     ]); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const SCHEMA_S = ["s" => "string"]; | ||||||
|  |   const SCHEMA_SD = ["s" => ["string", null]]; | ||||||
|  |   const SCHEMA_SND = ["s" => ["string", "not null"]]; | ||||||
|  |   const SCHEMA_RS = ["s" => ["string", "required" => true]]; | ||||||
|  |   const SCHEMA_RSD = ["s" => ["string", null, "required" => true]]; | ||||||
|  |   const SCHEMA_RSND = ["s" => ["string", "not null", "required" => true]]; | ||||||
|  |   const SCHEMA_NS = ["s" => "?string"]; | ||||||
|  |   const SCHEMA_NSD = ["s" => ["?string", null]]; | ||||||
|  |   const SCHEMA_NSND = ["s" => ["?string", "not null"]]; | ||||||
|  |   const SCHEMA_NRS = ["s" => ["?string", "required" => true]]; | ||||||
|  |   const SCHEMA_NRSD = ["s" => ["?string", null, "required" => true]]; | ||||||
|  |   const SCHEMA_NRSND = ["s" => ["?string", "not null", "required" => true]]; | ||||||
|  | 
 | ||||||
|  |   function testEnsureSchema2() { | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_S,   [], []); | ||||||
|  |     self::assertEnsureFail(self::SCHEMA_S, ["s" => null], ["s" => null]); | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_S,   ["s" => "not null"], ["s" => "not null"]); | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_NS,  [], []); | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_NS,  ["s" => null], ["s" => null]); | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_NS,  ["s" => "not null"], ["s" => "not null"]); | ||||||
|  | 
 | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_SD,   [], []); | ||||||
|  |     self::assertEnsureFail(self::SCHEMA_SD, ["s" => null], ["s" => null]); | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_SD,   ["s" => "not null"], ["s" => "not null"]); | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_NSD,  [], []); | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_NSD,  ["s" => null], ["s" => null]); | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_NSD,  ["s" => "not null"], ["s" => "not null"]); | ||||||
|  | 
 | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_SND,  [], ["s" => "not null"]); | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_SND,  ["s" => null], ["s" => "not null"]); | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_SND,  ["s" => "not null"], ["s" => "not null"]); | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_NSND, [], ["s" => "not null"]); | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_NSND, ["s" => null], ["s" => null]); | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_NSND, ["s" => "not null"], ["s" => "not null"]); | ||||||
|  | 
 | ||||||
|  |     self::assertEnsureFail(self::SCHEMA_RS,  [], []); | ||||||
|  |     self::assertEnsureFail(self::SCHEMA_RS,  ["s" => null], []); | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_RS,    ["s" => "not null"], ["s" => "not null"]); | ||||||
|  |     self::assertEnsureFail(self::SCHEMA_NRS, [], []); | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_NRS,   ["s" => null], ["s" => null]); | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_NRS,   ["s" => "not null"], ["s" => "not null"]); | ||||||
|  | 
 | ||||||
|  |     self::assertEnsureFail(self::SCHEMA_RSD, [], []); | ||||||
|  |     self::assertEnsureFail(self::SCHEMA_RSD, ["s" => null], []); | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_RSD, ["s" => "not null"], ["s" => "not null"]); | ||||||
|  |     self::assertEnsureFail(self::SCHEMA_NRSD, [], []); | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_NRSD, ["s" => null], ["s" => null]); | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_NRSD, ["s" => "not null"], ["s" => "not null"]); | ||||||
|  | 
 | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_RSND, [], ["s" => "not null"]); | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_RSND, ["s" => null], ["s" => "not null"]); | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_RSND, ["s" => "not null"], ["s" => "not null"]); | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_NRSND, [], ["s" => "not null"]); | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_NRSND, ["s" => null], ["s" => null]); | ||||||
|  |     self::assertEnsureOk(self::SCHEMA_NRSND, ["s" => "not null"], ["s" => "not null"]); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										60
									
								
								php/tests/php/types/scalarTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								php/tests/php/types/scalarTest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,60 @@ | |||||||
|  | <?php | ||||||
|  | namespace nulib\php\types; | ||||||
|  | 
 | ||||||
|  | use nulib\tests\TestCase; | ||||||
|  | use nulib\ValueException; | ||||||
|  | 
 | ||||||
|  | class scalarTest extends TestCase { | ||||||
|  |   function testCheckSchema() { | ||||||
|  |     self::assertTrue(scalar::check_schema(5, "int")); | ||||||
|  |     self::assertTrue(scalar::check_schema(5, "string")); | ||||||
|  |     self::assertTrue(scalar::check_schema(5, "float")); | ||||||
|  | 
 | ||||||
|  |     self::assertTrue(scalar::check_schema(5, "int", true)); | ||||||
|  |     self::assertFalse(scalar::check_schema(5, "string", true)); | ||||||
|  |     self::assertFalse(scalar::check_schema(5, "float", true)); | ||||||
|  | 
 | ||||||
|  |     self::assertTrue(scalar::check_schema("5", "int")); | ||||||
|  |     self::assertTrue(scalar::check_schema("5", "string")); | ||||||
|  |     self::assertTrue(scalar::check_schema("5", "float")); | ||||||
|  | 
 | ||||||
|  |     self::assertFalse(scalar::check_schema("5", "int", true)); | ||||||
|  |     self::assertTrue(scalar::check_schema("5", "string", true)); | ||||||
|  |     self::assertFalse(scalar::check_schema("5", "float", true)); | ||||||
|  | 
 | ||||||
|  |     self::assertFalse(scalar::check_schema("bad format", "int")); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function testEnsureSchema() { | ||||||
|  |     $v = 5; scalar::ensure_schema($v, "int"); | ||||||
|  |     self::assertSame(5, $v); | ||||||
|  |     $v = "5"; scalar::ensure_schema($v, "int"); | ||||||
|  |     self::assertSame(5, $v); | ||||||
|  |     $v = "5.0"; scalar::ensure_schema($v, "int"); | ||||||
|  |     self::assertSame(5, $v); | ||||||
|  |     $v = 5.0; scalar::ensure_schema($v, "int"); | ||||||
|  |     self::assertSame(5, $v); | ||||||
|  |      | ||||||
|  |     $v = 5; scalar::ensure_schema($v, "string"); | ||||||
|  |     self::assertSame("5", $v); | ||||||
|  |     $v = "5"; scalar::ensure_schema($v, "string"); | ||||||
|  |     self::assertSame("5", $v); | ||||||
|  |     $v = "5.0"; scalar::ensure_schema($v, "string"); | ||||||
|  |     self::assertSame("5.0", $v); | ||||||
|  |     $v = 5.0; scalar::ensure_schema($v, "string"); | ||||||
|  |     self::assertSame("5", $v); | ||||||
|  | 
 | ||||||
|  |     $v = 5; scalar::ensure_schema($v, "float"); | ||||||
|  |     self::assertSame(5.0, $v); | ||||||
|  |     $v = "5"; scalar::ensure_schema($v, "float"); | ||||||
|  |     self::assertSame(5.0, $v); | ||||||
|  |     $v = "5.0"; scalar::ensure_schema($v, "float"); | ||||||
|  |     self::assertSame(5.0, $v); | ||||||
|  |     $v = 5.0; scalar::ensure_schema($v, "float"); | ||||||
|  |     self::assertSame(5.0, $v); | ||||||
|  | 
 | ||||||
|  |     self::assertException(ValueException::class, function() { | ||||||
|  |       $v = "bad format"; scalar::ensure_schema($v, "int"); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user