|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
|
|
4
|
|
|
/***************************************************************************\ |
|
5
|
|
|
* SPIP, Systeme de publication pour l'internet * |
|
6
|
|
|
* * |
|
7
|
|
|
* Copyright (c) 2001-2018 * |
|
8
|
|
|
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James * |
|
9
|
|
|
* * |
|
10
|
|
|
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. * |
|
11
|
|
|
* Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. * |
|
12
|
|
|
\***************************************************************************/ |
|
13
|
|
|
|
|
14
|
|
|
if (!defined('_ECRIRE_INC_VERSION')) { |
|
15
|
|
|
return; |
|
16
|
|
|
} |
|
17
|
|
|
|
|
18
|
|
|
/** |
|
19
|
|
|
* Fabrique d'iterateur |
|
20
|
|
|
* permet de charger n'importe quel iterateur IterateurXXX |
|
21
|
|
|
* fourni dans le fichier iterateurs/xxx.php |
|
22
|
|
|
* |
|
23
|
|
|
*/ |
|
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
|
|
View Code Duplication |
case 3: |
|
|
|
|
|
|
66
|
|
|
$iter = new $iterateur($a[0], $a[1], $a[2]); |
|
67
|
|
|
break; |
|
68
|
|
View Code Duplication |
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
|
|
|
} |
|
98
|
|
|
|
|
99
|
|
|
|
|
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
|
|
|
/* |
|
218
|
|
|
if (property_exists($this->iter, $nom)) { |
|
219
|
|
|
return $this->iter->$nom; |
|
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
|
|
View Code Duplication |
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
|
|
|
// prendre en compte le cas particulier de sous-requetes |
|
261
|
|
|
// produites par sql_in quand plus de 255 valeurs passees a IN |
|
262
|
|
|
if (preg_match_all(',\s+IN\s+(\(.*\)),', $op, $s_req)) { |
|
263
|
|
|
$req = ''; |
|
264
|
|
|
foreach ($s_req[1] as $key => $val) { |
|
265
|
|
|
$req .= trim($val, '(,)') . ','; |
|
266
|
|
|
} |
|
267
|
|
|
$req = '(' . rtrim($req, ',') . ')'; |
|
268
|
|
|
} |
|
269
|
|
|
if (preg_match(',^\(\(([\w/]+)(\s+NOT)?\s+IN\s+(\(.*\))\)(?:\s+(AND|OR)\s+\(([\w/]+)(\s+NOT)?\s+IN\s+(\(.*\))\))*\)$,', |
|
270
|
|
|
$op, $regs)) { |
|
271
|
|
|
$this->ajouter_filtre($regs[1], 'IN', strlen($req) ? $req : $regs[3], $regs[2]); |
|
|
|
|
|
|
272
|
|
|
unset($op, $where[$k]); |
|
273
|
|
|
} |
|
274
|
|
|
} |
|
275
|
|
|
foreach ($where as $k => $v) { |
|
276
|
|
|
// 3 possibilites : count($v) = |
|
277
|
|
|
// * 1 : {x y} ; on recoit $v[0] = y |
|
278
|
|
|
// * 2 : {x !op y} ; on recoit $v[0] = 'NOT', $v[1] = array() // array du type {x op y} |
|
279
|
|
|
// * 3 : {x op y} ; on recoit $v[0] = 'op', $v[1] = x, $v[2] = y |
|
280
|
|
|
|
|
281
|
|
|
// 1 : forcement traite par un critere, on passe |
|
282
|
|
|
if (count($v) == 1) { |
|
283
|
|
|
continue; |
|
284
|
|
|
} |
|
285
|
|
|
if (count($v) == 2 and is_array($v[1])) { |
|
286
|
|
|
$this->ajouter_filtre($v[1][1], $v[1][0], $v[1][2], 'NOT'); |
|
287
|
|
|
} |
|
288
|
|
|
if (count($v) == 3) { |
|
289
|
|
|
$this->ajouter_filtre($v[1], $v[0], $v[2]); |
|
290
|
|
|
} |
|
291
|
|
|
} |
|
292
|
|
|
} |
|
293
|
|
|
|
|
294
|
|
|
// critere {2,7} |
|
295
|
|
|
if (isset($this->command['limit']) and $this->command['limit']) { |
|
296
|
|
|
$limit = explode(',', $this->command['limit']); |
|
297
|
|
|
$this->offset = $limit[0]; |
|
298
|
|
|
$this->limit = $limit[1]; |
|
299
|
|
|
} |
|
300
|
|
|
|
|
301
|
|
|
// Creer la fonction de filtrage sur $this |
|
302
|
|
|
if ($this->filtre) { |
|
|
|
|
|
|
303
|
|
|
$filtres = 'return (' . join(') AND (', $this->filtre) . ');'; |
|
304
|
|
|
$this->func_filtre = function () use ($filtres) { |
|
|
|
|
|
|
305
|
|
|
return eval($filtres); |
|
306
|
|
|
}; |
|
307
|
|
|
} |
|
308
|
|
|
} |
|
309
|
|
|
|
|
310
|
|
|
|
|
311
|
|
|
protected function ajouter_filtre($cle, $op, $valeur, $not = false) { |
|
312
|
|
|
if (method_exists($this->iter, 'exception_des_criteres')) { |
|
313
|
|
|
if (in_array($cle, $this->iter->exception_des_criteres())) { |
|
|
|
|
|
|
314
|
|
|
return; |
|
315
|
|
|
} |
|
316
|
|
|
} |
|
317
|
|
|
// TODO: analyser le filtre pour refuser ce qu'on ne sait pas traiter ? |
|
318
|
|
|
# mais c'est normalement deja opere par calculer_critere_infixe() |
|
319
|
|
|
# qui regarde la description 'desc' (en casse reelle d'ailleurs : {isDir=1} |
|
320
|
|
|
# ne sera pas vu si l'on a defini desc['field']['isdir'] pour que #ISDIR soit present. |
|
321
|
|
|
# il faudrait peut etre definir les 2 champs isDir et isdir... a reflechir... |
|
322
|
|
|
|
|
323
|
|
|
# if (!in_array($cle, array('cle', 'valeur'))) |
|
324
|
|
|
# return; |
|
325
|
|
|
|
|
326
|
|
|
$a = '$this->get_select(\'' . $cle . '\')'; |
|
327
|
|
|
|
|
328
|
|
|
$filtre = ''; |
|
329
|
|
|
|
|
330
|
|
|
if ($op == 'REGEXP') { |
|
331
|
|
|
$filtre = 'match(' . $a . ', ' . str_replace('\"', '"', $valeur) . ')'; |
|
332
|
|
|
$op = ''; |
|
333
|
|
|
} else { |
|
334
|
|
|
if ($op == 'LIKE') { |
|
335
|
|
|
$valeur = str_replace(array('\"', '_', '%'), array('"', '.', '.*'), preg_quote($valeur)); |
|
336
|
|
|
$filtre = 'match(' . $a . ', ' . $valeur . ')'; |
|
337
|
|
|
$op = ''; |
|
338
|
|
|
} else { |
|
339
|
|
|
if ($op == '=') { |
|
340
|
|
|
$op = '=='; |
|
341
|
|
|
} else { |
|
342
|
|
|
if ($op == 'IN') { |
|
343
|
|
|
$filtre = 'in_array(' . $a . ', array' . $valeur . ')'; |
|
344
|
|
|
$op = ''; |
|
345
|
|
|
} else { |
|
346
|
|
|
if (!in_array($op, array('<', '<=', '>', '>='))) { |
|
347
|
|
|
spip_log('operateur non reconnu ' . $op); // [todo] mettre une erreur de squelette |
|
348
|
|
|
$op = ''; |
|
349
|
|
|
} |
|
350
|
|
|
} |
|
351
|
|
|
} |
|
352
|
|
|
} |
|
353
|
|
|
} |
|
354
|
|
|
|
|
355
|
|
|
if ($op) { |
|
356
|
|
|
$filtre = $a . $op . str_replace('\"', '"', $valeur); |
|
357
|
|
|
} |
|
358
|
|
|
|
|
359
|
|
|
if ($not) { |
|
360
|
|
|
$filtre = "!($filtre)"; |
|
361
|
|
|
} |
|
362
|
|
|
|
|
363
|
|
|
if ($filtre) { |
|
364
|
|
|
$this->filtre[] = $filtre; |
|
365
|
|
|
} |
|
366
|
|
|
} |
|
367
|
|
|
|
|
368
|
|
|
|
|
369
|
|
|
public function next() { |
|
370
|
|
|
$this->pos++; |
|
371
|
|
|
parent::next(); |
|
372
|
|
|
} |
|
373
|
|
|
|
|
374
|
|
|
/** |
|
375
|
|
|
* revient au depart |
|
376
|
|
|
* |
|
377
|
|
|
* @return void |
|
378
|
|
|
*/ |
|
379
|
|
|
public function rewind() { |
|
380
|
|
|
$this->pos = 0; |
|
381
|
|
|
$this->fetched = 0; |
|
382
|
|
|
parent::rewind(); |
|
383
|
|
|
} |
|
384
|
|
|
|
|
385
|
|
|
|
|
386
|
|
|
# Extension SPIP des iterateurs PHP |
|
387
|
|
|
/** |
|
388
|
|
|
* type de l'iterateur |
|
389
|
|
|
* |
|
390
|
|
|
* @var string |
|
391
|
|
|
*/ |
|
392
|
|
|
protected $type; |
|
393
|
|
|
|
|
394
|
|
|
/** |
|
395
|
|
|
* parametres de l'iterateur |
|
396
|
|
|
* |
|
397
|
|
|
* @var array |
|
398
|
|
|
*/ |
|
399
|
|
|
protected $command; |
|
400
|
|
|
|
|
401
|
|
|
/** |
|
402
|
|
|
* infos de compilateur |
|
403
|
|
|
* |
|
404
|
|
|
* @var array |
|
405
|
|
|
*/ |
|
406
|
|
|
protected $info; |
|
407
|
|
|
|
|
408
|
|
|
/** |
|
409
|
|
|
* position courante de l'iterateur |
|
410
|
|
|
* |
|
411
|
|
|
* @var int |
|
412
|
|
|
*/ |
|
413
|
|
|
protected $pos = null; |
|
414
|
|
|
|
|
415
|
|
|
/** |
|
416
|
|
|
* nombre total resultats dans l'iterateur |
|
417
|
|
|
* |
|
418
|
|
|
* @var int |
|
419
|
|
|
*/ |
|
420
|
|
|
protected $total = null; |
|
421
|
|
|
|
|
422
|
|
|
/** |
|
423
|
|
|
* nombre maximal de recherche pour $total |
|
424
|
|
|
* si l'iterateur n'implemente pas de fonction specifique |
|
425
|
|
|
*/ |
|
426
|
|
|
protected $max = 100000; |
|
427
|
|
|
|
|
428
|
|
|
|
|
429
|
|
|
/** |
|
430
|
|
|
* Liste des champs a inserer dans les $row |
|
431
|
|
|
* retournes par ->fetch() |
|
432
|
|
|
*/ |
|
433
|
|
|
protected $select = array(); |
|
434
|
|
|
|
|
435
|
|
|
|
|
436
|
|
|
/** |
|
437
|
|
|
* aller a la position absolue n, |
|
438
|
|
|
* comptee depuis le debut |
|
439
|
|
|
* |
|
440
|
|
|
* @param int $n |
|
441
|
|
|
* absolute pos |
|
442
|
|
|
* @param string $continue |
|
|
|
|
|
|
443
|
|
|
* param for sql_ api |
|
444
|
|
|
* @return bool |
|
445
|
|
|
* success or fail if not implemented |
|
446
|
|
|
*/ |
|
447
|
|
|
public function seek($n = 0, $continue = null) { |
|
|
|
|
|
|
448
|
|
|
if ($this->func_filtre or !method_exists($this->iter, 'seek') or !$this->iter->seek($n)) { |
|
|
|
|
|
|
449
|
|
|
$this->seek_loop($n); |
|
450
|
|
|
} |
|
451
|
|
|
$this->pos = $n; |
|
452
|
|
|
$this->fetched = $n; |
|
453
|
|
|
|
|
454
|
|
|
return true; |
|
455
|
|
|
} |
|
456
|
|
|
|
|
457
|
|
|
/* |
|
458
|
|
|
* aller a la position $n en parcourant |
|
459
|
|
|
* un par un tous les elements |
|
460
|
|
|
*/ |
|
461
|
|
|
private function seek_loop($n) { |
|
462
|
|
|
if ($this->pos > $n) { |
|
463
|
|
|
$this->rewind(); |
|
464
|
|
|
} |
|
465
|
|
|
|
|
466
|
|
|
while ($this->pos < $n and $this->valid()) { |
|
467
|
|
|
$this->next(); |
|
468
|
|
|
} |
|
469
|
|
|
|
|
470
|
|
|
return true; |
|
471
|
|
|
} |
|
472
|
|
|
|
|
473
|
|
|
/** |
|
474
|
|
|
* Avancer de $saut pas |
|
475
|
|
|
* |
|
476
|
|
|
* @param $saut |
|
477
|
|
|
* @param $max |
|
478
|
|
|
* @return int |
|
479
|
|
|
*/ |
|
480
|
|
|
public function skip($saut, $max = null) { |
|
481
|
|
|
// pas de saut en arriere autorise pour cette fonction |
|
482
|
|
|
if (($saut = intval($saut)) <= 0) { |
|
483
|
|
|
return $this->pos; |
|
484
|
|
|
} |
|
485
|
|
|
$seek = $this->pos + $saut; |
|
486
|
|
|
// si le saut fait depasser le maxi, on libere la resource |
|
487
|
|
|
// et on sort |
|
488
|
|
|
if (is_null($max)) { |
|
489
|
|
|
$max = $this->count(); |
|
490
|
|
|
} |
|
491
|
|
|
|
|
492
|
|
|
if ($seek >= $max or $seek >= $this->count()) { |
|
493
|
|
|
// sortie plus rapide que de faire next() jusqu'a la fin ! |
|
494
|
|
|
$this->free(); |
|
495
|
|
|
|
|
496
|
|
|
return $max; |
|
497
|
|
|
} |
|
498
|
|
|
|
|
499
|
|
|
$this->seek($seek); |
|
500
|
|
|
|
|
501
|
|
|
return $this->pos; |
|
502
|
|
|
} |
|
503
|
|
|
|
|
504
|
|
|
/** |
|
505
|
|
|
* Renvoyer un tableau des donnees correspondantes |
|
506
|
|
|
* a la position courante de l'iterateur |
|
507
|
|
|
* en controlant si on respecte le filtre |
|
508
|
|
|
* Appliquer aussi le critere {offset,limit} |
|
509
|
|
|
* |
|
510
|
|
|
* @return array|bool |
|
511
|
|
|
*/ |
|
512
|
|
|
public function fetch() { |
|
513
|
|
|
if (method_exists($this->iter, 'fetch')) { |
|
514
|
|
|
return $this->iter->fetch(); |
|
|
|
|
|
|
515
|
|
|
} else { |
|
516
|
|
|
|
|
517
|
|
|
while ($this->valid() |
|
518
|
|
|
and ( |
|
519
|
|
|
!$this->accept() |
|
520
|
|
|
or (isset($this->offset) and $this->fetched++ < $this->offset) |
|
521
|
|
|
)) { |
|
522
|
|
|
$this->next(); |
|
523
|
|
|
} |
|
524
|
|
|
|
|
525
|
|
|
if (!$this->valid()) { |
|
526
|
|
|
return false; |
|
527
|
|
|
} |
|
528
|
|
|
|
|
529
|
|
|
if (isset($this->limit) |
|
530
|
|
|
and $this->fetched > $this->offset + $this->limit |
|
531
|
|
|
) { |
|
532
|
|
|
return false; |
|
533
|
|
|
} |
|
534
|
|
|
|
|
535
|
|
|
$r = array(); |
|
536
|
|
|
foreach ($this->select as $nom) { |
|
537
|
|
|
$r[$nom] = $this->get_select($nom); |
|
538
|
|
|
} |
|
539
|
|
|
$this->next(); |
|
540
|
|
|
|
|
541
|
|
|
return $r; |
|
542
|
|
|
} |
|
543
|
|
|
} |
|
544
|
|
|
|
|
545
|
|
|
// retourner la cle pour #CLE |
|
546
|
|
|
public function cle() { |
|
547
|
|
|
return $this->key(); |
|
548
|
|
|
} |
|
549
|
|
|
|
|
550
|
|
|
// retourner la valeur pour #VALEUR |
|
551
|
|
|
public function valeur() { |
|
552
|
|
|
# attention PHP est mechant avec les objets, parfois il ne les |
|
553
|
|
|
# clone pas proprement (directoryiterator sous php 5.2.2) |
|
554
|
|
|
# on se rabat sur la version __toString() |
|
555
|
|
|
if (is_object($v = $this->current())) { |
|
556
|
|
|
if (method_exists($v, '__toString')) { |
|
557
|
|
|
$v = $v->__toString(); |
|
558
|
|
|
} else { |
|
559
|
|
|
$v = (array)$v; |
|
560
|
|
|
} |
|
561
|
|
|
} |
|
562
|
|
|
|
|
563
|
|
|
return $v; |
|
564
|
|
|
} |
|
565
|
|
|
|
|
566
|
|
|
/** |
|
567
|
|
|
* Accepte-t-on l'entree courante lue ? |
|
568
|
|
|
* On execute les filtres pour le savoir. |
|
569
|
|
|
**/ |
|
570
|
|
|
public function accept() { |
|
571
|
|
|
if ($f = $this->func_filtre) { |
|
572
|
|
|
return $f(); |
|
573
|
|
|
} |
|
574
|
|
|
|
|
575
|
|
|
return true; |
|
576
|
|
|
} |
|
577
|
|
|
|
|
578
|
|
|
/** |
|
579
|
|
|
* liberer la ressource |
|
580
|
|
|
* |
|
581
|
|
|
* @return bool |
|
582
|
|
|
*/ |
|
583
|
|
|
public function free() { |
|
584
|
|
|
if (method_exists($this->iter, 'free')) { |
|
585
|
|
|
$this->iter->free(); |
|
|
|
|
|
|
586
|
|
|
} |
|
587
|
|
|
$this->pos = $this->total = 0; |
|
588
|
|
|
|
|
589
|
|
|
return true; |
|
590
|
|
|
} |
|
591
|
|
|
|
|
592
|
|
|
/** |
|
593
|
|
|
* Compter le nombre total de resultats |
|
594
|
|
|
* pour #TOTAL_BOUCLE |
|
595
|
|
|
* |
|
596
|
|
|
* @return int |
|
597
|
|
|
*/ |
|
598
|
|
|
public function count() { |
|
599
|
|
|
if (is_null($this->total)) { |
|
600
|
|
|
if (method_exists($this->iter, 'count') |
|
601
|
|
|
and !$this->func_filtre |
|
602
|
|
|
) { |
|
603
|
|
|
return $this->total = $this->iter->count(); |
|
|
|
|
|
|
604
|
|
|
} else { |
|
605
|
|
|
// compter les lignes et rembobiner |
|
606
|
|
|
$total = 0; |
|
607
|
|
|
$pos = $this->pos; // sauver la position |
|
608
|
|
|
$this->rewind(); |
|
609
|
|
|
while ($this->fetch() and $total < $this->max) { |
|
610
|
|
|
$total++; |
|
611
|
|
|
} |
|
612
|
|
|
$this->seek($pos); |
|
613
|
|
|
$this->total = $total; |
|
614
|
|
|
} |
|
615
|
|
|
} |
|
616
|
|
|
|
|
617
|
|
|
return $this->total; |
|
618
|
|
|
} |
|
619
|
|
|
|
|
620
|
|
|
} |
|
621
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.