Add interface PlIteraface and the corresponding abstract class
[platal.git] / classes / plfilter.php
CommitLineData
285fb262
RB
1<?php
2/***************************************************************************
3 * Copyright (C) 2003-2010 Polytechnique.org *
4 * http://opensource.polytechnique.org/ *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., *
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
20 ***************************************************************************/
21
857a2b96
FB
22__autoload('xdb');
23
0d78a96b 24// {{{ class PlLimit
bd9b36fe
RB
25class PlLimit
26{
27 private $count = null;
28 private $from = null;
29
30 public function __construct($count = null, $from = null)
31 {
32 $this->count = $count;
33 $this->from = $from;
34 }
35
36 public function getSql()
37 {
4aa4899b 38 if (!is_null($this->count) && $this->count != 0) {
bd9b36fe
RB
39 if (!is_null($this->from) && $this->from != 0) {
40 return XDB::format('LIMIT {?}, {?}', (int)$this->from, (int)$this->count);
41 } else {
42 return XDB::format('LIMIT {?}', (int)$this->count);
43 }
44 }
45 return '';
46 }
47}
0d78a96b 48// }}}
bd9b36fe 49
0d78a96b 50// {{{ class PlFilterOrder
7c44b8bc
RB
51/** Base class for ordering results of a query.
52 * Parameters for the ordering must be given to the constructor ($desc for a
53 * descending order).
54 * The getSortTokens function is used to get actual ordering part of the query.
55 */
f66f26e2
RB
56abstract class PlFilterOrder
57{
58 protected $desc = false;
59 public function __construct($desc = false)
60 {
61 $this->desc = $desc;
7c44b8bc 62 $this->_tokens = null;
f66f26e2
RB
63 }
64
65 public function toggleDesc()
66 {
067a59f4 67 $this->desc = !$this->desc;
f66f26e2
RB
68 }
69
70 public function setDescending($desc = true)
71 {
72 $this->desc = $desc;
73 }
74
75 public function buildSort(PlFilter &$pf)
76 {
77 $sel = $this->getSortTokens($pf);
7c44b8bc 78 $this->_tokens = $sel;
f66f26e2
RB
79 if (!is_array($sel)) {
80 $sel = array($sel);
81 }
82 if ($this->desc) {
83 foreach ($sel as $k => $s) {
84 $sel[$k] = $s . ' DESC';
85 }
86 }
87 return $sel;
88 }
89
7c44b8bc
RB
90 /** This function must return the tokens to use for ordering
91 * @param &$pf The PlFilter whose results must be ordered
92 * @return The name of the field to use for ordering results
93 */
0d78a96b 94 abstract protected function getSortTokens(PlFilter &$pf);
f66f26e2 95}
0d78a96b
RB
96// }}}
97
7c44b8bc
RB
98// {{{ class PlFilterGroupableOrder
99/** Extension of a PlFilterOrder, for orders where the value on which ordering
100 * is done could be used for grouping results (promo, country, ...)
101 */
85bb0c6f 102abstract class PlFilterGroupableOrder extends PlFilterOrder
7c44b8bc
RB
103{
104 /** This function will be called when trying to retrieve groups;
105 * the returned token will be used to group the values.
106 * It will always be called AFTER getSortTokens().
107 */
108 public function getGroupToken(PlFilter &$pf)
109 {
110 return $this->_tokens;
111 }
112}
113// }}}
114
0d78a96b
RB
115// {{{ class PFO_Random
116class PFO_Random extends PlFilterOrder
117{
118 private $seed = null;
119
120 public function __construct($seed = null, $desc = false)
121 {
122 parent::__construct($desc);
123 $this->seed = $seed;
124 }
125
126 protected function getSortTokens(PlFilter &$pf)
127 {
128 if ($this->seed == null) {
129 return 'RAND()';
130 } else {
131 return XDB::format('RAND({?})', $this->seed);
132 }
133 }
134}
135// }}}
f66f26e2
RB
136
137// {{{ interface PlFilterCondition
138interface PlFilterCondition
139{
140 const COND_TRUE = 'TRUE';
141 const COND_FALSE = 'FALSE';
142
143 public function buildCondition(PlFilter &$pf);
144}
145// }}}
146
147// {{{ class PFC_OneChild
148abstract class PFC_OneChild implements PlFilterCondition
149{
150 protected $child;
151
152 public function __construct(&$child = null)
153 {
154 if (!is_null($child) && ($child instanceof PlFilterCondition)) {
155 $this->setChild($child);
156 }
157 }
158
159 public function setChild(PlFilterCondition &$cond)
160 {
161 $this->child =& $cond;
162 }
163}
164// }}}
165
166// {{{ class PFC_NChildren
167abstract class PFC_NChildren implements PlFilterCondition
168{
169 protected $children = array();
170
171 public function __construct()
172 {
bf0ebb51
FB
173 $this->addChildren(pl_flatten(func_get_args()));
174 }
175
176 public function addChildren(array $conds)
177 {
178 foreach ($conds as &$cond) {
179 if (!is_null($cond) && ($cond instanceof PlFilterCondition)) {
180 $this->addChild($cond);
f66f26e2
RB
181 }
182 }
183 }
184
185 public function addChild(PlFilterCondition &$cond)
186 {
187 $this->children[] =& $cond;
188 }
189
190 protected function catConds(array $cond, $op, $fallback)
191 {
192 if (count($cond) == 0) {
193 return $fallback;
194 } else if (count($cond) == 1) {
195 return $cond[0];
196 } else {
197 return '(' . implode(') ' . $op . ' (', $cond) . ')';
198 }
199 }
200}
201// }}}
202
203// {{{ class PFC_True
204class PFC_True implements PlFilterCondition
205{
206 public function buildCondition(PlFilter &$uf)
207 {
208 return self::COND_TRUE;
209 }
210}
211// }}}
212
213// {{{ class PFC_False
214class PFC_False implements PlFilterCondition
215{
216 public function buildCondition(PlFilter &$uf)
217 {
218 return self::COND_FALSE;
219 }
220}
221// }}}
222
223// {{{ class PFC_Not
224class PFC_Not extends PFC_OneChild
225{
226 public function buildCondition(PlFilter &$uf)
227 {
228 $val = $this->child->buildCondition($uf);
229 if ($val == self::COND_TRUE) {
230 return self::COND_FALSE;
231 } else if ($val == self::COND_FALSE) {
232 return self::COND_TRUE;
233 } else {
234 return 'NOT (' . $val . ')';
235 }
236 }
237}
238// }}}
239
240// {{{ class PFC_And
241class PFC_And extends PFC_NChildren
242{
243 public function buildCondition(PlFilter &$uf)
244 {
245 if (empty($this->children)) {
246 return self::COND_FALSE;
247 } else {
248 $true = self::COND_FALSE;
249 $conds = array();
250 foreach ($this->children as &$child) {
251 $val = $child->buildCondition($uf);
252 if ($val == self::COND_TRUE) {
253 $true = self::COND_TRUE;
254 } else if ($val == self::COND_FALSE) {
255 return self::COND_FALSE;
256 } else {
257 $conds[] = $val;
258 }
259 }
260 return $this->catConds($conds, 'AND', $true);
261 }
262 }
263}
264// }}}
265
266// {{{ class PFC_Or
267class PFC_Or extends PFC_NChildren
268{
269 public function buildCondition(PlFilter &$uf)
270 {
271 if (empty($this->children)) {
272 return self::COND_TRUE;
273 } else {
274 $true = self::COND_TRUE;
275 $conds = array();
276 foreach ($this->children as &$child) {
277 $val = $child->buildCondition($uf);
278 if ($val == self::COND_TRUE) {
279 return self::COND_TRUE;
280 } else if ($val == self::COND_FALSE) {
281 $true = self::COND_FALSE;
282 } else {
283 $conds[] = $val;
284 }
285 }
286 return $this->catConds($conds, 'OR', $true);
287 }
288 }
289}
290// }}}
291
0d78a96b 292// {{{ class PlFilter
bd9b36fe
RB
293abstract class PlFilter
294{
295 /** Filters objects matching the PlFilter
296 * @param $objects The objects to filter
297 * @param $limit The portion of the matching objects to show
298 */
e1746810 299 public abstract function filter(array $objects, $limit = null);
bd9b36fe
RB
300
301 public abstract function setCondition(PlFilterCondition &$cond);
302
303 public abstract function addSort(PlFilterOrder &$sort);
304
305 public abstract function getTotalCount();
306
7c44b8bc
RB
307 /** Whether this PlFilter can return grouped results through
308 * $this->getGroups();
309 */
310 public abstract function hasGroups();
311
312 /** Used to retrieve value/amount resulting from grouping by the first
313 * given order.
314 */
315 public abstract function getGroups();
316
bd9b36fe
RB
317 /** Get objects, selecting only those within a limit
318 * @param $limit The portion of the matching objects to select
319 */
e1746810 320 public abstract function get($limit = null);
bd9b36fe
RB
321
322 /** PRIVATE FUNCTIONS
323 */
324
325 /** List of metas to replace in joins:
326 * '$COIN' => 'pan.x' means 'replace $COIN with pan.x in the condition of the joins'
327 *
328 * "$ME" => "joined table alias" is always added to these.
329 */
9a122520
RB
330 protected $joinMetas = array();
331
332 protected $joinMethods = array();
285fb262 333
bd9b36fe
RB
334 /** Build the 'join' part of the query
335 * This function will call all methods declared in self::$joinMethods
336 * to get an array of PlSqlJoin objects to merge
337 */
9a122520 338 protected function buildJoins()
285fb262
RB
339 {
340 $joins = array();
9a122520 341 foreach ($this->joinMethods as $method) {
285fb262
RB
342 $joins = array_merge($joins, $this->$method());
343 }
9a122520 344 return PlSqlJoin::formatJoins($joins, $this->joinMetas);
285fb262
RB
345 }
346
347}
0d78a96b 348// }}}
285fb262 349
ae3effcc 350// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
285fb262 351?>