source: pro-violet-viettel/sourcecode/application/libraries/Doctrine/ORM/QueryBuilder.php @ 353

Last change on this file since 353 was 345, checked in by quyenla, 11 years ago

collaborator page

File size: 32.6 KB
Line 
1<?php
2/*
3 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14 *
15 * This software consists of voluntary contributions made by many individuals
16 * and is licensed under the LGPL. For more information, see
17 * <http://www.doctrine-project.org>.
18 */
19
20namespace Doctrine\ORM;
21
22use Doctrine\ORM\Query\Expr;
23
24/**
25 * This class is responsible for building DQL query strings via an object oriented
26 * PHP interface.
27 *
28 * @since 2.0
29 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
30 * @author Jonathan Wage <jonwage@gmail.com>
31 * @author Roman Borschel <roman@code-factory.org>
32 */
33class QueryBuilder
34{
35    /* The query types. */
36    const SELECT = 0;
37    const DELETE = 1;
38    const UPDATE = 2;
39
40    /** The builder states. */
41    const STATE_DIRTY = 0;
42    const STATE_CLEAN = 1;
43
44    /**
45     * @var EntityManager The EntityManager used by this QueryBuilder.
46     */
47    private $_em;
48
49    /**
50     * @var array The array of DQL parts collected.
51     */
52    private $_dqlParts = array(
53        'distinct' => false,
54        'select'  => array(),
55        'from'    => array(),
56        'join'    => array(),
57        'set'     => array(),
58        'where'   => null,
59        'groupBy' => array(),
60        'having'  => null,
61        'orderBy' => array()
62    );
63
64    /**
65     * @var integer The type of query this is. Can be select, update or delete.
66     */
67    private $_type = self::SELECT;
68
69    /**
70     * @var integer The state of the query object. Can be dirty or clean.
71     */
72    private $_state = self::STATE_CLEAN;
73
74    /**
75     * @var string The complete DQL string for this query.
76     */
77    private $_dql;
78
79    /**
80     * @var array The query parameters.
81     */
82    private $_params = array();
83
84    /**
85     * @var array The parameter type map of this query.
86     */
87    private $_paramTypes = array();
88
89    /**
90     * @var integer The index of the first result to retrieve.
91     */
92    private $_firstResult = null;
93
94    /**
95     * @var integer The maximum number of results to retrieve.
96     */
97    private $_maxResults = null;
98
99    /**
100     * Initializes a new <tt>QueryBuilder</tt> that uses the given <tt>EntityManager</tt>.
101     *
102     * @param EntityManager $em The EntityManager to use.
103     */
104    public function __construct(EntityManager $em)
105    {
106        $this->_em = $em;
107    }
108
109    /**
110     * Gets an ExpressionBuilder used for object-oriented construction of query expressions.
111     * This producer method is intended for convenient inline usage. Example:
112     *
113     * <code>
114     *     $qb = $em->createQueryBuilder()
115     *         ->select('u')
116     *         ->from('User', 'u')
117     *         ->where($qb->expr()->eq('u.id', 1));
118     * </code>
119     *
120     * For more complex expression construction, consider storing the expression
121     * builder object in a local variable.
122     *
123     * @return Query\Expr
124     */
125    public function expr()
126    {
127        return $this->_em->getExpressionBuilder();
128    }
129
130    /**
131     * Get the type of the currently built query.
132     *
133     * @return integer
134     */
135    public function getType()
136    {
137        return $this->_type;
138    }
139
140    /**
141     * Get the associated EntityManager for this query builder.
142     *
143     * @return EntityManager
144     */
145    public function getEntityManager()
146    {
147        return $this->_em;
148    }
149
150    /**
151     * Get the state of this query builder instance.
152     *
153     * @return integer Either QueryBuilder::STATE_DIRTY or QueryBuilder::STATE_CLEAN.
154     */
155    public function getState()
156    {
157        return $this->_state;
158    }
159
160    /**
161     * Get the complete DQL string formed by the current specifications of this QueryBuilder.
162     *
163     * <code>
164     *     $qb = $em->createQueryBuilder()
165     *         ->select('u')
166     *         ->from('User', 'u')
167     *     echo $qb->getDql(); // SELECT u FROM User u
168     * </code>
169     *
170     * @return string The DQL query string.
171     */
172    public function getDQL()
173    {
174        if ($this->_dql !== null && $this->_state === self::STATE_CLEAN) {
175            return $this->_dql;
176        }
177
178        $dql = '';
179
180        switch ($this->_type) {
181            case self::DELETE:
182                $dql = $this->_getDQLForDelete();
183                break;
184
185            case self::UPDATE:
186                $dql = $this->_getDQLForUpdate();
187                break;
188
189            case self::SELECT:
190            default:
191                $dql = $this->_getDQLForSelect();
192                break;
193        }
194
195        $this->_state = self::STATE_CLEAN;
196        $this->_dql = $dql;
197
198        return $dql;
199    }
200
201    /**
202     * Constructs a Query instance from the current specifications of the builder.
203     *
204     * <code>
205     *     $qb = $em->createQueryBuilder()
206     *         ->select('u')
207     *         ->from('User', 'u');
208     *     $q = $qb->getQuery();
209     *     $results = $q->execute();
210     * </code>
211     *
212     * @return Query
213     */
214    public function getQuery()
215    {
216        return $this->_em->createQuery($this->getDQL())
217                ->setParameters($this->_params, $this->_paramTypes)
218                ->setFirstResult($this->_firstResult)
219                ->setMaxResults($this->_maxResults);
220    }
221
222    /**
223     * Gets the FIRST root alias of the query. This is the first entity alias involved
224     * in the construction of the query.
225     *
226     * <code>
227     * $qb = $em->createQueryBuilder()
228     * ->select('u')
229     * ->from('User', 'u');
230     *
231     * echo $qb->getRootAlias(); // u
232     * </code>
233     *
234     * @deprecated Please use $qb->getRootAliases() instead.
235     * @return string $rootAlias
236     */
237    public function getRootAlias()
238    {
239        $aliases = $this->getRootAliases();
240        return $aliases[0];
241    }
242
243    /**
244     * Gets the root aliases of the query. This is the entity aliases involved
245     * in the construction of the query.
246     *
247     * <code>
248     *     $qb = $em->createQueryBuilder()
249     *         ->select('u')
250     *         ->from('User', 'u');
251     *
252     *     $qb->getRootAliases(); // array('u')
253     * </code>
254     *
255     * @return array $rootAliases
256     */
257    public function getRootAliases()
258    {
259        $aliases = array();
260
261        foreach ($this->_dqlParts['from'] as &$fromClause) {
262            if (is_string($fromClause)) {
263                $spacePos = strrpos($fromClause, ' ');
264                $from     = substr($fromClause, 0, $spacePos);
265                $alias    = substr($fromClause, $spacePos + 1);
266
267                $fromClause = new Query\Expr\From($from, $alias);
268            }
269
270            $aliases[] = $fromClause->getAlias();
271        }
272
273        return $aliases;
274    }
275
276    /**
277     * Gets the root entities of the query. This is the entity aliases involved
278     * in the construction of the query.
279     *
280     * <code>
281     *     $qb = $em->createQueryBuilder()
282     *         ->select('u')
283     *         ->from('User', 'u');
284     *
285     *     $qb->getRootEntities(); // array('User')
286     * </code>
287     *
288     * @return array $rootEntities
289     */
290    public function getRootEntities()
291    {
292        $entities = array();
293
294        foreach ($this->_dqlParts['from'] as &$fromClause) {
295            if (is_string($fromClause)) {
296                $spacePos = strrpos($fromClause, ' ');
297                $from     = substr($fromClause, 0, $spacePos);
298                $alias    = substr($fromClause, $spacePos + 1);
299
300                $fromClause = new Query\Expr\From($from, $alias);
301            }
302
303            $entities[] = $fromClause->getFrom();
304        }
305
306        return $entities;
307    }
308
309    /**
310     * Sets a query parameter for the query being constructed.
311     *
312     * <code>
313     *     $qb = $em->createQueryBuilder()
314     *         ->select('u')
315     *         ->from('User', 'u')
316     *         ->where('u.id = :user_id')
317     *         ->setParameter('user_id', 1);
318     * </code>
319     *
320     * @param string|integer $key The parameter position or name.
321     * @param mixed $value The parameter value.
322     * @param string|null $type PDO::PARAM_* or \Doctrine\DBAL\Types\Type::* constant
323     * @return QueryBuilder This QueryBuilder instance.
324     */
325    public function setParameter($key, $value, $type = null)
326    {
327        $key = trim($key, ':');
328
329        if ($type === null) {
330            $type = Query\ParameterTypeInferer::inferType($value);
331        }
332
333        $this->_paramTypes[$key] = $type;
334        $this->_params[$key] = $value;
335
336        return $this;
337    }
338
339    /**
340     * Sets a collection of query parameters for the query being constructed.
341     *
342     * <code>
343     *     $qb = $em->createQueryBuilder()
344     *         ->select('u')
345     *         ->from('User', 'u')
346     *         ->where('u.id = :user_id1 OR u.id = :user_id2')
347     *         ->setParameters(array(
348     *             'user_id1' => 1,
349     *             'user_id2' => 2
350              ));
351     * </code>
352     *
353     * @param array $params The query parameters to set.
354     * @return QueryBuilder This QueryBuilder instance.
355     */
356    public function setParameters(array $params, array $types = array())
357    {
358        foreach ($params as $key => $value) {
359            $this->setParameter($key, $value, isset($types[$key]) ? $types[$key] : null);
360        }
361
362        return $this;
363    }
364
365    /**
366     * Gets all defined query parameters for the query being constructed.
367     *
368     * @return array The currently defined query parameters.
369     */
370    public function getParameters()
371    {
372        return $this->_params;
373    }
374
375    /**
376     * Gets a (previously set) query parameter of the query being constructed.
377     *
378     * @param mixed $key The key (index or name) of the bound parameter.
379     * @return mixed The value of the bound parameter.
380     */
381    public function getParameter($key)
382    {
383        return isset($this->_params[$key]) ? $this->_params[$key] : null;
384    }
385
386    /**
387     * Sets the position of the first result to retrieve (the "offset").
388     *
389     * @param integer $firstResult The first result to return.
390     * @return QueryBuilder This QueryBuilder instance.
391     */
392    public function setFirstResult($firstResult)
393    {
394        $this->_firstResult = $firstResult;
395
396        return $this;
397    }
398
399    /**
400     * Gets the position of the first result the query object was set to retrieve (the "offset").
401     * Returns NULL if {@link setFirstResult} was not applied to this QueryBuilder.
402     *
403     * @return integer The position of the first result.
404     */
405    public function getFirstResult()
406    {
407        return $this->_firstResult;
408    }
409
410    /**
411     * Sets the maximum number of results to retrieve (the "limit").
412     *
413     * @param integer $maxResults The maximum number of results to retrieve.
414     * @return QueryBuilder This QueryBuilder instance.
415     */
416    public function setMaxResults($maxResults)
417    {
418        $this->_maxResults = $maxResults;
419
420        return $this;
421    }
422
423    /**
424     * Gets the maximum number of results the query object was set to retrieve (the "limit").
425     * Returns NULL if {@link setMaxResults} was not applied to this query builder.
426     *
427     * @return integer Maximum number of results.
428     */
429    public function getMaxResults()
430    {
431        return $this->_maxResults;
432    }
433
434    /**
435     * Either appends to or replaces a single, generic query part.
436     *
437     * The available parts are: 'select', 'from', 'join', 'set', 'where',
438     * 'groupBy', 'having' and 'orderBy'.
439     *
440     * @param string $dqlPartName
441     * @param string $dqlPart
442     * @param string $append
443     * @return QueryBuilder This QueryBuilder instance.
444     */
445    public function add($dqlPartName, $dqlPart, $append = false)
446    {
447        $isMultiple = is_array($this->_dqlParts[$dqlPartName]);
448
449        // This is introduced for backwards compatibility reasons.
450        // TODO: Remove for 3.0
451        if ($dqlPartName == 'join') {
452            $newDqlPart = array();
453            foreach ($dqlPart AS $k => $v) {
454                if (is_numeric($k)) {
455                    $newDqlPart[$this->getRootAlias()] = $v;
456                } else {
457                    $newDqlPart[$k] = $v;
458                }
459            }
460            $dqlPart = $newDqlPart;
461        }
462
463        if ($append && $isMultiple) {
464            if (is_array($dqlPart)) {
465                $key = key($dqlPart);
466
467                $this->_dqlParts[$dqlPartName][$key][] = $dqlPart[$key];
468            } else {
469                $this->_dqlParts[$dqlPartName][] = $dqlPart;
470            }
471        } else {
472            $this->_dqlParts[$dqlPartName] = ($isMultiple) ? array($dqlPart) : $dqlPart;
473        }
474
475        $this->_state = self::STATE_DIRTY;
476
477        return $this;
478    }
479
480    /**
481     * Specifies an item that is to be returned in the query result.
482     * Replaces any previously specified selections, if any.
483     *
484     * <code>
485     *     $qb = $em->createQueryBuilder()
486     *         ->select('u', 'p')
487     *         ->from('User', 'u')
488     *         ->leftJoin('u.Phonenumbers', 'p');
489     * </code>
490     *
491     * @param mixed $select The selection expressions.
492     * @return QueryBuilder This QueryBuilder instance.
493     */
494    public function select($select = null)
495    {
496        $this->_type = self::SELECT;
497
498        if (empty($select)) {
499            return $this;
500        }
501
502        $selects = is_array($select) ? $select : func_get_args();
503
504        return $this->add('select', new Expr\Select($selects), false);
505    }
506
507    /**
508     * Add a DISTINCT flag to this query.
509     *
510     * <code>
511     *     $qb = $em->createQueryBuilder()
512     *         ->select('u')
513     *         ->distinct()
514     *         ->from('User', 'u');
515     * </code>
516     *
517     * @param bool
518     * @return QueryBuilder
519     */
520    public function distinct($flag = true)
521    {
522        $this->_dqlParts['distinct'] = (bool) $flag;
523        return $this;
524    }
525
526    /**
527     * Adds an item that is to be returned in the query result.
528     *
529     * <code>
530     *     $qb = $em->createQueryBuilder()
531     *         ->select('u')
532     *         ->addSelect('p')
533     *         ->from('User', 'u')
534     *         ->leftJoin('u.Phonenumbers', 'p');
535     * </code>
536     *
537     * @param mixed $select The selection expression.
538     * @return QueryBuilder This QueryBuilder instance.
539     */
540    public function addSelect($select = null)
541    {
542        $this->_type = self::SELECT;
543
544        if (empty($select)) {
545            return $this;
546        }
547
548        $selects = is_array($select) ? $select : func_get_args();
549
550        return $this->add('select', new Expr\Select($selects), true);
551    }
552
553    /**
554     * Turns the query being built into a bulk delete query that ranges over
555     * a certain entity type.
556     *
557     * <code>
558     *     $qb = $em->createQueryBuilder()
559     *         ->delete('User', 'u')
560     *         ->where('u.id = :user_id');
561     *         ->setParameter('user_id', 1);
562     * </code>
563     *
564     * @param string $delete The class/type whose instances are subject to the deletion.
565     * @param string $alias The class/type alias used in the constructed query.
566     * @return QueryBuilder This QueryBuilder instance.
567     */
568    public function delete($delete = null, $alias = null)
569    {
570        $this->_type = self::DELETE;
571
572        if ( ! $delete) {
573            return $this;
574        }
575
576        return $this->add('from', new Expr\From($delete, $alias));
577    }
578
579    /**
580     * Turns the query being built into a bulk update query that ranges over
581     * a certain entity type.
582     *
583     * <code>
584     *     $qb = $em->createQueryBuilder()
585     *         ->update('User', 'u')
586     *         ->set('u.password', md5('password'))
587     *         ->where('u.id = ?');
588     * </code>
589     *
590     * @param string $update The class/type whose instances are subject to the update.
591     * @param string $alias The class/type alias used in the constructed query.
592     * @return QueryBuilder This QueryBuilder instance.
593     */
594    public function update($update = null, $alias = null)
595    {
596        $this->_type = self::UPDATE;
597
598        if ( ! $update) {
599            return $this;
600        }
601
602        return $this->add('from', new Expr\From($update, $alias));
603    }
604
605    /**
606     * Create and add a query root corresponding to the entity identified by the given alias,
607     * forming a cartesian product with any existing query roots.
608     *
609     * <code>
610     *     $qb = $em->createQueryBuilder()
611     *         ->select('u')
612     *         ->from('User', 'u')
613     * </code>
614     *
615     * @param string $from   The class name.
616     * @param string $alias  The alias of the class.
617     * @param string $indexBy The index for the from.
618     * @return QueryBuilder This QueryBuilder instance.
619     */
620    public function from($from, $alias, $indexBy = null)
621    {
622        return $this->add('from', new Expr\From($from, $alias, $indexBy), true);
623    }
624
625    /**
626     * Creates and adds a join over an entity association to the query.
627     *
628     * The entities in the joined association will be fetched as part of the query
629     * result if the alias used for the joined association is placed in the select
630     * expressions.
631     *
632     * <code>
633     *     $qb = $em->createQueryBuilder()
634     *         ->select('u')
635     *         ->from('User', 'u')
636     *         ->join('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1');
637     * </code>
638     *
639     * @param string $join The relationship to join
640     * @param string $alias The alias of the join
641     * @param string $conditionType The condition type constant. Either ON or WITH.
642     * @param string $condition The condition for the join
643     * @param string $indexBy The index for the join
644     * @return QueryBuilder This QueryBuilder instance.
645     */
646    public function join($join, $alias, $conditionType = null, $condition = null, $indexBy = null)
647    {
648        return $this->innerJoin($join, $alias, $conditionType, $condition, $indexBy);
649    }
650
651    /**
652     * Creates and adds a join over an entity association to the query.
653     *
654     * The entities in the joined association will be fetched as part of the query
655     * result if the alias used for the joined association is placed in the select
656     * expressions.
657     *
658     *     [php]
659     *     $qb = $em->createQueryBuilder()
660     *         ->select('u')
661     *         ->from('User', 'u')
662     *         ->innerJoin('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1');
663     *
664     * @param string $join The relationship to join
665     * @param string $alias The alias of the join
666     * @param string $conditionType The condition type constant. Either ON or WITH.
667     * @param string $condition The condition for the join
668     * @param string $indexBy The index for the join
669     * @return QueryBuilder This QueryBuilder instance.
670     */
671    public function innerJoin($join, $alias, $conditionType = null, $condition = null, $indexBy = null)
672    {
673        $rootAlias = substr($join, 0, strpos($join, '.'));
674
675        if ( ! in_array($rootAlias, $this->getRootAliases())) {
676            $rootAlias = $this->getRootAlias();
677        }
678
679        $join = new Expr\Join(
680            Expr\Join::INNER_JOIN, $join, $alias, $conditionType, $condition, $indexBy
681        );
682
683        return $this->add('join', array($rootAlias => $join), true);
684    }
685
686    /**
687     * Creates and adds a left join over an entity association to the query.
688     *
689     * The entities in the joined association will be fetched as part of the query
690     * result if the alias used for the joined association is placed in the select
691     * expressions.
692     *
693     * <code>
694     *     $qb = $em->createQueryBuilder()
695     *         ->select('u')
696     *         ->from('User', 'u')
697     *         ->leftJoin('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1');
698     * </code>
699     *
700     * @param string $join The relationship to join
701     * @param string $alias The alias of the join
702     * @param string $conditionType The condition type constant. Either ON or WITH.
703     * @param string $condition The condition for the join
704     * @param string $indexBy The index for the join
705     * @return QueryBuilder This QueryBuilder instance.
706     */
707    public function leftJoin($join, $alias, $conditionType = null, $condition = null, $indexBy = null)
708    {
709        $rootAlias = substr($join, 0, strpos($join, '.'));
710
711        if ( ! in_array($rootAlias, $this->getRootAliases())) {
712            $rootAlias = $this->getRootAlias();
713        }
714
715        $join = new Expr\Join(
716            Expr\Join::LEFT_JOIN, $join, $alias, $conditionType, $condition, $indexBy
717        );
718
719        return $this->add('join', array($rootAlias => $join), true);
720    }
721
722    /**
723     * Sets a new value for a field in a bulk update query.
724     *
725     * <code>
726     *     $qb = $em->createQueryBuilder()
727     *         ->update('User', 'u')
728     *         ->set('u.password', md5('password'))
729     *         ->where('u.id = ?');
730     * </code>
731     *
732     * @param string $key The key/field to set.
733     * @param string $value The value, expression, placeholder, etc.
734     * @return QueryBuilder This QueryBuilder instance.
735     */
736    public function set($key, $value)
737    {
738        return $this->add('set', new Expr\Comparison($key, Expr\Comparison::EQ, $value), true);
739    }
740
741    /**
742     * Specifies one or more restrictions to the query result.
743     * Replaces any previously specified restrictions, if any.
744     *
745     * <code>
746     *     $qb = $em->createQueryBuilder()
747     *         ->select('u')
748     *         ->from('User', 'u')
749     *         ->where('u.id = ?');
750     *
751     *     // You can optionally programatically build and/or expressions
752     *     $qb = $em->createQueryBuilder();
753     *
754     *     $or = $qb->expr()->orx();
755     *     $or->add($qb->expr()->eq('u.id', 1));
756     *     $or->add($qb->expr()->eq('u.id', 2));
757     *
758     *     $qb->update('User', 'u')
759     *         ->set('u.password', md5('password'))
760     *         ->where($or);
761     * </code>
762     *
763     * @param mixed $predicates The restriction predicates.
764     * @return QueryBuilder This QueryBuilder instance.
765     */
766    public function where($predicates)
767    {
768        if ( ! (func_num_args() == 1 && $predicates instanceof Expr\Composite)) {
769            $predicates = new Expr\Andx(func_get_args());
770        }
771
772        return $this->add('where', $predicates);
773    }
774
775    /**
776     * Adds one or more restrictions to the query results, forming a logical
777     * conjunction with any previously specified restrictions.
778     *
779     * <code>
780     *     $qb = $em->createQueryBuilder()
781     *         ->select('u')
782     *         ->from('User', 'u')
783     *         ->where('u.username LIKE ?')
784     *         ->andWhere('u.is_active = 1');
785     * </code>
786     *
787     * @param mixed $where The query restrictions.
788     * @return QueryBuilder This QueryBuilder instance.
789     * @see where()
790     */
791    public function andWhere($where)
792    {
793        $where = $this->getDQLPart('where');
794        $args = func_get_args();
795
796        if ($where instanceof Expr\Andx) {
797            $where->addMultiple($args);
798        } else {
799            array_unshift($args, $where);
800            $where = new Expr\Andx($args);
801        }
802
803        return $this->add('where', $where, true);
804    }
805
806    /**
807     * Adds one or more restrictions to the query results, forming a logical
808     * disjunction with any previously specified restrictions.
809     *
810     * <code>
811     *     $qb = $em->createQueryBuilder()
812     *         ->select('u')
813     *         ->from('User', 'u')
814     *         ->where('u.id = 1')
815     *         ->orWhere('u.id = 2');
816     * </code>
817     *
818     * @param mixed $where The WHERE statement
819     * @return QueryBuilder $qb
820     * @see where()
821     */
822    public function orWhere($where)
823    {
824        $where = $this->getDqlPart('where');
825        $args = func_get_args();
826
827        if ($where instanceof Expr\Orx) {
828            $where->addMultiple($args);
829        } else {
830            array_unshift($args, $where);
831            $where = new Expr\Orx($args);
832        }
833
834        return $this->add('where', $where, true);
835    }
836
837    /**
838     * Specifies a grouping over the results of the query.
839     * Replaces any previously specified groupings, if any.
840     *
841     * <code>
842     *     $qb = $em->createQueryBuilder()
843     *         ->select('u')
844     *         ->from('User', 'u')
845     *         ->groupBy('u.id');
846     * </code>
847     *
848     * @param string $groupBy The grouping expression.
849     * @return QueryBuilder This QueryBuilder instance.
850     */
851    public function groupBy($groupBy)
852    {
853        return $this->add('groupBy', new Expr\GroupBy(func_get_args()));
854    }
855
856
857    /**
858     * Adds a grouping expression to the query.
859     *
860     * <code>
861     *     $qb = $em->createQueryBuilder()
862     *         ->select('u')
863     *         ->from('User', 'u')
864     *         ->groupBy('u.lastLogin');
865     *         ->addGroupBy('u.createdAt')
866     * </code>
867     *
868     * @param string $groupBy The grouping expression.
869     * @return QueryBuilder This QueryBuilder instance.
870     */
871    public function addGroupBy($groupBy)
872    {
873        return $this->add('groupBy', new Expr\GroupBy(func_get_args()), true);
874    }
875
876    /**
877     * Specifies a restriction over the groups of the query.
878     * Replaces any previous having restrictions, if any.
879     *
880     * @param mixed $having The restriction over the groups.
881     * @return QueryBuilder This QueryBuilder instance.
882     */
883    public function having($having)
884    {
885        if ( ! (func_num_args() == 1 && ($having instanceof Expr\Andx || $having instanceof Expr\Orx))) {
886            $having = new Expr\Andx(func_get_args());
887        }
888
889        return $this->add('having', $having);
890    }
891
892    /**
893     * Adds a restriction over the groups of the query, forming a logical
894     * conjunction with any existing having restrictions.
895     *
896     * @param mixed $having The restriction to append.
897     * @return QueryBuilder This QueryBuilder instance.
898     */
899    public function andHaving($having)
900    {
901        $having = $this->getDqlPart('having');
902        $args = func_get_args();
903
904        if ($having instanceof Expr\Andx) {
905            $having->addMultiple($args);
906        } else {
907            array_unshift($args, $having);
908            $having = new Expr\Andx($args);
909        }
910
911        return $this->add('having', $having);
912    }
913
914    /**
915     * Adds a restriction over the groups of the query, forming a logical
916     * disjunction with any existing having restrictions.
917     *
918     * @param mixed $having The restriction to add.
919     * @return QueryBuilder This QueryBuilder instance.
920     */
921    public function orHaving($having)
922    {
923        $having = $this->getDqlPart('having');
924        $args = func_get_args();
925
926        if ($having instanceof Expr\Orx) {
927            $having->addMultiple($args);
928        } else {
929            array_unshift($args, $having);
930            $having = new Expr\Orx($args);
931        }
932
933        return $this->add('having', $having);
934    }
935
936    /**
937     * Specifies an ordering for the query results.
938     * Replaces any previously specified orderings, if any.
939     *
940     * @param string $sort The ordering expression.
941     * @param string $order The ordering direction.
942     * @return QueryBuilder This QueryBuilder instance.
943     */
944    public function orderBy($sort, $order = null)
945    {
946        return $this->add('orderBy',  $sort instanceof Expr\OrderBy ? $sort
947                : new Expr\OrderBy($sort, $order));
948    }
949
950    /**
951     * Adds an ordering to the query results.
952     *
953     * @param string $sort The ordering expression.
954     * @param string $order The ordering direction.
955     * @return QueryBuilder This QueryBuilder instance.
956     */
957    public function addOrderBy($sort, $order = null)
958    {
959        return $this->add('orderBy', new Expr\OrderBy($sort, $order), true);
960    }
961
962    /**
963     * Get a query part by its name.
964     *
965     * @param string $queryPartName
966     * @return mixed $queryPart
967     * @todo Rename: getQueryPart (or remove?)
968     */
969    public function getDQLPart($queryPartName)
970    {
971        return $this->_dqlParts[$queryPartName];
972    }
973
974    /**
975     * Get all query parts.
976     *
977     * @return array $dqlParts
978     * @todo Rename: getQueryParts (or remove?)
979     */
980    public function getDQLParts()
981    {
982        return $this->_dqlParts;
983    }
984
985    private function _getDQLForDelete()
986    {
987         return 'DELETE'
988              . $this->_getReducedDQLQueryPart('from', array('pre' => ' ', 'separator' => ', '))
989              . $this->_getReducedDQLQueryPart('where', array('pre' => ' WHERE '))
990              . $this->_getReducedDQLQueryPart('orderBy', array('pre' => ' ORDER BY ', 'separator' => ', '));
991    }
992
993    private function _getDQLForUpdate()
994    {
995         return 'UPDATE'
996              . $this->_getReducedDQLQueryPart('from', array('pre' => ' ', 'separator' => ', '))
997              . $this->_getReducedDQLQueryPart('set', array('pre' => ' SET ', 'separator' => ', '))
998              . $this->_getReducedDQLQueryPart('where', array('pre' => ' WHERE '))
999              . $this->_getReducedDQLQueryPart('orderBy', array('pre' => ' ORDER BY ', 'separator' => ', '));
1000    }
1001
1002    private function _getDQLForSelect()
1003    {
1004        $dql = 'SELECT'
1005              . ($this->_dqlParts['distinct']===true ? ' DISTINCT' : '')
1006              . $this->_getReducedDQLQueryPart('select', array('pre' => ' ', 'separator' => ', '));
1007
1008        $fromParts   = $this->getDQLPart('from');
1009        $joinParts   = $this->getDQLPart('join');
1010        $fromClauses = array();
1011
1012        // Loop through all FROM clauses
1013        if ( ! empty($fromParts)) {
1014            $dql .= ' FROM ';
1015
1016            foreach ($fromParts as $from) {
1017                $fromClause = (string) $from;
1018
1019                if ($from instanceof Expr\From && isset($joinParts[$from->getAlias()])) {
1020                    foreach ($joinParts[$from->getAlias()] as $join) {
1021                        $fromClause .= ' ' . ((string) $join);
1022                    }
1023                }
1024
1025                $fromClauses[] = $fromClause;
1026            }
1027        }
1028
1029        $dql .= implode(', ', $fromClauses)
1030              . $this->_getReducedDQLQueryPart('where', array('pre' => ' WHERE '))
1031              . $this->_getReducedDQLQueryPart('groupBy', array('pre' => ' GROUP BY ', 'separator' => ', '))
1032              . $this->_getReducedDQLQueryPart('having', array('pre' => ' HAVING '))
1033              . $this->_getReducedDQLQueryPart('orderBy', array('pre' => ' ORDER BY ', 'separator' => ', '));
1034
1035        return $dql;
1036    }
1037
1038    private function _getReducedDQLQueryPart($queryPartName, $options = array())
1039    {
1040        $queryPart = $this->getDQLPart($queryPartName);
1041
1042        if (empty($queryPart)) {
1043            return (isset($options['empty']) ? $options['empty'] : '');
1044        }
1045
1046        return (isset($options['pre']) ? $options['pre'] : '')
1047             . (is_array($queryPart) ? implode($options['separator'], $queryPart) : $queryPart)
1048             . (isset($options['post']) ? $options['post'] : '');
1049    }
1050
1051    /**
1052     * Reset DQL parts
1053     *
1054     * @param array $parts
1055     * @return QueryBuilder
1056     */
1057    public function resetDQLParts($parts = null)
1058    {
1059        if (is_null($parts)) {
1060            $parts = array_keys($this->_dqlParts);
1061        }
1062        foreach ($parts as $part) {
1063            $this->resetDQLPart($part);
1064        }
1065        return $this;
1066    }
1067
1068    /**
1069     * Reset single DQL part
1070     *
1071     * @param string $part
1072     * @return QueryBuilder;
1073     */
1074    public function resetDQLPart($part)
1075    {
1076        if (is_array($this->_dqlParts[$part])) {
1077            $this->_dqlParts[$part] = array();
1078        } else {
1079            $this->_dqlParts[$part] = null;
1080        }
1081        $this->_state = self::STATE_DIRTY;
1082        return $this;
1083    }
1084
1085    /**
1086     * Gets a string representation of this QueryBuilder which corresponds to
1087     * the final DQL query being constructed.
1088     *
1089     * @return string The string representation of this QueryBuilder.
1090     */
1091    public function __toString()
1092    {
1093        return $this->getDQL();
1094    }
1095
1096    /**
1097     * Deep clone of all expression objects in the DQL parts.
1098     *
1099     * @return void
1100     */
1101    public function __clone()
1102    {
1103        foreach ($this->_dqlParts AS $part => $elements) {
1104            if (is_array($this->_dqlParts[$part])) {
1105                foreach ($this->_dqlParts[$part] AS $idx => $element) {
1106                    if (is_object($element)) {
1107                        $this->_dqlParts[$part][$idx] = clone $element;
1108                    }
1109                }
1110            } else if (\is_object($elements)) {
1111                $this->_dqlParts[$part] = clone $elements;
1112            }
1113        }
1114    }
1115}
Note: See TracBrowser for help on using the repository browser.