nulib-base/php/src/app/args.php

247 lines
8.0 KiB
PHP

<?php
namespace nulib\app;
use nulib\A;
use nulib\cl;
use nulib\cv;
use nulib\file;
use nulib\str;
class args {
/**
* transformer une liste d'argument de la forme
* - ["myArg" => $value] devient ["--my-arg", "$value"]
* - ["myOpt" => true] devient ["--my-opt"]
* - ["myOpt" => false] est omis
* - 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 {
$args = [];
if ($array === null) return $args;
$index = 0;
foreach ($array as $arg => $value) {
if ($value === false) continue;
if ($arg === $index) {
$index++;
} else {
$arg = str::us2camel($arg);
$arg = str::camel2us($arg, false, "-");
$arg = str_replace("_", "-", $arg);
$args[] = "--$arg";
if (is_array($value)) $value[] = "--";
elseif ($value === true) $value = null;
}
if (is_array($value)) {
A::merge($args, array_map("strval", $value));
} elseif ($value !== null) {
$args[] = "$value";
}
}
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;
}
}