Completed
Push — master ( 07a5e0...4d844b )
by cam
04:10
created
ecrire/public/iterateur.php 2 patches
Indentation   +564 added lines, -564 removed lines patch added patch discarded remove patch
@@ -12,7 +12,7 @@  discard block
 block discarded – undo
12 12
 \***************************************************************************/
13 13
 
14 14
 if (!defined('_ECRIRE_INC_VERSION')) {
15
-	return;
15
+    return;
16 16
 }
17 17
 
18 18
 /**
@@ -22,578 +22,578 @@  discard block
 block discarded – undo
22 22
  *
23 23
  */
24 24
 class IterFactory {
25
-	public static function create($iterateur, $command, $info = null) {
26
-
27
-		// cas des SI {si expression} analises tres tot
28
-		// pour eviter le chargement de tout iterateur
29
-		if (isset($command['si'])) {
30
-			foreach ($command['si'] as $si) {
31
-				if (!$si) {
32
-					// $command pour boucle SQL peut generer des erreurs de compilation
33
-					// s'il est transmis alors qu'on est dans un iterateur vide
34
-					return new IterDecorator(new EmptyIterator(), array(), $info);
35
-				}
36
-			}
37
-		}
38
-
39
-		// chercher un iterateur PHP existant (par exemple dans SPL)
40
-		// (il faudrait passer l'argument ->sql_serveur
41
-		// pour etre certain qu'on est sur un "php:")
42
-		if (class_exists($iterateur)) {
43
-			$a = isset($command['args']) ? $command['args'] : array();
44
-
45
-			// permettre de passer un Iterateur directement {args #ITERATEUR} :
46
-			// si on recoit deja un iterateur en argument, on l'utilise
47
-			if (count($a) == 1 and is_object($a[0]) and is_subclass_of($a[0], 'Iterator')) {
48
-				$iter = $a[0];
49
-
50
-				// sinon, on cree un iterateur du type donne
51
-			} else {
52
-				// arguments de creation de l'iterateur...
53
-				// (pas glop)
54
-				try {
55
-					switch (count($a)) {
56
-						case 0:
57
-							$iter = new $iterateur();
58
-							break;
59
-						case 1:
60
-							$iter = new $iterateur($a[0]);
61
-							break;
62
-						case 2:
63
-							$iter = new $iterateur($a[0], $a[1]);
64
-							break;
65
-						case 3:
66
-							$iter = new $iterateur($a[0], $a[1], $a[2]);
67
-							break;
68
-						case 4:
69
-							$iter = new $iterateur($a[0], $a[1], $a[2], $a[3]);
70
-							break;
71
-					}
72
-				} catch (Exception $e) {
73
-					spip_log("Erreur de chargement de l'iterateur $iterateur");
74
-					spip_log($e->getMessage());
75
-					$iter = new EmptyIterator();
76
-				}
77
-			}
78
-		} else {
79
-			// chercher la classe d'iterateur
80
-			// IterateurXXX
81
-			// definie dans le fichier iterateurs/xxx.php
82
-			$class = "Iterateur" . $iterateur;
83
-			if (!class_exists($class)) {
84
-				if (!include_spip("iterateur/" . strtolower($iterateur))
85
-					or !class_exists($class)
86
-				) {
87
-					die("Iterateur $iterateur non trouvé");
88
-					// si l'iterateur n'existe pas, on se rabat sur le generique
89
-					# $iter = new EmptyIterator();
90
-				}
91
-			}
92
-			$iter = new $class($command, $info);
93
-		}
94
-
95
-		return new IterDecorator($iter, $command, $info);
96
-	}
25
+    public static function create($iterateur, $command, $info = null) {
26
+
27
+        // cas des SI {si expression} analises tres tot
28
+        // pour eviter le chargement de tout iterateur
29
+        if (isset($command['si'])) {
30
+            foreach ($command['si'] as $si) {
31
+                if (!$si) {
32
+                    // $command pour boucle SQL peut generer des erreurs de compilation
33
+                    // s'il est transmis alors qu'on est dans un iterateur vide
34
+                    return new IterDecorator(new EmptyIterator(), array(), $info);
35
+                }
36
+            }
37
+        }
38
+
39
+        // chercher un iterateur PHP existant (par exemple dans SPL)
40
+        // (il faudrait passer l'argument ->sql_serveur
41
+        // pour etre certain qu'on est sur un "php:")
42
+        if (class_exists($iterateur)) {
43
+            $a = isset($command['args']) ? $command['args'] : array();
44
+
45
+            // permettre de passer un Iterateur directement {args #ITERATEUR} :
46
+            // si on recoit deja un iterateur en argument, on l'utilise
47
+            if (count($a) == 1 and is_object($a[0]) and is_subclass_of($a[0], 'Iterator')) {
48
+                $iter = $a[0];
49
+
50
+                // sinon, on cree un iterateur du type donne
51
+            } else {
52
+                // arguments de creation de l'iterateur...
53
+                // (pas glop)
54
+                try {
55
+                    switch (count($a)) {
56
+                        case 0:
57
+                            $iter = new $iterateur();
58
+                            break;
59
+                        case 1:
60
+                            $iter = new $iterateur($a[0]);
61
+                            break;
62
+                        case 2:
63
+                            $iter = new $iterateur($a[0], $a[1]);
64
+                            break;
65
+                        case 3:
66
+                            $iter = new $iterateur($a[0], $a[1], $a[2]);
67
+                            break;
68
+                        case 4:
69
+                            $iter = new $iterateur($a[0], $a[1], $a[2], $a[3]);
70
+                            break;
71
+                    }
72
+                } catch (Exception $e) {
73
+                    spip_log("Erreur de chargement de l'iterateur $iterateur");
74
+                    spip_log($e->getMessage());
75
+                    $iter = new EmptyIterator();
76
+                }
77
+            }
78
+        } else {
79
+            // chercher la classe d'iterateur
80
+            // IterateurXXX
81
+            // definie dans le fichier iterateurs/xxx.php
82
+            $class = "Iterateur" . $iterateur;
83
+            if (!class_exists($class)) {
84
+                if (!include_spip("iterateur/" . strtolower($iterateur))
85
+                    or !class_exists($class)
86
+                ) {
87
+                    die("Iterateur $iterateur non trouvé");
88
+                    // si l'iterateur n'existe pas, on se rabat sur le generique
89
+                    # $iter = new EmptyIterator();
90
+                }
91
+            }
92
+            $iter = new $class($command, $info);
93
+        }
94
+
95
+        return new IterDecorator($iter, $command, $info);
96
+    }
97 97
 }
98 98
 
99 99
 
100 100
 class IterDecorator extends FilterIterator {
101
-	private $iter;
102
-
103
-	/**
104
-	 * Conditions de filtrage
105
-	 * ie criteres de selection
106
-	 *
107
-	 * @var array
108
-	 */
109
-	protected $filtre = array();
110
-
111
-	/**
112
-	 * Fonction de filtrage compilee a partir des criteres de filtre
113
-	 *
114
-	 * @var string
115
-	 */
116
-	protected $func_filtre = null;
117
-
118
-	/**
119
-	 * Critere {offset, limit}
120
-	 *
121
-	 * @var int
122
-	 * @var int
123
-	 */
124
-	protected $offset = null;
125
-	protected $limit = null;
126
-
127
-	/**
128
-	 * nombre d'elements recuperes depuis la position 0,
129
-	 * en tenant compte des filtres
130
-	 *
131
-	 * @var int
132
-	 */
133
-	protected $fetched = 0;
134
-
135
-	/**
136
-	 * Y a t'il une erreur ?
137
-	 *
138
-	 * @var bool
139
-	 **/
140
-	protected $err = false;
141
-
142
-	/**
143
-	 * Drapeau a activer en cas d'echec
144
-	 * (select SQL errone, non chargement des DATA, etc)
145
-	 */
146
-	public function err() {
147
-		if (method_exists($this->iter, 'err')) {
148
-			return $this->iter->err();
149
-		}
150
-		if (property_exists($this->iter, 'err')) {
151
-			return $this->iter->err;
152
-		}
153
-
154
-		return false;
155
-	}
156
-
157
-	public function __construct(Iterator $iter, $command, $info) {
158
-		parent::__construct($iter);
159
-		parent::rewind(); // remettre a la premiere position (bug? connu de FilterIterator)
160
-
161
-		// recuperer l'iterateur transmis
162
-		$this->iter = $this->getInnerIterator();
163
-		$this->command = $command;
164
-		$this->info = $info;
165
-		$this->pos = 0;
166
-		$this->fetched = 0;
167
-
168
-		// chercher la liste des champs a retourner par
169
-		// fetch si l'objet ne les calcule pas tout seul
170
-		if (!method_exists($this->iter, 'fetch')) {
171
-			$this->calculer_select();
172
-			$this->calculer_filtres();
173
-		}
174
-
175
-		// emptyIterator critere {si} faux n'a pas d'erreur !
176
-		if (isset($this->iter->err)) {
177
-			$this->err = $this->iter->err;
178
-		}
179
-
180
-		// pas d'init a priori, le calcul ne sera fait qu'en cas de besoin (provoque une double requete souvent inutile en sqlite)
181
-		//$this->total = $this->count();
182
-	}
183
-
184
-
185
-	// calcule les elements a retournes par fetch()
186
-	// enleve les elements inutiles du select()
187
-	// 
188
-	private function calculer_select() {
189
-		if ($select = &$this->command['select']) {
190
-			foreach ($select as $s) {
191
-				// /!\ $s = '.nom'
192
-				if ($s[0] == '.') {
193
-					$s = substr($s, 1);
194
-				}
195
-				$this->select[] = $s;
196
-			}
197
-		}
198
-	}
199
-
200
-	// recuperer la valeur d'une balise #X
201
-	// en fonction des methodes 
202
-	// et proprietes disponibles
203
-	public function get_select($nom) {
204
-		if (is_object($this->iter)
205
-			and method_exists($this->iter, $nom)
206
-		) {
207
-			try {
208
-				return $this->iter->$nom();
209
-			} catch (Exception $e) {
210
-				// #GETCHILDREN sur un fichier de DirectoryIterator ...
211
-				spip_log("Methode $nom en echec sur " . get_class($this->iter));
212
-				spip_log("Cela peut être normal : retour d'une ligne de resultat ne pouvant pas calculer cette methode");
213
-
214
-				return '';
215
-			}
216
-		}
217
-		/*
101
+    private $iter;
102
+
103
+    /**
104
+     * Conditions de filtrage
105
+     * ie criteres de selection
106
+     *
107
+     * @var array
108
+     */
109
+    protected $filtre = array();
110
+
111
+    /**
112
+     * Fonction de filtrage compilee a partir des criteres de filtre
113
+     *
114
+     * @var string
115
+     */
116
+    protected $func_filtre = null;
117
+
118
+    /**
119
+     * Critere {offset, limit}
120
+     *
121
+     * @var int
122
+     * @var int
123
+     */
124
+    protected $offset = null;
125
+    protected $limit = null;
126
+
127
+    /**
128
+     * nombre d'elements recuperes depuis la position 0,
129
+     * en tenant compte des filtres
130
+     *
131
+     * @var int
132
+     */
133
+    protected $fetched = 0;
134
+
135
+    /**
136
+     * Y a t'il une erreur ?
137
+     *
138
+     * @var bool
139
+     **/
140
+    protected $err = false;
141
+
142
+    /**
143
+     * Drapeau a activer en cas d'echec
144
+     * (select SQL errone, non chargement des DATA, etc)
145
+     */
146
+    public function err() {
147
+        if (method_exists($this->iter, 'err')) {
148
+            return $this->iter->err();
149
+        }
150
+        if (property_exists($this->iter, 'err')) {
151
+            return $this->iter->err;
152
+        }
153
+
154
+        return false;
155
+    }
156
+
157
+    public function __construct(Iterator $iter, $command, $info) {
158
+        parent::__construct($iter);
159
+        parent::rewind(); // remettre a la premiere position (bug? connu de FilterIterator)
160
+
161
+        // recuperer l'iterateur transmis
162
+        $this->iter = $this->getInnerIterator();
163
+        $this->command = $command;
164
+        $this->info = $info;
165
+        $this->pos = 0;
166
+        $this->fetched = 0;
167
+
168
+        // chercher la liste des champs a retourner par
169
+        // fetch si l'objet ne les calcule pas tout seul
170
+        if (!method_exists($this->iter, 'fetch')) {
171
+            $this->calculer_select();
172
+            $this->calculer_filtres();
173
+        }
174
+
175
+        // emptyIterator critere {si} faux n'a pas d'erreur !
176
+        if (isset($this->iter->err)) {
177
+            $this->err = $this->iter->err;
178
+        }
179
+
180
+        // pas d'init a priori, le calcul ne sera fait qu'en cas de besoin (provoque une double requete souvent inutile en sqlite)
181
+        //$this->total = $this->count();
182
+    }
183
+
184
+
185
+    // calcule les elements a retournes par fetch()
186
+    // enleve les elements inutiles du select()
187
+    // 
188
+    private function calculer_select() {
189
+        if ($select = &$this->command['select']) {
190
+            foreach ($select as $s) {
191
+                // /!\ $s = '.nom'
192
+                if ($s[0] == '.') {
193
+                    $s = substr($s, 1);
194
+                }
195
+                $this->select[] = $s;
196
+            }
197
+        }
198
+    }
199
+
200
+    // recuperer la valeur d'une balise #X
201
+    // en fonction des methodes 
202
+    // et proprietes disponibles
203
+    public function get_select($nom) {
204
+        if (is_object($this->iter)
205
+            and method_exists($this->iter, $nom)
206
+        ) {
207
+            try {
208
+                return $this->iter->$nom();
209
+            } catch (Exception $e) {
210
+                // #GETCHILDREN sur un fichier de DirectoryIterator ...
211
+                spip_log("Methode $nom en echec sur " . get_class($this->iter));
212
+                spip_log("Cela peut être normal : retour d'une ligne de resultat ne pouvant pas calculer cette methode");
213
+
214
+                return '';
215
+            }
216
+        }
217
+        /*
218 218
 		if (property_exists($this->iter, $nom)) {
219 219
 			return $this->iter->$nom;
220 220
 		}*/
221
-		// cle et valeur par defaut
222
-		// ICI PLANTAGE SI ON NE CONTROLE PAS $nom
223
-		if (in_array($nom, array('cle', 'valeur'))
224
-			and method_exists($this, $nom)
225
-		) {
226
-			return $this->$nom();
227
-		}
228
-
229
-		// Par defaut chercher en xpath dans la valeur()
230
-		return table_valeur($this->valeur(), $nom, null);
231
-	}
232
-
233
-
234
-	private function calculer_filtres() {
235
-
236
-		// Issu de calculer_select() de public/composer L.519
237
-		// TODO: externaliser...
238
-		//
239
-		// retirer les criteres vides:
240
-		// {X ?} avec X absent de l'URL
241
-		// {par #ENV{X}} avec X absent de l'URL
242
-		// IN sur collection vide (ce dernier devrait pouvoir etre fait a la compil)
243
-		if ($where = &$this->command['where']) {
244
-			foreach ($where as $k => $v) {
245
-				if (is_array($v)) {
246
-					if ((count($v) >= 2) && ($v[0] == 'REGEXP') && ($v[2] == "'.*'")) {
247
-						$op = false;
248
-					} elseif ((count($v) >= 2) && ($v[0] == 'LIKE') && ($v[2] == "'%'")) {
249
-						$op = false;
250
-					} else {
251
-						$op = $v[0] ? $v[0] : $v;
252
-					}
253
-				} else {
254
-					$op = $v;
255
-				}
256
-				if ((!$op) or ($op == 1) or ($op == '0=0')) {
257
-					unset($where[$k]);
258
-				}
259
-				// traiter {cle IN a,b} ou {valeur !IN a,b}
260
-				if (preg_match(',^\(([\w/]+)(\s+NOT)?\s+IN\s+(\(.*\))\)$,', $op, $regs)) {
261
-					$this->ajouter_filtre($regs[1], 'IN', $regs[3], $regs[2]);
262
-					unset($op, $where[$k]);
263
-				}
264
-			}
265
-			foreach ($where as $k => $v) {
266
-				// 3 possibilites : count($v) =
267
-				// * 1 : {x y} ; on recoit $v[0] = y
268
-				// * 2 : {x !op y} ; on recoit $v[0] = 'NOT', $v[1] = array() // array du type {x op y}
269
-				// * 3 : {x op y} ; on recoit $v[0] = 'op', $v[1] = x, $v[2] = y
270
-
271
-				// 1 : forcement traite par un critere, on passe
272
-				if (count($v) == 1) {
273
-					continue;
274
-				}
275
-				if (count($v) == 2 and is_array($v[1])) {
276
-					$this->ajouter_filtre($v[1][1], $v[1][0], $v[1][2], 'NOT');
277
-				}
278
-				if (count($v) == 3) {
279
-					$this->ajouter_filtre($v[1], $v[0], $v[2]);
280
-				}
281
-			}
282
-		}
283
-
284
-		// critere {2,7}
285
-		if (isset($this->command['limit']) and $this->command['limit']) {
286
-			$limit = explode(',', $this->command['limit']);
287
-			$this->offset = $limit[0];
288
-			$this->limit = $limit[1];
289
-		}
290
-
291
-		// Creer la fonction de filtrage sur $this
292
-		if ($this->filtre) {
293
-			$filtres = 'return (' . join(') AND (', $this->filtre) . ');';
294
-			$this->func_filtre = function () use ($filtres) {
295
-				return eval($filtres);
296
-			};
297
-		}
298
-	}
299
-
300
-
301
-	protected function ajouter_filtre($cle, $op, $valeur, $not = false) {
302
-		if (method_exists($this->iter, 'exception_des_criteres')) {
303
-			if (in_array($cle, $this->iter->exception_des_criteres())) {
304
-				return;
305
-			}
306
-		}
307
-		// TODO: analyser le filtre pour refuser ce qu'on ne sait pas traiter ?
308
-		# mais c'est normalement deja opere par calculer_critere_infixe()
309
-		# qui regarde la description 'desc' (en casse reelle d'ailleurs : {isDir=1}
310
-		# ne sera pas vu si l'on a defini desc['field']['isdir'] pour que #ISDIR soit present.
311
-		# il faudrait peut etre definir les 2 champs isDir et isdir... a reflechir...
312
-
313
-		# if (!in_array($cle, array('cle', 'valeur')))
314
-		#	return;
315
-
316
-		$a = '$this->get_select(\'' . $cle . '\')';
317
-
318
-		$filtre = '';
319
-
320
-		if ($op == 'REGEXP') {
321
-			$filtre = 'match(' . $a . ', ' . str_replace('\"', '"', $valeur) . ')';
322
-			$op = '';
323
-		} else {
324
-			if ($op == 'LIKE') {
325
-				$valeur = str_replace(array('\"', '_', '%'), array('"', '.', '.*'), preg_quote($valeur));
326
-				$filtre = 'match(' . $a . ', ' . $valeur . ')';
327
-				$op = '';
328
-			} else {
329
-				if ($op == '=') {
330
-					$op = '==';
331
-				} else {
332
-					if ($op == 'IN') {
333
-						$filtre = 'in_array(' . $a . ', array' . $valeur . ')';
334
-						$op = '';
335
-					} else {
336
-						if (!in_array($op, array('<', '<=', '>', '>='))) {
337
-							spip_log('operateur non reconnu ' . $op); // [todo] mettre une erreur de squelette
338
-							$op = '';
339
-						}
340
-					}
341
-				}
342
-			}
343
-		}
344
-
345
-		if ($op) {
346
-			$filtre = $a . $op . str_replace('\"', '"', $valeur);
347
-		}
348
-
349
-		if ($not) {
350
-			$filtre = "!($filtre)";
351
-		}
352
-
353
-		if ($filtre) {
354
-			$this->filtre[] = $filtre;
355
-		}
356
-	}
357
-
358
-
359
-	public function next() {
360
-		$this->pos++;
361
-		parent::next();
362
-	}
363
-
364
-	/**
365
-	 * revient au depart
366
-	 *
367
-	 * @return void
368
-	 */
369
-	public function rewind() {
370
-		$this->pos = 0;
371
-		$this->fetched = 0;
372
-		parent::rewind();
373
-	}
374
-
375
-
376
-	# Extension SPIP des iterateurs PHP
377
-	/**
378
-	 * type de l'iterateur
379
-	 *
380
-	 * @var string
381
-	 */
382
-	protected $type;
383
-
384
-	/**
385
-	 * parametres de l'iterateur
386
-	 *
387
-	 * @var array
388
-	 */
389
-	protected $command;
390
-
391
-	/**
392
-	 * infos de compilateur
393
-	 *
394
-	 * @var array
395
-	 */
396
-	protected $info;
397
-
398
-	/**
399
-	 * position courante de l'iterateur
400
-	 *
401
-	 * @var int
402
-	 */
403
-	protected $pos = null;
404
-
405
-	/**
406
-	 * nombre total resultats dans l'iterateur
407
-	 *
408
-	 * @var int
409
-	 */
410
-	protected $total = null;
411
-
412
-	/**
413
-	 * nombre maximal de recherche pour $total
414
-	 * si l'iterateur n'implemente pas de fonction specifique
415
-	 */
416
-	protected $max = 100000;
417
-
418
-
419
-	/**
420
-	 * Liste des champs a inserer dans les $row
421
-	 * retournes par ->fetch()
422
-	 */
423
-	protected $select = array();
424
-
425
-
426
-	/**
427
-	 * aller a la position absolue n,
428
-	 * comptee depuis le debut
429
-	 *
430
-	 * @param int $n
431
-	 *   absolute pos
432
-	 * @param string $continue
433
-	 *   param for sql_ api
434
-	 * @return bool
435
-	 *   success or fail if not implemented
436
-	 */
437
-	public function seek($n = 0, $continue = null) {
438
-		if ($this->func_filtre or !method_exists($this->iter, 'seek') or !$this->iter->seek($n)) {
439
-			$this->seek_loop($n);
440
-		}
441
-		$this->pos = $n;
442
-		$this->fetched = $n;
443
-
444
-		return true;
445
-	}
446
-
447
-	/*
221
+        // cle et valeur par defaut
222
+        // ICI PLANTAGE SI ON NE CONTROLE PAS $nom
223
+        if (in_array($nom, array('cle', 'valeur'))
224
+            and method_exists($this, $nom)
225
+        ) {
226
+            return $this->$nom();
227
+        }
228
+
229
+        // Par defaut chercher en xpath dans la valeur()
230
+        return table_valeur($this->valeur(), $nom, null);
231
+    }
232
+
233
+
234
+    private function calculer_filtres() {
235
+
236
+        // Issu de calculer_select() de public/composer L.519
237
+        // TODO: externaliser...
238
+        //
239
+        // retirer les criteres vides:
240
+        // {X ?} avec X absent de l'URL
241
+        // {par #ENV{X}} avec X absent de l'URL
242
+        // IN sur collection vide (ce dernier devrait pouvoir etre fait a la compil)
243
+        if ($where = &$this->command['where']) {
244
+            foreach ($where as $k => $v) {
245
+                if (is_array($v)) {
246
+                    if ((count($v) >= 2) && ($v[0] == 'REGEXP') && ($v[2] == "'.*'")) {
247
+                        $op = false;
248
+                    } elseif ((count($v) >= 2) && ($v[0] == 'LIKE') && ($v[2] == "'%'")) {
249
+                        $op = false;
250
+                    } else {
251
+                        $op = $v[0] ? $v[0] : $v;
252
+                    }
253
+                } else {
254
+                    $op = $v;
255
+                }
256
+                if ((!$op) or ($op == 1) or ($op == '0=0')) {
257
+                    unset($where[$k]);
258
+                }
259
+                // traiter {cle IN a,b} ou {valeur !IN a,b}
260
+                if (preg_match(',^\(([\w/]+)(\s+NOT)?\s+IN\s+(\(.*\))\)$,', $op, $regs)) {
261
+                    $this->ajouter_filtre($regs[1], 'IN', $regs[3], $regs[2]);
262
+                    unset($op, $where[$k]);
263
+                }
264
+            }
265
+            foreach ($where as $k => $v) {
266
+                // 3 possibilites : count($v) =
267
+                // * 1 : {x y} ; on recoit $v[0] = y
268
+                // * 2 : {x !op y} ; on recoit $v[0] = 'NOT', $v[1] = array() // array du type {x op y}
269
+                // * 3 : {x op y} ; on recoit $v[0] = 'op', $v[1] = x, $v[2] = y
270
+
271
+                // 1 : forcement traite par un critere, on passe
272
+                if (count($v) == 1) {
273
+                    continue;
274
+                }
275
+                if (count($v) == 2 and is_array($v[1])) {
276
+                    $this->ajouter_filtre($v[1][1], $v[1][0], $v[1][2], 'NOT');
277
+                }
278
+                if (count($v) == 3) {
279
+                    $this->ajouter_filtre($v[1], $v[0], $v[2]);
280
+                }
281
+            }
282
+        }
283
+
284
+        // critere {2,7}
285
+        if (isset($this->command['limit']) and $this->command['limit']) {
286
+            $limit = explode(',', $this->command['limit']);
287
+            $this->offset = $limit[0];
288
+            $this->limit = $limit[1];
289
+        }
290
+
291
+        // Creer la fonction de filtrage sur $this
292
+        if ($this->filtre) {
293
+            $filtres = 'return (' . join(') AND (', $this->filtre) . ');';
294
+            $this->func_filtre = function () use ($filtres) {
295
+                return eval($filtres);
296
+            };
297
+        }
298
+    }
299
+
300
+
301
+    protected function ajouter_filtre($cle, $op, $valeur, $not = false) {
302
+        if (method_exists($this->iter, 'exception_des_criteres')) {
303
+            if (in_array($cle, $this->iter->exception_des_criteres())) {
304
+                return;
305
+            }
306
+        }
307
+        // TODO: analyser le filtre pour refuser ce qu'on ne sait pas traiter ?
308
+        # mais c'est normalement deja opere par calculer_critere_infixe()
309
+        # qui regarde la description 'desc' (en casse reelle d'ailleurs : {isDir=1}
310
+        # ne sera pas vu si l'on a defini desc['field']['isdir'] pour que #ISDIR soit present.
311
+        # il faudrait peut etre definir les 2 champs isDir et isdir... a reflechir...
312
+
313
+        # if (!in_array($cle, array('cle', 'valeur')))
314
+        #	return;
315
+
316
+        $a = '$this->get_select(\'' . $cle . '\')';
317
+
318
+        $filtre = '';
319
+
320
+        if ($op == 'REGEXP') {
321
+            $filtre = 'match(' . $a . ', ' . str_replace('\"', '"', $valeur) . ')';
322
+            $op = '';
323
+        } else {
324
+            if ($op == 'LIKE') {
325
+                $valeur = str_replace(array('\"', '_', '%'), array('"', '.', '.*'), preg_quote($valeur));
326
+                $filtre = 'match(' . $a . ', ' . $valeur . ')';
327
+                $op = '';
328
+            } else {
329
+                if ($op == '=') {
330
+                    $op = '==';
331
+                } else {
332
+                    if ($op == 'IN') {
333
+                        $filtre = 'in_array(' . $a . ', array' . $valeur . ')';
334
+                        $op = '';
335
+                    } else {
336
+                        if (!in_array($op, array('<', '<=', '>', '>='))) {
337
+                            spip_log('operateur non reconnu ' . $op); // [todo] mettre une erreur de squelette
338
+                            $op = '';
339
+                        }
340
+                    }
341
+                }
342
+            }
343
+        }
344
+
345
+        if ($op) {
346
+            $filtre = $a . $op . str_replace('\"', '"', $valeur);
347
+        }
348
+
349
+        if ($not) {
350
+            $filtre = "!($filtre)";
351
+        }
352
+
353
+        if ($filtre) {
354
+            $this->filtre[] = $filtre;
355
+        }
356
+    }
357
+
358
+
359
+    public function next() {
360
+        $this->pos++;
361
+        parent::next();
362
+    }
363
+
364
+    /**
365
+     * revient au depart
366
+     *
367
+     * @return void
368
+     */
369
+    public function rewind() {
370
+        $this->pos = 0;
371
+        $this->fetched = 0;
372
+        parent::rewind();
373
+    }
374
+
375
+
376
+    # Extension SPIP des iterateurs PHP
377
+    /**
378
+     * type de l'iterateur
379
+     *
380
+     * @var string
381
+     */
382
+    protected $type;
383
+
384
+    /**
385
+     * parametres de l'iterateur
386
+     *
387
+     * @var array
388
+     */
389
+    protected $command;
390
+
391
+    /**
392
+     * infos de compilateur
393
+     *
394
+     * @var array
395
+     */
396
+    protected $info;
397
+
398
+    /**
399
+     * position courante de l'iterateur
400
+     *
401
+     * @var int
402
+     */
403
+    protected $pos = null;
404
+
405
+    /**
406
+     * nombre total resultats dans l'iterateur
407
+     *
408
+     * @var int
409
+     */
410
+    protected $total = null;
411
+
412
+    /**
413
+     * nombre maximal de recherche pour $total
414
+     * si l'iterateur n'implemente pas de fonction specifique
415
+     */
416
+    protected $max = 100000;
417
+
418
+
419
+    /**
420
+     * Liste des champs a inserer dans les $row
421
+     * retournes par ->fetch()
422
+     */
423
+    protected $select = array();
424
+
425
+
426
+    /**
427
+     * aller a la position absolue n,
428
+     * comptee depuis le debut
429
+     *
430
+     * @param int $n
431
+     *   absolute pos
432
+     * @param string $continue
433
+     *   param for sql_ api
434
+     * @return bool
435
+     *   success or fail if not implemented
436
+     */
437
+    public function seek($n = 0, $continue = null) {
438
+        if ($this->func_filtre or !method_exists($this->iter, 'seek') or !$this->iter->seek($n)) {
439
+            $this->seek_loop($n);
440
+        }
441
+        $this->pos = $n;
442
+        $this->fetched = $n;
443
+
444
+        return true;
445
+    }
446
+
447
+    /*
448 448
 	 * aller a la position $n en parcourant
449 449
 	 * un par un tous les elements
450 450
 	 */
451
-	private function seek_loop($n) {
452
-		if ($this->pos > $n) {
453
-			$this->rewind();
454
-		}
455
-
456
-		while ($this->pos < $n and $this->valid()) {
457
-			$this->next();
458
-		}
459
-
460
-		return true;
461
-	}
462
-
463
-	/**
464
-	 * Avancer de $saut pas
465
-	 *
466
-	 * @param  $saut
467
-	 * @param  $max
468
-	 * @return int
469
-	 */
470
-	public function skip($saut, $max = null) {
471
-		// pas de saut en arriere autorise pour cette fonction
472
-		if (($saut = intval($saut)) <= 0) {
473
-			return $this->pos;
474
-		}
475
-		$seek = $this->pos + $saut;
476
-		// si le saut fait depasser le maxi, on libere la resource
477
-		// et on sort
478
-		if (is_null($max)) {
479
-			$max = $this->count();
480
-		}
481
-
482
-		if ($seek >= $max or $seek >= $this->count()) {
483
-			// sortie plus rapide que de faire next() jusqu'a la fin !
484
-			$this->free();
485
-
486
-			return $max;
487
-		}
488
-
489
-		$this->seek($seek);
490
-
491
-		return $this->pos;
492
-	}
493
-
494
-	/**
495
-	 * Renvoyer un tableau des donnees correspondantes
496
-	 * a la position courante de l'iterateur
497
-	 * en controlant si on respecte le filtre
498
-	 * Appliquer aussi le critere {offset,limit}
499
-	 *
500
-	 * @return array|bool
501
-	 */
502
-	public function fetch() {
503
-		if (method_exists($this->iter, 'fetch')) {
504
-			return $this->iter->fetch();
505
-		} else {
506
-
507
-			while ($this->valid()
508
-				and (
509
-					!$this->accept()
510
-					or (isset($this->offset) and $this->fetched++ < $this->offset)
511
-				)) {
512
-				$this->next();
513
-			}
514
-
515
-			if (!$this->valid()) {
516
-				return false;
517
-			}
518
-
519
-			if (isset($this->limit)
520
-				and $this->fetched > $this->offset + $this->limit
521
-			) {
522
-				return false;
523
-			}
524
-
525
-			$r = array();
526
-			foreach ($this->select as $nom) {
527
-				$r[$nom] = $this->get_select($nom);
528
-			}
529
-			$this->next();
530
-
531
-			return $r;
532
-		}
533
-	}
534
-
535
-	// retourner la cle pour #CLE
536
-	public function cle() {
537
-		return $this->key();
538
-	}
539
-
540
-	// retourner la valeur pour #VALEUR
541
-	public function valeur() {
542
-		return $this->current();
543
-	}
544
-
545
-	/**
546
-	 * Accepte-t-on l'entree courante lue ?
547
-	 * On execute les filtres pour le savoir.
548
-	 **/
549
-	public function accept() {
550
-		if ($f = $this->func_filtre) {
551
-			return $f();
552
-		}
553
-
554
-		return true;
555
-	}
556
-
557
-	/**
558
-	 * liberer la ressource
559
-	 *
560
-	 * @return bool
561
-	 */
562
-	public function free() {
563
-		if (method_exists($this->iter, 'free')) {
564
-			$this->iter->free();
565
-		}
566
-		$this->pos = $this->total = 0;
567
-
568
-		return true;
569
-	}
570
-
571
-	/**
572
-	 * Compter le nombre total de resultats
573
-	 * pour #TOTAL_BOUCLE
574
-	 *
575
-	 * @return int
576
-	 */
577
-	public function count() {
578
-		if (is_null($this->total)) {
579
-			if (method_exists($this->iter, 'count')
580
-				and !$this->func_filtre
581
-			) {
582
-				return $this->total = $this->iter->count();
583
-			} else {
584
-				// compter les lignes et rembobiner
585
-				$total = 0;
586
-				$pos = $this->pos; // sauver la position
587
-				$this->rewind();
588
-				while ($this->fetch() and $total < $this->max) {
589
-					$total++;
590
-				}
591
-				$this->seek($pos);
592
-				$this->total = $total;
593
-			}
594
-		}
595
-
596
-		return $this->total;
597
-	}
451
+    private function seek_loop($n) {
452
+        if ($this->pos > $n) {
453
+            $this->rewind();
454
+        }
455
+
456
+        while ($this->pos < $n and $this->valid()) {
457
+            $this->next();
458
+        }
459
+
460
+        return true;
461
+    }
462
+
463
+    /**
464
+     * Avancer de $saut pas
465
+     *
466
+     * @param  $saut
467
+     * @param  $max
468
+     * @return int
469
+     */
470
+    public function skip($saut, $max = null) {
471
+        // pas de saut en arriere autorise pour cette fonction
472
+        if (($saut = intval($saut)) <= 0) {
473
+            return $this->pos;
474
+        }
475
+        $seek = $this->pos + $saut;
476
+        // si le saut fait depasser le maxi, on libere la resource
477
+        // et on sort
478
+        if (is_null($max)) {
479
+            $max = $this->count();
480
+        }
481
+
482
+        if ($seek >= $max or $seek >= $this->count()) {
483
+            // sortie plus rapide que de faire next() jusqu'a la fin !
484
+            $this->free();
485
+
486
+            return $max;
487
+        }
488
+
489
+        $this->seek($seek);
490
+
491
+        return $this->pos;
492
+    }
493
+
494
+    /**
495
+     * Renvoyer un tableau des donnees correspondantes
496
+     * a la position courante de l'iterateur
497
+     * en controlant si on respecte le filtre
498
+     * Appliquer aussi le critere {offset,limit}
499
+     *
500
+     * @return array|bool
501
+     */
502
+    public function fetch() {
503
+        if (method_exists($this->iter, 'fetch')) {
504
+            return $this->iter->fetch();
505
+        } else {
506
+
507
+            while ($this->valid()
508
+                and (
509
+                    !$this->accept()
510
+                    or (isset($this->offset) and $this->fetched++ < $this->offset)
511
+                )) {
512
+                $this->next();
513
+            }
514
+
515
+            if (!$this->valid()) {
516
+                return false;
517
+            }
518
+
519
+            if (isset($this->limit)
520
+                and $this->fetched > $this->offset + $this->limit
521
+            ) {
522
+                return false;
523
+            }
524
+
525
+            $r = array();
526
+            foreach ($this->select as $nom) {
527
+                $r[$nom] = $this->get_select($nom);
528
+            }
529
+            $this->next();
530
+
531
+            return $r;
532
+        }
533
+    }
534
+
535
+    // retourner la cle pour #CLE
536
+    public function cle() {
537
+        return $this->key();
538
+    }
539
+
540
+    // retourner la valeur pour #VALEUR
541
+    public function valeur() {
542
+        return $this->current();
543
+    }
544
+
545
+    /**
546
+     * Accepte-t-on l'entree courante lue ?
547
+     * On execute les filtres pour le savoir.
548
+     **/
549
+    public function accept() {
550
+        if ($f = $this->func_filtre) {
551
+            return $f();
552
+        }
553
+
554
+        return true;
555
+    }
556
+
557
+    /**
558
+     * liberer la ressource
559
+     *
560
+     * @return bool
561
+     */
562
+    public function free() {
563
+        if (method_exists($this->iter, 'free')) {
564
+            $this->iter->free();
565
+        }
566
+        $this->pos = $this->total = 0;
567
+
568
+        return true;
569
+    }
570
+
571
+    /**
572
+     * Compter le nombre total de resultats
573
+     * pour #TOTAL_BOUCLE
574
+     *
575
+     * @return int
576
+     */
577
+    public function count() {
578
+        if (is_null($this->total)) {
579
+            if (method_exists($this->iter, 'count')
580
+                and !$this->func_filtre
581
+            ) {
582
+                return $this->total = $this->iter->count();
583
+            } else {
584
+                // compter les lignes et rembobiner
585
+                $total = 0;
586
+                $pos = $this->pos; // sauver la position
587
+                $this->rewind();
588
+                while ($this->fetch() and $total < $this->max) {
589
+                    $total++;
590
+                }
591
+                $this->seek($pos);
592
+                $this->total = $total;
593
+            }
594
+        }
595
+
596
+        return $this->total;
597
+    }
598 598
 
599 599
 }
Please login to merge, or discard this patch.
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -79,9 +79,9 @@  discard block
 block discarded – undo
79 79
 			// chercher la classe d'iterateur
80 80
 			// IterateurXXX
81 81
 			// definie dans le fichier iterateurs/xxx.php
82
-			$class = "Iterateur" . $iterateur;
82
+			$class = "Iterateur".$iterateur;
83 83
 			if (!class_exists($class)) {
84
-				if (!include_spip("iterateur/" . strtolower($iterateur))
84
+				if (!include_spip("iterateur/".strtolower($iterateur))
85 85
 					or !class_exists($class)
86 86
 				) {
87 87
 					die("Iterateur $iterateur non trouv&#233;");
@@ -208,7 +208,7 @@  discard block
 block discarded – undo
208 208
 				return $this->iter->$nom();
209 209
 			} catch (Exception $e) {
210 210
 				// #GETCHILDREN sur un fichier de DirectoryIterator ...
211
-				spip_log("Methode $nom en echec sur " . get_class($this->iter));
211
+				spip_log("Methode $nom en echec sur ".get_class($this->iter));
212 212
 				spip_log("Cela peut être normal : retour d'une ligne de resultat ne pouvant pas calculer cette methode");
213 213
 
214 214
 				return '';
@@ -290,8 +290,8 @@  discard block
 block discarded – undo
290 290
 
291 291
 		// Creer la fonction de filtrage sur $this
292 292
 		if ($this->filtre) {
293
-			$filtres = 'return (' . join(') AND (', $this->filtre) . ');';
294
-			$this->func_filtre = function () use ($filtres) {
293
+			$filtres = 'return ('.join(') AND (', $this->filtre).');';
294
+			$this->func_filtre = function() use ($filtres) {
295 295
 				return eval($filtres);
296 296
 			};
297 297
 		}
@@ -313,28 +313,28 @@  discard block
 block discarded – undo
313 313
 		# if (!in_array($cle, array('cle', 'valeur')))
314 314
 		#	return;
315 315
 
316
-		$a = '$this->get_select(\'' . $cle . '\')';
316
+		$a = '$this->get_select(\''.$cle.'\')';
317 317
 
318 318
 		$filtre = '';
319 319
 
320 320
 		if ($op == 'REGEXP') {
321
-			$filtre = 'match(' . $a . ', ' . str_replace('\"', '"', $valeur) . ')';
321
+			$filtre = 'match('.$a.', '.str_replace('\"', '"', $valeur).')';
322 322
 			$op = '';
323 323
 		} else {
324 324
 			if ($op == 'LIKE') {
325 325
 				$valeur = str_replace(array('\"', '_', '%'), array('"', '.', '.*'), preg_quote($valeur));
326
-				$filtre = 'match(' . $a . ', ' . $valeur . ')';
326
+				$filtre = 'match('.$a.', '.$valeur.')';
327 327
 				$op = '';
328 328
 			} else {
329 329
 				if ($op == '=') {
330 330
 					$op = '==';
331 331
 				} else {
332 332
 					if ($op == 'IN') {
333
-						$filtre = 'in_array(' . $a . ', array' . $valeur . ')';
333
+						$filtre = 'in_array('.$a.', array'.$valeur.')';
334 334
 						$op = '';
335 335
 					} else {
336 336
 						if (!in_array($op, array('<', '<=', '>', '>='))) {
337
-							spip_log('operateur non reconnu ' . $op); // [todo] mettre une erreur de squelette
337
+							spip_log('operateur non reconnu '.$op); // [todo] mettre une erreur de squelette
338 338
 							$op = '';
339 339
 						}
340 340
 					}
@@ -343,7 +343,7 @@  discard block
 block discarded – undo
343 343
 		}
344 344
 
345 345
 		if ($op) {
346
-			$filtre = $a . $op . str_replace('\"', '"', $valeur);
346
+			$filtre = $a.$op.str_replace('\"', '"', $valeur);
347 347
 		}
348 348
 
349 349
 		if ($not) {
Please login to merge, or discard this patch.