[SPIP] v3.2.1-->v3.2.2
[lhc/web/www.git] / www / ecrire / iterateur / sql.php
1 <?php
2
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2019 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
8 * *
9 * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
10 * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
11 \***************************************************************************/
12
13 /**
14 * Gestion de l'itérateur SQL
15 *
16 * @package SPIP\Core\Iterateur\SQL
17 **/
18
19 if (!defined('_ECRIRE_INC_VERSION')) {
20 return;
21 }
22
23
24 /**
25 * Itérateur SQL
26 *
27 * Permet d'itérer sur des données en base de données
28 */
29 class IterateurSQL implements Iterator {
30
31 /**
32 * ressource sql
33 *
34 * @var resource|bool
35 */
36 protected $sqlresult = false;
37
38 /**
39 * row sql courante
40 *
41 * @var array|null
42 */
43 protected $row = null;
44
45 protected $firstseek = false;
46
47 /**
48 * Erreur presente ?
49 *
50 * @var bool
51 **/
52 public $err = false;
53
54 /**
55 * Calcul du total des elements
56 *
57 * @var int|null
58 **/
59 public $total = null;
60
61 /**
62 * selectionner les donnees, ie faire la requete SQL
63 *
64 * @return void
65 */
66 protected function select() {
67 $this->row = null;
68 $v = &$this->command;
69 $this->sqlresult = calculer_select($v['select'], $v['from'], $v['type'], $v['where'], $v['join'], $v['groupby'],
70 $v['orderby'], $v['limit'], $v['having'], $v['table'], $v['id'], $v['connect'], $this->info);
71 $this->err = !$this->sqlresult;
72 $this->firstseek = false;
73 $this->pos = -1;
74
75 // pas d'init a priori, le calcul ne sera fait qu'en cas de besoin (provoque une double requete souvent inutile en sqlite)
76 //$this->total = $this->count();
77 }
78
79 /*
80 * array command: les commandes d'initialisation
81 * array info: les infos sur le squelette
82 */
83 public function __construct($command, $info = array()) {
84 $this->type = 'SQL';
85 $this->command = $command;
86 $this->info = $info;
87 $this->select();
88 }
89
90 /**
91 * Rembobiner
92 *
93 * @return bool
94 */
95 public function rewind() {
96 return ($this->pos > 0)
97 ? $this->seek(0)
98 : true;
99 }
100
101 /**
102 * Verifier l'etat de l'iterateur
103 *
104 * @return bool
105 */
106 public function valid() {
107 if ($this->err) {
108 return false;
109 }
110 if (!$this->firstseek) {
111 $this->next();
112 }
113
114 return is_array($this->row);
115 }
116
117 /**
118 * Valeurs sur la position courante
119 *
120 * @return array
121 */
122 public function current() {
123 return $this->row;
124 }
125
126 public function key() {
127 return $this->pos;
128 }
129
130 /**
131 * Sauter a une position absolue
132 *
133 * @param int $n
134 * @param null|string $continue
135 * @return bool
136 */
137 public function seek($n = 0, $continue = null) {
138 if (!sql_seek($this->sqlresult, $n, $this->command['connect'], $continue)) {
139 // SQLite ne sait pas seek(), il faut relancer la query
140 // si la position courante est apres la position visee
141 // il faut relancer la requete
142 if ($this->pos > $n) {
143 $this->free();
144 $this->select();
145 $this->valid();
146 }
147 // et utiliser la methode par defaut pour se deplacer au bon endroit
148 // (sera fait en cas d'echec de cette fonction)
149 return false;
150 }
151 $this->row = sql_fetch($this->sqlresult, $this->command['connect']);
152 $this->pos = min($n, $this->count());
153
154 return true;
155 }
156
157 /**
158 * Avancer d'un cran
159 *
160 * @return void
161 */
162 public function next() {
163 $this->row = sql_fetch($this->sqlresult, $this->command['connect']);
164 $this->pos++;
165 $this->firstseek |= true;
166 }
167
168 /**
169 * Avancer et retourner les donnees pour le nouvel element
170 *
171 * @return array|bool|null
172 */
173 public function fetch() {
174 if ($this->valid()) {
175 $r = $this->current();
176 $this->next();
177 } else {
178 $r = false;
179 }
180
181 return $r;
182 }
183
184 /**
185 * liberer les ressources
186 *
187 * @return bool
188 */
189 public function free() {
190 if (!$this->sqlresult) {
191 return true;
192 }
193 $a = sql_free($this->sqlresult, $this->command['connect']);
194 $this->sqlresult = null;
195
196 return $a;
197 }
198
199 /**
200 * Compter le nombre de resultats
201 *
202 * @return int
203 */
204 public function count() {
205 if (is_null($this->total)) {
206 if (!$this->sqlresult) {
207 $this->total = 0;
208 } else {
209 # cas count(*)
210 if (in_array('count(*)', $this->command['select'])) {
211 $this->valid();
212 $s = $this->current();
213 $this->total = $s['count(*)'];
214 } else {
215 $this->total = sql_count($this->sqlresult, $this->command['connect']);
216 }
217 }
218 }
219
220 return $this->total;
221 }
222 }