vendor/doctrine/orm/lib/Doctrine/ORM/QueryBuilder.php line 37

Open in your IDE?
  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 MIT license. For more information, see
  17.  * <http://www.doctrine-project.org>.
  18.  */
  19. namespace Doctrine\ORM;
  20. use Doctrine\Common\Collections\ArrayCollection;
  21. use Doctrine\Common\Collections\Criteria;
  22. use Doctrine\ORM\Query\Expr;
  23. use Doctrine\ORM\Query\QueryExpressionVisitor;
  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 <[email protected]>
  30.  * @author Jonathan Wage <[email protected]>
  31.  * @author Roman Borschel <[email protected]>
  32.  */
  33. class QueryBuilder
  34. {
  35.     /* The query types. */
  36.     const SELECT 0;
  37.     const DELETE 1;
  38.     const UPDATE 2;
  39.     /* The builder states. */
  40.     const STATE_DIRTY 0;
  41.     const STATE_CLEAN 1;
  42.     /**
  43.      * The EntityManager used by this QueryBuilder.
  44.      *
  45.      * @var EntityManagerInterface
  46.      */
  47.     private $_em;
  48.     /**
  49.      * The array of DQL parts collected.
  50.      *
  51.      * @var array
  52.      */
  53.     private $_dqlParts = [
  54.         'distinct' => false,
  55.         'select'  => [],
  56.         'from'    => [],
  57.         'join'    => [],
  58.         'set'     => [],
  59.         'where'   => null,
  60.         'groupBy' => [],
  61.         'having'  => null,
  62.         'orderBy' => []
  63.     ];
  64.     /**
  65.      * The type of query this is. Can be select, update or delete.
  66.      *
  67.      * @var integer
  68.      */
  69.     private $_type self::SELECT;
  70.     /**
  71.      * The state of the query object. Can be dirty or clean.
  72.      *
  73.      * @var integer
  74.      */
  75.     private $_state self::STATE_CLEAN;
  76.     /**
  77.      * The complete DQL string for this query.
  78.      *
  79.      * @var string
  80.      */
  81.     private $_dql;
  82.     /**
  83.      * The query parameters.
  84.      *
  85.      * @var \Doctrine\Common\Collections\ArrayCollection
  86.      */
  87.     private $parameters;
  88.     /**
  89.      * The index of the first result to retrieve.
  90.      *
  91.      * @var int|null
  92.      */
  93.     private $_firstResult null;
  94.     /**
  95.      * The maximum number of results to retrieve.
  96.      *
  97.      * @var integer|null
  98.      */
  99.     private $_maxResults null;
  100.     /**
  101.      * Keeps root entity alias names for join entities.
  102.      *
  103.      * @var array
  104.      */
  105.     private $joinRootAliases = [];
  106.      /**
  107.      * Whether to use second level cache, if available.
  108.      *
  109.      * @var boolean
  110.      */
  111.     protected $cacheable false;
  112.     /**
  113.      * Second level cache region name.
  114.      *
  115.      * @var string|null
  116.      */
  117.     protected $cacheRegion;
  118.     /**
  119.      * Second level query cache mode.
  120.      *
  121.      * @var integer|null
  122.      */
  123.     protected $cacheMode;
  124.     /**
  125.      * @var integer
  126.      */
  127.     protected $lifetime 0;
  128.     /**
  129.      * Initializes a new <tt>QueryBuilder</tt> that uses the given <tt>EntityManager</tt>.
  130.      *
  131.      * @param EntityManagerInterface $em The EntityManager to use.
  132.      */
  133.     public function __construct(EntityManagerInterface $em)
  134.     {
  135.         $this->_em $em;
  136.         $this->parameters = new ArrayCollection();
  137.     }
  138.     /**
  139.      * Gets an ExpressionBuilder used for object-oriented construction of query expressions.
  140.      * This producer method is intended for convenient inline usage. Example:
  141.      *
  142.      * <code>
  143.      *     $qb = $em->createQueryBuilder();
  144.      *     $qb
  145.      *         ->select('u')
  146.      *         ->from('User', 'u')
  147.      *         ->where($qb->expr()->eq('u.id', 1));
  148.      * </code>
  149.      *
  150.      * For more complex expression construction, consider storing the expression
  151.      * builder object in a local variable.
  152.      *
  153.      * @return Query\Expr
  154.      */
  155.     public function expr()
  156.     {
  157.         return $this->_em->getExpressionBuilder();
  158.     }
  159.     /**
  160.      *
  161.      * Enable/disable second level query (result) caching for this query.
  162.      *
  163.      * @param boolean $cacheable
  164.      *
  165.      * @return self
  166.      */
  167.     public function setCacheable($cacheable)
  168.     {
  169.         $this->cacheable = (boolean) $cacheable;
  170.         return $this;
  171.     }
  172.     /**
  173.      * @return boolean TRUE if the query results are enable for second level cache, FALSE otherwise.
  174.      */
  175.     public function isCacheable()
  176.     {
  177.         return $this->cacheable;
  178.     }
  179.     /**
  180.      * @param string $cacheRegion
  181.      *
  182.      * @return self
  183.      */
  184.     public function setCacheRegion($cacheRegion)
  185.     {
  186.         $this->cacheRegion = (string) $cacheRegion;
  187.         return $this;
  188.     }
  189.     /**
  190.     * Obtain the name of the second level query cache region in which query results will be stored
  191.     *
  192.     * @return string|null The cache region name; NULL indicates the default region.
  193.     */
  194.     public function getCacheRegion()
  195.     {
  196.         return $this->cacheRegion;
  197.     }
  198.     /**
  199.      * @return integer
  200.      */
  201.     public function getLifetime()
  202.     {
  203.         return $this->lifetime;
  204.     }
  205.     /**
  206.      * Sets the life-time for this query into second level cache.
  207.      *
  208.      * @param integer $lifetime
  209.      *
  210.      * @return self
  211.      */
  212.     public function setLifetime($lifetime)
  213.     {
  214.         $this->lifetime = (integer) $lifetime;
  215.         return $this;
  216.     }
  217.     /**
  218.      * @return integer
  219.      */
  220.     public function getCacheMode()
  221.     {
  222.         return $this->cacheMode;
  223.     }
  224.     /**
  225.      * @param integer $cacheMode
  226.      *
  227.      * @return self
  228.      */
  229.     public function setCacheMode($cacheMode)
  230.     {
  231.         $this->cacheMode = (integer) $cacheMode;
  232.         return $this;
  233.     }
  234.     /**
  235.      * Gets the type of the currently built query.
  236.      *
  237.      * @return integer
  238.      */
  239.     public function getType()
  240.     {
  241.         return $this->_type;
  242.     }
  243.     /**
  244.      * Gets the associated EntityManager for this query builder.
  245.      *
  246.      * @return EntityManager
  247.      */
  248.     public function getEntityManager()
  249.     {
  250.         return $this->_em;
  251.     }
  252.     /**
  253.      * Gets the state of this query builder instance.
  254.      *
  255.      * @return integer Either QueryBuilder::STATE_DIRTY or QueryBuilder::STATE_CLEAN.
  256.      */
  257.     public function getState()
  258.     {
  259.         return $this->_state;
  260.     }
  261.     /**
  262.      * Gets the complete DQL string formed by the current specifications of this QueryBuilder.
  263.      *
  264.      * <code>
  265.      *     $qb = $em->createQueryBuilder()
  266.      *         ->select('u')
  267.      *         ->from('User', 'u');
  268.      *     echo $qb->getDql(); // SELECT u FROM User u
  269.      * </code>
  270.      *
  271.      * @return string The DQL query string.
  272.      */
  273.     public function getDQL()
  274.     {
  275.         if ($this->_dql !== null && $this->_state === self::STATE_CLEAN) {
  276.             return $this->_dql;
  277.         }
  278.         switch ($this->_type) {
  279.             case self::DELETE:
  280.                 $dql $this->_getDQLForDelete();
  281.                 break;
  282.             case self::UPDATE:
  283.                 $dql $this->_getDQLForUpdate();
  284.                 break;
  285.             case self::SELECT:
  286.             default:
  287.                 $dql $this->_getDQLForSelect();
  288.                 break;
  289.         }
  290.         $this->_state self::STATE_CLEAN;
  291.         $this->_dql   $dql;
  292.         return $dql;
  293.     }
  294.     /**
  295.      * Constructs a Query instance from the current specifications of the builder.
  296.      *
  297.      * <code>
  298.      *     $qb = $em->createQueryBuilder()
  299.      *         ->select('u')
  300.      *         ->from('User', 'u');
  301.      *     $q = $qb->getQuery();
  302.      *     $results = $q->execute();
  303.      * </code>
  304.      *
  305.      * @return Query
  306.      */
  307.     public function getQuery()
  308.     {
  309.         $parameters = clone $this->parameters;
  310.         $query      $this->_em->createQuery($this->getDQL())
  311.             ->setParameters($parameters)
  312.             ->setFirstResult($this->_firstResult)
  313.             ->setMaxResults($this->_maxResults);
  314.         if ($this->lifetime) {
  315.             $query->setLifetime($this->lifetime);
  316.         }
  317.         if ($this->cacheMode) {
  318.             $query->setCacheMode($this->cacheMode);
  319.         }
  320.         if ($this->cacheable) {
  321.             $query->setCacheable($this->cacheable);
  322.         }
  323.         if ($this->cacheRegion) {
  324.             $query->setCacheRegion($this->cacheRegion);
  325.         }
  326.         return $query;
  327.     }
  328.     /**
  329.      * Finds the root entity alias of the joined entity.
  330.      *
  331.      * @param string $alias       The alias of the new join entity
  332.      * @param string $parentAlias The parent entity alias of the join relationship
  333.      *
  334.      * @return string
  335.      */
  336.     private function findRootAlias($alias$parentAlias)
  337.     {
  338.         $rootAlias null;
  339.         if (in_array($parentAlias$this->getRootAliases())) {
  340.             $rootAlias $parentAlias;
  341.         } elseif (isset($this->joinRootAliases[$parentAlias])) {
  342.             $rootAlias $this->joinRootAliases[$parentAlias];
  343.         } else {
  344.             // Should never happen with correct joining order. Might be
  345.             // thoughtful to throw exception instead.
  346.             $rootAlias $this->getRootAlias();
  347.         }
  348.         $this->joinRootAliases[$alias] = $rootAlias;
  349.         return $rootAlias;
  350.     }
  351.     /**
  352.      * Gets the FIRST root alias of the query. This is the first entity alias involved
  353.      * in the construction of the query.
  354.      *
  355.      * <code>
  356.      * $qb = $em->createQueryBuilder()
  357.      *     ->select('u')
  358.      *     ->from('User', 'u');
  359.      *
  360.      * echo $qb->getRootAlias(); // u
  361.      * </code>
  362.      *
  363.      * @deprecated Please use $qb->getRootAliases() instead.
  364.      * @throws \RuntimeException
  365.      *
  366.      * @return string
  367.      */
  368.     public function getRootAlias()
  369.     {
  370.         $aliases $this->getRootAliases();
  371.         if ( ! isset($aliases[0])) {
  372.             throw new \RuntimeException('No alias was set before invoking getRootAlias().');
  373.         }
  374.         return $aliases[0];
  375.     }
  376.     /**
  377.      * Gets the root aliases of the query. This is the entity aliases involved
  378.      * in the construction of the query.
  379.      *
  380.      * <code>
  381.      *     $qb = $em->createQueryBuilder()
  382.      *         ->select('u')
  383.      *         ->from('User', 'u');
  384.      *
  385.      *     $qb->getRootAliases(); // array('u')
  386.      * </code>
  387.      *
  388.      * @return array
  389.      */
  390.     public function getRootAliases()
  391.     {
  392.         $aliases = [];
  393.         foreach ($this->_dqlParts['from'] as &$fromClause) {
  394.             if (is_string($fromClause)) {
  395.                 $spacePos strrpos($fromClause' ');
  396.                 $from     substr($fromClause0$spacePos);
  397.                 $alias    substr($fromClause$spacePos 1);
  398.                 $fromClause = new Query\Expr\From($from$alias);
  399.             }
  400.             $aliases[] = $fromClause->getAlias();
  401.         }
  402.         return $aliases;
  403.     }
  404.     /**
  405.      * Gets all the aliases that have been used in the query.
  406.      * Including all select root aliases and join aliases
  407.      *
  408.      * <code>
  409.      *     $qb = $em->createQueryBuilder()
  410.      *         ->select('u')
  411.      *         ->from('User', 'u')
  412.      *         ->join('u.articles','a');
  413.      *
  414.      *     $qb->getAllAliases(); // array('u','a')
  415.      * </code>
  416.      * @return array
  417.      */
  418.     public function getAllAliases()
  419.     {
  420.         return array_merge($this->getRootAliases(), array_keys($this->joinRootAliases));
  421.     }
  422.     /**
  423.      * Gets the root entities of the query. This is the entity aliases involved
  424.      * in the construction of the query.
  425.      *
  426.      * <code>
  427.      *     $qb = $em->createQueryBuilder()
  428.      *         ->select('u')
  429.      *         ->from('User', 'u');
  430.      *
  431.      *     $qb->getRootEntities(); // array('User')
  432.      * </code>
  433.      *
  434.      * @return array
  435.      */
  436.     public function getRootEntities()
  437.     {
  438.         $entities = [];
  439.         foreach ($this->_dqlParts['from'] as &$fromClause) {
  440.             if (is_string($fromClause)) {
  441.                 $spacePos strrpos($fromClause' ');
  442.                 $from     substr($fromClause0$spacePos);
  443.                 $alias    substr($fromClause$spacePos 1);
  444.                 $fromClause = new Query\Expr\From($from$alias);
  445.             }
  446.             $entities[] = $fromClause->getFrom();
  447.         }
  448.         return $entities;
  449.     }
  450.     /**
  451.      * Sets a query parameter for the query being constructed.
  452.      *
  453.      * <code>
  454.      *     $qb = $em->createQueryBuilder()
  455.      *         ->select('u')
  456.      *         ->from('User', 'u')
  457.      *         ->where('u.id = :user_id')
  458.      *         ->setParameter('user_id', 1);
  459.      * </code>
  460.      *
  461.      * @param string|integer $key   The parameter position or name.
  462.      * @param mixed          $value The parameter value.
  463.      * @param string|integer|null    $type  PDO::PARAM_* or \Doctrine\DBAL\Types\Type::* constant
  464.      *
  465.      * @return self
  466.      */
  467.     public function setParameter($key$value$type null)
  468.     {
  469.         $existingParameter $this->getParameter($key);
  470.         if ($existingParameter !== null) {
  471.             $existingParameter->setValue($value$type);
  472.             return $this;
  473.         }
  474.         $this->parameters->add(new Query\Parameter($key$value$type));
  475.         return $this;
  476.     }
  477.     /**
  478.      * Sets a collection of query parameters for the query being constructed.
  479.      *
  480.      * <code>
  481.      *     $qb = $em->createQueryBuilder()
  482.      *         ->select('u')
  483.      *         ->from('User', 'u')
  484.      *         ->where('u.id = :user_id1 OR u.id = :user_id2')
  485.      *         ->setParameters(new ArrayCollection(array(
  486.      *             new Parameter('user_id1', 1),
  487.      *             new Parameter('user_id2', 2)
  488.      *        )));
  489.      * </code>
  490.      *
  491.      * @param \Doctrine\Common\Collections\ArrayCollection|array $parameters The query parameters to set.
  492.      *
  493.      * @return self
  494.      */
  495.     public function setParameters($parameters)
  496.     {
  497.         // BC compatibility with 2.3-
  498.         if (is_array($parameters)) {
  499.             $parameterCollection = new ArrayCollection();
  500.             foreach ($parameters as $key => $value) {
  501.                 $parameter = new Query\Parameter($key$value);
  502.                 $parameterCollection->add($parameter);
  503.             }
  504.             $parameters $parameterCollection;
  505.         }
  506.         $this->parameters $parameters;
  507.         return $this;
  508.     }
  509.     /**
  510.      * Gets all defined query parameters for the query being constructed.
  511.      *
  512.      * @return \Doctrine\Common\Collections\ArrayCollection The currently defined query parameters.
  513.      */
  514.     public function getParameters()
  515.     {
  516.         return $this->parameters;
  517.     }
  518.     /**
  519.      * Gets a (previously set) query parameter of the query being constructed.
  520.      *
  521.      * @param mixed $key The key (index or name) of the bound parameter.
  522.      *
  523.      * @return Query\Parameter|null The value of the bound parameter.
  524.      */
  525.     public function getParameter($key)
  526.     {
  527.         $filteredParameters $this->parameters->filter(
  528.             function (Query\Parameter $parameter) use ($key) : bool {
  529.                 $parameterName $parameter->getName();
  530.                 return $key === $parameterName || (string) $key === (string) $parameterName;
  531.             }
  532.         );
  533.         return ! $filteredParameters->isEmpty() ? $filteredParameters->first() : null;
  534.     }
  535.     /**
  536.      * Sets the position of the first result to retrieve (the "offset").
  537.      *
  538.      * @param int|null $firstResult The first result to return.
  539.      *
  540.      * @return self
  541.      */
  542.     public function setFirstResult($firstResult)
  543.     {
  544.         $this->_firstResult $firstResult;
  545.         return $this;
  546.     }
  547.     /**
  548.      * Gets the position of the first result the query object was set to retrieve (the "offset").
  549.      * Returns NULL if {@link setFirstResult} was not applied to this QueryBuilder.
  550.      *
  551.      * @return int|null The position of the first result.
  552.      */
  553.     public function getFirstResult()
  554.     {
  555.         return $this->_firstResult;
  556.     }
  557.     /**
  558.      * Sets the maximum number of results to retrieve (the "limit").
  559.      *
  560.      * @param integer|null $maxResults The maximum number of results to retrieve.
  561.      *
  562.      * @return self
  563.      */
  564.     public function setMaxResults($maxResults)
  565.     {
  566.         $this->_maxResults $maxResults;
  567.         return $this;
  568.     }
  569.     /**
  570.      * Gets the maximum number of results the query object was set to retrieve (the "limit").
  571.      * Returns NULL if {@link setMaxResults} was not applied to this query builder.
  572.      *
  573.      * @return integer|null Maximum number of results.
  574.      */
  575.     public function getMaxResults()
  576.     {
  577.         return $this->_maxResults;
  578.     }
  579.     /**
  580.      * Either appends to or replaces a single, generic query part.
  581.      *
  582.      * The available parts are: 'select', 'from', 'join', 'set', 'where',
  583.      * 'groupBy', 'having' and 'orderBy'.
  584.      *
  585.      * @param string       $dqlPartName The DQL part name.
  586.      * @param object|array $dqlPart     An Expr object.
  587.      * @param bool         $append      Whether to append (true) or replace (false).
  588.      *
  589.      * @return self
  590.      */
  591.     public function add($dqlPartName$dqlPart$append false)
  592.     {
  593.         if ($append && ($dqlPartName === "where" || $dqlPartName === "having")) {
  594.             throw new \InvalidArgumentException(
  595.                 "Using \$append = true does not have an effect with 'where' or 'having' ".
  596.                 "parts. See QueryBuilder#andWhere() for an example for correct usage."
  597.             );
  598.         }
  599.         $isMultiple is_array($this->_dqlParts[$dqlPartName])
  600.             && !($dqlPartName == 'join' && !$append);
  601.         // Allow adding any part retrieved from self::getDQLParts().
  602.         if (is_array($dqlPart) && $dqlPartName != 'join') {
  603.             $dqlPart reset($dqlPart);
  604.         }
  605.         // This is introduced for backwards compatibility reasons.
  606.         // TODO: Remove for 3.0
  607.         if ($dqlPartName == 'join') {
  608.             $newDqlPart = [];
  609.             foreach ($dqlPart as $k => $v) {
  610.                 $k is_numeric($k) ? $this->getRootAlias() : $k;
  611.                 $newDqlPart[$k] = $v;
  612.             }
  613.             $dqlPart $newDqlPart;
  614.         }
  615.         if ($append && $isMultiple) {
  616.             if (is_array($dqlPart)) {
  617.                 $key key($dqlPart);
  618.                 $this->_dqlParts[$dqlPartName][$key][] = $dqlPart[$key];
  619.             } else {
  620.                 $this->_dqlParts[$dqlPartName][] = $dqlPart;
  621.             }
  622.         } else {
  623.             $this->_dqlParts[$dqlPartName] = ($isMultiple) ? [$dqlPart] : $dqlPart;
  624.         }
  625.         $this->_state self::STATE_DIRTY;
  626.         return $this;
  627.     }
  628.     /**
  629.      * Specifies an item that is to be returned in the query result.
  630.      * Replaces any previously specified selections, if any.
  631.      *
  632.      * <code>
  633.      *     $qb = $em->createQueryBuilder()
  634.      *         ->select('u', 'p')
  635.      *         ->from('User', 'u')
  636.      *         ->leftJoin('u.Phonenumbers', 'p');
  637.      * </code>
  638.      *
  639.      * @param mixed $select The selection expressions.
  640.      *
  641.      * @return self
  642.      */
  643.     public function select($select null)
  644.     {
  645.         $this->_type self::SELECT;
  646.         if (empty($select)) {
  647.             return $this;
  648.         }
  649.         $selects is_array($select) ? $select func_get_args();
  650.         return $this->add('select', new Expr\Select($selects), false);
  651.     }
  652.     /**
  653.      * Adds a DISTINCT flag to this query.
  654.      *
  655.      * <code>
  656.      *     $qb = $em->createQueryBuilder()
  657.      *         ->select('u')
  658.      *         ->distinct()
  659.      *         ->from('User', 'u');
  660.      * </code>
  661.      *
  662.      * @param bool $flag
  663.      *
  664.      * @return self
  665.      */
  666.     public function distinct($flag true)
  667.     {
  668.         $this->_dqlParts['distinct'] = (bool) $flag;
  669.         return $this;
  670.     }
  671.     /**
  672.      * Adds an item that is to be returned in the query result.
  673.      *
  674.      * <code>
  675.      *     $qb = $em->createQueryBuilder()
  676.      *         ->select('u')
  677.      *         ->addSelect('p')
  678.      *         ->from('User', 'u')
  679.      *         ->leftJoin('u.Phonenumbers', 'p');
  680.      * </code>
  681.      *
  682.      * @param mixed $select The selection expression.
  683.      *
  684.      * @return self
  685.      */
  686.     public function addSelect($select null)
  687.     {
  688.         $this->_type self::SELECT;
  689.         if (empty($select)) {
  690.             return $this;
  691.         }
  692.         $selects is_array($select) ? $select func_get_args();
  693.         return $this->add('select', new Expr\Select($selects), true);
  694.     }
  695.     /**
  696.      * Turns the query being built into a bulk delete query that ranges over
  697.      * a certain entity type.
  698.      *
  699.      * <code>
  700.      *     $qb = $em->createQueryBuilder()
  701.      *         ->delete('User', 'u')
  702.      *         ->where('u.id = :user_id')
  703.      *         ->setParameter('user_id', 1);
  704.      * </code>
  705.      *
  706.      * @param string $delete The class/type whose instances are subject to the deletion.
  707.      * @param string $alias  The class/type alias used in the constructed query.
  708.      *
  709.      * @return self
  710.      */
  711.     public function delete($delete null$alias null)
  712.     {
  713.         $this->_type self::DELETE;
  714.         if ( ! $delete) {
  715.             return $this;
  716.         }
  717.         return $this->add('from', new Expr\From($delete$alias));
  718.     }
  719.     /**
  720.      * Turns the query being built into a bulk update query that ranges over
  721.      * a certain entity type.
  722.      *
  723.      * <code>
  724.      *     $qb = $em->createQueryBuilder()
  725.      *         ->update('User', 'u')
  726.      *         ->set('u.password', '?1')
  727.      *         ->where('u.id = ?2');
  728.      * </code>
  729.      *
  730.      * @param string $update The class/type whose instances are subject to the update.
  731.      * @param string $alias  The class/type alias used in the constructed query.
  732.      *
  733.      * @return self
  734.      */
  735.     public function update($update null$alias null)
  736.     {
  737.         $this->_type self::UPDATE;
  738.         if ( ! $update) {
  739.             return $this;
  740.         }
  741.         return $this->add('from', new Expr\From($update$alias));
  742.     }
  743.     /**
  744.      * Creates and adds a query root corresponding to the entity identified by the given alias,
  745.      * forming a cartesian product with any existing query roots.
  746.      *
  747.      * <code>
  748.      *     $qb = $em->createQueryBuilder()
  749.      *         ->select('u')
  750.      *         ->from('User', 'u');
  751.      * </code>
  752.      *
  753.      * @param string $from    The class name.
  754.      * @param string $alias   The alias of the class.
  755.      * @param string $indexBy The index for the from.
  756.      *
  757.      * @return self
  758.      */
  759.     public function from($from$alias$indexBy null)
  760.     {
  761.         return $this->add('from', new Expr\From($from$alias$indexBy), true);
  762.     }
  763.     /**
  764.      * Updates a query root corresponding to an entity setting its index by. This method is intended to be used with
  765.      * EntityRepository->createQueryBuilder(), which creates the initial FROM clause and do not allow you to update it
  766.      * setting an index by.
  767.      *
  768.      * <code>
  769.      *     $qb = $userRepository->createQueryBuilder('u')
  770.      *         ->indexBy('u', 'u.id');
  771.      *
  772.      *     // Is equivalent to...
  773.      *
  774.      *     $qb = $em->createQueryBuilder()
  775.      *         ->select('u')
  776.      *         ->from('User', 'u', 'u.id');
  777.      * </code>
  778.      *
  779.      * @param string $alias   The root alias of the class.
  780.      * @param string $indexBy The index for the from.
  781.      *
  782.      * @return self
  783.      *
  784.      * @throws Query\QueryException
  785.      */
  786.     public function indexBy($alias$indexBy)
  787.     {
  788.         $rootAliases $this->getRootAliases();
  789.         if (!in_array($alias$rootAliases)) {
  790.             throw new Query\QueryException(
  791.                 sprintf('Specified root alias %s must be set before invoking indexBy().'$alias)
  792.             );
  793.         }
  794.         foreach ($this->_dqlParts['from'] as &$fromClause) {
  795.             /* @var Expr\From $fromClause */
  796.             if ($fromClause->getAlias() !== $alias) {
  797.                 continue;
  798.             }
  799.             $fromClause = new Expr\From($fromClause->getFrom(), $fromClause->getAlias(), $indexBy);
  800.         }
  801.         return $this;
  802.     }
  803.     /**
  804.      * Creates and adds a join over an entity association to the query.
  805.      *
  806.      * The entities in the joined association will be fetched as part of the query
  807.      * result if the alias used for the joined association is placed in the select
  808.      * expressions.
  809.      *
  810.      * <code>
  811.      *     $qb = $em->createQueryBuilder()
  812.      *         ->select('u')
  813.      *         ->from('User', 'u')
  814.      *         ->join('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1');
  815.      * </code>
  816.      *
  817.      * @param string      $join          The relationship to join.
  818.      * @param string      $alias         The alias of the join.
  819.      * @param string|null $conditionType The condition type constant. Either ON or WITH.
  820.      * @param string|null $condition     The condition for the join.
  821.      * @param string|null $indexBy       The index for the join.
  822.      *
  823.      * @return self
  824.      */
  825.     public function join($join$alias$conditionType null$condition null$indexBy null)
  826.     {
  827.         return $this->innerJoin($join$alias$conditionType$condition$indexBy);
  828.     }
  829.     /**
  830.      * Creates and adds a join over an entity association to the query.
  831.      *
  832.      * The entities in the joined association will be fetched as part of the query
  833.      * result if the alias used for the joined association is placed in the select
  834.      * expressions.
  835.      *
  836.      *     [php]
  837.      *     $qb = $em->createQueryBuilder()
  838.      *         ->select('u')
  839.      *         ->from('User', 'u')
  840.      *         ->innerJoin('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1');
  841.      *
  842.      * @param string      $join          The relationship to join.
  843.      * @param string      $alias         The alias of the join.
  844.      * @param string|null $conditionType The condition type constant. Either ON or WITH.
  845.      * @param string|null $condition     The condition for the join.
  846.      * @param string|null $indexBy       The index for the join.
  847.      *
  848.      * @return self
  849.      */
  850.     public function innerJoin($join$alias$conditionType null$condition null$indexBy null)
  851.     {
  852.         $parentAlias substr($join0strpos($join'.'));
  853.         $rootAlias $this->findRootAlias($alias$parentAlias);
  854.         $join = new Expr\Join(
  855.             Expr\Join::INNER_JOIN$join$alias$conditionType$condition$indexBy
  856.         );
  857.         return $this->add('join', [$rootAlias => $join], true);
  858.     }
  859.     /**
  860.      * Creates and adds a left join over an entity association to the query.
  861.      *
  862.      * The entities in the joined association will be fetched as part of the query
  863.      * result if the alias used for the joined association is placed in the select
  864.      * expressions.
  865.      *
  866.      * <code>
  867.      *     $qb = $em->createQueryBuilder()
  868.      *         ->select('u')
  869.      *         ->from('User', 'u')
  870.      *         ->leftJoin('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1');
  871.      * </code>
  872.      *
  873.      * @param string      $join          The relationship to join.
  874.      * @param string      $alias         The alias of the join.
  875.      * @param string|null $conditionType The condition type constant. Either ON or WITH.
  876.      * @param string|null $condition     The condition for the join.
  877.      * @param string|null $indexBy       The index for the join.
  878.      *
  879.      * @return self
  880.      */
  881.     public function leftJoin($join$alias$conditionType null$condition null$indexBy null)
  882.     {
  883.         $parentAlias substr($join0strpos($join'.'));
  884.         $rootAlias $this->findRootAlias($alias$parentAlias);
  885.         $join = new Expr\Join(
  886.             Expr\Join::LEFT_JOIN$join$alias$conditionType$condition$indexBy
  887.         );
  888.         return $this->add('join', [$rootAlias => $join], true);
  889.     }
  890.     /**
  891.      * Sets a new value for a field in a bulk update query.
  892.      *
  893.      * <code>
  894.      *     $qb = $em->createQueryBuilder()
  895.      *         ->update('User', 'u')
  896.      *         ->set('u.password', '?1')
  897.      *         ->where('u.id = ?2');
  898.      * </code>
  899.      *
  900.      * @param string $key   The key/field to set.
  901.      * @param mixed  $value The value, expression, placeholder, etc.
  902.      *
  903.      * @return self
  904.      */
  905.     public function set($key$value)
  906.     {
  907.         return $this->add('set', new Expr\Comparison($keyExpr\Comparison::EQ$value), true);
  908.     }
  909.     /**
  910.      * Specifies one or more restrictions to the query result.
  911.      * Replaces any previously specified restrictions, if any.
  912.      *
  913.      * <code>
  914.      *     $qb = $em->createQueryBuilder()
  915.      *         ->select('u')
  916.      *         ->from('User', 'u')
  917.      *         ->where('u.id = ?');
  918.      *
  919.      *     // You can optionally programmatically build and/or expressions
  920.      *     $qb = $em->createQueryBuilder();
  921.      *
  922.      *     $or = $qb->expr()->orX();
  923.      *     $or->add($qb->expr()->eq('u.id', 1));
  924.      *     $or->add($qb->expr()->eq('u.id', 2));
  925.      *
  926.      *     $qb->update('User', 'u')
  927.      *         ->set('u.password', '?')
  928.      *         ->where($or);
  929.      * </code>
  930.      *
  931.      * @param mixed $predicates The restriction predicates.
  932.      *
  933.      * @return self
  934.      */
  935.     public function where($predicates)
  936.     {
  937.         if ( ! (func_num_args() == && $predicates instanceof Expr\Composite)) {
  938.             $predicates = new Expr\Andx(func_get_args());
  939.         }
  940.         return $this->add('where'$predicates);
  941.     }
  942.     /**
  943.      * Adds one or more restrictions to the query results, forming a logical
  944.      * conjunction with any previously specified restrictions.
  945.      *
  946.      * <code>
  947.      *     $qb = $em->createQueryBuilder()
  948.      *         ->select('u')
  949.      *         ->from('User', 'u')
  950.      *         ->where('u.username LIKE ?')
  951.      *         ->andWhere('u.is_active = 1');
  952.      * </code>
  953.      *
  954.      * @param mixed $where The query restrictions.
  955.      *
  956.      * @return self
  957.      *
  958.      * @see where()
  959.      */
  960.     public function andWhere()
  961.     {
  962.         $args  func_get_args();
  963.         $where $this->getDQLPart('where');
  964.         if ($where instanceof Expr\Andx) {
  965.             $where->addMultiple($args);
  966.         } else {
  967.             array_unshift($args$where);
  968.             $where = new Expr\Andx($args);
  969.         }
  970.         return $this->add('where'$where);
  971.     }
  972.     /**
  973.      * Adds one or more restrictions to the query results, forming a logical
  974.      * disjunction with any previously specified restrictions.
  975.      *
  976.      * <code>
  977.      *     $qb = $em->createQueryBuilder()
  978.      *         ->select('u')
  979.      *         ->from('User', 'u')
  980.      *         ->where('u.id = 1')
  981.      *         ->orWhere('u.id = 2');
  982.      * </code>
  983.      *
  984.      * @param mixed $where The WHERE statement.
  985.      *
  986.      * @return self
  987.      *
  988.      * @see where()
  989.      */
  990.     public function orWhere()
  991.     {
  992.         $args  func_get_args();
  993.         $where $this->getDQLPart('where');
  994.         if ($where instanceof Expr\Orx) {
  995.             $where->addMultiple($args);
  996.         } else {
  997.             array_unshift($args$where);
  998.             $where = new Expr\Orx($args);
  999.         }
  1000.         return $this->add('where'$where);
  1001.     }
  1002.     /**
  1003.      * Specifies a grouping over the results of the query.
  1004.      * Replaces any previously specified groupings, if any.
  1005.      *
  1006.      * <code>
  1007.      *     $qb = $em->createQueryBuilder()
  1008.      *         ->select('u')
  1009.      *         ->from('User', 'u')
  1010.      *         ->groupBy('u.id');
  1011.      * </code>
  1012.      *
  1013.      * @param string $groupBy The grouping expression.
  1014.      *
  1015.      * @return self
  1016.      */
  1017.     public function groupBy($groupBy)
  1018.     {
  1019.         return $this->add('groupBy', new Expr\GroupBy(func_get_args()));
  1020.     }
  1021.     /**
  1022.      * Adds a grouping expression to the query.
  1023.      *
  1024.      * <code>
  1025.      *     $qb = $em->createQueryBuilder()
  1026.      *         ->select('u')
  1027.      *         ->from('User', 'u')
  1028.      *         ->groupBy('u.lastLogin')
  1029.      *         ->addGroupBy('u.createdAt');
  1030.      * </code>
  1031.      *
  1032.      * @param string $groupBy The grouping expression.
  1033.      *
  1034.      * @return self
  1035.      */
  1036.     public function addGroupBy($groupBy)
  1037.     {
  1038.         return $this->add('groupBy', new Expr\GroupBy(func_get_args()), true);
  1039.     }
  1040.     /**
  1041.      * Specifies a restriction over the groups of the query.
  1042.      * Replaces any previous having restrictions, if any.
  1043.      *
  1044.      * @param mixed $having The restriction over the groups.
  1045.      *
  1046.      * @return self
  1047.      */
  1048.     public function having($having)
  1049.     {
  1050.         if ( ! (func_num_args() == && ($having instanceof Expr\Andx || $having instanceof Expr\Orx))) {
  1051.             $having = new Expr\Andx(func_get_args());
  1052.         }
  1053.         return $this->add('having'$having);
  1054.     }
  1055.     /**
  1056.      * Adds a restriction over the groups of the query, forming a logical
  1057.      * conjunction with any existing having restrictions.
  1058.      *
  1059.      * @param mixed $having The restriction to append.
  1060.      *
  1061.      * @return self
  1062.      */
  1063.     public function andHaving($having)
  1064.     {
  1065.         $args   func_get_args();
  1066.         $having $this->getDQLPart('having');
  1067.         if ($having instanceof Expr\Andx) {
  1068.             $having->addMultiple($args);
  1069.         } else {
  1070.             array_unshift($args$having);
  1071.             $having = new Expr\Andx($args);
  1072.         }
  1073.         return $this->add('having'$having);
  1074.     }
  1075.     /**
  1076.      * Adds a restriction over the groups of the query, forming a logical
  1077.      * disjunction with any existing having restrictions.
  1078.      *
  1079.      * @param mixed $having The restriction to add.
  1080.      *
  1081.      * @return self
  1082.      */
  1083.     public function orHaving($having)
  1084.     {
  1085.         $args   func_get_args();
  1086.         $having $this->getDQLPart('having');
  1087.         if ($having instanceof Expr\Orx) {
  1088.             $having->addMultiple($args);
  1089.         } else {
  1090.             array_unshift($args$having);
  1091.             $having = new Expr\Orx($args);
  1092.         }
  1093.         return $this->add('having'$having);
  1094.     }
  1095.     /**
  1096.      * Specifies an ordering for the query results.
  1097.      * Replaces any previously specified orderings, if any.
  1098.      *
  1099.      * @param string|Expr\OrderBy $sort  The ordering expression.
  1100.      * @param string              $order The ordering direction.
  1101.      *
  1102.      * @return self
  1103.      */
  1104.     public function orderBy($sort$order null)
  1105.     {
  1106.         $orderBy = ($sort instanceof Expr\OrderBy) ? $sort : new Expr\OrderBy($sort$order);
  1107.         return $this->add('orderBy'$orderBy);
  1108.     }
  1109.     /**
  1110.      * Adds an ordering to the query results.
  1111.      *
  1112.      * @param string|Expr\OrderBy $sort  The ordering expression.
  1113.      * @param string              $order The ordering direction.
  1114.      *
  1115.      * @return self
  1116.      */
  1117.     public function addOrderBy($sort$order null)
  1118.     {
  1119.         $orderBy = ($sort instanceof Expr\OrderBy) ? $sort : new Expr\OrderBy($sort$order);
  1120.         return $this->add('orderBy'$orderBytrue);
  1121.     }
  1122.     /**
  1123.      * Adds criteria to the query.
  1124.      *
  1125.      * Adds where expressions with AND operator.
  1126.      * Adds orderings.
  1127.      * Overrides firstResult and maxResults if they're set.
  1128.      *
  1129.      * @param Criteria $criteria
  1130.      *
  1131.      * @return self
  1132.      *
  1133.      * @throws Query\QueryException
  1134.      */
  1135.     public function addCriteria(Criteria $criteria)
  1136.     {
  1137.         $allAliases $this->getAllAliases();
  1138.         if ( ! isset($allAliases[0])) {
  1139.             throw new Query\QueryException('No aliases are set before invoking addCriteria().');
  1140.         }
  1141.         $visitor = new QueryExpressionVisitor($this->getAllAliases());
  1142.         if ($whereExpression $criteria->getWhereExpression()) {
  1143.             $this->andWhere($visitor->dispatch($whereExpression));
  1144.             foreach ($visitor->getParameters() as $parameter) {
  1145.                 $this->parameters->add($parameter);
  1146.             }
  1147.         }
  1148.         if ($criteria->getOrderings()) {
  1149.             foreach ($criteria->getOrderings() as $sort => $order) {
  1150.                 $hasValidAlias false;
  1151.                 foreach($allAliases as $alias) {
  1152.                     if(strpos($sort '.'$alias '.') === 0) {
  1153.                         $hasValidAlias true;
  1154.                         break;
  1155.                     }
  1156.                 }
  1157.                 if(!$hasValidAlias) {
  1158.                     $sort $allAliases[0] . '.' $sort;
  1159.                 }
  1160.                 $this->addOrderBy($sort$order);
  1161.             }
  1162.         }
  1163.         // Overwrite limits only if they was set in criteria
  1164.         if (($firstResult $criteria->getFirstResult()) !== null) {
  1165.             $this->setFirstResult($firstResult);
  1166.         }
  1167.         if (($maxResults $criteria->getMaxResults()) !== null) {
  1168.             $this->setMaxResults($maxResults);
  1169.         }
  1170.         return $this;
  1171.     }
  1172.     /**
  1173.      * Gets a query part by its name.
  1174.      *
  1175.      * @param string $queryPartName
  1176.      *
  1177.      * @return mixed $queryPart
  1178.      */
  1179.     public function getDQLPart($queryPartName)
  1180.     {
  1181.         return $this->_dqlParts[$queryPartName];
  1182.     }
  1183.     /**
  1184.      * Gets all query parts.
  1185.      *
  1186.      * @return array $dqlParts
  1187.      */
  1188.     public function getDQLParts()
  1189.     {
  1190.         return $this->_dqlParts;
  1191.     }
  1192.     /**
  1193.      * @return string
  1194.      */
  1195.     private function _getDQLForDelete()
  1196.     {
  1197.          return 'DELETE'
  1198.               $this->_getReducedDQLQueryPart('from', ['pre' => ' ''separator' => ', '])
  1199.               . $this->_getReducedDQLQueryPart('where', ['pre' => ' WHERE '])
  1200.               . $this->_getReducedDQLQueryPart('orderBy', ['pre' => ' ORDER BY ''separator' => ', ']);
  1201.     }
  1202.     /**
  1203.      * @return string
  1204.      */
  1205.     private function _getDQLForUpdate()
  1206.     {
  1207.          return 'UPDATE'
  1208.               $this->_getReducedDQLQueryPart('from', ['pre' => ' ''separator' => ', '])
  1209.               . $this->_getReducedDQLQueryPart('set', ['pre' => ' SET ''separator' => ', '])
  1210.               . $this->_getReducedDQLQueryPart('where', ['pre' => ' WHERE '])
  1211.               . $this->_getReducedDQLQueryPart('orderBy', ['pre' => ' ORDER BY ''separator' => ', ']);
  1212.     }
  1213.     /**
  1214.      * @return string
  1215.      */
  1216.     private function _getDQLForSelect()
  1217.     {
  1218.         $dql 'SELECT'
  1219.              . ($this->_dqlParts['distinct']===true ' DISTINCT' '')
  1220.              . $this->_getReducedDQLQueryPart('select', ['pre' => ' ''separator' => ', ']);
  1221.         $fromParts   $this->getDQLPart('from');
  1222.         $joinParts   $this->getDQLPart('join');
  1223.         $fromClauses = [];
  1224.         // Loop through all FROM clauses
  1225.         if ( ! empty($fromParts)) {
  1226.             $dql .= ' FROM ';
  1227.             foreach ($fromParts as $from) {
  1228.                 $fromClause = (string) $from;
  1229.                 if ($from instanceof Expr\From && isset($joinParts[$from->getAlias()])) {
  1230.                     foreach ($joinParts[$from->getAlias()] as $join) {
  1231.                         $fromClause .= ' ' . ((string) $join);
  1232.                     }
  1233.                 }
  1234.                 $fromClauses[] = $fromClause;
  1235.             }
  1236.         }
  1237.         $dql .= implode(', '$fromClauses)
  1238.               . $this->_getReducedDQLQueryPart('where', ['pre' => ' WHERE '])
  1239.               . $this->_getReducedDQLQueryPart('groupBy', ['pre' => ' GROUP BY ''separator' => ', '])
  1240.               . $this->_getReducedDQLQueryPart('having', ['pre' => ' HAVING '])
  1241.               . $this->_getReducedDQLQueryPart('orderBy', ['pre' => ' ORDER BY ''separator' => ', ']);
  1242.         return $dql;
  1243.     }
  1244.     /**
  1245.      * @param string $queryPartName
  1246.      * @param array  $options
  1247.      *
  1248.      * @return string
  1249.      */
  1250.     private function _getReducedDQLQueryPart($queryPartName$options = [])
  1251.     {
  1252.         $queryPart $this->getDQLPart($queryPartName);
  1253.         if (empty($queryPart)) {
  1254.             return ($options['empty'] ?? '');
  1255.         }
  1256.         return ($options['pre'] ?? '')
  1257.              . (is_array($queryPart) ? implode($options['separator'], $queryPart) : $queryPart)
  1258.              . ($options['post'] ?? '');
  1259.     }
  1260.     /**
  1261.      * Resets DQL parts.
  1262.      *
  1263.      * @param array|null $parts
  1264.      *
  1265.      * @return self
  1266.      */
  1267.     public function resetDQLParts($parts null)
  1268.     {
  1269.         if (null === $parts) {
  1270.             $parts array_keys($this->_dqlParts);
  1271.         }
  1272.         foreach ($parts as $part) {
  1273.             $this->resetDQLPart($part);
  1274.         }
  1275.         return $this;
  1276.     }
  1277.     /**
  1278.      * Resets single DQL part.
  1279.      *
  1280.      * @param string $part
  1281.      *
  1282.      * @return self
  1283.      */
  1284.     public function resetDQLPart($part)
  1285.     {
  1286.         $this->_dqlParts[$part] = is_array($this->_dqlParts[$part]) ? [] : null;
  1287.         $this->_state           self::STATE_DIRTY;
  1288.         return $this;
  1289.     }
  1290.     /**
  1291.      * Gets a string representation of this QueryBuilder which corresponds to
  1292.      * the final DQL query being constructed.
  1293.      *
  1294.      * @return string The string representation of this QueryBuilder.
  1295.      */
  1296.     public function __toString()
  1297.     {
  1298.         return $this->getDQL();
  1299.     }
  1300.     /**
  1301.      * Deep clones all expression objects in the DQL parts.
  1302.      *
  1303.      * @return void
  1304.      */
  1305.     public function __clone()
  1306.     {
  1307.         foreach ($this->_dqlParts as $part => $elements) {
  1308.             if (is_array($this->_dqlParts[$part])) {
  1309.                 foreach ($this->_dqlParts[$part] as $idx => $element) {
  1310.                     if (is_object($element)) {
  1311.                         $this->_dqlParts[$part][$idx] = clone $element;
  1312.                     }
  1313.                 }
  1314.             } else if (is_object($elements)) {
  1315.                 $this->_dqlParts[$part] = clone $elements;
  1316.             }
  1317.         }
  1318.         $parameters = [];
  1319.         foreach ($this->parameters as $parameter) {
  1320.             $parameters[] = clone $parameter;
  1321.         }
  1322.         $this->parameters = new ArrayCollection($parameters);
  1323.     }
  1324. }