Completed
Push — master ( babdec...a304d7 )
by cam
01:10
created
ecrire/src/Compilateur/Iterateur/Data.php 1 patch
Indentation   +492 added lines, -492 removed lines patch added patch discarded remove patch
@@ -12,500 +12,500 @@
 block discarded – undo
12 12
  */
13 13
 class Data extends AbstractIterateur implements Iterator
14 14
 {
15
-	/** Tableau de données */
16
-	protected array $tableau = [];
17
-
18
-	/**
19
-	 * Conditions de filtrage
20
-	 * ie criteres de selection
21
-	 */
22
-	protected array $filtre = [];
23
-
24
-	/**
25
-	 * Cle courante
26
-	 *
27
-	 * @var scalar
28
-	 */
29
-	protected $cle = null;
30
-
31
-	/**
32
-	 * Valeur courante
33
-	 *
34
-	 * @var mixed
35
-	 */
36
-	protected $valeur = null;
37
-
38
-	/**
39
-	 * Constructeur
40
-	 *
41
-	 * @param  $command
42
-	 * @param array $info
43
-	 */
44
-	public function __construct(array $command, array $info = []) {
45
-		include_spip('iterateur/data');
46
-		$this->type = 'DATA';
47
-		$this->command = $command;
48
-		$this->info = $info;
49
-		$this->select($command);
50
-	}
51
-
52
-	/**
53
-	 * Revenir au depart
54
-	 *
55
-	 * @return void
56
-	 */
57
-	public function rewind(): void {
58
-		reset($this->tableau);
59
-		$this->cle = array_key_first($this->tableau);
60
-		$this->valeur = current($this->tableau);
61
-		next($this->tableau);
62
-	}
63
-
64
-	/**
65
-	 * Déclarer les critères exceptions
66
-	 *
67
-	 * @return array
68
-	 */
69
-	public function exception_des_criteres() {
70
-		return ['tableau'];
71
-	}
72
-
73
-	/**
74
-	 * Récupérer depuis le cache si possible
75
-	 *
76
-	 * @param string $cle
77
-	 * @return mixed
78
-	 */
79
-	protected function cache_get($cle) {
80
-		if (!$cle) {
81
-			return;
82
-		}
83
-		# utiliser memoization si dispo
84
-		if (!function_exists('cache_get')) {
85
-			return;
86
-		}
87
-
88
-		return cache_get($cle);
89
-	}
90
-
91
-	/**
92
-	 * Stocker en cache si possible
93
-	 *
94
-	 * @param string $cle
95
-	 * @param int $ttl
96
-	 * @param null|mixed $valeur
97
-	 * @return bool
98
-	 */
99
-	protected function cache_set($cle, $ttl, $valeur = null) {
100
-		if (!$cle) {
101
-			return;
102
-		}
103
-		if (is_null($valeur)) {
104
-			$valeur = $this->tableau;
105
-		}
106
-		# utiliser memoization si dispo
107
-		if (!function_exists('cache_set')) {
108
-			return;
109
-		}
110
-
111
-		return cache_set(
112
-			$cle,
113
-			[
114
-				'data' => $valeur,
115
-				'time' => time(),
116
-				'ttl' => $ttl
117
-			],
118
-			3600 + $ttl
119
-		);
120
-		# conserver le cache 1h de plus que la validite demandee,
121
-		# pour le cas ou le serveur distant ne reponde plus
122
-	}
123
-
124
-	/**
125
-	 * Aller chercher les données de la boucle DATA
126
-	 *
127
-	 * @throws Exception
128
-	 * @param array $command
129
-	 * @return void
130
-	 */
131
-	protected function select($command) {
132
-
133
-		// l'iterateur DATA peut etre appele en passant (data:type)
134
-		// le type se retrouve dans la commande 'from'
135
-		// dans ce cas la le critere {source}, si present, n'a pas besoin du 1er argument
136
-		if (isset($this->command['from'][0])) {
137
-			if (isset($this->command['source']) and is_array($this->command['source'])) {
138
-				array_unshift($this->command['source'], $this->command['sourcemode']);
139
-			}
140
-			$this->command['sourcemode'] = $this->command['from'][0];
141
-		}
142
-
143
-		// cherchons differents moyens de creer le tableau de donnees
144
-		// les commandes connues pour l'iterateur DATA
145
-		// sont : {tableau #ARRAY} ; {cle=...} ; {valeur=...}
146
-
147
-		// {source format, [URL], [arg2]...}
148
-		if (
149
-			isset($this->command['source'])
150
-			and isset($this->command['sourcemode'])
151
-		) {
152
-			$this->select_source();
153
-		}
154
-
155
-		// Critere {liste X1, X2, X3}
156
-		if (isset($this->command['liste'])) {
157
-			$this->select_liste();
158
-		}
159
-		if (isset($this->command['enum'])) {
160
-			$this->select_enum();
161
-		}
162
-
163
-		// Si a ce stade on n'a pas de table, il y a un bug
164
-		if (!is_array($this->tableau)) {
165
-			$this->err = true;
166
-			spip_log('erreur datasource ' . var_export($command, true));
167
-		}
168
-
169
-		// {datapath query.results}
170
-		// extraire le chemin "query.results" du tableau de donnees
171
-		if (
172
-			!$this->err
173
-			and isset($this->command['datapath'])
174
-			and is_array($this->command['datapath'])
175
-		) {
176
-			$this->select_datapath();
177
-		}
178
-
179
-		// tri {par x}
180
-		if ($this->command['orderby']) {
181
-			$this->select_orderby();
182
-		}
183
-
184
-		// grouper les resultats {fusion /x/y/z} ;
185
-		if ($this->command['groupby']) {
186
-			$this->select_groupby();
187
-		}
188
-
189
-		$this->rewind();
190
-		#var_dump($this->tableau);
191
-	}
192
-
193
-
194
-	/**
195
-	 * Aller chercher les donnees de la boucle DATA
196
-	 * depuis une source
197
-	 * {source format, [URL], [arg2]...}
198
-	 */
199
-	protected function select_source() {
200
-		# un peu crado : avant de charger le cache il faut charger
201
-		# les class indispensables, sinon PHP ne saura pas gerer
202
-		# l'objet en cache ; cf plugins/icalendar
203
-		# perf : pas de fonction table_to_array ! (table est deja un array)
204
-		if (
205
-			isset($this->command['sourcemode'])
206
-			and !in_array($this->command['sourcemode'], ['table', 'array', 'tableau'])
207
-		) {
208
-			charger_fonction($this->command['sourcemode'] . '_to_array', 'inc', true);
209
-		}
210
-
211
-		# le premier argument peut etre un array, une URL etc.
212
-		$src = $this->command['source'][0] ?? null;
213
-
214
-		# avons-nous un cache dispo ?
215
-		$cle = null;
216
-		if (is_string($src)) {
217
-			$cle = 'datasource_' . md5($this->command['sourcemode'] . ':' . var_export($this->command['source'], true));
218
-		}
219
-
220
-		$cache = $this->cache_get($cle);
221
-		if (isset($this->command['datacache'])) {
222
-			$ttl = intval($this->command['datacache']);
223
-		}
224
-		if (
225
-			$cache
226
-			and ($cache['time'] + ($ttl ?? $cache['ttl'])
227
-				> time())
228
-			and !(_request('var_mode') === 'recalcul'
229
-				and include_spip('inc/autoriser')
230
-				and autoriser('recalcul')
231
-			)
232
-		) {
233
-			$this->tableau = $cache['data'];
234
-		} else {
235
-			try {
236
-				if (
237
-					isset($this->command['sourcemode'])
238
-					and in_array(
239
-						$this->command['sourcemode'],
240
-						['table', 'array', 'tableau']
241
-					)
242
-				) {
243
-					if (
244
-						is_array($a = $src)
245
-						or (is_string($a)
246
-							and $a = str_replace('"', '"', $a) # fragile!
247
-							and is_array($a = @unserialize($a)))
248
-					) {
249
-						$this->tableau = $a;
250
-					}
251
-				} else {
252
-					$data = $src;
253
-					if (is_string($src)) {
254
-						if (tester_url_absolue($src)) {
255
-							include_spip('inc/distant');
256
-							$data = recuperer_url($src, ['taille_max' => _DATA_SOURCE_MAX_SIZE]);
257
-							$data = $data['page'] ?? '';
258
-							if (!$data) {
259
-								throw new Exception('404');
260
-							}
261
-							if (!isset($ttl)) {
262
-								$ttl = 24 * 3600;
263
-							}
264
-						} elseif (@is_dir($src)) {
265
-							$data = $src;
266
-						} elseif (@is_readable($src) && @is_file($src)) {
267
-							$data = spip_file_get_contents($src);
268
-						}
269
-						if (!isset($ttl)) {
270
-							$ttl = 10;
271
-						}
272
-					}
273
-					if (
274
-						!$this->err
275
-						and $data_to_array = charger_fonction($this->command['sourcemode'] . '_to_array', 'inc', true)
276
-					) {
277
-						$args = $this->command['source'];
278
-						$args[0] = $data;
279
-						if (is_array($a = $data_to_array(...$args))) {
280
-							$this->tableau = $a;
281
-						}
282
-					}
283
-				}
284
-
285
-				if (!is_array($this->tableau)) {
286
-					$this->err = true;
287
-				}
288
-
289
-				if (!$this->err and isset($ttl) and $ttl > 0) {
290
-					$this->cache_set($cle, $ttl);
291
-				}
292
-			} catch (Exception $e) {
293
-				$e = $e->getMessage();
294
-				$err = sprintf(
295
-					"[%s, %s] $e",
296
-					$src,
297
-					$this->command['sourcemode']
298
-				);
299
-				erreur_squelette([$err, []]);
300
-				$this->err = true;
301
-			}
302
-		}
303
-
304
-		# en cas d'erreur, utiliser le cache si encore dispo
305
-		if (
306
-			$this->err
307
-			and $cache
308
-		) {
309
-			$this->tableau = $cache['data'];
310
-			$this->err = false;
311
-		}
312
-	}
313
-
314
-
315
-	/**
316
-	 * Retourne un tableau donne depuis un critère liste
317
-	 *
318
-	 * Critère `{liste X1, X2, X3}`
319
-	 *
320
-	 * @see critere_DATA_liste_dist()
321
-	 *
322
-	 **/
323
-	protected function select_liste() {
324
-		# s'il n'y a qu'une valeur dans la liste, sans doute une #BALISE
325
-		if (!isset($this->command['liste'][1])) {
326
-			if (!is_array($this->command['liste'][0])) {
327
-				$this->command['liste'] = explode(',', $this->command['liste'][0]);
328
-			} else {
329
-				$this->command['liste'] = $this->command['liste'][0];
330
-			}
331
-		}
332
-		$this->tableau = $this->command['liste'];
333
-	}
334
-
335
-	/**
336
-	 * Retourne un tableau donne depuis un critere liste
337
-	 * Critere {enum Xmin, Xmax}
338
-	 *
339
-	 **/
340
-	protected function select_enum() {
341
-		# s'il n'y a qu'une valeur dans la liste, sans doute une #BALISE
342
-		if (!isset($this->command['enum'][1])) {
343
-			if (!is_array($this->command['enum'][0])) {
344
-				$this->command['enum'] = explode(',', $this->command['enum'][0]);
345
-			} else {
346
-				$this->command['enum'] = $this->command['enum'][0];
347
-			}
348
-		}
349
-		if ((is_countable($this->command['enum']) ? count($this->command['enum']) : 0) >= 3) {
350
-			$enum = range(
351
-				array_shift($this->command['enum']),
352
-				array_shift($this->command['enum']),
353
-				array_shift($this->command['enum'])
354
-			);
355
-		} else {
356
-			$enum = range(array_shift($this->command['enum']), array_shift($this->command['enum']));
357
-		}
358
-		$this->tableau = $enum;
359
-	}
360
-
361
-
362
-	/**
363
-	 * extraire le chemin "query.results" du tableau de donnees
364
-	 * {datapath query.results}
365
-	 *
366
-	 **/
367
-	protected function select_datapath() {
368
-		$base = reset($this->command['datapath']);
369
-		if (strlen($base = ltrim(trim($base), '/'))) {
370
-			$results = table_valeur($this->tableau, $base);
371
-			if (is_array($results)) {
372
-				$this->tableau = $results;
373
-			} else {
374
-				$this->tableau = [];
375
-				$this->err = true;
376
-				spip_log("datapath '$base' absent");
377
-			}
378
-		}
379
-	}
380
-
381
-	/**
382
-	 * Ordonner les resultats
383
-	 * {par x}
384
-	 *
385
-	 **/
386
-	protected function select_orderby() {
387
-		$sortfunc = '';
388
-		$aleas = 0;
389
-		foreach ($this->command['orderby'] as $tri) {
390
-			// virer le / initial pour les criteres de la forme {par /xx}
391
-			if (preg_match(',^\.?([/\w:_-]+)( DESC)?$,iS', ltrim($tri, '/'), $r)) {
392
-				$r = array_pad($r, 3, null);
393
-
394
-				// tri par cle
395
-				if ($r[1] == 'cle') {
396
-					if (isset($r[2]) and $r[2]) {
397
-						krsort($this->tableau);
398
-					} else {
399
-						ksort($this->tableau);
400
-					}
401
-				} # {par hasard}
402
-				else {
403
-					if ($r[1] == 'hasard') {
404
-						$k = array_keys($this->tableau);
405
-						shuffle($k);
406
-						$v = [];
407
-						foreach ($k as $cle) {
408
-							$v[$cle] = $this->tableau[$cle];
409
-						}
410
-						$this->tableau = $v;
411
-					} else {
412
-						# {par valeur}
413
-						if ($r[1] == 'valeur') {
414
-							$tv = '%s';
415
-						} # {par valeur/xx/yy} ??
416
-						else {
417
-							$tv = 'table_valeur(%s, ' . var_export($r[1], true) . ')';
418
-						}
419
-						$sortfunc .= '
15
+    /** Tableau de données */
16
+    protected array $tableau = [];
17
+
18
+    /**
19
+     * Conditions de filtrage
20
+     * ie criteres de selection
21
+     */
22
+    protected array $filtre = [];
23
+
24
+    /**
25
+     * Cle courante
26
+     *
27
+     * @var scalar
28
+     */
29
+    protected $cle = null;
30
+
31
+    /**
32
+     * Valeur courante
33
+     *
34
+     * @var mixed
35
+     */
36
+    protected $valeur = null;
37
+
38
+    /**
39
+     * Constructeur
40
+     *
41
+     * @param  $command
42
+     * @param array $info
43
+     */
44
+    public function __construct(array $command, array $info = []) {
45
+        include_spip('iterateur/data');
46
+        $this->type = 'DATA';
47
+        $this->command = $command;
48
+        $this->info = $info;
49
+        $this->select($command);
50
+    }
51
+
52
+    /**
53
+     * Revenir au depart
54
+     *
55
+     * @return void
56
+     */
57
+    public function rewind(): void {
58
+        reset($this->tableau);
59
+        $this->cle = array_key_first($this->tableau);
60
+        $this->valeur = current($this->tableau);
61
+        next($this->tableau);
62
+    }
63
+
64
+    /**
65
+     * Déclarer les critères exceptions
66
+     *
67
+     * @return array
68
+     */
69
+    public function exception_des_criteres() {
70
+        return ['tableau'];
71
+    }
72
+
73
+    /**
74
+     * Récupérer depuis le cache si possible
75
+     *
76
+     * @param string $cle
77
+     * @return mixed
78
+     */
79
+    protected function cache_get($cle) {
80
+        if (!$cle) {
81
+            return;
82
+        }
83
+        # utiliser memoization si dispo
84
+        if (!function_exists('cache_get')) {
85
+            return;
86
+        }
87
+
88
+        return cache_get($cle);
89
+    }
90
+
91
+    /**
92
+     * Stocker en cache si possible
93
+     *
94
+     * @param string $cle
95
+     * @param int $ttl
96
+     * @param null|mixed $valeur
97
+     * @return bool
98
+     */
99
+    protected function cache_set($cle, $ttl, $valeur = null) {
100
+        if (!$cle) {
101
+            return;
102
+        }
103
+        if (is_null($valeur)) {
104
+            $valeur = $this->tableau;
105
+        }
106
+        # utiliser memoization si dispo
107
+        if (!function_exists('cache_set')) {
108
+            return;
109
+        }
110
+
111
+        return cache_set(
112
+            $cle,
113
+            [
114
+                'data' => $valeur,
115
+                'time' => time(),
116
+                'ttl' => $ttl
117
+            ],
118
+            3600 + $ttl
119
+        );
120
+        # conserver le cache 1h de plus que la validite demandee,
121
+        # pour le cas ou le serveur distant ne reponde plus
122
+    }
123
+
124
+    /**
125
+     * Aller chercher les données de la boucle DATA
126
+     *
127
+     * @throws Exception
128
+     * @param array $command
129
+     * @return void
130
+     */
131
+    protected function select($command) {
132
+
133
+        // l'iterateur DATA peut etre appele en passant (data:type)
134
+        // le type se retrouve dans la commande 'from'
135
+        // dans ce cas la le critere {source}, si present, n'a pas besoin du 1er argument
136
+        if (isset($this->command['from'][0])) {
137
+            if (isset($this->command['source']) and is_array($this->command['source'])) {
138
+                array_unshift($this->command['source'], $this->command['sourcemode']);
139
+            }
140
+            $this->command['sourcemode'] = $this->command['from'][0];
141
+        }
142
+
143
+        // cherchons differents moyens de creer le tableau de donnees
144
+        // les commandes connues pour l'iterateur DATA
145
+        // sont : {tableau #ARRAY} ; {cle=...} ; {valeur=...}
146
+
147
+        // {source format, [URL], [arg2]...}
148
+        if (
149
+            isset($this->command['source'])
150
+            and isset($this->command['sourcemode'])
151
+        ) {
152
+            $this->select_source();
153
+        }
154
+
155
+        // Critere {liste X1, X2, X3}
156
+        if (isset($this->command['liste'])) {
157
+            $this->select_liste();
158
+        }
159
+        if (isset($this->command['enum'])) {
160
+            $this->select_enum();
161
+        }
162
+
163
+        // Si a ce stade on n'a pas de table, il y a un bug
164
+        if (!is_array($this->tableau)) {
165
+            $this->err = true;
166
+            spip_log('erreur datasource ' . var_export($command, true));
167
+        }
168
+
169
+        // {datapath query.results}
170
+        // extraire le chemin "query.results" du tableau de donnees
171
+        if (
172
+            !$this->err
173
+            and isset($this->command['datapath'])
174
+            and is_array($this->command['datapath'])
175
+        ) {
176
+            $this->select_datapath();
177
+        }
178
+
179
+        // tri {par x}
180
+        if ($this->command['orderby']) {
181
+            $this->select_orderby();
182
+        }
183
+
184
+        // grouper les resultats {fusion /x/y/z} ;
185
+        if ($this->command['groupby']) {
186
+            $this->select_groupby();
187
+        }
188
+
189
+        $this->rewind();
190
+        #var_dump($this->tableau);
191
+    }
192
+
193
+
194
+    /**
195
+     * Aller chercher les donnees de la boucle DATA
196
+     * depuis une source
197
+     * {source format, [URL], [arg2]...}
198
+     */
199
+    protected function select_source() {
200
+        # un peu crado : avant de charger le cache il faut charger
201
+        # les class indispensables, sinon PHP ne saura pas gerer
202
+        # l'objet en cache ; cf plugins/icalendar
203
+        # perf : pas de fonction table_to_array ! (table est deja un array)
204
+        if (
205
+            isset($this->command['sourcemode'])
206
+            and !in_array($this->command['sourcemode'], ['table', 'array', 'tableau'])
207
+        ) {
208
+            charger_fonction($this->command['sourcemode'] . '_to_array', 'inc', true);
209
+        }
210
+
211
+        # le premier argument peut etre un array, une URL etc.
212
+        $src = $this->command['source'][0] ?? null;
213
+
214
+        # avons-nous un cache dispo ?
215
+        $cle = null;
216
+        if (is_string($src)) {
217
+            $cle = 'datasource_' . md5($this->command['sourcemode'] . ':' . var_export($this->command['source'], true));
218
+        }
219
+
220
+        $cache = $this->cache_get($cle);
221
+        if (isset($this->command['datacache'])) {
222
+            $ttl = intval($this->command['datacache']);
223
+        }
224
+        if (
225
+            $cache
226
+            and ($cache['time'] + ($ttl ?? $cache['ttl'])
227
+                > time())
228
+            and !(_request('var_mode') === 'recalcul'
229
+                and include_spip('inc/autoriser')
230
+                and autoriser('recalcul')
231
+            )
232
+        ) {
233
+            $this->tableau = $cache['data'];
234
+        } else {
235
+            try {
236
+                if (
237
+                    isset($this->command['sourcemode'])
238
+                    and in_array(
239
+                        $this->command['sourcemode'],
240
+                        ['table', 'array', 'tableau']
241
+                    )
242
+                ) {
243
+                    if (
244
+                        is_array($a = $src)
245
+                        or (is_string($a)
246
+                            and $a = str_replace('"', '"', $a) # fragile!
247
+                            and is_array($a = @unserialize($a)))
248
+                    ) {
249
+                        $this->tableau = $a;
250
+                    }
251
+                } else {
252
+                    $data = $src;
253
+                    if (is_string($src)) {
254
+                        if (tester_url_absolue($src)) {
255
+                            include_spip('inc/distant');
256
+                            $data = recuperer_url($src, ['taille_max' => _DATA_SOURCE_MAX_SIZE]);
257
+                            $data = $data['page'] ?? '';
258
+                            if (!$data) {
259
+                                throw new Exception('404');
260
+                            }
261
+                            if (!isset($ttl)) {
262
+                                $ttl = 24 * 3600;
263
+                            }
264
+                        } elseif (@is_dir($src)) {
265
+                            $data = $src;
266
+                        } elseif (@is_readable($src) && @is_file($src)) {
267
+                            $data = spip_file_get_contents($src);
268
+                        }
269
+                        if (!isset($ttl)) {
270
+                            $ttl = 10;
271
+                        }
272
+                    }
273
+                    if (
274
+                        !$this->err
275
+                        and $data_to_array = charger_fonction($this->command['sourcemode'] . '_to_array', 'inc', true)
276
+                    ) {
277
+                        $args = $this->command['source'];
278
+                        $args[0] = $data;
279
+                        if (is_array($a = $data_to_array(...$args))) {
280
+                            $this->tableau = $a;
281
+                        }
282
+                    }
283
+                }
284
+
285
+                if (!is_array($this->tableau)) {
286
+                    $this->err = true;
287
+                }
288
+
289
+                if (!$this->err and isset($ttl) and $ttl > 0) {
290
+                    $this->cache_set($cle, $ttl);
291
+                }
292
+            } catch (Exception $e) {
293
+                $e = $e->getMessage();
294
+                $err = sprintf(
295
+                    "[%s, %s] $e",
296
+                    $src,
297
+                    $this->command['sourcemode']
298
+                );
299
+                erreur_squelette([$err, []]);
300
+                $this->err = true;
301
+            }
302
+        }
303
+
304
+        # en cas d'erreur, utiliser le cache si encore dispo
305
+        if (
306
+            $this->err
307
+            and $cache
308
+        ) {
309
+            $this->tableau = $cache['data'];
310
+            $this->err = false;
311
+        }
312
+    }
313
+
314
+
315
+    /**
316
+     * Retourne un tableau donne depuis un critère liste
317
+     *
318
+     * Critère `{liste X1, X2, X3}`
319
+     *
320
+     * @see critere_DATA_liste_dist()
321
+     *
322
+     **/
323
+    protected function select_liste() {
324
+        # s'il n'y a qu'une valeur dans la liste, sans doute une #BALISE
325
+        if (!isset($this->command['liste'][1])) {
326
+            if (!is_array($this->command['liste'][0])) {
327
+                $this->command['liste'] = explode(',', $this->command['liste'][0]);
328
+            } else {
329
+                $this->command['liste'] = $this->command['liste'][0];
330
+            }
331
+        }
332
+        $this->tableau = $this->command['liste'];
333
+    }
334
+
335
+    /**
336
+     * Retourne un tableau donne depuis un critere liste
337
+     * Critere {enum Xmin, Xmax}
338
+     *
339
+     **/
340
+    protected function select_enum() {
341
+        # s'il n'y a qu'une valeur dans la liste, sans doute une #BALISE
342
+        if (!isset($this->command['enum'][1])) {
343
+            if (!is_array($this->command['enum'][0])) {
344
+                $this->command['enum'] = explode(',', $this->command['enum'][0]);
345
+            } else {
346
+                $this->command['enum'] = $this->command['enum'][0];
347
+            }
348
+        }
349
+        if ((is_countable($this->command['enum']) ? count($this->command['enum']) : 0) >= 3) {
350
+            $enum = range(
351
+                array_shift($this->command['enum']),
352
+                array_shift($this->command['enum']),
353
+                array_shift($this->command['enum'])
354
+            );
355
+        } else {
356
+            $enum = range(array_shift($this->command['enum']), array_shift($this->command['enum']));
357
+        }
358
+        $this->tableau = $enum;
359
+    }
360
+
361
+
362
+    /**
363
+     * extraire le chemin "query.results" du tableau de donnees
364
+     * {datapath query.results}
365
+     *
366
+     **/
367
+    protected function select_datapath() {
368
+        $base = reset($this->command['datapath']);
369
+        if (strlen($base = ltrim(trim($base), '/'))) {
370
+            $results = table_valeur($this->tableau, $base);
371
+            if (is_array($results)) {
372
+                $this->tableau = $results;
373
+            } else {
374
+                $this->tableau = [];
375
+                $this->err = true;
376
+                spip_log("datapath '$base' absent");
377
+            }
378
+        }
379
+    }
380
+
381
+    /**
382
+     * Ordonner les resultats
383
+     * {par x}
384
+     *
385
+     **/
386
+    protected function select_orderby() {
387
+        $sortfunc = '';
388
+        $aleas = 0;
389
+        foreach ($this->command['orderby'] as $tri) {
390
+            // virer le / initial pour les criteres de la forme {par /xx}
391
+            if (preg_match(',^\.?([/\w:_-]+)( DESC)?$,iS', ltrim($tri, '/'), $r)) {
392
+                $r = array_pad($r, 3, null);
393
+
394
+                // tri par cle
395
+                if ($r[1] == 'cle') {
396
+                    if (isset($r[2]) and $r[2]) {
397
+                        krsort($this->tableau);
398
+                    } else {
399
+                        ksort($this->tableau);
400
+                    }
401
+                } # {par hasard}
402
+                else {
403
+                    if ($r[1] == 'hasard') {
404
+                        $k = array_keys($this->tableau);
405
+                        shuffle($k);
406
+                        $v = [];
407
+                        foreach ($k as $cle) {
408
+                            $v[$cle] = $this->tableau[$cle];
409
+                        }
410
+                        $this->tableau = $v;
411
+                    } else {
412
+                        # {par valeur}
413
+                        if ($r[1] == 'valeur') {
414
+                            $tv = '%s';
415
+                        } # {par valeur/xx/yy} ??
416
+                        else {
417
+                            $tv = 'table_valeur(%s, ' . var_export($r[1], true) . ')';
418
+                        }
419
+                        $sortfunc .= '
420 420
 					$a = ' . sprintf($tv, '$aa') . ';
421 421
 					$b = ' . sprintf($tv, '$bb') . ';
422 422
 					if ($a <> $b)
423 423
 						return ($a ' . (!empty($r[2]) ? '>' : '<') . ' $b) ? -1 : 1;';
424
-					}
425
-				}
426
-			}
427
-		}
428
-
429
-		if ($sortfunc) {
430
-			$sortfunc .= "\n return 0;";
431
-			uasort($this->tableau, fn($aa, $bb) => eval($sortfunc));
432
-		}
433
-	}
434
-
435
-
436
-	/**
437
-	 * Grouper les resultats
438
-	 * {fusion /x/y/z}
439
-	 *
440
-	 **/
441
-	protected function select_groupby() {
442
-		// virer le / initial pour les criteres de la forme {fusion /xx}
443
-		if (strlen($fusion = ltrim($this->command['groupby'][0], '/'))) {
444
-			$vu = [];
445
-			foreach ($this->tableau as $k => $v) {
446
-				$val = table_valeur($v, $fusion);
447
-				if (isset($vu[$val])) {
448
-					unset($this->tableau[$k]);
449
-				} else {
450
-					$vu[$val] = true;
451
-				}
452
-			}
453
-		}
454
-	}
455
-
456
-
457
-	/**
458
-	 * L'iterateur est-il encore valide ?
459
-	 *
460
-	 * @return bool
461
-	 */
462
-	public function valid(): bool {
463
-		return !is_null($this->cle);
464
-	}
465
-
466
-	/**
467
-	 * Retourner la valeur
468
-	 *
469
-	 * @return mixed
470
-	 */
471
-	#[\ReturnTypeWillChange]
472
-	public function current() {
473
-		return $this->valeur;
474
-	}
475
-
476
-	/**
477
-	 * Retourner la cle
478
-	 *
479
-	 * @return mixed
480
-	 */
481
-	#[\ReturnTypeWillChange]
482
-	public function key() {
483
-		return $this->cle;
484
-	}
485
-
486
-	/**
487
-	 * Passer a la valeur suivante
488
-	 *
489
-	 * @return void
490
-	 */
491
-	public function next(): void {
492
-		if ($this->valid()) {
493
-			$this->cle = key($this->tableau);
494
-			$this->valeur = current($this->tableau);
495
-			next($this->tableau);
496
-		}
497
-	}
498
-
499
-	/**
500
-	 * Compter le nombre total de resultats
501
-	 *
502
-	 * @return int
503
-	 */
504
-	public function count() {
505
-		if (is_null($this->total)) {
506
-			$this->total = count($this->tableau);
507
-		}
508
-
509
-		return $this->total;
510
-	}
424
+                    }
425
+                }
426
+            }
427
+        }
428
+
429
+        if ($sortfunc) {
430
+            $sortfunc .= "\n return 0;";
431
+            uasort($this->tableau, fn($aa, $bb) => eval($sortfunc));
432
+        }
433
+    }
434
+
435
+
436
+    /**
437
+     * Grouper les resultats
438
+     * {fusion /x/y/z}
439
+     *
440
+     **/
441
+    protected function select_groupby() {
442
+        // virer le / initial pour les criteres de la forme {fusion /xx}
443
+        if (strlen($fusion = ltrim($this->command['groupby'][0], '/'))) {
444
+            $vu = [];
445
+            foreach ($this->tableau as $k => $v) {
446
+                $val = table_valeur($v, $fusion);
447
+                if (isset($vu[$val])) {
448
+                    unset($this->tableau[$k]);
449
+                } else {
450
+                    $vu[$val] = true;
451
+                }
452
+            }
453
+        }
454
+    }
455
+
456
+
457
+    /**
458
+     * L'iterateur est-il encore valide ?
459
+     *
460
+     * @return bool
461
+     */
462
+    public function valid(): bool {
463
+        return !is_null($this->cle);
464
+    }
465
+
466
+    /**
467
+     * Retourner la valeur
468
+     *
469
+     * @return mixed
470
+     */
471
+    #[\ReturnTypeWillChange]
472
+    public function current() {
473
+        return $this->valeur;
474
+    }
475
+
476
+    /**
477
+     * Retourner la cle
478
+     *
479
+     * @return mixed
480
+     */
481
+    #[\ReturnTypeWillChange]
482
+    public function key() {
483
+        return $this->cle;
484
+    }
485
+
486
+    /**
487
+     * Passer a la valeur suivante
488
+     *
489
+     * @return void
490
+     */
491
+    public function next(): void {
492
+        if ($this->valid()) {
493
+            $this->cle = key($this->tableau);
494
+            $this->valeur = current($this->tableau);
495
+            next($this->tableau);
496
+        }
497
+    }
498
+
499
+    /**
500
+     * Compter le nombre total de resultats
501
+     *
502
+     * @return int
503
+     */
504
+    public function count() {
505
+        if (is_null($this->total)) {
506
+            $this->total = count($this->tableau);
507
+        }
508
+
509
+        return $this->total;
510
+    }
511 511
 }
Please login to merge, or discard this patch.