1 |
<?php
|
2 |
/*
|
3 |
* $Id: Query.php 1393 2007-05-19 17:49:16Z zYne $
|
4 |
*
|
5 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
6 |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
7 |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
8 |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
9 |
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
10 |
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
11 |
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
12 |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
13 |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
14 |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
15 |
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
16 |
*
|
17 |
* This software consists of voluntary contributions made by many individuals
|
18 |
* and is licensed under the LGPL. For more information, see
|
19 |
* <http://www.phpdoctrine.org>.
|
20 |
*/
|
21 |
Doctrine::autoload('Doctrine_Hydrate');
|
22 |
/**
|
23 |
* Doctrine_Query_Abstract
|
24 |
*
|
25 |
* @package Doctrine
|
26 |
* @subpackage Query
|
27 |
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
28 |
* @link www.phpdoctrine.org
|
29 |
* @since 1.0
|
30 |
* @version $Revision: 1393 $
|
31 |
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
32 |
* @todo See {@link Doctrine_Query}
|
33 |
*/
|
34 |
abstract class Doctrine_Query_Abstract
|
35 |
{
|
36 |
/**
|
37 |
* QUERY TYPE CONSTANTS
|
38 |
*/
|
39 |
|
40 |
/**
|
41 |
* constant for SELECT queries
|
42 |
*/
|
43 |
const SELECT = 0;
|
44 |
|
45 |
/**
|
46 |
* constant for DELETE queries
|
47 |
*/
|
48 |
const DELETE = 1;
|
49 |
|
50 |
/**
|
51 |
* constant for UPDATE queries
|
52 |
*/
|
53 |
const UPDATE = 2;
|
54 |
|
55 |
/**
|
56 |
* constant for INSERT queries
|
57 |
*/
|
58 |
const INSERT = 3;
|
59 |
|
60 |
/**
|
61 |
* constant for CREATE queries
|
62 |
*/
|
63 |
const CREATE = 4;
|
64 |
|
65 |
/** @todo document the query states (and the transitions between them). */
|
66 |
/**
|
67 |
* A query object is in CLEAN state when it has NO unparsed/unprocessed DQL parts.
|
68 |
*/
|
69 |
const STATE_CLEAN = 1;
|
70 |
|
71 |
/**
|
72 |
* A query object is in state DIRTY when it has DQL parts that have not yet been
|
73 |
* parsed/processed.
|
74 |
*/
|
75 |
const STATE_DIRTY = 2;
|
76 |
|
77 |
/**
|
78 |
* A query is in DIRECT state when ... ?
|
79 |
*/
|
80 |
const STATE_DIRECT = 3;
|
81 |
|
82 |
/**
|
83 |
* A query object is on LOCKED state when ... ?
|
84 |
*/
|
85 |
const STATE_LOCKED = 4;
|
86 |
|
87 |
/**
|
88 |
* @var array Table alias map. Keys are SQL aliases and values DQL aliases.
|
89 |
*/
|
90 |
protected $_tableAliasMap = array();
|
91 |
|
92 |
/**
|
93 |
* @var Doctrine_View The view object used by this query, if any.
|
94 |
*/
|
95 |
protected $_view;
|
96 |
|
97 |
/**
|
98 |
* @var integer $_state The current state of this query.
|
99 |
*/
|
100 |
protected $_state = Doctrine_Query::STATE_CLEAN;
|
101 |
|
102 |
/**
|
103 |
* @var array $params The parameters of this query.
|
104 |
*/
|
105 |
protected $_params = array('where' => array(),
|
106 |
'set' => array(),
|
107 |
'having' => array());
|
108 |
|
109 |
/* Caching properties */
|
110 |
/**
|
111 |
* @var Doctrine_Cache_Interface The cache driver used for caching result sets.
|
112 |
*/
|
113 |
protected $_resultCache;
|
114 |
/**
|
115 |
* @var boolean $_expireResultCache A boolean value that indicates whether or not
|
116 |
* expire the result cache.
|
117 |
*/
|
118 |
protected $_expireResultCache = false;
|
119 |
protected $_resultCacheTTL;
|
120 |
|
121 |
/**
|
122 |
* @var Doctrine_Cache_Interface The cache driver used for caching queries.
|
123 |
*/
|
124 |
protected $_queryCache;
|
125 |
protected $_expireQueryCache = false;
|
126 |
protected $_queryCacheTTL;
|
127 |
|
128 |
|
129 |
/**
|
130 |
* @var Doctrine_Connection The connection used by this query object.
|
131 |
*/
|
132 |
protected $_conn;
|
133 |
|
134 |
|
135 |
/**
|
136 |
* @var array $_sqlParts The SQL query string parts. Filled during the DQL parsing process.
|
137 |
*/
|
138 |
protected $_sqlParts = array(
|
139 |
'select' => array(),
|
140 |
'distinct' => false,
|
141 |
'forUpdate' => false,
|
142 |
'from' => array(),
|
143 |
'set' => array(),
|
144 |
'join' => array(),
|
145 |
'where' => array(),
|
146 |
'groupby' => array(),
|
147 |
'having' => array(),
|
148 |
'orderby' => array(),
|
149 |
'limit' => false,
|
150 |
'offset' => false,
|
151 |
);
|
152 |
|
153 |
/**
|
154 |
* @var array $_dqlParts an array containing all DQL query parts
|
155 |
*/
|
156 |
protected $_dqlParts = array(
|
157 |
'from' => array(),
|
158 |
'select' => array(),
|
159 |
'forUpdate' => false,
|
160 |
'set' => array(),
|
161 |
'join' => array(),
|
162 |
'where' => array(),
|
163 |
'groupby' => array(),
|
164 |
'having' => array(),
|
165 |
'orderby' => array(),
|
166 |
'limit' => array(),
|
167 |
'offset' => array(),
|
168 |
);
|
169 |
|
170 |
|
171 |
/**
|
172 |
* @var array $_queryComponents Two dimensional array containing the components of this query,
|
173 |
* informations about their relations and other related information.
|
174 |
* The components are constructed during query parsing.
|
175 |
*
|
176 |
* Keys are component aliases and values the following:
|
177 |
*
|
178 |
* table table object associated with given alias
|
179 |
*
|
180 |
* relation the relation object owned by the parent
|
181 |
*
|
182 |
* parent the alias of the parent
|
183 |
*
|
184 |
* agg the aggregates of this component
|
185 |
*
|
186 |
* map the name of the column / aggregate value this
|
187 |
* component is mapped to a collection
|
188 |
*/
|
189 |
protected $_queryComponents = array();
|
190 |
|
191 |
/**
|
192 |
* @var integer $type the query type
|
193 |
*
|
194 |
* @see Doctrine_Query::* constants
|
195 |
*/
|
196 |
protected $_type = self::SELECT;
|
197 |
|
198 |
/**
|
199 |
* @var Doctrine_Hydrator The hydrator object used to hydrate query results.
|
200 |
*/
|
201 |
protected $_hydrator;
|
202 |
|
203 |
/**
|
204 |
* @var Doctrine_Query_Tokenizer The tokenizer that is used during the query parsing process.
|
205 |
*/
|
206 |
protected $_tokenizer;
|
207 |
|
208 |
/**
|
209 |
* @var Doctrine_Query_Parser The parser that is used for query parsing.
|
210 |
*/
|
211 |
protected $_parser;
|
212 |
|
213 |
/**
|
214 |
* @var array $_tableAliasSeeds A simple array keys representing table aliases and values
|
215 |
* table alias seeds. The seeds are used for generating short table
|
216 |
* aliases.
|
217 |
*/
|
218 |
protected $_tableAliasSeeds = array();
|
219 |
|
220 |
/**
|
221 |
* @var array $_options an array of options
|
222 |
*/
|
223 |
protected $_options = array(
|
224 |
'fetchMode' => Doctrine::FETCH_RECORD
|
225 |
);
|
226 |
|
227 |
/**
|
228 |
* @var array $_enumParams an array containing the keys of the parameters that should be enumerated
|
229 |
*/
|
230 |
protected $_enumParams = array();
|
231 |
|
232 |
/**
|
233 |
* @var boolean
|
234 |
*/
|
235 |
protected $_isLimitSubqueryUsed = false;
|
236 |
|
237 |
|
238 |
/**
|
239 |
* Constructor.
|
240 |
*
|
241 |
* @param Doctrine_Connection The connection object the query will use.
|
242 |
* @param Doctrine_Hydrator_Abstract The hydrator that will be used for generating result sets.
|
243 |
*/
|
244 |
public function __construct(Doctrine_Connection $connection = null,
|
245 |
Doctrine_Hydrator_Abstract $hydrator = null)
|
246 |
{
|
247 |
if ($connection === null) {
|
248 |
$connection = Doctrine_Manager::getInstance()->getCurrentConnection();
|
249 |
}
|
250 |
if ($hydrator === null) {
|
251 |
$hydrator = new Doctrine_Hydrator();
|
252 |
}
|
253 |
$this->_conn = $connection;
|
254 |
$this->_hydrator = $hydrator;
|
255 |
$this->_tokenizer = new Doctrine_Query_Tokenizer();
|
256 |
}
|
257 |
|
258 |
/**
|
259 |
* setOption
|
260 |
*
|
261 |
* @param string $name option name
|
262 |
* @param string $value option value
|
263 |
* @return Doctrine_Query this object
|
264 |
*/
|
265 |
public function setOption($name, $value)
|
266 |
{
|
267 |
if ( ! isset($this->_options[$name])) {
|
268 |
throw new Doctrine_Query_Exception('Unknown option ' . $name);
|
269 |
}
|
270 |
$this->_options[$name] = $value;
|
271 |
}
|
272 |
|
273 |
/**
|
274 |
* hasTableAlias
|
275 |
* whether or not this object has given tableAlias
|
276 |
*
|
277 |
* @param string $tableAlias the table alias to be checked
|
278 |
* @return boolean true if this object has given alias, otherwise false
|
279 |
* @deprecated
|
280 |
*/
|
281 |
public function hasTableAlias($sqlTableAlias)
|
282 |
{
|
283 |
return $this->hasSqlTableAlias($sqlTableAlias);
|
284 |
}
|
285 |
|
286 |
/**
|
287 |
* hasSqlTableAlias
|
288 |
* whether or not this object has given tableAlias
|
289 |
*
|
290 |
* @param string $tableAlias the table alias to be checked
|
291 |
* @return boolean true if this object has given alias, otherwise false
|
292 |
*/
|
293 |
public function hasSqlTableAlias($sqlTableAlias)
|
294 |
{
|
295 |
return (isset($this->_tableAliasMap[$sqlTableAlias]));
|
296 |
}
|
297 |
|
298 |
/**
|
299 |
* getTableAliases
|
300 |
* returns all table aliases
|
301 |
*
|
302 |
* @return array table aliases as an array
|
303 |
* @deprecated
|
304 |
*/
|
305 |
public function getTableAliases()
|
306 |
{
|
307 |
return $this->getTableAliasMap();
|
308 |
}
|
309 |
|
310 |
/**
|
311 |
* getTableAliasMap
|
312 |
* returns all table aliases
|
313 |
*
|
314 |
* @return array table aliases as an array
|
315 |
*/
|
316 |
public function getTableAliasMap()
|
317 |
{
|
318 |
return $this->_tableAliasMap;
|
319 |
}
|
320 |
|
321 |
/**
|
322 |
* getQueryPart
|
323 |
* gets a query part from the query part array
|
324 |
*
|
325 |
* @param string $name the name of the query part to be set
|
326 |
* @param string $part query part string
|
327 |
* @throws Doctrine_Query_Exception if trying to set unknown query part
|
328 |
* @return Doctrine_Query_Abstract this object
|
329 |
* @deprecated
|
330 |
*/
|
331 |
public function getQueryPart($part)
|
332 |
{
|
333 |
return $this->getSqlQueryPart($part);
|
334 |
}
|
335 |
|
336 |
/**
|
337 |
* getSqlQueryPart
|
338 |
* gets an SQL query part from the SQL query part array
|
339 |
*
|
340 |
* @param string $name the name of the query part to be set
|
341 |
* @param string $part query part string
|
342 |
* @throws Doctrine_Query_Exception if trying to set unknown query part
|
343 |
* @return Doctrine_Hydrate this object
|
344 |
*/
|
345 |
public function getSqlQueryPart($part)
|
346 |
{
|
347 |
if ( ! isset($this->_sqlParts[$part])) {
|
348 |
throw new Doctrine_Query_Exception('Unknown SQL query part ' . $part);
|
349 |
}
|
350 |
return $this->_sqlParts[$part];
|
351 |
}
|
352 |
|
353 |
/**
|
354 |
* setQueryPart
|
355 |
* sets a query part in the query part array
|
356 |
*
|
357 |
* @param string $name the name of the query part to be set
|
358 |
* @param string $part query part string
|
359 |
* @throws Doctrine_Query_Exception if trying to set unknown query part
|
360 |
* @return Doctrine_Hydrate this object
|
361 |
* @deprecated
|
362 |
*/
|
363 |
public function setQueryPart($name, $part)
|
364 |
{
|
365 |
return $this->setSqlQueryPart($name, $part);
|
366 |
}
|
367 |
|
368 |
/**
|
369 |
* setSqlQueryPart
|
370 |
* sets an SQL query part in the SQL query part array
|
371 |
*
|
372 |
* @param string $name the name of the query part to be set
|
373 |
* @param string $part query part string
|
374 |
* @throws Doctrine_Query_Exception if trying to set unknown query part
|
375 |
* @return Doctrine_Hydrate this object
|
376 |
*/
|
377 |
public function setSqlQueryPart($name, $part)
|
378 |
{
|
379 |
if ( ! isset($this->_sqlParts[$name])) {
|
380 |
throw new Doctrine_Query_Exception('Unknown query part ' . $name);
|
381 |
}
|
382 |
|
383 |
if ($name !== 'limit' && $name !== 'offset') {
|
384 |
if (is_array($part)) {
|
385 |
$this->_sqlParts[$name] = $part;
|
386 |
} else {
|
387 |
$this->_sqlParts[$name] = array($part);
|
388 |
}
|
389 |
} else {
|
390 |
$this->_sqlParts[$name] = $part;
|
391 |
}
|
392 |
|
393 |
return $this;
|
394 |
}
|
395 |
|
396 |
/**
|
397 |
* addQueryPart
|
398 |
* adds a query part in the query part array
|
399 |
*
|
400 |
* @param string $name the name of the query part to be added
|
401 |
* @param string $part query part string
|
402 |
* @throws Doctrine_Query_Exception if trying to add unknown query part
|
403 |
* @return Doctrine_Hydrate this object
|
404 |
* @deprecated
|
405 |
*/
|
406 |
public function addQueryPart($name, $part)
|
407 |
{
|
408 |
return $this->addSqlQueryPart($name, $part);
|
409 |
}
|
410 |
|
411 |
/**
|
412 |
* addSqlQueryPart
|
413 |
* adds an SQL query part to the SQL query part array
|
414 |
*
|
415 |
* @param string $name the name of the query part to be added
|
416 |
* @param string $part query part string
|
417 |
* @throws Doctrine_Query_Exception if trying to add unknown query part
|
418 |
* @return Doctrine_Hydrate this object
|
419 |
*/
|
420 |
public function addSqlQueryPart($name, $part)
|
421 |
{
|
422 |
if ( ! isset($this->_sqlParts[$name])) {
|
423 |
throw new Doctrine_Query_Exception('Unknown query part ' . $name);
|
424 |
}
|
425 |
if (is_array($part)) {
|
426 |
$this->_sqlParts[$name] = array_merge($this->_sqlParts[$name], $part);
|
427 |
} else {
|
428 |
$this->_sqlParts[$name][] = $part;
|
429 |
}
|
430 |
return $this;
|
431 |
}
|
432 |
|
433 |
/**
|
434 |
* removeQueryPart
|
435 |
* removes a query part from the query part array
|
436 |
*
|
437 |
* @param string $name the name of the query part to be removed
|
438 |
* @throws Doctrine_Query_Exception if trying to remove unknown query part
|
439 |
* @return Doctrine_Hydrate this object
|
440 |
* @deprecated
|
441 |
*/
|
442 |
public function removeQueryPart($name)
|
443 |
{
|
444 |
return $this->removeSqlQueryPart($name);
|
445 |
}
|
446 |
|
447 |
/**
|
448 |
* removeSqlQueryPart
|
449 |
* removes a query part from the query part array
|
450 |
*
|
451 |
* @param string $name the name of the query part to be removed
|
452 |
* @throws Doctrine_Query_Exception if trying to remove unknown query part
|
453 |
* @return Doctrine_Hydrate this object
|
454 |
*/
|
455 |
public function removeSqlQueryPart($name)
|
456 |
{
|
457 |
try {
|
458 |
if ( ! isset($this->_sqlParts[$name])) {
|
459 |
throw new Doctrine_Query_Exception('Unknown query part ' . $name);
|
460 |
}}
|
461 |
catch (Exception $e) {echo $e->getTraceAsString(); echo "<br /><br /><br />";}
|
462 |
|
463 |
if ($name == 'limit' || $name == 'offset') {
|
464 |
$this->_sqlParts[$name] = false;
|
465 |
} else {
|
466 |
$this->_sqlParts[$name] = array();
|
467 |
}
|
468 |
return $this;
|
469 |
}
|
470 |
|
471 |
/**
|
472 |
* setView
|
473 |
* sets a database view this query object uses
|
474 |
* this method should only be called internally by doctrine
|
475 |
*
|
476 |
* @param Doctrine_View $view database view
|
477 |
* @return void
|
478 |
*/
|
479 |
public function setView(Doctrine_View $view)
|
480 |
{
|
481 |
$this->_view = $view;
|
482 |
}
|
483 |
|
484 |
/**
|
485 |
* getView
|
486 |
* returns the view associated with this query object (if any)
|
487 |
*
|
488 |
* @return Doctrine_View the view associated with this query object
|
489 |
*/
|
490 |
public function getView()
|
491 |
{
|
492 |
return $this->_view;
|
493 |
}
|
494 |
|
495 |
/**
|
496 |
* limitSubqueryUsed
|
497 |
*
|
498 |
* @return boolean
|
499 |
*/
|
500 |
public function isLimitSubqueryUsed()
|
501 |
{
|
502 |
return $this->_isLimitSubqueryUsed;
|
503 |
}
|
504 |
|
505 |
/**
|
506 |
* convertEnums
|
507 |
* convert enum parameters to their integer equivalents
|
508 |
*
|
509 |
* @return array converted parameter array
|
510 |
*/
|
511 |
public function convertEnums($params)
|
512 |
{
|
513 |
foreach ($this->_enumParams as $key => $values) {
|
514 |
if (isset($params[$key])) {
|
515 |
if ( ! empty($values)) {
|
516 |
$params[$key] = $values[0]->enumIndex($values[1], $params[$key]);
|
517 |
}
|
518 |
}
|
519 |
}
|
520 |
return $params;
|
521 |
}
|
522 |
|
523 |
/**
|
524 |
* applyInheritance
|
525 |
* applies column aggregation inheritance to DQL / SQL query
|
526 |
*
|
527 |
* @return string
|
528 |
*/
|
529 |
public function applyInheritance()
|
530 |
{
|
531 |
// get the inheritance maps
|
532 |
$array = array();
|
533 |
|
534 |
foreach ($this->_queryComponents as $componentAlias => $data) {
|
535 |
$tableAlias = $this->getSqlTableAlias($componentAlias);
|
536 |
$array[$tableAlias][] = $data['table']->inheritanceMap;
|
537 |
}
|
538 |
|
539 |
// apply inheritance maps
|
540 |
$str = '';
|
541 |
$c = array();
|
542 |
|
543 |
$index = 0;
|
544 |
foreach ($array as $tableAlias => $maps) {
|
545 |
$a = array();
|
546 |
|
547 |
// don't use table aliases if the query isn't a select query
|
548 |
if ($this->_type !== Doctrine_Query::SELECT) {
|
549 |
$tableAlias = '';
|
550 |
} else {
|
551 |
$tableAlias .= '.';
|
552 |
}
|
553 |
|
554 |
foreach ($maps as $map) {
|
555 |
$b = array();
|
556 |
foreach ($map as $field => $value) {
|
557 |
$identifier = $this->_conn->quoteIdentifier($tableAlias . $field);
|
558 |
|
559 |
if ($index > 0) {
|
560 |
$b[] = '(' . $identifier . ' = ' . $this->_conn->quote($value)
|
561 |
. ' OR ' . $identifier . ' IS NULL)';
|
562 |
} else {
|
563 |
$b[] = $identifier . ' = ' . $this->_conn->quote($value);
|
564 |
}
|
565 |
}
|
566 |
|
567 |
if ( ! empty($b)) {
|
568 |
$a[] = implode(' AND ', $b);
|
569 |
}
|
570 |
}
|
571 |
|
572 |
if ( ! empty($a)) {
|
573 |
$c[] = implode(' AND ', $a);
|
574 |
}
|
575 |
$index++;
|
576 |
}
|
577 |
|
578 |
$str .= implode(' AND ', $c);
|
579 |
|
580 |
return $str;
|
581 |
}
|
582 |
|
583 |
/**
|
584 |
* getTableAlias
|
585 |
* some database such as Oracle need the identifier lengths to be < ~30 chars
|
586 |
* hence Doctrine creates as short identifier aliases as possible
|
587 |
*
|
588 |
* this method is used for the creation of short table aliases, its also
|
589 |
* smart enough to check if an alias already exists for given component (componentAlias)
|
590 |
*
|
591 |
* @param string $componentAlias the alias for the query component to search table alias for
|
592 |
* @param string $tableName the table name from which the table alias is being created
|
593 |
* @return string the generated / fetched short alias
|
594 |
* @deprecated
|
595 |
*/
|
596 |
public function getTableAlias($componentAlias, $tableName = null)
|
597 |
{
|
598 |
return $this->getSqlTableAlias($componentAlias, $tableName);
|
599 |
}
|
600 |
|
601 |
/**
|
602 |
* getSqlTableAlias
|
603 |
* some database such as Oracle need the identifier lengths to be < ~30 chars
|
604 |
* hence Doctrine creates as short identifier aliases as possible
|
605 |
*
|
606 |
* this method is used for the creation of short table aliases, its also
|
607 |
* smart enough to check if an alias already exists for given component (componentAlias)
|
608 |
*
|
609 |
* @param string $componentAlias the alias for the query component to search table alias for
|
610 |
* @param string $tableName the table name from which the table alias is being created
|
611 |
* @return string the generated / fetched short alias
|
612 |
*/
|
613 |
public function getSqlTableAlias($componentAlias, $tableName = null)
|
614 |
{
|
615 |
$alias = array_search($componentAlias, $this->_tableAliasMap);
|
616 |
|
617 |
if ($alias !== false) {
|
618 |
return $alias;
|
619 |
}
|
620 |
|
621 |
if ($tableName === null) {
|
622 |
throw new Doctrine_Query_Exception("Couldn't get short alias for " . $componentAlias);
|
623 |
}
|
624 |
|
625 |
return $this->generateTableAlias($componentAlias, $tableName);
|
626 |
}
|
627 |
|
628 |
/**
|
629 |
* generateNewTableAlias
|
630 |
* generates a new alias from given table alias
|
631 |
*
|
632 |
* @param string $tableAlias table alias from which to generate the new alias from
|
633 |
* @return string the created table alias
|
634 |
* @deprecated
|
635 |
*/
|
636 |
public function generateNewTableAlias($oldAlias)
|
637 |
{
|
638 |
return $this->generateNewSqlTableAlias($oldAlias);
|
639 |
}
|
640 |
|
641 |
/**
|
642 |
* generateNewSqlTableAlias
|
643 |
* generates a new alias from given table alias
|
644 |
*
|
645 |
* @param string $tableAlias table alias from which to generate the new alias from
|
646 |
* @return string the created table alias
|
647 |
*/
|
648 |
public function generateNewSqlTableAlias($oldAlias)
|
649 |
{
|
650 |
if (isset($this->_tableAliasMap[$oldAlias])) {
|
651 |
// generate a new alias
|
652 |
$name = substr($oldAlias, 0, 1);
|
653 |
$i = ((int) substr($oldAlias, 1));
|
654 |
|
655 |
if ($i == 0) {
|
656 |
$i = 1;
|
657 |
}
|
658 |
|
659 |
$newIndex = ($this->_tableAliasSeeds[$name] + $i);
|
660 |
|
661 |
return $name . $newIndex;
|
662 |
}
|
663 |
|
664 |
return $oldAlias;
|
665 |
}
|
666 |
|
667 |
/**
|
668 |
* getTableAliasSeed
|
669 |
* returns the alias seed for given table alias
|
670 |
*
|
671 |
* @param string $tableAlias table alias that identifies the alias seed
|
672 |
* @return integer table alias seed
|
673 |
* @deprecated
|
674 |
*/
|
675 |
public function getTableAliasSeed($sqlTableAlias)
|
676 |
{
|
677 |
return $this->getSqlTableAliasSeed($sqlTableAlias);
|
678 |
}
|
679 |
|
680 |
/**
|
681 |
* getSqlTableAliasSeed
|
682 |
* returns the alias seed for given table alias
|
683 |
*
|
684 |
* @param string $tableAlias table alias that identifies the alias seed
|
685 |
* @return integer table alias seed
|
686 |
*/
|
687 |
public function getSqlTableAliasSeed($sqlTableAlias)
|
688 |
{
|
689 |
if ( ! isset($this->_tableAliasSeeds[$sqlTableAlias])) {
|
690 |
return 0;
|
691 |
}
|
692 |
return $this->_tableAliasSeeds[$sqlTableAlias];
|
693 |
}
|
694 |
|
695 |
/**
|
696 |
* hasAliasDeclaration
|
697 |
* whether or not this object has a declaration for given component alias
|
698 |
*
|
699 |
* @param string $componentAlias the component alias the retrieve the declaration from
|
700 |
* @return boolean
|
701 |
*/
|
702 |
public function hasAliasDeclaration($componentAlias)
|
703 |
{
|
704 |
return isset($this->_queryComponents[$componentAlias]);
|
705 |
}
|
706 |
|
707 |
/**
|
708 |
* getAliasDeclaration
|
709 |
* get the declaration for given component alias
|
710 |
*
|
711 |
* @param string $componentAlias the component alias the retrieve the declaration from
|
712 |
* @return array the alias declaration
|
713 |
* @deprecated
|
714 |
*/
|
715 |
public function getAliasDeclaration($componentAlias)
|
716 |
{
|
717 |
return $this->getQueryComponent($componentAlias);
|
718 |
}
|
719 |
|
720 |
/**
|
721 |
* getQueryComponent
|
722 |
* get the declaration for given component alias
|
723 |
*
|
724 |
* @param string $componentAlias the component alias the retrieve the declaration from
|
725 |
* @return array the alias declaration
|
726 |
*/
|
727 |
public function getQueryComponent($componentAlias)
|
728 |
{
|
729 |
if ( ! isset($this->_queryComponents[$componentAlias])) {
|
730 |
throw new Doctrine_Query_Exception('Unknown component alias ' . $componentAlias);
|
731 |
}
|
732 |
|
733 |
return $this->_queryComponents[$componentAlias];
|
734 |
}
|
735 |
|
736 |
/**
|
737 |
* copyAliases
|
738 |
* copy aliases from another Hydrate object
|
739 |
*
|
740 |
* this method is needed by DQL subqueries which need the aliases
|
741 |
* of the parent query
|
742 |
*
|
743 |
* @param Doctrine_Hydrate $query the query object from which the
|
744 |
* aliases are copied from
|
745 |
* @return Doctrine_Hydrate this object
|
746 |
*/
|
747 |
public function copyAliases(Doctrine_Query_Abstract $query)
|
748 |
{
|
749 |
$this->_tableAliasMap = $query->_tableAliasMap;
|
750 |
$this->_queryComponents = $query->_queryComponents;
|
751 |
$this->_tableAliasSeeds = $query->_tableAliasSeeds;
|
752 |
return $this;
|
753 |
}
|
754 |
|
755 |
/**
|
756 |
* getRootAlias
|
757 |
* returns the alias of the the root component
|
758 |
*
|
759 |
* @return array
|
760 |
*/
|
761 |
public function getRootAlias()
|
762 |
{
|
763 |
if ( ! $this->_queryComponents) {
|
764 |
$this->getSql();
|
765 |
}
|
766 |
reset($this->_queryComponents);
|
767 |
|
768 |
return key($this->_queryComponents);
|
769 |
}
|
770 |
|
771 |
/**
|
772 |
* getRootDeclaration
|
773 |
* returns the root declaration
|
774 |
*
|
775 |
* @return array
|
776 |
*/
|
777 |
public function getRootDeclaration()
|
778 |
{
|
779 |
$map = reset($this->_queryComponents);
|
780 |
return $map;
|
781 |
}
|
782 |
|
783 |
/**
|
784 |
* getRoot
|
785 |
* returns the root component for this object
|
786 |
*
|
787 |
* @return Doctrine_Table root components table
|
788 |
*/
|
789 |
public function getRoot()
|
790 |
{
|
791 |
$map = reset($this->_queryComponents);
|
792 |
|
793 |
if ( ! isset($map['table'])) {
|
794 |
throw new Doctrine_Query_Exception('Root component not initialized.');
|
795 |
}
|
796 |
|
797 |
return $map['table'];
|
798 |
}
|
799 |
|
800 |
/**
|
801 |
* generateTableAlias
|
802 |
* generates a table alias from given table name and associates
|
803 |
* it with given component alias
|
804 |
*
|
805 |
* @param string $componentAlias the component alias to be associated with generated table alias
|
806 |
* @param string $tableName the table name from which to generate the table alias
|
807 |
* @return string the generated table alias
|
808 |
* @deprecated
|
809 |
*/
|
810 |
public function generateTableAlias($componentAlias, $tableName)
|
811 |
{
|
812 |
return $this->generateSqlTableAlias($componentAlias, $tableName);
|
813 |
}
|
814 |
|
815 |
/**
|
816 |
* generateSqlTableAlias
|
817 |
* generates a table alias from given table name and associates
|
818 |
* it with given component alias
|
819 |
*
|
820 |
* @param string $componentAlias the component alias to be associated with generated table alias
|
821 |
* @param string $tableName the table name from which to generate the table alias
|
822 |
* @return string the generated table alias
|
823 |
*/
|
824 |
public function generateSqlTableAlias($componentAlias, $tableName)
|
825 |
{
|
826 |
$char = strtolower(substr($tableName, 0, 1));
|
827 |
|
828 |
$alias = $char;
|
829 |
|
830 |
if ( ! isset($this->_tableAliasSeeds[$alias])) {
|
831 |
$this->_tableAliasSeeds[$alias] = 1;
|
832 |
}
|
833 |
|
834 |
while (isset($this->_tableAliasMap[$alias])) {
|
835 |
if ( ! isset($this->_tableAliasSeeds[$alias])) {
|
836 |
$this->_tableAliasSeeds[$alias] = 1;
|
837 |
}
|
838 |
$alias = $char . ++$this->_tableAliasSeeds[$alias];
|
839 |
}
|
840 |
|
841 |
$this->_tableAliasMap[$alias] = $componentAlias;
|
842 |
|
843 |
return $alias;
|
844 |
}
|
845 |
|
846 |
/**
|
847 |
* getComponentAlias
|
848 |
* get component alias associated with given table alias
|
849 |
*
|
850 |
* @param string $sqlTableAlias the SQL table alias that identifies the component alias
|
851 |
* @return string component alias
|
852 |
*/
|
853 |
public function getComponentAlias($sqlTableAlias)
|
854 |
{
|
855 |
if ( ! isset($this->_tableAliasMap[$sqlTableAlias])) {
|
856 |
throw new Doctrine_Query_Exception('Unknown table alias ' . $sqlTableAlias);
|
857 |
}
|
858 |
return $this->_tableAliasMap[$sqlTableAlias];
|
859 |
}
|
860 |
|
861 |
/**
|
862 |
* _execute
|
863 |
*
|
864 |
* @param array $params
|
865 |
* @return PDOStatement The executed PDOStatement.
|
866 |
*/
|
867 |
protected function _execute($params)
|
868 |
{
|
869 |
$params = $this->_conn->convertBooleans($params);
|
870 |
|
871 |
if ( ! $this->_view) {
|
872 |
if ($this->_queryCache || $this->_conn->getAttribute(Doctrine::ATTR_QUERY_CACHE)) {
|
873 |
$queryCacheDriver = $this->getQueryCacheDriver();
|
874 |
// calculate hash for dql query
|
875 |
$dql = $this->getDql();
|
876 |
$hash = md5($dql . 'DOCTRINE_QUERY_CACHE_SALT');
|
877 |
$cached = $queryCacheDriver->fetch($hash);
|
878 |
if ($cached) {
|
879 |
$query = $this->_constructQueryFromCache($cached);
|
880 |
} else {
|
881 |
$query = $this->getSqlQuery($params);
|
882 |
$serializedQuery = $this->getCachedForm($query);
|
883 |
$queryCacheDriver->save($hash, $serializedQuery, $this->_queryCacheTTL);
|
884 |
}
|
885 |
} else {
|
886 |
$query = $this->getSqlQuery($params);
|
887 |
}
|
888 |
} else {
|
889 |
$query = $this->_view->getSelectSql();
|
890 |
}
|
891 |
|
892 |
$params = $this->convertEnums($params);
|
893 |
|
894 |
if ($this->isLimitSubqueryUsed() &&
|
895 |
$this->_conn->getAttribute(Doctrine::ATTR_DRIVER_NAME) !== 'mysql') {
|
896 |
$params = array_merge($params, $params);
|
897 |
}
|
898 |
|
899 |
if ($this->_type !== self::SELECT) {
|
900 |
return $this->_conn->exec($query, $params);
|
901 |
}
|
902 |
|
903 |
$stmt = $this->_conn->execute($query, $params);
|
904 |
return $stmt;
|
905 |
}
|
906 |
|
907 |
/**
|
908 |
* execute
|
909 |
* executes the query and populates the data set
|
910 |
*
|
911 |
* @param string $params
|
912 |
* @return Doctrine_Collection the root collection
|
913 |
*/
|
914 |
public function execute($params = array(), $hydrationMode = null)
|
915 |
{
|
916 |
$params = array_merge($this->_params['set'],
|
917 |
$this->_params['where'],
|
918 |
$this->_params['having'],
|
919 |
$params);
|
920 |
|
921 |
if ($this->_resultCache) {
|
922 |
$cacheDriver = $this->getResultCacheDriver();
|
923 |
|
924 |
$dql = $this->getDql();
|
925 |
// calculate hash for dql query
|
926 |
$hash = md5($dql . var_export($params, true));
|
927 |
|
928 |
$cached = ($this->_expireResultCache) ? false : $cacheDriver->fetch($hash);
|
929 |
|
930 |
if ($cached === false) {
|
931 |
// cache miss
|
932 |
$stmt = $this->_execute($params);
|
933 |
$this->_hydrator->setQueryComponents($this->_queryComponents);
|
934 |
$result = $this->_hydrator->hydrateResultSet($stmt, $this->_tableAliasMap,
|
935 |
Doctrine::HYDRATE_ARRAY);
|
936 |
|
937 |
$cached = $this->getCachedForm($result);
|
938 |
$cacheDriver->save($hash, $cached, $this->_resultCacheTTL);
|
939 |
return $result;
|
940 |
} else {
|
941 |
return $this->_constructQueryFromCache($cached);
|
942 |
}
|
943 |
} else {
|
944 |
$stmt = $this->_execute($params);
|
945 |
|
946 |
if (is_integer($stmt)) {
|
947 |
return $stmt;
|
948 |
}
|
949 |
|
950 |
$this->_hydrator->setQueryComponents($this->_queryComponents);
|
951 |
return $this->_hydrator->hydrateResultSet($stmt, $this->_tableAliasMap, $hydrationMode);
|
952 |
}
|
953 |
}
|
954 |
|
955 |
/**
|
956 |
* Constructs the query from the cached form.
|
957 |
*
|
958 |
* @param string The cached query, in a serialized form.
|
959 |
* @return array The custom component that was cached together with the essential
|
960 |
* query data. This can be either a result set (result caching)
|
961 |
* or an SQL query string (query caching).
|
962 |
*/
|
963 |
protected function _constructQueryFromCache($cached)
|
964 |
{
|
965 |
$cached = unserialize($cached);
|
966 |
$this->_tableAliasMap = $cached[2];
|
967 |
$customComponent = $cached[0];
|
968 |
|
969 |
$queryComponents = array();
|
970 |
$cachedComponents = $cached[1];
|
971 |
foreach ($cachedComponents as $alias => $components) {
|
972 |
$e = explode('.', $components[0]);
|
973 |
if (count($e) === 1) {
|
974 |
$queryComponents[$alias]['table'] = $this->_conn->getTable($e[0]);
|
975 |
} else {
|
976 |
$queryComponents[$alias]['parent'] = $e[0];
|
977 |
$queryComponents[$alias]['relation'] = $queryComponents[$e[0]]['table']->getRelation($e[1]);
|
978 |
$queryComponents[$alias]['table'] = $queryComponents[$alias]['relation']->getTable();
|
979 |
}
|
980 |
if (isset($v[1])) {
|
981 |
$queryComponents[$alias]['agg'] = $components[1];
|
982 |
}
|
983 |
if (isset($v[2])) {
|
984 |
$queryComponents[$alias]['map'] = $components[2];
|
985 |
}
|
986 |
}
|
987 |
$this->_queryComponents = $queryComponents;
|
988 |
|
989 |
return $customComponent;
|
990 |
}
|
991 |
|
992 |
/**
|
993 |
* getCachedForm
|
994 |
* returns the cached form of this query for given resultSet
|
995 |
*
|
996 |
* @param array $resultSet
|
997 |
* @return string serialized string representation of this query
|
998 |
*/
|
999 |
public function getCachedForm($customComponent = null)
|
1000 |
{
|
1001 |
$componentInfo = array();
|
1002 |
|
1003 |
foreach ($this->getQueryComponents() as $alias => $components) {
|
1004 |
if ( ! isset($components['parent'])) {
|
1005 |
$componentInfo[$alias][] = $components['table']->getComponentName();
|
1006 |
} else {
|
1007 |
$componentInfo[$alias][] = $components['parent'] . '.' . $components['relation']->getAlias();
|
1008 |
}
|
1009 |
if (isset($components['agg'])) {
|
1010 |
$componentInfo[$alias][] = $components['agg'];
|
1011 |
}
|
1012 |
if (isset($components['map'])) {
|
1013 |
$componentInfo[$alias][] = $components['map'];
|
1014 |
}
|
1015 |
}
|
1016 |
|
1017 |
return serialize(array($customComponent, $componentInfo, $this->getTableAliasMap()));
|
1018 |
}
|
1019 |
|
1020 |
/**
|
1021 |
* addSelect
|
1022 |
* adds fields to the SELECT part of the query
|
1023 |
*
|
1024 |
* @param string $select Query SELECT part
|
1025 |
* @return Doctrine_Query
|
1026 |
*/
|
1027 |
public function addSelect($select)
|
1028 |
{
|
1029 |
return $this->_addDqlQueryPart('select', $select, true);
|
1030 |
}
|
1031 |
|
1032 |
/**
|
1033 |
* addTableAlias
|
1034 |
* adds an alias for table and associates it with given component alias
|
1035 |
*
|
1036 |
* @param string $componentAlias the alias for the query component associated with given tableAlias
|
1037 |
* @param string $tableAlias the table alias to be added
|
1038 |
* @return Doctrine_Hydrate
|
1039 |
* @deprecated
|
1040 |
*/
|
1041 |
public function addTableAlias($tableAlias, $componentAlias)
|
1042 |
{
|
1043 |
return $this->addSqlTableAlias($tableAlias, $componentAlias);
|
1044 |
}
|
1045 |
|
1046 |
/**
|
1047 |
* addSqlTableAlias
|
1048 |
* adds an SQL table alias and associates it a component alias
|
1049 |
*
|
1050 |
* @param string $componentAlias the alias for the query component associated with given tableAlias
|
1051 |
* @param string $tableAlias the table alias to be added
|
1052 |
* @return Doctrine_Query_Abstract
|
1053 |
*/
|
1054 |
public function addSqlTableAlias($sqlTableAlias, $componentAlias)
|
1055 |
{
|
1056 |
$this->_tableAliasMap[$sqlTableAlias] = $componentAlias;
|
1057 |
return $this;
|
1058 |
}
|
1059 |
|
1060 |
/**
|
1061 |
* addFrom
|
1062 |
* adds fields to the FROM part of the query
|
1063 |
*
|
1064 |
* @param string $from Query FROM part
|
1065 |
* @return Doctrine_Query
|
1066 |
*/
|
1067 |
public function addFrom($from)
|
1068 |
{
|
1069 |
return $this->_addDqlQueryPart('from', $from, true);
|
1070 |
}
|
1071 |
|
1072 |
/**
|
1073 |
* addWhere
|
1074 |
* adds conditions to the WHERE part of the query
|
1075 |
*
|
1076 |
* @param string $where Query WHERE part
|
1077 |
* @param mixed $params an array of parameters or a simple scalar
|
1078 |
* @return Doctrine_Query
|
1079 |
*/
|
1080 |
public function addWhere($where, $params = array())
|
1081 |
{
|
1082 |
if (is_array($params)) {
|
1083 |
$this->_params['where'] = array_merge($this->_params['where'], $params);
|
1084 |
} else {
|
1085 |
$this->_params['where'][] = $params;
|
1086 |
}
|
1087 |
return $this->_addDqlQueryPart('where', $where, true);
|
1088 |
}
|
1089 |
|
1090 |
/**
|
1091 |
* whereIn
|
1092 |
* adds IN condition to the query WHERE part
|
1093 |
*
|
1094 |
* @param string $expr the operand of the IN
|
1095 |
* @param mixed $params an array of parameters or a simple scalar
|
1096 |
* @param boolean $not whether or not to use NOT in front of IN
|
1097 |
* @return Doctrine_Query
|
1098 |
*/
|
1099 |
public function whereIn($expr, $params = array(), $not = false)
|
1100 |
{
|
1101 |
$params = (array) $params;
|
1102 |
$a = array();
|
1103 |
foreach ($params as $k => $value) {
|
1104 |
if ($value instanceof Doctrine_Expression) {
|
1105 |
$value = $value->getSql();
|
1106 |
unset($params[$k]);
|
1107 |
} else {
|
1108 |
$value = '?';
|
1109 |
}
|
1110 |
$a[] = $value;
|
1111 |
}
|
1112 |
|
1113 |
$this->_params['where'] = array_merge($this->_params['where'], $params);
|
1114 |
|
1115 |
$where = $expr . ($not === true ? ' NOT ':'') . ' IN (' . implode(', ', $a) . ')';
|
1116 |
|
1117 |
return $this->_addDqlQueryPart('where', $where, true);
|
1118 |
}
|
1119 |
|
1120 |
/**
|
1121 |
* whereNotIn
|
1122 |
* adds NOT IN condition to the query WHERE part
|
1123 |
*
|
1124 |
* @param string $expr the operand of the NOT IN
|
1125 |
* @param mixed $params an array of parameters or a simple scalar
|
1126 |
* @return Doctrine_Query
|
1127 |
*/
|
1128 |
public function whereNotIn($expr, $params = array())
|
1129 |
{
|
1130 |
return $this->whereIn($expr, $params, true);
|
1131 |
}
|
1132 |
|
1133 |
/**
|
1134 |
* addGroupBy
|
1135 |
* adds fields to the GROUP BY part of the query
|
1136 |
*
|
1137 |
* @param string $groupby Query GROUP BY part
|
1138 |
* @return Doctrine_Query
|
1139 |
*/
|
1140 |
public function addGroupBy($groupby)
|
1141 |
{
|
1142 |
return $this->_addDqlQueryPart('groupby', $groupby, true);
|
1143 |
}
|
1144 |
|
1145 |
/**
|
1146 |
* addHaving
|
1147 |
* adds conditions to the HAVING part of the query
|
1148 |
*
|
1149 |
* @param string $having Query HAVING part
|
1150 |
* @param mixed $params an array of parameters or a simple scalar
|
1151 |
* @return Doctrine_Query
|
1152 |
*/
|
1153 |
public function addHaving($having, $params = array())
|
1154 |
{
|
1155 |
if (is_array($params)) {
|
1156 |
$this->_params['having'] = array_merge($this->_params['having'], $params);
|
1157 |
} else {
|
1158 |
$this->_params['having'][] = $params;
|
1159 |
}
|
1160 |
return $this->_addDqlQueryPart('having', $having, true);
|
1161 |
}
|
1162 |
|
1163 |
/**
|
1164 |
* addOrderBy
|
1165 |
* adds fields to the ORDER BY part of the query
|
1166 |
*
|
1167 |
* @param string $orderby Query ORDER BY part
|
1168 |
* @return Doctrine_Query
|
1169 |
*/
|
1170 |
public function addOrderBy($orderby)
|
1171 |
{
|
1172 |
return $this->_addDqlQueryPart('orderby', $orderby, true);
|
1173 |
}
|
1174 |
|
1175 |
/**
|
1176 |
* select
|
1177 |
* sets the SELECT part of the query
|
1178 |
*
|
1179 |
* @param string $select Query SELECT part
|
1180 |
* @return Doctrine_Query
|
1181 |
*/
|
1182 |
public function select($select)
|
1183 |
{
|
1184 |
return $this->_addDqlQueryPart('select', $select);
|
1185 |
}
|
1186 |
|
1187 |
/**
|
1188 |
* distinct
|
1189 |
* Makes the query SELECT DISTINCT.
|
1190 |
*
|
1191 |
* @param bool $flag Whether or not the SELECT is DISTINCT (default true).
|
1192 |
* @return Doctrine_Query
|
1193 |
*/
|
1194 |
public function distinct($flag = true)
|
1195 |
{
|
1196 |
$this->_sqlParts['distinct'] = (bool) $flag;
|
1197 |
return $this;
|
1198 |
}
|
1199 |
|
1200 |
/**
|
1201 |
* forUpdate
|
1202 |
* Makes the query SELECT FOR UPDATE.
|
1203 |
*
|
1204 |
* @param bool $flag Whether or not the SELECT is FOR UPDATE (default true).
|
1205 |
* @return Doctrine_Query
|
1206 |
*/
|
1207 |
public function forUpdate($flag = true)
|
1208 |
{
|
1209 |
$this->_sqlParts[self::FOR_UPDATE] = (bool) $flag;
|
1210 |
return $this;
|
1211 |
}
|
1212 |
|
1213 |
/**
|
1214 |
* delete
|
1215 |
* sets the query type to DELETE
|
1216 |
*
|
1217 |
* @return Doctrine_Query
|
1218 |
*/
|
1219 |
public function delete()
|
1220 |
{
|
1221 |
$this->_type = self::DELETE;
|
1222 |
return $this;
|
1223 |
}
|
1224 |
|
1225 |
/**
|
1226 |
* update
|
1227 |
* sets the UPDATE part of the query
|
1228 |
*
|
1229 |
* @param string $update Query UPDATE part
|
1230 |
* @return Doctrine_Query
|
1231 |
*/
|
1232 |
public function update($update)
|
1233 |
{
|
1234 |
$this->_type = self::UPDATE;
|
1235 |
return $this->_addDqlQueryPart('from', $update);
|
1236 |
}
|
1237 |
|
1238 |
/**
|
1239 |
* set
|
1240 |
* sets the SET part of the query
|
1241 |
*
|
1242 |
* @param string $update Query UPDATE part
|
1243 |
* @return Doctrine_Query
|
1244 |
*/
|
1245 |
public function set($key, $value, $params = null)
|
1246 |
{
|
1247 |
if (is_array($key)) {
|
1248 |
foreach ($key as $k => $v) {
|
1249 |
$this->set($k, '?', array($v));
|
1250 |
}
|
1251 |
return $this;
|
1252 |
} else {
|
1253 |
if ($params !== null) {
|
1254 |
if (is_array($params)) {
|
1255 |
$this->_params['set'] = array_merge($this->_params['set'], $params);
|
1256 |
} else {
|
1257 |
$this->_params['set'][] = $params;
|
1258 |
}
|
1259 |
}
|
1260 |
return $this->_addDqlQueryPart('set', $key . ' = ' . $value, true);
|
1261 |
}
|
1262 |
}
|
1263 |
|
1264 |
/**
|
1265 |
* from
|
1266 |
* sets the FROM part of the query
|
1267 |
*
|
1268 |
* @param string $from Query FROM part
|
1269 |
* @return Doctrine_Query
|
1270 |
*/
|
1271 |
public function from($from)
|
1272 |
{
|
1273 |
return $this->_addDqlQueryPart('from', $from);
|
1274 |
}
|
1275 |
|
1276 |
/**
|
1277 |
* innerJoin
|
1278 |
* appends an INNER JOIN to the FROM part of the query
|
1279 |
*
|
1280 |
* @param string $join Query INNER JOIN
|
1281 |
* @return Doctrine_Query
|
1282 |
*/
|
1283 |
public function innerJoin($join)
|
1284 |
{
|
1285 |
return $this->_addDqlQueryPart('from', 'INNER JOIN ' . $join, true);
|
1286 |
}
|
1287 |
|
1288 |
/**
|
1289 |
* leftJoin
|
1290 |
* appends a LEFT JOIN to the FROM part of the query
|
1291 |
*
|
1292 |
* @param string $join Query LEFT JOIN
|
1293 |
* @return Doctrine_Query
|
1294 |
*/
|
1295 |
public function leftJoin($join)
|
1296 |
{
|
1297 |
return $this->_addDqlQueryPart('from', 'LEFT JOIN ' . $join, true);
|
1298 |
}
|
1299 |
|
1300 |
/**
|
1301 |
* groupBy
|
1302 |
* sets the GROUP BY part of the query
|
1303 |
*
|
1304 |
* @param string $groupby Query GROUP BY part
|
1305 |
* @return Doctrine_Query
|
1306 |
*/
|
1307 |
public function groupBy($groupby)
|
1308 |
{
|
1309 |
return $this->_addDqlQueryPart('groupby', $groupby);
|
1310 |
}
|
1311 |
|
1312 |
/**
|
1313 |
* where
|
1314 |
* sets the WHERE part of the query
|
1315 |
*
|
1316 |
* @param string $join Query WHERE part
|
1317 |
* @param mixed $params an array of parameters or a simple scalar
|
1318 |
* @return Doctrine_Query
|
1319 |
*/
|
1320 |
public function where($where, $params = array())
|
1321 |
{
|
1322 |
$this->_params['where'] = array();
|
1323 |
if (is_array($params)) {
|
1324 |
$this->_params['where'] = $params;
|
1325 |
} else {
|
1326 |
$this->_params['where'][] = $params;
|
1327 |
}
|
1328 |
|
1329 |
return $this->_addDqlQueryPart('where', $where);
|
1330 |
}
|
1331 |
|
1332 |
/**
|
1333 |
* having
|
1334 |
* sets the HAVING part of the query
|
1335 |
*
|
1336 |
* @param string $having Query HAVING part
|
1337 |
* @param mixed $params an array of parameters or a simple scalar
|
1338 |
* @return Doctrine_Query
|
1339 |
*/
|
1340 |
public function having($having, $params = array())
|
1341 |
{
|
1342 |
$this->_params['having'] = array();
|
1343 |
if (is_array($params)) {
|
1344 |
$this->_params['having'] = $params;
|
1345 |
} else {
|
1346 |
$this->_params['having'][] = $params;
|
1347 |
}
|
1348 |
|
1349 |
return $this->_addDqlQueryPart('having', $having);
|
1350 |
}
|
1351 |
|
1352 |
/**
|
1353 |
* orderBy
|
1354 |
* sets the ORDER BY part of the query
|
1355 |
*
|
1356 |
* @param string $orderby Query ORDER BY part
|
1357 |
* @return Doctrine_Query
|
1358 |
*/
|
1359 |
public function orderBy($orderby)
|
1360 |
{
|
1361 |
return $this->_addDqlQueryPart('orderby', $orderby);
|
1362 |
}
|
1363 |
|
1364 |
/**
|
1365 |
* limit
|
1366 |
* sets the Query query limit
|
1367 |
*
|
1368 |
* @param integer $limit limit to be used for limiting the query results
|
1369 |
* @return Doctrine_Query
|
1370 |
*/
|
1371 |
public function limit($limit)
|
1372 |
{
|
1373 |
return $this->_addDqlQueryPart('limit', $limit);
|
1374 |
}
|
1375 |
|
1376 |
/**
|
1377 |
* offset
|
1378 |
* sets the Query query offset
|
1379 |
*
|
1380 |
* @param integer $offset offset to be used for paginating the query
|
1381 |
* @return Doctrine_Query
|
1382 |
*/
|
1383 |
public function offset($offset)
|
1384 |
{
|
1385 |
return $this->_addDqlQueryPart('offset', $offset);
|
1386 |
}
|
1387 |
|
1388 |
/**
|
1389 |
* getSql
|
1390 |
* shortcut for {@link getSqlQuery()}.
|
1391 |
*
|
1392 |
* @return string sql query string
|
1393 |
*/
|
1394 |
public function getSql()
|
1395 |
{
|
1396 |
return $this->getSqlQuery();
|
1397 |
}
|
1398 |
|
1399 |
/**
|
1400 |
* clear
|
1401 |
* resets all the variables
|
1402 |
*
|
1403 |
* @return void
|
1404 |
*/
|
1405 |
protected function clear()
|
1406 |
{
|
1407 |
$this->_sqlParts = array(
|
1408 |
'select' => array(),
|
1409 |
'distinct' => false,
|
1410 |
'forUpdate' => false,
|
1411 |
'from' => array(),
|
1412 |
'set' => array(),
|
1413 |
'join' => array(),
|
1414 |
'where' => array(),
|
1415 |
'groupby' => array(),
|
1416 |
'having' => array(),
|
1417 |
'orderby' => array(),
|
1418 |
'limit' => false,
|
1419 |
'offset' => false,
|
1420 |
);
|
1421 |
}
|
1422 |
|
1423 |
public function setHydrationMode($hydrationMode)
|
1424 |
{
|
1425 |
$this->_hydrator->setHydrationMode($hydrationMode);
|
1426 |
return $this;
|
1427 |
}
|
1428 |
|
1429 |
/**
|
1430 |
* @deprecated
|
1431 |
*/
|
1432 |
public function getAliasMap()
|
1433 |
{
|
1434 |
return $this->_queryComponents;
|
1435 |
}
|
1436 |
|
1437 |
/**
|
1438 |
* Gets the components of this query.
|
1439 |
*/
|
1440 |
public function getQueryComponents()
|
1441 |
{
|
1442 |
return $this->_queryComponents;
|
1443 |
}
|
1444 |
|
1445 |
/**
|
1446 |
* Return the SQL parts.
|
1447 |
*
|
1448 |
* @return array The parts
|
1449 |
* @deprecated
|
1450 |
*/
|
1451 |
public function getParts()
|
1452 |
{
|
1453 |
return $this->getSqlParts();
|
1454 |
}
|
1455 |
|
1456 |
/**
|
1457 |
* Return the SQL parts.
|
1458 |
*
|
1459 |
* @return array The parts
|
1460 |
*/
|
1461 |
public function getSqlParts()
|
1462 |
{
|
1463 |
return $this->_sqlParts;
|
1464 |
}
|
1465 |
|
1466 |
/**
|
1467 |
* getType
|
1468 |
*
|
1469 |
* returns the type of this query object
|
1470 |
* by default the type is Doctrine_Query_Abstract::SELECT but if update() or delete()
|
1471 |
* are being called the type is Doctrine_Query_Abstract::UPDATE and Doctrine_Query_Abstract::DELETE,
|
1472 |
* respectively
|
1473 |
*
|
1474 |
* @see Doctrine_Query_Abstract::SELECT
|
1475 |
* @see Doctrine_Query_Abstract::UPDATE
|
1476 |
* @see Doctrine_Query_Abstract::DELETE
|
1477 |
*
|
1478 |
* @return integer return the query type
|
1479 |
*/
|
1480 |
public function getType()
|
1481 |
{
|
1482 |
return $this->_type;
|
1483 |
}
|
1484 |
|
1485 |
/**
|
1486 |
* useCache
|
1487 |
*
|
1488 |
* @param Doctrine_Cache_Interface|bool $driver cache driver
|
1489 |
* @param integer $timeToLive how long the cache entry is valid
|
1490 |
* @return Doctrine_Hydrate this object
|
1491 |
* @deprecated Use useResultCache()
|
1492 |
*/
|
1493 |
public function useCache($driver = true, $timeToLive = null)
|
1494 |
{
|
1495 |
return $this->useResultCache($driver, $timeToLive);
|
1496 |
}
|
1497 |
|
1498 |
/**
|
1499 |
* useResultCache
|
1500 |
*
|
1501 |
* @param Doctrine_Cache_Interface|bool $driver cache driver
|
1502 |
* @param integer $timeToLive how long the cache entry is valid
|
1503 |
* @return Doctrine_Hydrate this object
|
1504 |
*/
|
1505 |
public function useResultCache($driver = true, $timeToLive = null)
|
1506 |
{
|
1507 |
if ($driver !== null && $driver !== true && ! ($driver instanceOf Doctrine_Cache_Interface)){
|
1508 |
$msg = 'First argument should be instance of Doctrine_Cache_Interface or null.';
|
1509 |
throw new Doctrine_Query_Exception($msg);
|
1510 |
}
|
1511 |
$this->_resultCache = $driver;
|
1512 |
|
1513 |
return $this->setResultCacheLifeSpan($timeToLive);
|
1514 |
}
|
1515 |
|
1516 |
/**
|
1517 |
* useQueryCache
|
1518 |
*
|
1519 |
* @param Doctrine_Cache_Interface|bool $driver cache driver
|
1520 |
* @param integer $timeToLive how long the cache entry is valid
|
1521 |
* @return Doctrine_Hydrate this object
|
1522 |
*/
|
1523 |
public function useQueryCache(Doctrine_Cache_Interface $driver, $timeToLive = null)
|
1524 |
{
|
1525 |
$this->_queryCache = $driver;
|
1526 |
return $this->setQueryCacheLifeSpan($timeToLive);
|
1527 |
}
|
1528 |
|
1529 |
/**
|
1530 |
* expireCache
|
1531 |
*
|
1532 |
* @param boolean $expire whether or not to force cache expiration
|
1533 |
* @return Doctrine_Hydrate this object
|
1534 |
* @deprecated Use expireResultCache()
|
1535 |
*/
|
1536 |
public function expireCache($expire = true)
|
1537 |
{
|
1538 |
return $this->expireResultCache($expire);
|
1539 |
}
|
1540 |
|
1541 |
/**
|
1542 |
* expireCache
|
1543 |
*
|
1544 |
* @param boolean $expire whether or not to force cache expiration
|
1545 |
* @return Doctrine_Hydrate this object
|
1546 |
*/
|
1547 |
public function expireResultCache($expire = true)
|
1548 |
{
|
1549 |
$this->_expireResultCache = true;
|
1550 |
return $this;
|
1551 |
}
|
1552 |
|
1553 |
/**
|
1554 |
* expireQueryCache
|
1555 |
*
|
1556 |
* @param boolean $expire whether or not to force cache expiration
|
1557 |
* @return Doctrine_Hydrate this object
|
1558 |
*/
|
1559 |
public function expireQueryCache($expire = true)
|
1560 |
{
|
1561 |
$this->_expireQueryCache = true;
|
1562 |
return $this;
|
1563 |
}
|
1564 |
|
1565 |
/**
|
1566 |
* setCacheLifeSpan
|
1567 |
*
|
1568 |
* @param integer $timeToLive how long the cache entry is valid
|
1569 |
* @return Doctrine_Hydrate this object
|
1570 |
* @deprecated Use setResultCacheLifeSpan()
|
1571 |
*/
|
1572 |
public function setCacheLifeSpan($timeToLive)
|
1573 |
{
|
1574 |
return $this->setResultCacheLifeSpan($timeToLive);
|
1575 |
}
|
1576 |
|
1577 |
/**
|
1578 |
* setResultCacheLifeSpan
|
1579 |
*
|
1580 |
* @param integer $timeToLive how long the cache entry is valid
|
1581 |
* @return Doctrine_Hydrate this object
|
1582 |
*/
|
1583 |
public function setResultCacheLifeSpan($timeToLive)
|
1584 |
{
|
1585 |
if ($timeToLive !== null) {
|
1586 |
$timeToLive = (int) $timeToLive;
|
1587 |
}
|
1588 |
$this->_resultCacheTTL = $timeToLive;
|
1589 |
|
1590 |
return $this;
|
1591 |
}
|
1592 |
|
1593 |
/**
|
1594 |
* setQueryCacheLifeSpan
|
1595 |
*
|
1596 |
* @param integer $timeToLive how long the cache entry is valid
|
1597 |
* @return Doctrine_Hydrate this object
|
1598 |
*/
|
1599 |
public function setQueryCacheLifeSpan($timeToLive)
|
1600 |
{
|
1601 |
if ($timeToLive !== null) {
|
1602 |
$timeToLive = (int) $timeToLive;
|
1603 |
}
|
1604 |
$this->_queryCacheTTL = $timeToLive;
|
1605 |
|
1606 |
return $this;
|
1607 |
}
|
1608 |
|
1609 |
/**
|
1610 |
* getCacheDriver
|
1611 |
* returns the cache driver associated with this object
|
1612 |
*
|
1613 |
* @return Doctrine_Cache_Interface|boolean|null cache driver
|
1614 |
* @deprecated Use getResultCacheDriver()
|
1615 |
*/
|
1616 |
public function getCacheDriver()
|
1617 |
{
|
1618 |
return $this->getResultCacheDriver();
|
1619 |
}
|
1620 |
|
1621 |
/**
|
1622 |
* getResultCacheDriver
|
1623 |
* returns the cache driver used for caching result sets
|
1624 |
*
|
1625 |
* @return Doctrine_Cache_Interface|boolean|null cache driver
|
1626 |
*/
|
1627 |
public function getResultCacheDriver()
|
1628 |
{
|
1629 |
if ($this->_resultCache instanceof Doctrine_Cache_Interface) {
|
1630 |
return $this->_resultCache;
|
1631 |
} else {
|
1632 |
return $this->_conn->getResultCacheDriver();
|
1633 |
}
|
1634 |
}
|
1635 |
|
1636 |
/**
|
1637 |
* getQueryCacheDriver
|
1638 |
* returns the cache driver used for caching queries
|
1639 |
*
|
1640 |
* @return Doctrine_Cache_Interface|boolean|null cache driver
|
1641 |
*/
|
1642 |
public function getQueryCacheDriver()
|
1643 |
{
|
1644 |
if ($this->_queryCache instanceof Doctrine_Cache_Interface) {
|
1645 |
return $this->_queryCache;
|
1646 |
} else {
|
1647 |
return $this->_conn->getQueryCacheDriver();
|
1648 |
}
|
1649 |
}
|
1650 |
|
1651 |
/**
|
1652 |
* getConnection
|
1653 |
*
|
1654 |
* @return Doctrine_Connection
|
1655 |
*/
|
1656 |
public function getConnection()
|
1657 |
{
|
1658 |
return $this->_conn;
|
1659 |
}
|
1660 |
|
1661 |
/**
|
1662 |
* Adds a DQL part to the internal parts collection.
|
1663 |
*
|
1664 |
* @param string $queryPartName The name of the query part.
|
1665 |
* @param string $queryPart The actual query part to add.
|
1666 |
* @param boolean $append Whether to append $queryPart to already existing
|
1667 |
* parts under the same $queryPartName. Defaults to FALSE
|
1668 |
* (previously added parts with the same name get overridden).
|
1669 |
*/
|
1670 |
protected function _addDqlQueryPart($queryPartName, $queryPart, $append = false)
|
1671 |
{
|
1672 |
if ($append) {
|
1673 |
$this->_dqlParts[$queryPartName][] = $queryPart;
|
1674 |
} else {
|
1675 |
$this->_dqlParts[$queryPartName] = array($queryPart);
|
1676 |
}
|
1677 |
|
1678 |
$this->_state = Doctrine_Query::STATE_DIRTY;
|
1679 |
return $this;
|
1680 |
}
|
1681 |
|
1682 |
/**
|
1683 |
* _processDqlQueryPart
|
1684 |
* parses given query part
|
1685 |
*
|
1686 |
* @param string $queryPartName the name of the query part
|
1687 |
* @param array $queryParts an array containing the query part data
|
1688 |
* @return Doctrine_Query this object
|
1689 |
* @todo Better description. "parses given query part" ??? Then wheres the difference
|
1690 |
* between process/parseQueryPart? I suppose this does something different.
|
1691 |
*/
|
1692 |
protected function _processDqlQueryPart($queryPartName, $queryParts)
|
1693 |
{
|
1694 |
$this->removeSqlQueryPart($queryPartName);
|
1695 |
|
1696 |
if (is_array($queryParts) && ! empty($queryParts)) {
|
1697 |
foreach ($queryParts as $queryPart) {
|
1698 |
$parser = $this->_getParser($queryPartName);
|
1699 |
$sql = $parser->parse($queryPart);
|
1700 |
if (isset($sql)) {
|
1701 |
if ($queryPartName == 'limit' || $queryPartName == 'offset') {
|
1702 |
$this->setSqlQueryPart($queryPartName, $sql);
|
1703 |
} else {
|
1704 |
$this->addSqlQueryPart($queryPartName, $sql);
|
1705 |
}
|
1706 |
}
|
1707 |
}
|
1708 |
}
|
1709 |
}
|
1710 |
|
1711 |
/**
|
1712 |
* _getParser
|
1713 |
* parser lazy-loader
|
1714 |
*
|
1715 |
* @throws Doctrine_Query_Exception if unknown parser name given
|
1716 |
* @return Doctrine_Query_Part
|
1717 |
* @todo Doc/Description: What is the parameter for? Which parsers are available?
|
1718 |
*/
|
1719 |
protected function _getParser($name)
|
1720 |
{
|
1721 |
if ( ! isset($this->_parsers[$name])) {
|
1722 |
$class = 'Doctrine_Query_' . ucwords(strtolower($name));
|
1723 |
|
1724 |
Doctrine::autoload($class);
|
1725 |
|
1726 |
if ( ! class_exists($class)) {
|
1727 |
throw new Doctrine_Query_Exception('Unknown parser ' . $name);
|
1728 |
}
|
1729 |
|
1730 |
$this->_parsers[$name] = new $class($this, $this->_tokenizer);
|
1731 |
}
|
1732 |
|
1733 |
return $this->_parsers[$name];
|
1734 |
}
|
1735 |
|
1736 |
/**
|
1737 |
* Gets the SQL query that corresponds to this query object.
|
1738 |
* The returned SQL syntax depends on the connection driver that is used
|
1739 |
* by this query object at the time of this method call.
|
1740 |
*
|
1741 |
* @param array $params
|
1742 |
*/
|
1743 |
abstract public function getSqlQuery($params = array());
|
1744 |
|
1745 |
/**
|
1746 |
* parseDqlQuery
|
1747 |
* parses a dql query
|
1748 |
*
|
1749 |
* @param string $query query to be parsed
|
1750 |
* @return Doctrine_Query_Abstract this object
|
1751 |
*/
|
1752 |
abstract public function parseDqlQuery($query);
|
1753 |
|
1754 |
/**
|
1755 |
* @deprecated
|
1756 |
*/
|
1757 |
public function parseQuery($query)
|
1758 |
{
|
1759 |
return $this->parseDqlQuery($query);
|
1760 |
}
|
1761 |
|
1762 |
/**
|
1763 |
* @deprecated
|
1764 |
*/
|
1765 |
public function getQuery($params = array())
|
1766 |
{
|
1767 |
return $this->getSqlQuery($params);
|
1768 |
}
|
1769 |
}
|