Skip to content
Extraits de code Groupes Projets
Valider 3d6830e4 rédigé par JamesRezo's avatar JamesRezo :tada: Validation de Gitea
Parcourir les fichiers

refactor: Déplacer d’autres classes dans Spip\ (dont les itérateurs)

parent b1cdeda0
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
Affichage de
avec 1181 ajouts et 1147 suppressions
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
"packages": [ "packages": [
{ {
"name": "symfony/polyfill-mbstring", "name": "symfony/polyfill-mbstring",
"version": "v1.24.0", "version": "v1.25.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git", "url": "https://github.com/symfony/polyfill-mbstring.git",
...@@ -71,7 +71,7 @@ ...@@ -71,7 +71,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.24.0" "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0"
}, },
"funding": [ "funding": [
{ {
...@@ -91,16 +91,16 @@ ...@@ -91,16 +91,16 @@
}, },
{ {
"name": "symfony/polyfill-php80", "name": "symfony/polyfill-php80",
"version": "v1.24.0", "version": "v1.25.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-php80.git", "url": "https://github.com/symfony/polyfill-php80.git",
"reference": "57b712b08eddb97c762a8caa32c84e037892d2e9" "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/57b712b08eddb97c762a8caa32c84e037892d2e9", "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4407588e0d3f1f52efb65fbe92babe41f37fe50c",
"reference": "57b712b08eddb97c762a8caa32c84e037892d2e9", "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
...@@ -154,7 +154,7 @@ ...@@ -154,7 +154,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.24.0" "source": "https://github.com/symfony/polyfill-php80/tree/v1.25.0"
}, },
"funding": [ "funding": [
{ {
...@@ -170,11 +170,11 @@ ...@@ -170,11 +170,11 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-09-13T13:58:33+00:00" "time": "2022-03-04T08:16:47+00:00"
}, },
{ {
"name": "symfony/polyfill-php81", "name": "symfony/polyfill-php81",
"version": "v1.24.0", "version": "v1.25.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-php81.git", "url": "https://github.com/symfony/polyfill-php81.git",
...@@ -233,7 +233,7 @@ ...@@ -233,7 +233,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-php81/tree/v1.24.0" "source": "https://github.com/symfony/polyfill-php81/tree/v1.25.0"
}, },
"funding": [ "funding": [
{ {
...@@ -392,16 +392,16 @@ ...@@ -392,16 +392,16 @@
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "1.4.6", "version": "1.4.8",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan.git", "url": "https://github.com/phpstan/phpstan.git",
"reference": "8a7761f1c520e0dad6e04d862fdc697445457cfe" "reference": "2a6d6704b17c4db6190cc3104056c0aad740cb15"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/8a7761f1c520e0dad6e04d862fdc697445457cfe", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/2a6d6704b17c4db6190cc3104056c0aad740cb15",
"reference": "8a7761f1c520e0dad6e04d862fdc697445457cfe", "reference": "2a6d6704b17c4db6190cc3104056c0aad740cb15",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
...@@ -432,7 +432,7 @@ ...@@ -432,7 +432,7 @@
"description": "PHPStan - PHP Static Analysis Tool", "description": "PHPStan - PHP Static Analysis Tool",
"support": { "support": {
"issues": "https://github.com/phpstan/phpstan/issues", "issues": "https://github.com/phpstan/phpstan/issues",
"source": "https://github.com/phpstan/phpstan/tree/1.4.6" "source": "https://github.com/phpstan/phpstan/tree/1.4.8"
}, },
"funding": [ "funding": [
{ {
...@@ -452,7 +452,7 @@ ...@@ -452,7 +452,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-02-06T12:56:13+00:00" "time": "2022-03-04T13:03:56+00:00"
}, },
{ {
"name": "spip/coding-standards", "name": "spip/coding-standards",
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
* Pour plus de détails voir le fichier COPYING.txt ou l'aide en ligne. * * Pour plus de détails voir le fichier COPYING.txt ou l'aide en ligne. *
\***************************************************************************/ \***************************************************************************/
use Spip\Admin\Bouton;
/** /**
* Ce fichier gère le bandeau supérieur de l'espace privé * Ce fichier gère le bandeau supérieur de l'espace privé
* *
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
* Pour plus de détails voir le fichier COPYING.txt ou l'aide en ligne. * * Pour plus de détails voir le fichier COPYING.txt ou l'aide en ligne. *
\***************************************************************************/ \***************************************************************************/
use Spip\Admin\Bouton;
/** /**
* Gestion des boutons de l'interface privée * Gestion des boutons de l'interface privée
* *
...@@ -20,65 +22,6 @@ if (!defined('_ECRIRE_INC_VERSION')) { ...@@ -20,65 +22,6 @@ if (!defined('_ECRIRE_INC_VERSION')) {
return; return;
} }
/**
* Classe définissant un bouton dans la barre du haut de l'interface
* privée ou dans un de ses sous menus
*/
class Bouton {
/** L'icone à mettre dans le bouton */
public string $icone;
/** Le nom de l'entrée d'i18n associé */
public string $libelle;
/** @var null|string L'URL de la page (null => ?exec=nom) */
public $url = null;
/** @var null|string|array Arguments supplementaires de l'URL */
public $urlArg = null;
/** @var null|string URL du javascript */
public $url2 = null;
/** @var null|string Pour ouvrir dans une fenetre a part */
public $target = null;
/** Sous-barre de boutons / onglets */
public array $sousmenu = [];
/** Position dans le menu */
public int $position = 0;
/** Entrée favorite (sa position dans les favoris) ? */
public int $favori = 0;
/**
* Définit un bouton
*
* @param string $icone
* L'icone à mettre dans le bouton
* @param string $libelle
* Le nom de l'entrée i18n associé
* @param null|string $url
* L'URL de la page
* @param null|string|array $urlArg
* Arguments supplémentaires de l'URL
* @param null|string $url2
* URL du javascript
* @param null|mixed $target
* Pour ouvrir une fenêtre à part
*/
public function __construct($icone, $libelle, $url = null, $urlArg = null, $url2 = null, $target = null) {
$this->icone = $icone;
$this->libelle = $libelle;
$this->url = $url;
$this->urlArg = $urlArg;
$this->url2 = $url2;
$this->target = $target;
}
}
/** /**
* Définir la liste des onglets dans une page de l'interface privée. * Définir la liste des onglets dans une page de l'interface privée.
* *
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
* Pour plus de détails voir le fichier COPYING.txt ou l'aide en ligne. * * Pour plus de détails voir le fichier COPYING.txt ou l'aide en ligne. *
\***************************************************************************/ \***************************************************************************/
use Spip\I18n\Description;
/** /**
* Outils pour la traduction et recherche de traductions * Outils pour la traduction et recherche de traductions
* *
...@@ -202,24 +204,6 @@ function surcharger_langue($fichiers) { ...@@ -202,24 +204,6 @@ function surcharger_langue($fichiers) {
} }
} }
class SPIP_Traductions_Description {
/** @var string code de langue (hors module) */
public $code;
/** @var string nom du module de langue */
public $module;
/** @var string langue de la traduction */
public $langue;
/** @var string traduction */
public $texte;
/** @var string var mode particulier appliqué ? */
public $mode;
/** @var bool Corrections des textes appliqué ? */
public $corrections = false;
}
/** /**
* Traduire une chaine internationalisée * Traduire une chaine internationalisée
* *
...@@ -253,9 +237,9 @@ class SPIP_Traductions_Description { ...@@ -253,9 +237,9 @@ class SPIP_Traductions_Description {
* @param bool $raw * @param bool $raw
* - false : retourne le texte (par défaut) * - false : retourne le texte (par défaut)
* - true : retourne une description de la chaine de langue (module, texte, langue) * - true : retourne une description de la chaine de langue (module, texte, langue)
* @return string|SPIP_Traductions_Description * @return string|Description
* - string : Traduction demandée. Chaîne vide si aucune traduction trouvée. * - string : Traduction demandée. Chaîne vide si aucune traduction trouvée.
* - SPIP_Traductions_Description : traduction et description (texte, module, langue) * - Description : traduction et description (texte, module, langue)
**/ **/
function inc_traduire_dist($ori, $lang, $raw = false) { function inc_traduire_dist($ori, $lang, $raw = false) {
static $deja_vu = []; static $deja_vu = [];
...@@ -276,7 +260,7 @@ function inc_traduire_dist($ori, $lang, $raw = false) { ...@@ -276,7 +260,7 @@ function inc_traduire_dist($ori, $lang, $raw = false) {
$ori_complet = implode('|', $modules) . ':' . $ori; $ori_complet = implode('|', $modules) . ':' . $ori;
} }
$desc = new SPIP_Traductions_Description(); $desc = new Description();
// parcourir tous les modules jusqu'a ce qu'on trouve // parcourir tous les modules jusqu'a ce qu'on trouve
foreach ($modules as $module) { foreach ($modules as $module) {
...@@ -357,9 +341,9 @@ function inc_traduire_dist($ori, $lang, $raw = false) { ...@@ -357,9 +341,9 @@ function inc_traduire_dist($ori, $lang, $raw = false) {
* Modifie le texte de traduction pour indiquer des éléments * Modifie le texte de traduction pour indiquer des éléments
* servant au debug de celles-ci. (pour var_mode=traduction) * servant au debug de celles-ci. (pour var_mode=traduction)
* *
* @param SPIP_Traductions_Description $desc * @param Description $desc
* @param string $modules Les modules qui étaient demandés * @param string $modules Les modules qui étaient demandés
* @return SPIP_Traductions_Description * @return Description
*/ */
function definir_details_traduction($desc, $modules) { function definir_details_traduction($desc, $modules) {
if (!$desc->mode and $desc->texte) { if (!$desc->mode and $desc->texte) {
......
...@@ -44,19 +44,3 @@ function iterateur_CONDITION_dist($b) { ...@@ -44,19 +44,3 @@ function iterateur_CONDITION_dist($b) {
return $b; return $b;
} }
/**
* Iterateur CONDITION pour itérer sur des données
*
* La boucle condition n'a toujours qu'un seul élément.
*/
class IterateurCONDITION extends IterateurData {
/**
* Obtenir les données de la boucle CONDITION
*
* @param array $command
**/
protected function select($command) {
$this->tableau = [0 => 1];
}
}
...@@ -58,526 +58,6 @@ function iterateur_DATA_dist($b) { ...@@ -58,526 +58,6 @@ function iterateur_DATA_dist($b) {
} }
/**
* Itérateur DATA
*
* Pour itérer sur des données quelconques (transformables en tableau)
*/
class IterateurDATA implements Iterator {
/** Tableau de données */
protected array $tableau = [];
/**
* Conditions de filtrage
* ie criteres de selection
*/
protected array $filtre = [];
/**
* Cle courante
*
* @var scalar
*/
protected $cle = null;
/**
* Valeur courante
*
* @var mixed
*/
protected $valeur = null;
protected string $type = 'DATA';
protected array $command = [];
protected array $info = [];
/** Erreur presente ? */
public bool $err = false;
/**
* Calcul du total des elements
*
* @var int|null
**/
public $total = null;
/**
* Constructeur
*
* @param $command
* @param array $info
*/
public function __construct($command, $info = []) {
$this->type = 'DATA';
$this->command = $command;
$this->info = $info;
$this->select($command);
}
/**
* Revenir au depart
*
* @return void
*/
public function rewind(): void {
reset($this->tableau);
$this->cle = array_key_first($this->tableau);
$this->valeur = current($this->tableau);
next($this->tableau);
}
/**
* Déclarer les critères exceptions
*
* @return array
*/
public function exception_des_criteres() {
return ['tableau'];
}
/**
* Récupérer depuis le cache si possible
*
* @param string $cle
* @return mixed
*/
protected function cache_get($cle) {
if (!$cle) {
return;
}
# utiliser memoization si dispo
if (!function_exists('cache_get')) {
return;
}
return cache_get($cle);
}
/**
* Stocker en cache si possible
*
* @param string $cle
* @param int $ttl
* @param null|mixed $valeur
* @return bool
*/
protected function cache_set($cle, $ttl, $valeur = null) {
if (!$cle) {
return;
}
if (is_null($valeur)) {
$valeur = $this->tableau;
}
# utiliser memoization si dispo
if (!function_exists('cache_set')) {
return;
}
return cache_set(
$cle,
[
'data' => $valeur,
'time' => time(),
'ttl' => $ttl
],
3600 + $ttl
);
# conserver le cache 1h de plus que la validite demandee,
# pour le cas ou le serveur distant ne reponde plus
}
/**
* Aller chercher les données de la boucle DATA
*
* @throws Exception
* @param array $command
* @return void
*/
protected function select($command) {
// l'iterateur DATA peut etre appele en passant (data:type)
// le type se retrouve dans la commande 'from'
// dans ce cas la le critere {source}, si present, n'a pas besoin du 1er argument
if (isset($this->command['from'][0])) {
if (isset($this->command['source']) and is_array($this->command['source'])) {
array_unshift($this->command['source'], $this->command['sourcemode']);
}
$this->command['sourcemode'] = $this->command['from'][0];
}
// cherchons differents moyens de creer le tableau de donnees
// les commandes connues pour l'iterateur DATA
// sont : {tableau #ARRAY} ; {cle=...} ; {valeur=...}
// {source format, [URL], [arg2]...}
if (
isset($this->command['source'])
and isset($this->command['sourcemode'])
) {
$this->select_source();
}
// Critere {liste X1, X2, X3}
if (isset($this->command['liste'])) {
$this->select_liste();
}
if (isset($this->command['enum'])) {
$this->select_enum();
}
// Si a ce stade on n'a pas de table, il y a un bug
if (!is_array($this->tableau)) {
$this->err = true;
spip_log('erreur datasource ' . var_export($command, true));
}
// {datapath query.results}
// extraire le chemin "query.results" du tableau de donnees
if (
!$this->err
and isset($this->command['datapath'])
and is_array($this->command['datapath'])
) {
$this->select_datapath();
}
// tri {par x}
if ($this->command['orderby']) {
$this->select_orderby();
}
// grouper les resultats {fusion /x/y/z} ;
if ($this->command['groupby']) {
$this->select_groupby();
}
$this->rewind();
#var_dump($this->tableau);
}
/**
* Aller chercher les donnees de la boucle DATA
* depuis une source
* {source format, [URL], [arg2]...}
*/
protected function select_source() {
# un peu crado : avant de charger le cache il faut charger
# les class indispensables, sinon PHP ne saura pas gerer
# l'objet en cache ; cf plugins/icalendar
# perf : pas de fonction table_to_array ! (table est deja un array)
if (
isset($this->command['sourcemode'])
and !in_array($this->command['sourcemode'], ['table', 'array', 'tableau'])
) {
charger_fonction($this->command['sourcemode'] . '_to_array', 'inc', true);
}
# le premier argument peut etre un array, une URL etc.
$src = $this->command['source'][0];
# avons-nous un cache dispo ?
$cle = null;
if (is_string($src)) {
$cle = 'datasource_' . md5($this->command['sourcemode'] . ':' . var_export($this->command['source'], true));
}
$cache = $this->cache_get($cle);
if (isset($this->command['datacache'])) {
$ttl = intval($this->command['datacache']);
}
if (
$cache
and ($cache['time'] + ($ttl ?? $cache['ttl'])
> time())
and !(_request('var_mode') === 'recalcul'
and include_spip('inc/autoriser')
and autoriser('recalcul')
)
) {
$this->tableau = $cache['data'];
} else {
try {
if (
isset($this->command['sourcemode'])
and in_array(
$this->command['sourcemode'],
['table', 'array', 'tableau']
)
) {
if (
is_array($a = $src)
or (is_string($a)
and $a = str_replace('"', '"', $a) # fragile!
and is_array($a = @unserialize($a)))
) {
$this->tableau = $a;
}
} else {
$data = $src;
if (is_string($src)) {
if (tester_url_absolue($src)) {
include_spip('inc/distant');
$data = recuperer_url($src, ['taille_max' => _DATA_SOURCE_MAX_SIZE]);
$data = $data['page'] ?? '';
if (!$data) {
throw new Exception('404');
}
if (!isset($ttl)) {
$ttl = 24 * 3600;
}
} elseif (@is_dir($src)) {
$data = $src;
} elseif (@is_readable($src) && @is_file($src)) {
$data = spip_file_get_contents($src);
}
if (!isset($ttl)) {
$ttl = 10;
}
}
if (
!$this->err
and $data_to_array = charger_fonction($this->command['sourcemode'] . '_to_array', 'inc', true)
) {
$args = $this->command['source'];
$args[0] = $data;
if (is_array($a = $data_to_array(...$args))) {
$this->tableau = $a;
}
}
}
if (!is_array($this->tableau)) {
$this->err = true;
}
if (!$this->err and isset($ttl) and $ttl > 0) {
$this->cache_set($cle, $ttl);
}
} catch (Exception $e) {
$e = $e->getMessage();
$err = sprintf(
"[%s, %s] $e",
$src,
$this->command['sourcemode']
);
erreur_squelette([$err, []]);
$this->err = true;
}
}
# en cas d'erreur, utiliser le cache si encore dispo
if (
$this->err
and $cache
) {
$this->tableau = $cache['data'];
$this->err = false;
}
}
/**
* Retourne un tableau donne depuis un critère liste
*
* Critère `{liste X1, X2, X3}`
*
* @see critere_DATA_liste_dist()
*
**/
protected function select_liste() {
# s'il n'y a qu'une valeur dans la liste, sans doute une #BALISE
if (!isset($this->command['liste'][1])) {
if (!is_array($this->command['liste'][0])) {
$this->command['liste'] = explode(',', $this->command['liste'][0]);
} else {
$this->command['liste'] = $this->command['liste'][0];
}
}
$this->tableau = $this->command['liste'];
}
/**
* Retourne un tableau donne depuis un critere liste
* Critere {enum Xmin, Xmax}
*
**/
protected function select_enum() {
# s'il n'y a qu'une valeur dans la liste, sans doute une #BALISE
if (!isset($this->command['enum'][1])) {
if (!is_array($this->command['enum'][0])) {
$this->command['enum'] = explode(',', $this->command['enum'][0]);
} else {
$this->command['enum'] = $this->command['enum'][0];
}
}
if ((is_countable($this->command['enum']) ? count($this->command['enum']) : 0) >= 3) {
$enum = range(
array_shift($this->command['enum']),
array_shift($this->command['enum']),
array_shift($this->command['enum'])
);
} else {
$enum = range(array_shift($this->command['enum']), array_shift($this->command['enum']));
}
$this->tableau = $enum;
}
/**
* extraire le chemin "query.results" du tableau de donnees
* {datapath query.results}
*
**/
protected function select_datapath() {
$base = reset($this->command['datapath']);
if (strlen($base = ltrim(trim($base), '/'))) {
$this->tableau = table_valeur($this->tableau, $base);
if (!is_array($this->tableau)) {
$this->tableau = [];
$this->err = true;
spip_log("datapath '$base' absent");
}
}
}
/**
* Ordonner les resultats
* {par x}
*
**/
protected function select_orderby() {
$sortfunc = '';
$aleas = 0;
foreach ($this->command['orderby'] as $tri) {
// virer le / initial pour les criteres de la forme {par /xx}
if (preg_match(',^\.?([/\w:_-]+)( DESC)?$,iS', ltrim($tri, '/'), $r)) {
$r = array_pad($r, 3, null);
// tri par cle
if ($r[1] == 'cle') {
if (isset($r[2]) and $r[2]) {
krsort($this->tableau);
} else {
ksort($this->tableau);
}
} # {par hasard}
else {
if ($r[1] == 'hasard') {
$k = array_keys($this->tableau);
shuffle($k);
$v = [];
foreach ($k as $cle) {
$v[$cle] = $this->tableau[$cle];
}
$this->tableau = $v;
} else {
# {par valeur}
if ($r[1] == 'valeur') {
$tv = '%s';
} # {par valeur/xx/yy} ??
else {
$tv = 'table_valeur(%s, ' . var_export($r[1], true) . ')';
}
$sortfunc .= '
$a = ' . sprintf($tv, '$aa') . ';
$b = ' . sprintf($tv, '$bb') . ';
if ($a <> $b)
return ($a ' . (!empty($r[2]) ? '>' : '<') . ' $b) ? -1 : 1;';
}
}
}
}
if ($sortfunc) {
$sortfunc .= "\n return 0;";
uasort($this->tableau, fn($aa, $bb) => eval($sortfunc));
}
}
/**
* Grouper les resultats
* {fusion /x/y/z}
*
**/
protected function select_groupby() {
// virer le / initial pour les criteres de la forme {fusion /xx}
if (strlen($fusion = ltrim($this->command['groupby'][0], '/'))) {
$vu = [];
foreach ($this->tableau as $k => $v) {
$val = table_valeur($v, $fusion);
if (isset($vu[$val])) {
unset($this->tableau[$k]);
} else {
$vu[$val] = true;
}
}
}
}
/**
* L'iterateur est-il encore valide ?
*
* @return bool
*/
public function valid(): bool {
return !is_null($this->cle);
}
/**
* Retourner la valeur
*
* @return mixed
*/
#[\ReturnTypeWillChange]
public function current() {
return $this->valeur;
}
/**
* Retourner la cle
*
* @return mixed
*/
#[\ReturnTypeWillChange]
public function key() {
return $this->cle;
}
/**
* Passer a la valeur suivante
*
* @return void
*/
public function next(): void {
if ($this->valid()) {
$this->cle = key($this->tableau);
$this->valeur = current($this->tableau);
next($this->tableau);
}
}
/**
* Compter le nombre total de resultats
*
* @return int
*/
public function count() {
if (is_null($this->total)) {
$this->total = count($this->tableau);
}
return $this->total;
}
}
/* /*
* Fonctions de transformation donnee => tableau * Fonctions de transformation donnee => tableau
*/ */
......
...@@ -45,15 +45,10 @@ function iterateur_php_dist($b, $iteratorName) { ...@@ -45,15 +45,10 @@ function iterateur_php_dist($b, $iteratorName) {
'valeur' => 'STRING', 'valeur' => 'STRING',
] ]
]; ];
foreach (get_class_methods($iteratorName) as $method) { foreach (get_class_methods($iteratorName) as $method) {
$b->show['field'][strtolower($method)] = 'METHOD'; $b->show['field'][strtolower($method)] = 'METHOD';
} }
/*
foreach (get_class_vars($iteratorName) as $property) {
$b->show['field'][ strtolower($property) ] = 'PROPERTY';
}
*/
return $b; return $b;
} }
...@@ -22,9 +22,6 @@ if (!defined('_ECRIRE_INC_VERSION')) { ...@@ -22,9 +22,6 @@ if (!defined('_ECRIRE_INC_VERSION')) {
return; return;
} }
include_spip('iterateur/data');
/** /**
* Créer une boucle sur un itérateur POUR * Créer une boucle sur un itérateur POUR
* *
......
...@@ -451,7 +451,7 @@ define('CODE_CORPS_BOUCLE', '%s ...@@ -451,7 +451,7 @@ define('CODE_CORPS_BOUCLE', '%s
if (defined("_BOUCLE_PROFILER")) $timer = time()+(float)microtime(); if (defined("_BOUCLE_PROFILER")) $timer = time()+(float)microtime();
$t0 = ""; $t0 = "";
// REQUETE // REQUETE
$iter = IterFactory::create( $iter = Spip\\Core\\Iterateur\\Factory::create(
"%s", "%s",
%s, %s,
array(%s) array(%s)
...@@ -465,8 +465,7 @@ define('CODE_CORPS_BOUCLE', '%s ...@@ -465,8 +465,7 @@ define('CODE_CORPS_BOUCLE', '%s
if (defined("_BOUCLE_PROFILER") if (defined("_BOUCLE_PROFILER")
AND 1000*($timer = (time()+(float)microtime())-$timer) > _BOUCLE_PROFILER) AND 1000*($timer = (time()+(float)microtime())-$timer) > _BOUCLE_PROFILER)
spip_log(intval(1000*$timer)."ms %s","profiler"._LOG_AVERTISSEMENT); spip_log(intval(1000*$timer)."ms %s","profiler"._LOG_AVERTISSEMENT);
return $t0;' return $t0;');
);
/** /**
* Compilation d'une boucle (non recursive). * Compilation d'une boucle (non recursive).
......
...@@ -28,7 +28,6 @@ include_spip('inc/rubriques'); # pour calcul_branche (cf critere branche) ...@@ -28,7 +28,6 @@ include_spip('inc/rubriques'); # pour calcul_branche (cf critere branche)
include_spip('inc/acces'); // Gestion des acces pour ical include_spip('inc/acces'); // Gestion des acces pour ical
include_spip('inc/actions'); include_spip('inc/actions');
include_spip('public/fonctions'); include_spip('public/fonctions');
include_spip('public/iterateur');
include_spip('public/interfaces'); include_spip('public/interfaces');
include_spip('public/quete'); include_spip('public/quete');
......
<?php <?php
use Spip\Core\Champ;
use Spip\Core\Texte; use Spip\Core\Texte;
/***************************************************************************\ /***************************************************************************\
......
<?php
namespace Spip\Admin;
/**
* Classe définissant un bouton dans la barre du haut de l'interface
* privée ou dans un de ses sous menus
*/
class Bouton {
/** L'icone à mettre dans le bouton */
public string $icone;
/** Le nom de l'entrée d'i18n associé */
public string $libelle;
/** @var null|string L'URL de la page (null => ?exec=nom) */
public $url = null;
/** @var null|string|array Arguments supplementaires de l'URL */
public $urlArg = null;
/** @var null|string URL du javascript */
public $url2 = null;
/** @var null|string Pour ouvrir dans une fenetre a part */
public $target = null;
/** Sous-barre de boutons / onglets */
public array $sousmenu = [];
/** Position dans le menu */
public int $position = 0;
/** Entrée favorite (sa position dans les favoris) ? */
public int $favori = 0;
/**
* Définit un bouton
*
* @param string $icone
* L'icone à mettre dans le bouton
* @param string $libelle
* Le nom de l'entrée i18n associé
* @param null|string $url
* L'URL de la page
* @param null|string|array $urlArg
* Arguments supplémentaires de l'URL
* @param null|string $url2
* URL du javascript
* @param null|mixed $target
* Pour ouvrir une fenêtre à part
*/
public function __construct($icone, $libelle, $url = null, $urlArg = null, $url2 = null, $target = null) {
$this->icone = $icone;
$this->libelle = $libelle;
$this->url = $url;
$this->urlArg = $urlArg;
$this->url2 = $url2;
$this->target = $target;
}
}
<?php
namespace Spip\Core\Iterateur;
abstract class AbstractIterateur
{
/**
* Erreur presente ?
*
* @var bool
*/
public $err = false;
public $command;
public $info;
public function __construct($command, $info = []) {
$this->command = $command;
$this->info = $info;
}
}
<?php
namespace Spip\Core\Iterateur;
/**
* Iterateur CONDITION pour itérer sur des données.
*
* La boucle condition n'a toujours qu'un seul élément.
*/
class Condition extends Data
{
/**
* Obtenir les données de la boucle CONDITION.
*
* @param array $command
*/
protected function select($command) {
$this->tableau = [0 => 1];
}
}
<?php
namespace Spip\Core\Iterateur;
use Exception;
use Iterator;
/**
* Itérateur DATA.
*
* Pour itérer sur des données quelconques (transformables en tableau)
*/
class Data extends AbstractIterateur implements Iterator
{
/** Tableau de données */
protected array $tableau = [];
/**
* Conditions de filtrage
* ie criteres de selection
*/
protected array $filtre = [];
/**
* Cle courante
*
* @var scalar
*/
protected $cle = null;
/**
* Valeur courante
*
* @var mixed
*/
protected $valeur = null;
protected string $type = 'DATA';
protected array $command = [];
protected array $info = [];
/** Erreur presente ? */
public bool $err = false;
/**
* Calcul du total des elements
*
* @var int|null
**/
public $total = null;
/**
* Constructeur
*
* @param $command
* @param array $info
*/
public function __construct($command, $info = []) {
$this->type = 'DATA';
$this->command = $command;
$this->info = $info;
$this->select($command);
}
/**
* Revenir au depart
*
* @return void
*/
public function rewind(): void {
reset($this->tableau);
$this->cle = array_key_first($this->tableau);
$this->valeur = current($this->tableau);
next($this->tableau);
}
/**
* Déclarer les critères exceptions
*
* @return array
*/
public function exception_des_criteres() {
return ['tableau'];
}
/**
* Récupérer depuis le cache si possible
*
* @param string $cle
* @return mixed
*/
protected function cache_get($cle) {
if (!$cle) {
return;
}
# utiliser memoization si dispo
if (!function_exists('cache_get')) {
return;
}
return cache_get($cle);
}
/**
* Stocker en cache si possible
*
* @param string $cle
* @param int $ttl
* @param null|mixed $valeur
* @return bool
*/
protected function cache_set($cle, $ttl, $valeur = null) {
if (!$cle) {
return;
}
if (is_null($valeur)) {
$valeur = $this->tableau;
}
# utiliser memoization si dispo
if (!function_exists('cache_set')) {
return;
}
return cache_set(
$cle,
[
'data' => $valeur,
'time' => time(),
'ttl' => $ttl
],
3600 + $ttl
);
# conserver le cache 1h de plus que la validite demandee,
# pour le cas ou le serveur distant ne reponde plus
}
/**
* Aller chercher les données de la boucle DATA
*
* @throws Exception
* @param array $command
* @return void
*/
protected function select($command) {
// l'iterateur DATA peut etre appele en passant (data:type)
// le type se retrouve dans la commande 'from'
// dans ce cas la le critere {source}, si present, n'a pas besoin du 1er argument
if (isset($this->command['from'][0])) {
if (isset($this->command['source']) and is_array($this->command['source'])) {
array_unshift($this->command['source'], $this->command['sourcemode']);
}
$this->command['sourcemode'] = $this->command['from'][0];
}
// cherchons differents moyens de creer le tableau de donnees
// les commandes connues pour l'iterateur DATA
// sont : {tableau #ARRAY} ; {cle=...} ; {valeur=...}
// {source format, [URL], [arg2]...}
if (
isset($this->command['source'])
and isset($this->command['sourcemode'])
) {
$this->select_source();
}
// Critere {liste X1, X2, X3}
if (isset($this->command['liste'])) {
$this->select_liste();
}
if (isset($this->command['enum'])) {
$this->select_enum();
}
// Si a ce stade on n'a pas de table, il y a un bug
if (!is_array($this->tableau)) {
$this->err = true;
spip_log('erreur datasource ' . var_export($command, true));
}
// {datapath query.results}
// extraire le chemin "query.results" du tableau de donnees
if (
!$this->err
and isset($this->command['datapath'])
and is_array($this->command['datapath'])
) {
$this->select_datapath();
}
// tri {par x}
if ($this->command['orderby']) {
$this->select_orderby();
}
// grouper les resultats {fusion /x/y/z} ;
if ($this->command['groupby']) {
$this->select_groupby();
}
$this->rewind();
#var_dump($this->tableau);
}
/**
* Aller chercher les donnees de la boucle DATA
* depuis une source
* {source format, [URL], [arg2]...}
*/
protected function select_source() {
# un peu crado : avant de charger le cache il faut charger
# les class indispensables, sinon PHP ne saura pas gerer
# l'objet en cache ; cf plugins/icalendar
# perf : pas de fonction table_to_array ! (table est deja un array)
if (
isset($this->command['sourcemode'])
and !in_array($this->command['sourcemode'], ['table', 'array', 'tableau'])
) {
charger_fonction($this->command['sourcemode'] . '_to_array', 'inc', true);
}
# le premier argument peut etre un array, une URL etc.
$src = $this->command['source'][0];
# avons-nous un cache dispo ?
$cle = null;
if (is_string($src)) {
$cle = 'datasource_' . md5($this->command['sourcemode'] . ':' . var_export($this->command['source'], true));
}
$cache = $this->cache_get($cle);
if (isset($this->command['datacache'])) {
$ttl = intval($this->command['datacache']);
}
if (
$cache
and ($cache['time'] + ($ttl ?? $cache['ttl'])
> time())
and !(_request('var_mode') === 'recalcul'
and include_spip('inc/autoriser')
and autoriser('recalcul')
)
) {
$this->tableau = $cache['data'];
} else {
try {
if (
isset($this->command['sourcemode'])
and in_array(
$this->command['sourcemode'],
['table', 'array', 'tableau']
)
) {
if (
is_array($a = $src)
or (is_string($a)
and $a = str_replace('&quot;', '"', $a) # fragile!
and is_array($a = @unserialize($a)))
) {
$this->tableau = $a;
}
} else {
$data = $src;
if (is_string($src)) {
if (tester_url_absolue($src)) {
include_spip('inc/distant');
$data = recuperer_url($src, ['taille_max' => _DATA_SOURCE_MAX_SIZE]);
$data = $data['page'] ?? '';
if (!$data) {
throw new Exception('404');
}
if (!isset($ttl)) {
$ttl = 24 * 3600;
}
} elseif (@is_dir($src)) {
$data = $src;
} elseif (@is_readable($src) && @is_file($src)) {
$data = spip_file_get_contents($src);
}
if (!isset($ttl)) {
$ttl = 10;
}
}
if (
!$this->err
and $data_to_array = charger_fonction($this->command['sourcemode'] . '_to_array', 'inc', true)
) {
$args = $this->command['source'];
$args[0] = $data;
if (is_array($a = $data_to_array(...$args))) {
$this->tableau = $a;
}
}
}
if (!is_array($this->tableau)) {
$this->err = true;
}
if (!$this->err and isset($ttl) and $ttl > 0) {
$this->cache_set($cle, $ttl);
}
} catch (Exception $e) {
$e = $e->getMessage();
$err = sprintf(
"[%s, %s] $e",
$src,
$this->command['sourcemode']
);
erreur_squelette([$err, []]);
$this->err = true;
}
}
# en cas d'erreur, utiliser le cache si encore dispo
if (
$this->err
and $cache
) {
$this->tableau = $cache['data'];
$this->err = false;
}
}
/**
* Retourne un tableau donne depuis un critère liste
*
* Critère `{liste X1, X2, X3}`
*
* @see critere_DATA_liste_dist()
*
**/
protected function select_liste() {
# s'il n'y a qu'une valeur dans la liste, sans doute une #BALISE
if (!isset($this->command['liste'][1])) {
if (!is_array($this->command['liste'][0])) {
$this->command['liste'] = explode(',', $this->command['liste'][0]);
} else {
$this->command['liste'] = $this->command['liste'][0];
}
}
$this->tableau = $this->command['liste'];
}
/**
* Retourne un tableau donne depuis un critere liste
* Critere {enum Xmin, Xmax}
*
**/
protected function select_enum() {
# s'il n'y a qu'une valeur dans la liste, sans doute une #BALISE
if (!isset($this->command['enum'][1])) {
if (!is_array($this->command['enum'][0])) {
$this->command['enum'] = explode(',', $this->command['enum'][0]);
} else {
$this->command['enum'] = $this->command['enum'][0];
}
}
if ((is_countable($this->command['enum']) ? count($this->command['enum']) : 0) >= 3) {
$enum = range(
array_shift($this->command['enum']),
array_shift($this->command['enum']),
array_shift($this->command['enum'])
);
} else {
$enum = range(array_shift($this->command['enum']), array_shift($this->command['enum']));
}
$this->tableau = $enum;
}
/**
* extraire le chemin "query.results" du tableau de donnees
* {datapath query.results}
*
**/
protected function select_datapath() {
$base = reset($this->command['datapath']);
if (strlen($base = ltrim(trim($base), '/'))) {
$this->tableau = table_valeur($this->tableau, $base);
if (!is_array($this->tableau)) {
$this->tableau = [];
$this->err = true;
spip_log("datapath '$base' absent");
}
}
}
/**
* Ordonner les resultats
* {par x}
*
**/
protected function select_orderby() {
$sortfunc = '';
$aleas = 0;
foreach ($this->command['orderby'] as $tri) {
// virer le / initial pour les criteres de la forme {par /xx}
if (preg_match(',^\.?([/\w:_-]+)( DESC)?$,iS', ltrim($tri, '/'), $r)) {
$r = array_pad($r, 3, null);
// tri par cle
if ($r[1] == 'cle') {
if (isset($r[2]) and $r[2]) {
krsort($this->tableau);
} else {
ksort($this->tableau);
}
} # {par hasard}
else {
if ($r[1] == 'hasard') {
$k = array_keys($this->tableau);
shuffle($k);
$v = [];
foreach ($k as $cle) {
$v[$cle] = $this->tableau[$cle];
}
$this->tableau = $v;
} else {
# {par valeur}
if ($r[1] == 'valeur') {
$tv = '%s';
} # {par valeur/xx/yy} ??
else {
$tv = 'table_valeur(%s, ' . var_export($r[1], true) . ')';
}
$sortfunc .= '
$a = ' . sprintf($tv, '$aa') . ';
$b = ' . sprintf($tv, '$bb') . ';
if ($a <> $b)
return ($a ' . (!empty($r[2]) ? '>' : '<') . ' $b) ? -1 : 1;';
}
}
}
}
if ($sortfunc) {
$sortfunc .= "\n return 0;";
uasort($this->tableau, fn($aa, $bb) => eval($sortfunc));
}
}
/**
* Grouper les resultats
* {fusion /x/y/z}
*
**/
protected function select_groupby() {
// virer le / initial pour les criteres de la forme {fusion /xx}
if (strlen($fusion = ltrim($this->command['groupby'][0], '/'))) {
$vu = [];
foreach ($this->tableau as $k => $v) {
$val = table_valeur($v, $fusion);
if (isset($vu[$val])) {
unset($this->tableau[$k]);
} else {
$vu[$val] = true;
}
}
}
}
/**
* L'iterateur est-il encore valide ?
*
* @return bool
*/
public function valid(): bool {
return !is_null($this->cle);
}
/**
* Retourner la valeur
*
* @return mixed
*/
#[\ReturnTypeWillChange]
public function current() {
return $this->valeur;
}
/**
* Retourner la cle
*
* @return mixed
*/
#[\ReturnTypeWillChange]
public function key() {
return $this->cle;
}
/**
* Passer a la valeur suivante
*
* @return void
*/
public function next(): void {
if ($this->valid()) {
$this->cle = key($this->tableau);
$this->valeur = current($this->tableau);
next($this->tableau);
}
}
/**
* Compter le nombre total de resultats
*
* @return int
*/
public function count() {
if (is_null($this->total)) {
$this->total = count($this->tableau);
}
return $this->total;
}
}
<?php
namespace Spip\Core\Iterateur;
use EmptyIterator;
use Exception;
/**
* Fabrique d'iterateur
* permet de charger n'importe quel iterateur IterateurXXX
* fourni dans le fichier iterateurs/xxx.php.
*/
class Factory
{
public static function create($iterateur, $command, $info = null) {
$iter = null;
// cas des SI {si expression} analises tres tot
// pour eviter le chargement de tout iterateur
if (isset($command['si'])) {
foreach ($command['si'] as $si) {
if (!$si) {
// $command pour boucle SQL peut generer des erreurs de compilation
// s'il est transmis alors qu'on est dans un iterateur vide
return new Decorator(new EmptyIterator(), [], $info);
}
}
}
// chercher un iterateur PHP existant (par exemple dans SPL)
// (il faudrait passer l'argument ->sql_serveur
// pour etre certain qu'on est sur un "php:")
if (class_exists($iterateur)) {
$a = $command['args'] ?? [];
// permettre de passer un Iterateur directement {args #ITERATEUR} :
// si on recoit deja un iterateur en argument, on l'utilise
if ((is_countable($a) ? count($a) : 0) == 1 and is_object($a[0]) and is_subclass_of($a[0], \Iterator::class)) {
$iter = $a[0];
// sinon, on cree un iterateur du type donne
} else {
// arguments de creation de l'iterateur...
// (pas glop)
try {
switch (is_countable($a) ? count($a) : 0) {
case 0:
$iter = new $iterateur();
break;
case 1:
$iter = new $iterateur($a[0]);
break;
case 2:
$iter = new $iterateur($a[0], $a[1]);
break;
case 3:
$iter = new $iterateur($a[0], $a[1], $a[2]);
break;
case 4:
$iter = new $iterateur($a[0], $a[1], $a[2], $a[3]);
break;
}
} catch (Exception $e) {
spip_log("Erreur de chargement de l'iterateur {$iterateur}");
spip_log($e->getMessage());
$iter = new EmptyIterator();
}
}
} else {
// chercher la classe d'iterateur
// IterateurXXX
// definie dans le fichier src/Core/Iterateur/xxx.php
$class = 'Spip\\Core\\Iterateur\\' . ucfirst($iterateur);
if (!class_exists($class)) {
exit("Iterateur {$iterateur} non trouv&#233;");
// si l'iterateur n'existe pas, on se rabat sur le generique
// $iter = new EmptyIterator();
}
$iter = new $class($command, $info);
}
return new Decorator($iter, $command, $info);
}
}
<?php <?php
/***************************************************************************\ namespace Spip\Core\Iterateur;
* SPIP, Système de publication pour l'internet *
* *
* Copyright © avec tendresse depuis 2001 *
* Arnaud Martin, Antoine Pitrou, Philippe Rivière, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribué sous licence GNU/GPL. *
* Pour plus de détails voir le fichier COPYING.txt ou l'aide en ligne. *
\***************************************************************************/
/**
* Gestion de l'itérateur SQL
*
* @package SPIP\Core\Iterateur\SQL
**/
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
use Iterator;
/** /**
* Itérateur SQL * Itérateur SQL.
* *
* Permet d'itérer sur des données en base de données * Permet d'itérer sur des données en base de données
*/ */
class IterateurSQL implements Iterator { class Sql extends AbstractIterateur implements Iterator
{
/** /**
* Ressource sql * Calcul du total des elements.
* *
* @var Object|bool * @var null|int
*/
public $total;
/**
* Ressource sql.
*
* @var bool|object
*/ */
protected $sqlresult = false; protected $sqlresult = false;
/** /**
* row sql courante * row sql courante.
* *
* @var array|null * @var null|array
*/ */
protected $row = null; protected $row;
protected bool $firstseek = false; protected bool $firstseek = false;
...@@ -55,57 +46,18 @@ class IterateurSQL implements Iterator { ...@@ -55,57 +46,18 @@ class IterateurSQL implements Iterator {
/** Erreur presente ? **/ /** Erreur presente ? **/
public bool $err = false; public bool $err = false;
/**
* Calcul du total des elements
*
* @var int|null
**/
public $total = null;
/**
* selectionner les donnees, ie faire la requete SQL
*
* @return void
*/
protected function select() {
$this->row = null;
$v = &$this->command;
$this->sqlresult = calculer_select(
$v['select'],
$v['from'],
$v['type'],
$v['where'],
$v['join'],
$v['groupby'],
$v['orderby'],
$v['limit'],
$v['having'],
$v['table'],
$v['id'],
$v['connect'],
$this->info
);
$this->err = !$this->sqlresult;
$this->firstseek = false;
$this->pos = -1;
// pas d'init a priori, le calcul ne sera fait qu'en cas de besoin (provoque une double requete souvent inutile en sqlite)
//$this->total = $this->count();
}
/* /*
* array command: les commandes d'initialisation * array command: les commandes d'initialisation
* array info: les infos sur le squelette * array info: les infos sur le squelette
*/ */
public function __construct($command, $info = []) { public function __construct($command, $info = []) {
$this->type = 'SQL'; parent::__construct($command, $info);
$this->command = $command;
$this->info = $info;
$this->select(); $this->select();
} }
/** /**
* Rembobiner * Rembobiner.
* *
* @return bool * @return bool
*/ */
...@@ -116,9 +68,7 @@ class IterateurSQL implements Iterator { ...@@ -116,9 +68,7 @@ class IterateurSQL implements Iterator {
} }
/** /**
* Verifier l'etat de l'iterateur * Verifier l'etat de l'iterateur.
*
* @return bool
*/ */
public function valid(): bool { public function valid(): bool {
if ($this->err) { if ($this->err) {
...@@ -132,7 +82,7 @@ class IterateurSQL implements Iterator { ...@@ -132,7 +82,7 @@ class IterateurSQL implements Iterator {
} }
/** /**
* Valeurs sur la position courante * Valeurs sur la position courante.
* *
* @return array * @return array
*/ */
...@@ -147,10 +97,11 @@ class IterateurSQL implements Iterator { ...@@ -147,10 +97,11 @@ class IterateurSQL implements Iterator {
} }
/** /**
* Sauter a une position absolue * Sauter a une position absolue.
* *
* @param int $n * @param int $n
* @param null|string $continue * @param null|string $continue
*
* @return bool * @return bool
*/ */
public function seek($n = 0, $continue = null) { public function seek($n = 0, $continue = null) {
...@@ -174,20 +125,18 @@ class IterateurSQL implements Iterator { ...@@ -174,20 +125,18 @@ class IterateurSQL implements Iterator {
} }
/** /**
* Avancer d'un cran * Avancer d'un cran.
*
* @return void
*/ */
public function next(): void { public function next(): void {
$this->row = sql_fetch($this->sqlresult, $this->command['connect']); $this->row = sql_fetch($this->sqlresult, $this->command['connect']);
$this->pos++; ++$this->pos;
$this->firstseek |= true; $this->firstseek |= true;
} }
/** /**
* Avancer et retourner les donnees pour le nouvel element * Avancer et retourner les donnees pour le nouvel element.
* *
* @return array|bool|null * @return null|array|bool
*/ */
public function fetch() { public function fetch() {
if ($this->valid()) { if ($this->valid()) {
...@@ -201,7 +150,7 @@ class IterateurSQL implements Iterator { ...@@ -201,7 +150,7 @@ class IterateurSQL implements Iterator {
} }
/** /**
* liberer les ressources * liberer les ressources.
* *
* @return bool * @return bool
*/ */
...@@ -216,7 +165,7 @@ class IterateurSQL implements Iterator { ...@@ -216,7 +165,7 @@ class IterateurSQL implements Iterator {
} }
/** /**
* Compter le nombre de resultats * Compter le nombre de resultats.
* *
* @return int * @return int
*/ */
...@@ -225,7 +174,7 @@ class IterateurSQL implements Iterator { ...@@ -225,7 +174,7 @@ class IterateurSQL implements Iterator {
if (!$this->sqlresult) { if (!$this->sqlresult) {
$this->total = 0; $this->total = 0;
} else { } else {
# cas count(*) // cas count(*)
if (in_array('count(*)', $this->command['select'])) { if (in_array('count(*)', $this->command['select'])) {
$this->valid(); $this->valid();
$s = $this->current(); $s = $this->current();
...@@ -238,4 +187,33 @@ class IterateurSQL implements Iterator { ...@@ -238,4 +187,33 @@ class IterateurSQL implements Iterator {
return $this->total; return $this->total;
} }
/**
* selectionner les donnees, ie faire la requete SQL.
*/
protected function select() {
$this->row = null;
$v = &$this->command;
$this->sqlresult = calculer_select(
$v['select'],
$v['from'],
$v['type'],
$v['where'],
$v['join'],
$v['groupby'],
$v['orderby'],
$v['limit'],
$v['having'],
$v['table'],
$v['id'],
$v['connect'],
$this->info
);
$this->err = !$this->sqlresult;
$this->firstseek = false;
$this->pos = -1;
// pas d'init a priori, le calcul ne sera fait qu'en cas de besoin (provoque une double requete souvent inutile en sqlite)
//$this->total = $this->count();
}
} }
<?php
namespace Spip\Css\Vars;
/**
* Collection de variables CSS
* @internal
*/
class Collection {
private array $vars = [];
public function add(string $var, string $value) {
$this->vars[$var] = $value;
}
public function getString(): string {
$string = '';
foreach ($this->vars as $key => $value) {
$string .= "$key: $value;\n";
}
return $string;
}
public function __toString(): string {
return $this->getString();
}
}
<?php
namespace Spip\I18n;
class Description {
/** @var string code de langue (hors module) */
public $code;
/** @var string nom du module de langue */
public $module;
/** @var string langue de la traduction */
public $langue;
/** @var string traduction */
public $texte;
/** @var string var mode particulier appliqué ? */
public $mode;
/** @var bool Corrections des textes appliqué ? */
public $corrections = false;
}
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter