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.
15 * This software consists of voluntary contributions made by many individuals
16 * and is licensed under the MIT license. For more information, see
17 * <http://www.doctrine-project.org>.
20 namespace Doctrine\ORM;
22 use Doctrine\Common\Collections\ArrayCollection;
24 use Doctrine\ORM\Query\Expr;
27 * This class is responsible for building DQL query strings via an object oriented
31 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
32 * @author Jonathan Wage <jonwage@gmail.com>
33 * @author Roman Borschel <roman@code-factory.org>
37 /* The query types. */
42 /** The builder states. */
43 const STATE_DIRTY = 0;
44 const STATE_CLEAN = 1;
47 * @var EntityManager The EntityManager used by this QueryBuilder.
52 * @var array The array of DQL parts collected.
54 private $_dqlParts = array(
67 * @var integer The type of query this is. Can be select, update or delete.
69 private $_type = self::SELECT;
72 * @var integer The state of the query object. Can be dirty or clean.
74 private $_state = self::STATE_CLEAN;
77 * @var string The complete DQL string for this query.
82 * @var \Doctrine\Common\Collections\ArrayCollection The query parameters.
84 private $parameters = array();
87 * @var integer The index of the first result to retrieve.
89 private $_firstResult = null;
92 * @var integer The maximum number of results to retrieve.
94 private $_maxResults = null;
97 * @var array Keeps root entity alias names for join entities.
99 private $joinRootAliases = array();
102 * Initializes a new <tt>QueryBuilder</tt> that uses the given <tt>EntityManager</tt>.
104 * @param EntityManager $em The EntityManager to use.
106 public function __construct(EntityManager $em)
109 $this->parameters = new ArrayCollection();
113 * Gets an ExpressionBuilder used for object-oriented construction of query expressions.
114 * This producer method is intended for convenient inline usage. Example:
117 * $qb = $em->createQueryBuilder()
119 * ->from('User', 'u')
120 * ->where($qb->expr()->eq('u.id', 1));
123 * For more complex expression construction, consider storing the expression
124 * builder object in a local variable.
128 public function expr()
130 return $this->_em->getExpressionBuilder();
134 * Get the type of the currently built query.
138 public function getType()
144 * Get the associated EntityManager for this query builder.
146 * @return EntityManager
148 public function getEntityManager()
154 * Get the state of this query builder instance.
156 * @return integer Either QueryBuilder::STATE_DIRTY or QueryBuilder::STATE_CLEAN.
158 public function getState()
160 return $this->_state;
164 * Get the complete DQL string formed by the current specifications of this QueryBuilder.
167 * $qb = $em->createQueryBuilder()
169 * ->from('User', 'u')
170 * echo $qb->getDql(); // SELECT u FROM User u
173 * @return string The DQL query string.
175 public function getDQL()
177 if ($this->_dql !== null && $this->_state === self::STATE_CLEAN) {
183 switch ($this->_type) {
185 $dql = $this->_getDQLForDelete();
189 $dql = $this->_getDQLForUpdate();
194 $dql = $this->_getDQLForSelect();
198 $this->_state = self::STATE_CLEAN;
205 * Constructs a Query instance from the current specifications of the builder.
208 * $qb = $em->createQueryBuilder()
210 * ->from('User', 'u');
211 * $q = $qb->getQuery();
212 * $results = $q->execute();
217 public function getQuery()
219 $parameters = clone $this->parameters;
221 return $this->_em->createQuery($this->getDQL())
222 ->setParameters($parameters)
223 ->setFirstResult($this->_firstResult)
224 ->setMaxResults($this->_maxResults);
228 * Finds the root entity alias of the joined entity.
230 * @param string $alias The alias of the new join entity
231 * @param string $parentAlias The parent entity alias of the join relationship
234 private function findRootAlias($alias, $parentAlias)
238 if (in_array($parentAlias, $this->getRootAliases())) {
239 $rootAlias = $parentAlias;
240 } elseif (isset($this->joinRootAliases[$parentAlias])) {
241 $rootAlias = $this->joinRootAliases[$parentAlias];
243 // Should never happen with correct joining order. Might be
244 // thoughtful to throw exception instead.
245 $rootAlias = $this->getRootAlias();
248 $this->joinRootAliases[$alias] = $rootAlias;
254 * Gets the FIRST root alias of the query. This is the first entity alias involved
255 * in the construction of the query.
258 * $qb = $em->createQueryBuilder()
260 * ->from('User', 'u');
262 * echo $qb->getRootAlias(); // u
265 * @deprecated Please use $qb->getRootAliases() instead.
266 * @return string $rootAlias
268 public function getRootAlias()
270 $aliases = $this->getRootAliases();
275 * Gets the root aliases of the query. This is the entity aliases involved
276 * in the construction of the query.
279 * $qb = $em->createQueryBuilder()
281 * ->from('User', 'u');
283 * $qb->getRootAliases(); // array('u')
286 * @return array $rootAliases
288 public function getRootAliases()
292 foreach ($this->_dqlParts['from'] as &$fromClause) {
293 if (is_string($fromClause)) {
294 $spacePos = strrpos($fromClause, ' ');
295 $from = substr($fromClause, 0, $spacePos);
296 $alias = substr($fromClause, $spacePos + 1);
298 $fromClause = new Query\Expr\From($from, $alias);
301 $aliases[] = $fromClause->getAlias();
308 * Gets the root entities of the query. This is the entity aliases involved
309 * in the construction of the query.
312 * $qb = $em->createQueryBuilder()
314 * ->from('User', 'u');
316 * $qb->getRootEntities(); // array('User')
319 * @return array $rootEntities
321 public function getRootEntities()
325 foreach ($this->_dqlParts['from'] as &$fromClause) {
326 if (is_string($fromClause)) {
327 $spacePos = strrpos($fromClause, ' ');
328 $from = substr($fromClause, 0, $spacePos);
329 $alias = substr($fromClause, $spacePos + 1);
331 $fromClause = new Query\Expr\From($from, $alias);
334 $entities[] = $fromClause->getFrom();
341 * Sets a query parameter for the query being constructed.
344 * $qb = $em->createQueryBuilder()
346 * ->from('User', 'u')
347 * ->where('u.id = :user_id')
348 * ->setParameter('user_id', 1);
351 * @param string|integer $key The parameter position or name.
352 * @param mixed $value The parameter value.
353 * @param string|null $type PDO::PARAM_* or \Doctrine\DBAL\Types\Type::* constant
354 * @return QueryBuilder This QueryBuilder instance.
356 public function setParameter($key, $value, $type = null)
358 $filteredParameters = $this->parameters->filter(
359 function ($parameter) use ($key)
361 // Must not be identical because of string to integer conversion
362 return ($key == $parameter->getName());
366 if (count($filteredParameters)) {
367 $parameter = $filteredParameters->first();
368 $parameter->setValue($value, $type);
373 $parameter = new Query\Parameter($key, $value, $type);
375 $this->parameters->add($parameter);
381 * Sets a collection of query parameters for the query being constructed.
384 * $qb = $em->createQueryBuilder()
386 * ->from('User', 'u')
387 * ->where('u.id = :user_id1 OR u.id = :user_id2')
388 * ->setParameters(new ArrayCollection(array(
389 * new Parameter('user_id1', 1),
390 * new Parameter('user_id2', 2)
394 * @param \Doctrine\Common\Collections\ArrayCollection|array $params The query parameters to set.
395 * @return QueryBuilder This QueryBuilder instance.
397 public function setParameters($parameters)
399 // BC compatibility with 2.3-
400 if (is_array($parameters)) {
401 $parameterCollection = new ArrayCollection();
403 foreach ($parameters as $key => $value) {
404 $parameter = new Query\Parameter($key, $value);
406 $parameterCollection->add($parameter);
409 $parameters = $parameterCollection;
412 $this->parameters = $parameters;
418 * Gets all defined query parameters for the query being constructed.
420 * @return \Doctrine\Common\Collections\ArrayCollection The currently defined query parameters.
422 public function getParameters()
424 return $this->parameters;
428 * Gets a (previously set) query parameter of the query being constructed.
430 * @param mixed $key The key (index or name) of the bound parameter.
432 * @return Query\Parameter|null The value of the bound parameter.
434 public function getParameter($key)
436 $filteredParameters = $this->parameters->filter(
437 function ($parameter) use ($key)
439 // Must not be identical because of string to integer conversion
440 return ($key == $parameter->getName());
444 return count($filteredParameters) ? $filteredParameters->first() : null;
448 * Sets the position of the first result to retrieve (the "offset").
450 * @param integer $firstResult The first result to return.
451 * @return QueryBuilder This QueryBuilder instance.
453 public function setFirstResult($firstResult)
455 $this->_firstResult = $firstResult;
461 * Gets the position of the first result the query object was set to retrieve (the "offset").
462 * Returns NULL if {@link setFirstResult} was not applied to this QueryBuilder.
464 * @return integer The position of the first result.
466 public function getFirstResult()
468 return $this->_firstResult;
472 * Sets the maximum number of results to retrieve (the "limit").
474 * @param integer $maxResults The maximum number of results to retrieve.
475 * @return QueryBuilder This QueryBuilder instance.
477 public function setMaxResults($maxResults)
479 $this->_maxResults = $maxResults;
485 * Gets the maximum number of results the query object was set to retrieve (the "limit").
486 * Returns NULL if {@link setMaxResults} was not applied to this query builder.
488 * @return integer Maximum number of results.
490 public function getMaxResults()
492 return $this->_maxResults;
496 * Either appends to or replaces a single, generic query part.
498 * The available parts are: 'select', 'from', 'join', 'set', 'where',
499 * 'groupBy', 'having' and 'orderBy'.
501 * @param string $dqlPartName
502 * @param string $dqlPart
503 * @param string $append
504 * @return QueryBuilder This QueryBuilder instance.
506 public function add($dqlPartName, $dqlPart, $append = false)
508 $isMultiple = is_array($this->_dqlParts[$dqlPartName]);
510 // This is introduced for backwards compatibility reasons.
511 // TODO: Remove for 3.0
512 if ($dqlPartName == 'join') {
513 $newDqlPart = array();
515 foreach ($dqlPart as $k => $v) {
516 $k = is_numeric($k) ? $this->getRootAlias() : $k;
518 $newDqlPart[$k] = $v;
521 $dqlPart = $newDqlPart;
524 if ($append && $isMultiple) {
525 if (is_array($dqlPart)) {
526 $key = key($dqlPart);
528 $this->_dqlParts[$dqlPartName][$key][] = $dqlPart[$key];
530 $this->_dqlParts[$dqlPartName][] = $dqlPart;
533 $this->_dqlParts[$dqlPartName] = ($isMultiple) ? array($dqlPart) : $dqlPart;
536 $this->_state = self::STATE_DIRTY;
542 * Specifies an item that is to be returned in the query result.
543 * Replaces any previously specified selections, if any.
546 * $qb = $em->createQueryBuilder()
548 * ->from('User', 'u')
549 * ->leftJoin('u.Phonenumbers', 'p');
552 * @param mixed $select The selection expressions.
553 * @return QueryBuilder This QueryBuilder instance.
555 public function select($select = null)
557 $this->_type = self::SELECT;
559 if (empty($select)) {
563 $selects = is_array($select) ? $select : func_get_args();
565 return $this->add('select', new Expr\Select($selects), false);
569 * Add a DISTINCT flag to this query.
572 * $qb = $em->createQueryBuilder()
575 * ->from('User', 'u');
579 * @return QueryBuilder
581 public function distinct($flag = true)
583 $this->_dqlParts['distinct'] = (bool) $flag;
589 * Adds an item that is to be returned in the query result.
592 * $qb = $em->createQueryBuilder()
595 * ->from('User', 'u')
596 * ->leftJoin('u.Phonenumbers', 'p');
599 * @param mixed $select The selection expression.
600 * @return QueryBuilder This QueryBuilder instance.
602 public function addSelect($select = null)
604 $this->_type = self::SELECT;
606 if (empty($select)) {
610 $selects = is_array($select) ? $select : func_get_args();
612 return $this->add('select', new Expr\Select($selects), true);
616 * Turns the query being built into a bulk delete query that ranges over
617 * a certain entity type.
620 * $qb = $em->createQueryBuilder()
621 * ->delete('User', 'u')
622 * ->where('u.id = :user_id');
623 * ->setParameter('user_id', 1);
626 * @param string $delete The class/type whose instances are subject to the deletion.
627 * @param string $alias The class/type alias used in the constructed query.
628 * @return QueryBuilder This QueryBuilder instance.
630 public function delete($delete = null, $alias = null)
632 $this->_type = self::DELETE;
638 return $this->add('from', new Expr\From($delete, $alias));
642 * Turns the query being built into a bulk update query that ranges over
643 * a certain entity type.
646 * $qb = $em->createQueryBuilder()
647 * ->update('User', 'u')
648 * ->set('u.password', md5('password'))
649 * ->where('u.id = ?');
652 * @param string $update The class/type whose instances are subject to the update.
653 * @param string $alias The class/type alias used in the constructed query.
654 * @return QueryBuilder This QueryBuilder instance.
656 public function update($update = null, $alias = null)
658 $this->_type = self::UPDATE;
664 return $this->add('from', new Expr\From($update, $alias));
668 * Create and add a query root corresponding to the entity identified by the given alias,
669 * forming a cartesian product with any existing query roots.
672 * $qb = $em->createQueryBuilder()
674 * ->from('User', 'u')
677 * @param string $from The class name.
678 * @param string $alias The alias of the class.
679 * @param string $indexBy The index for the from.
680 * @return QueryBuilder This QueryBuilder instance.
682 public function from($from, $alias, $indexBy = null)
684 return $this->add('from', new Expr\From($from, $alias, $indexBy), true);
688 * Creates and adds a join over an entity association to the query.
690 * The entities in the joined association will be fetched as part of the query
691 * result if the alias used for the joined association is placed in the select
695 * $qb = $em->createQueryBuilder()
697 * ->from('User', 'u')
698 * ->join('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1');
701 * @param string $join The relationship to join
702 * @param string $alias The alias of the join
703 * @param string $conditionType The condition type constant. Either ON or WITH.
704 * @param string $condition The condition for the join
705 * @param string $indexBy The index for the join
706 * @return QueryBuilder This QueryBuilder instance.
708 public function join($join, $alias, $conditionType = null, $condition = null, $indexBy = null)
710 return $this->innerJoin($join, $alias, $conditionType, $condition, $indexBy);
714 * Creates and adds a join over an entity association to the query.
716 * The entities in the joined association will be fetched as part of the query
717 * result if the alias used for the joined association is placed in the select
721 * $qb = $em->createQueryBuilder()
723 * ->from('User', 'u')
724 * ->innerJoin('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1');
726 * @param string $join The relationship to join
727 * @param string $alias The alias of the join
728 * @param string $conditionType The condition type constant. Either ON or WITH.
729 * @param string $condition The condition for the join
730 * @param string $indexBy The index for the join
731 * @return QueryBuilder This QueryBuilder instance.
733 public function innerJoin($join, $alias, $conditionType = null, $condition = null, $indexBy = null)
735 $parentAlias = substr($join, 0, strpos($join, '.'));
737 $rootAlias = $this->findRootAlias($alias, $parentAlias);
739 $join = new Expr\Join(
740 Expr\Join::INNER_JOIN, $join, $alias, $conditionType, $condition, $indexBy
743 return $this->add('join', array($rootAlias => $join), true);
747 * Creates and adds a left join over an entity association to the query.
749 * The entities in the joined association will be fetched as part of the query
750 * result if the alias used for the joined association is placed in the select
754 * $qb = $em->createQueryBuilder()
756 * ->from('User', 'u')
757 * ->leftJoin('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1');
760 * @param string $join The relationship to join
761 * @param string $alias The alias of the join
762 * @param string $conditionType The condition type constant. Either ON or WITH.
763 * @param string $condition The condition for the join
764 * @param string $indexBy The index for the join
765 * @return QueryBuilder This QueryBuilder instance.
767 public function leftJoin($join, $alias, $conditionType = null, $condition = null, $indexBy = null)
769 $parentAlias = substr($join, 0, strpos($join, '.'));
771 $rootAlias = $this->findRootAlias($alias, $parentAlias);
773 $join = new Expr\Join(
774 Expr\Join::LEFT_JOIN, $join, $alias, $conditionType, $condition, $indexBy
777 return $this->add('join', array($rootAlias => $join), true);
781 * Sets a new value for a field in a bulk update query.
784 * $qb = $em->createQueryBuilder()
785 * ->update('User', 'u')
786 * ->set('u.password', md5('password'))
787 * ->where('u.id = ?');
790 * @param string $key The key/field to set.
791 * @param string $value The value, expression, placeholder, etc.
792 * @return QueryBuilder This QueryBuilder instance.
794 public function set($key, $value)
796 return $this->add('set', new Expr\Comparison($key, Expr\Comparison::EQ, $value), true);
800 * Specifies one or more restrictions to the query result.
801 * Replaces any previously specified restrictions, if any.
804 * $qb = $em->createQueryBuilder()
806 * ->from('User', 'u')
807 * ->where('u.id = ?');
809 * // You can optionally programatically build and/or expressions
810 * $qb = $em->createQueryBuilder();
812 * $or = $qb->expr()->orx();
813 * $or->add($qb->expr()->eq('u.id', 1));
814 * $or->add($qb->expr()->eq('u.id', 2));
816 * $qb->update('User', 'u')
817 * ->set('u.password', md5('password'))
821 * @param mixed $predicates The restriction predicates.
822 * @return QueryBuilder This QueryBuilder instance.
824 public function where($predicates)
826 if ( ! (func_num_args() == 1 && $predicates instanceof Expr\Composite)) {
827 $predicates = new Expr\Andx(func_get_args());
830 return $this->add('where', $predicates);
834 * Adds one or more restrictions to the query results, forming a logical
835 * conjunction with any previously specified restrictions.
838 * $qb = $em->createQueryBuilder()
840 * ->from('User', 'u')
841 * ->where('u.username LIKE ?')
842 * ->andWhere('u.is_active = 1');
845 * @param mixed $where The query restrictions.
846 * @return QueryBuilder This QueryBuilder instance.
849 public function andWhere($where)
851 $where = $this->getDQLPart('where');
852 $args = func_get_args();
854 if ($where instanceof Expr\Andx) {
855 $where->addMultiple($args);
857 array_unshift($args, $where);
858 $where = new Expr\Andx($args);
861 return $this->add('where', $where, true);
865 * Adds one or more restrictions to the query results, forming a logical
866 * disjunction with any previously specified restrictions.
869 * $qb = $em->createQueryBuilder()
871 * ->from('User', 'u')
872 * ->where('u.id = 1')
873 * ->orWhere('u.id = 2');
876 * @param mixed $where The WHERE statement
877 * @return QueryBuilder $qb
880 public function orWhere($where)
882 $where = $this->getDqlPart('where');
883 $args = func_get_args();
885 if ($where instanceof Expr\Orx) {
886 $where->addMultiple($args);
888 array_unshift($args, $where);
889 $where = new Expr\Orx($args);
892 return $this->add('where', $where, true);
896 * Specifies a grouping over the results of the query.
897 * Replaces any previously specified groupings, if any.
900 * $qb = $em->createQueryBuilder()
902 * ->from('User', 'u')
906 * @param string $groupBy The grouping expression.
907 * @return QueryBuilder This QueryBuilder instance.
909 public function groupBy($groupBy)
911 return $this->add('groupBy', new Expr\GroupBy(func_get_args()));
916 * Adds a grouping expression to the query.
919 * $qb = $em->createQueryBuilder()
921 * ->from('User', 'u')
922 * ->groupBy('u.lastLogin');
923 * ->addGroupBy('u.createdAt')
926 * @param string $groupBy The grouping expression.
927 * @return QueryBuilder This QueryBuilder instance.
929 public function addGroupBy($groupBy)
931 return $this->add('groupBy', new Expr\GroupBy(func_get_args()), true);
935 * Specifies a restriction over the groups of the query.
936 * Replaces any previous having restrictions, if any.
938 * @param mixed $having The restriction over the groups.
939 * @return QueryBuilder This QueryBuilder instance.
941 public function having($having)
943 if ( ! (func_num_args() == 1 && ($having instanceof Expr\Andx || $having instanceof Expr\Orx))) {
944 $having = new Expr\Andx(func_get_args());
947 return $this->add('having', $having);
951 * Adds a restriction over the groups of the query, forming a logical
952 * conjunction with any existing having restrictions.
954 * @param mixed $having The restriction to append.
955 * @return QueryBuilder This QueryBuilder instance.
957 public function andHaving($having)
959 $having = $this->getDqlPart('having');
960 $args = func_get_args();
962 if ($having instanceof Expr\Andx) {
963 $having->addMultiple($args);
965 array_unshift($args, $having);
966 $having = new Expr\Andx($args);
969 return $this->add('having', $having);
973 * Adds a restriction over the groups of the query, forming a logical
974 * disjunction with any existing having restrictions.
976 * @param mixed $having The restriction to add.
977 * @return QueryBuilder This QueryBuilder instance.
979 public function orHaving($having)
981 $having = $this->getDqlPart('having');
982 $args = func_get_args();
984 if ($having instanceof Expr\Orx) {
985 $having->addMultiple($args);
987 array_unshift($args, $having);
988 $having = new Expr\Orx($args);
991 return $this->add('having', $having);
995 * Specifies an ordering for the query results.
996 * Replaces any previously specified orderings, if any.
998 * @param string $sort The ordering expression.
999 * @param string $order The ordering direction.
1000 * @return QueryBuilder This QueryBuilder instance.
1002 public function orderBy($sort, $order = null)
1004 $orderBy = ($sort instanceof Expr\OrderBy) ? $sort : new Expr\OrderBy($sort, $order);
1006 return $this->add('orderBy', $orderBy);
1010 * Adds an ordering to the query results.
1012 * @param string $sort The ordering expression.
1013 * @param string $order The ordering direction.
1014 * @return QueryBuilder This QueryBuilder instance.
1016 public function addOrderBy($sort, $order = null)
1018 return $this->add('orderBy', new Expr\OrderBy($sort, $order), true);
1022 * Get a query part by its name.
1024 * @param string $queryPartName
1025 * @return mixed $queryPart
1026 * @todo Rename: getQueryPart (or remove?)
1028 public function getDQLPart($queryPartName)
1030 return $this->_dqlParts[$queryPartName];
1034 * Get all query parts.
1036 * @return array $dqlParts
1037 * @todo Rename: getQueryParts (or remove?)
1039 public function getDQLParts()
1041 return $this->_dqlParts;
1044 private function _getDQLForDelete()
1047 . $this->_getReducedDQLQueryPart('from', array('pre' => ' ', 'separator' => ', '))
1048 . $this->_getReducedDQLQueryPart('where', array('pre' => ' WHERE '))
1049 . $this->_getReducedDQLQueryPart('orderBy', array('pre' => ' ORDER BY ', 'separator' => ', '));
1052 private function _getDQLForUpdate()
1055 . $this->_getReducedDQLQueryPart('from', array('pre' => ' ', 'separator' => ', '))
1056 . $this->_getReducedDQLQueryPart('set', array('pre' => ' SET ', 'separator' => ', '))
1057 . $this->_getReducedDQLQueryPart('where', array('pre' => ' WHERE '))
1058 . $this->_getReducedDQLQueryPart('orderBy', array('pre' => ' ORDER BY ', 'separator' => ', '));
1061 private function _getDQLForSelect()
1064 . ($this->_dqlParts['distinct']===true ? ' DISTINCT' : '')
1065 . $this->_getReducedDQLQueryPart('select', array('pre' => ' ', 'separator' => ', '));
1067 $fromParts = $this->getDQLPart('from');
1068 $joinParts = $this->getDQLPart('join');
1069 $fromClauses = array();
1071 // Loop through all FROM clauses
1072 if ( ! empty($fromParts)) {
1075 foreach ($fromParts as $from) {
1076 $fromClause = (string) $from;
1078 if ($from instanceof Expr\From && isset($joinParts[$from->getAlias()])) {
1079 foreach ($joinParts[$from->getAlias()] as $join) {
1080 $fromClause .= ' ' . ((string) $join);
1084 $fromClauses[] = $fromClause;
1088 $dql .= implode(', ', $fromClauses)
1089 . $this->_getReducedDQLQueryPart('where', array('pre' => ' WHERE '))
1090 . $this->_getReducedDQLQueryPart('groupBy', array('pre' => ' GROUP BY ', 'separator' => ', '))
1091 . $this->_getReducedDQLQueryPart('having', array('pre' => ' HAVING '))
1092 . $this->_getReducedDQLQueryPart('orderBy', array('pre' => ' ORDER BY ', 'separator' => ', '));
1097 private function _getReducedDQLQueryPart($queryPartName, $options = array())
1099 $queryPart = $this->getDQLPart($queryPartName);
1101 if (empty($queryPart)) {
1102 return (isset($options['empty']) ? $options['empty'] : '');
1105 return (isset($options['pre']) ? $options['pre'] : '')
1106 . (is_array($queryPart) ? implode($options['separator'], $queryPart) : $queryPart)
1107 . (isset($options['post']) ? $options['post'] : '');
1113 * @param array $parts
1114 * @return QueryBuilder
1116 public function resetDQLParts($parts = null)
1118 if (is_null($parts)) {
1119 $parts = array_keys($this->_dqlParts);
1122 foreach ($parts as $part) {
1123 $this->resetDQLPart($part);
1130 * Reset single DQL part
1132 * @param string $part
1133 * @return QueryBuilder;
1135 public function resetDQLPart($part)
1137 $this->_dqlParts[$part] = is_array($this->_dqlParts[$part]) ? array() : null;
1138 $this->_state = self::STATE_DIRTY;
1144 * Gets a string representation of this QueryBuilder which corresponds to
1145 * the final DQL query being constructed.
1147 * @return string The string representation of this QueryBuilder.
1149 public function __toString()
1151 return $this->getDQL();
1155 * Deep clone of all expression objects in the DQL parts.
1159 public function __clone()
1161 foreach ($this->_dqlParts as $part => $elements) {
1162 if (is_array($this->_dqlParts[$part])) {
1163 foreach ($this->_dqlParts[$part] as $idx => $element) {
1164 if (is_object($element)) {
1165 $this->_dqlParts[$part][$idx] = clone $element;
1168 } else if (is_object($elements)) {
1169 $this->_dqlParts[$part] = clone $elements;
1173 $parameters = array();
1175 foreach ($this->parameters as $parameter) {
1176 $parameters[] = clone $parameter;
1179 $this->parameters = new ArrayCollection($parameters);