Framework  3.9
query.inc
Go to the documentation of this file.
1 <?php
5 /**************************************************************
6 
7  Copyright (c) 2007-2010 Sonjara, Inc
8 
9  Permission is hereby granted, free of charge, to any person
10  obtaining a copy of this software and associated documentation
11  files (the "Software"), to deal in the Software without
12  restriction, including without limitation the rights to use,
13  copy, modify, merge, publish, distribute, sublicense, and/or sell
14  copies of the Software, and to permit persons to whom the
15  Software is furnished to do so, subject to the following
16  conditions:
17 
18  The above copyright notice and this permission notice shall be
19  included in all copies or substantial portions of the Software.
20 
21  Except as contained in this notice, the name(s) of the above
22  copyright holders shall not be used in advertising or otherwise
23  to promote the sale, use or other dealings in this Software
24  without prior written authorization.
25 
26  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
28  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
30  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
31  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
33  OTHER DEALINGS IN THE SOFTWARE.
34 
35 *****************************************************************/
36 
37 abstract class AbstractQuery
38 {
39  var $class;
41  var $filter;
42  var $params;
43 
44  public function __construct($class, $constraints = "")
45  {
46  $this->class = $class;
47  $this->constraints = $this->massageSQL($constraints);
48 
49  $this->filter = null;
50  $this->params = array();
51  }
52 
53  private function massageSQL($sql)
54  {
55  $version = ConnectionManager::getVersion();
56  if (!startsWith($version, "5."))
57  {
58  $sql = str_replace(array("[[:<:]]", "[[:>:]]"), array('\\\\b', '\\\\b'), $sql);
59  }
60  return $sql;
61  }
62 
69  {
70  $this->constraints = $this->massageSQL($constraints);
71  return $this;
72  }
73 
79  function filter($filter)
80  {
81  $this->filter = $filter;
82  return $this;
83  }
84 
91  function params($params)
92  {
93  $this->params = $params;
94  return $this;
95  }
96 
101  function bind()
102  {
103  $num = func_num_args();
104  for($i = 0; $i < $num; $i += 2)
105  {
106  $this->params[func_get_arg($i)] = $this->massageSQL(func_get_arg($i + 1));
107  }
108 
109  return $this;
110  }
111 
112  abstract function execute();
113 }
114 
125 class Query extends AbstractQuery
126 {
127  var $page;
128  var $size;
130 
137  public function __construct($class, $constraints = "")
138  {
139  parent::__construct($class, $constraints);
140 
141  $this->page = -1;
142  $this->size = -1;
143 
144  $this->tableAlias = "";
145  }
146 
147 
155  function page($page, $size)
156  {
157  $this->page = $page;
158  $this->size = $size;
159  return $this;
160  }
161 
162 
171  function tableAlias($alias)
172  {
173  $this->tableAlias = $alias;
174  return $this;
175  }
176 
180  function exists()
181  {
182  $prototype = new $this->class;
183  $pk = $prototype->getPrimaryKey();
184 
185  $query = "SELECT $pk FROM {$prototype->table} {$this->tableAlias} {$this->constraints} LIMIT 1";
186 
187  $exists = false;
188 
189  try
190  {
192 
193  $result = $db->prepare($query);
194  $result->execute($this->params);
195 
196  if ($result->fetch()) $exists = true;
197 
198  unset($result);
199  }
200  catch(PDOException $e)
201  {
202  throw new DataItemException($e->getMessage());
203  }
204 
205  return $exists;
206 
207  }
208 
214  function execute()
215  {
216  $prototype = new $this->class;
217  $prototype->filter = $this->filter;
218 
219  $order_by_idx = strpos(strtoupper($this->constraints), "ORDER BY");
220  $orderBy = "";
221 
222  if ($order_by_idx !== false)
223  {
224  $orderBy = substr($this->constraints, $order_by_idx);
225 
226  $this->constraints = substr($this->constraints, 0, $order_by_idx);
227  }
228 
229  if ($this->constraints == "") $this->constraints = "WHERE 1=1"; //TODO - tidy this up some day
230  $this->constraints .= " ".$prototype->getIdentityConstraint();
231 
232  $query = "SELECT ".$prototype->getFieldList()." FROM {$prototype->table} {$this->tableAlias} {$this->constraints} $orderBy";
233 
234  trace("$query", 3);
235  trace("Page: $this->page Size: $this->size", 3);
236  $items = array();
237 
238  $size = $this->size;
239 
240  try
241  {
243 
244  $result = $db->prepare($query);
245  $result->execute($this->params);
246 
247  if ($this->page > 0)
248  {
249  $count = ($this->page - 1) * $this->size;
250  while($count--)
251  {
252  $result->fetch();
253  }
254  }
255 
256  while($line = $result->fetch())
257  {
258  $item = new $this->class;
259  $item->filter = $this->filter;
260  $item->populate($line);
261  $items[] = $item;
262 
263  --$size;
264  if ($size == 0) break;
265  }
266 
267  unset($result);
268  }
269  catch(PDOException $e)
270  {
271  $err = "query() failed - " . $e->getMessage();
272  trace($err, 2);
273  throw new DataItemException($err);
274  }
275 
276  trace(count($items)." items found", 3);
277  return $items;
278  }
279 
286  function executeSingle()
287  {
288  $results = $this->execute();
289  if (count($results) == 1)
290  {
291  return $results[0];
292  }
293 
294  if (count($results) == 0)
295  {
296  throw new DataNotFoundException();
297  }
298  else
299  {
300  throw new DataItemException("Ambiguous singleton query");
301  }
302  }
303 
309  function executeValue($func)
310  {
311  $prototype = new $this->class;
312 
313  if ($this->constraints == "") $this->constraints = "WHERE 1=1"; //TODO - tidy this up some day
314  $this->constraints .= " ".$prototype->getIdentityConstraint();
315 
316  $query = "SELECT $func as result FROM {$prototype->table} {$this->tableAlias} {$this->constraints}";
317 
318  trace($query, 3);
319 
320  try
321  {
323 
324  $result = $db->prepare($query);
325  $result->execute($this->params);
326 
327  if ($row = $result->fetch())
328  {
329  $value = $row['result'];
330  }
331 
332  unset($result);
333  }
334  catch(PDOException $e)
335  {
336  $err = "Query::executeValue() failed - " . $e->getMessage();
337  trace($err, 2);
338  throw new DataItemException($err);
339  }
340 
341  return $value;
342  }
343 
347  function count()
348  {
349  return $this->executeValue("COUNT(1)");
350  }
351 
358  static function create($class, $constraints = "")
359  {
360  return new Query($class, $constraints);
361  }
362 }
363 
373 function query($class)
374 {
375  $query = new Query($class);
376 
377  if (func_num_args() > 1)
378  {
379  $idx = 1;
380 
381  if (is_object(func_get_arg(1)))
382  {
383  $query->filter($filter);
384  ++$idx;
385  }
386 
387  if (is_array(func_get_arg($idx)))
388  {
389  $query->params(func_get_arg($idx++));
390  }
391 
392  if (func_num_args() > $idx)
393  {
394  $query->constraints(func_get_arg($idx));
395 
396  if (func_num_args() == $idx + 3)
397  {
398  $query->page(func_get_arg($idx + 1), func_get_arg($idx + 2));
399  }
400  }
401  }
402 
403  return $query->execute();
404 }
405 ?>
bind()
Binds placeholders to parameter values.
Definition: query.inc:101
__construct($class, $constraints="")
Definition: query.inc:44
constraints($constraints)
Sets the constraint clause for the Query.
Definition: query.inc:68
filter($filter)
Sets a filter to constrain the fields retrieved when the query is executed.
Definition: query.inc:79
params($params)
Sets the bound parameters array.
Definition: query.inc:91
static getVersion()
Determine the version of the connected database.
static getConnection()
Retrieves a reference to the global database connection.
Query provides an object-oriented interface for database queries.
Definition: query.inc:126
executeSingle()
Executes the query and returns a singleton result row.
Definition: query.inc:286
exists()
Return true if the query matches one or more rows in the database.
Definition: query.inc:180
tableAlias($alias)
Sometimes when you are creating abonimable SQL constraints you might need to refer back to the main o...
Definition: query.inc:171
__construct($class, $constraints="")
Creates a new Query object.
Definition: query.inc:137
executeValue($func)
Query the database to calculate an aggregate value.
Definition: query.inc:309
$size
Definition: query.inc:128
static create($class, $constraints="")
Static factory method to create a new Query.
Definition: query.inc:358
execute()
Executes the query and returns an array of DataItems containing the results (the class of items retur...
Definition: query.inc:214
$page
Definition: query.inc:127
count()
Return the count of matching results.
Definition: query.inc:347
page($page, $size)
Sets the page number and size for constraining the result set by page.
Definition: query.inc:155
$tableAlias
Definition: query.inc:129
trace($msg, $lvl=3, $callStack=null)
Send output to the trace log.
Definition: functions.inc:1010
startsWith($text, $start)
Tests whether a string starts with a given sub-string.
Definition: functions.inc:1470
query($class)
Performs a query against the database, returning an array of DataItem objects of the specified class.
Definition: query.inc:373