PageRenderTime 54ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Doctrine/ORM/QueryBuilder.php

https://bitbucket.org/maatao/estrutura-b-sica-doctrine
PHP | 955 lines | 352 code | 91 blank | 512 comment | 35 complexity | 6f022f5a279405ed6a23b122df5744d5 MD5 | raw file
  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. namespace Doctrine\ORM;
  20. use Doctrine\ORM\Query\Expr;
  21. /**
  22. * This class is responsible for building DQL query strings via an object oriented
  23. * PHP interface.
  24. *
  25. * @since 2.0
  26. * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
  27. * @author Jonathan Wage <jonwage@gmail.com>
  28. * @author Roman Borschel <roman@code-factory.org>
  29. */
  30. class QueryBuilder
  31. {
  32. /* The query types. */
  33. const SELECT = 0;
  34. const DELETE = 1;
  35. const UPDATE = 2;
  36. /** The builder states. */
  37. const STATE_DIRTY = 0;
  38. const STATE_CLEAN = 1;
  39. /**
  40. * @var EntityManager The EntityManager used by this QueryBuilder.
  41. */
  42. private $_em;
  43. /**
  44. * @var array The array of DQL parts collected.
  45. */
  46. private $_dqlParts = array(
  47. 'select' => array(),
  48. 'from' => array(),
  49. 'join' => array(),
  50. 'set' => array(),
  51. 'where' => null,
  52. 'groupBy' => array(),
  53. 'having' => null,
  54. 'orderBy' => array()
  55. );
  56. /**
  57. * @var integer The type of query this is. Can be select, update or delete.
  58. */
  59. private $_type = self::SELECT;
  60. /**
  61. * @var integer The state of the query object. Can be dirty or clean.
  62. */
  63. private $_state = self::STATE_CLEAN;
  64. /**
  65. * @var string The complete DQL string for this query.
  66. */
  67. private $_dql;
  68. /**
  69. * @var array The query parameters.
  70. */
  71. private $_params = array();
  72. /**
  73. * @var array The parameter type map of this query.
  74. */
  75. private $_paramTypes = array();
  76. /**
  77. * @var integer The index of the first result to retrieve.
  78. */
  79. private $_firstResult = null;
  80. /**
  81. * @var integer The maximum number of results to retrieve.
  82. */
  83. private $_maxResults = null;
  84. /**
  85. * Initializes a new <tt>QueryBuilder</tt> that uses the given <tt>EntityManager</tt>.
  86. *
  87. * @param EntityManager $em The EntityManager to use.
  88. */
  89. public function __construct(EntityManager $em)
  90. {
  91. $this->_em = $em;
  92. }
  93. /**
  94. * Gets an ExpressionBuilder used for object-oriented construction of query expressions.
  95. * This producer method is intended for convenient inline usage. Example:
  96. *
  97. * <code>
  98. * $qb = $em->createQueryBuilder()
  99. * ->select('u')
  100. * ->from('User', 'u')
  101. * ->where($qb->expr()->eq('u.id', 1));
  102. * </code>
  103. *
  104. * For more complex expression construction, consider storing the expression
  105. * builder object in a local variable.
  106. *
  107. * @return Expr
  108. */
  109. public function expr()
  110. {
  111. return $this->_em->getExpressionBuilder();
  112. }
  113. /**
  114. * Get the type of the currently built query.
  115. *
  116. * @return integer
  117. */
  118. public function getType()
  119. {
  120. return $this->_type;
  121. }
  122. /**
  123. * Get the associated EntityManager for this query builder.
  124. *
  125. * @return EntityManager
  126. */
  127. public function getEntityManager()
  128. {
  129. return $this->_em;
  130. }
  131. /**
  132. * Get the state of this query builder instance.
  133. *
  134. * @return integer Either QueryBuilder::STATE_DIRTY or QueryBuilder::STATE_CLEAN.
  135. */
  136. public function getState()
  137. {
  138. return $this->_state;
  139. }
  140. /**
  141. * Get the complete DQL string formed by the current specifications of this QueryBuilder.
  142. *
  143. * <code>
  144. * $qb = $em->createQueryBuilder()
  145. * ->select('u')
  146. * ->from('User', 'u')
  147. * echo $qb->getDql(); // SELECT u FROM User u
  148. * </code>
  149. *
  150. * @return string The DQL query string.
  151. */
  152. public function getDQL()
  153. {
  154. if ($this->_dql !== null && $this->_state === self::STATE_CLEAN) {
  155. return $this->_dql;
  156. }
  157. $dql = '';
  158. switch ($this->_type) {
  159. case self::DELETE:
  160. $dql = $this->_getDQLForDelete();
  161. break;
  162. case self::UPDATE:
  163. $dql = $this->_getDQLForUpdate();
  164. break;
  165. case self::SELECT:
  166. default:
  167. $dql = $this->_getDQLForSelect();
  168. break;
  169. }
  170. $this->_state = self::STATE_CLEAN;
  171. $this->_dql = $dql;
  172. return $dql;
  173. }
  174. /**
  175. * Constructs a Query instance from the current specifications of the builder.
  176. *
  177. * <code>
  178. * $qb = $em->createQueryBuilder()
  179. * ->select('u')
  180. * ->from('User', 'u');
  181. * $q = $qb->getQuery();
  182. * $results = $q->execute();
  183. * </code>
  184. *
  185. * @return Query
  186. */
  187. public function getQuery()
  188. {
  189. return $this->_em->createQuery($this->getDQL())
  190. ->setParameters($this->_params, $this->_paramTypes)
  191. ->setFirstResult($this->_firstResult)
  192. ->setMaxResults($this->_maxResults);
  193. }
  194. /**
  195. * Gets the root alias of the query. This is the first entity alias involved
  196. * in the construction of the query.
  197. *
  198. * <code>
  199. * $qb = $em->createQueryBuilder()
  200. * ->select('u')
  201. * ->from('User', 'u');
  202. *
  203. * echo $qb->getRootAlias(); // u
  204. * </code>
  205. *
  206. * @return string $rootAlias
  207. * @todo Rename/Refactor: getRootAliases(), there can be multiple roots!
  208. */
  209. public function getRootAlias()
  210. {
  211. return $this->_dqlParts['from'][0]->getAlias();
  212. }
  213. /**
  214. * Sets a query parameter for the query being constructed.
  215. *
  216. * <code>
  217. * $qb = $em->createQueryBuilder()
  218. * ->select('u')
  219. * ->from('User', 'u')
  220. * ->where('u.id = :user_id')
  221. * ->setParameter(':user_id', 1);
  222. * </code>
  223. *
  224. * @param string|integer $key The parameter position or name.
  225. * @param mixed $value The parameter value.
  226. * @param string|null $type PDO::PARAM_* or \Doctrine\DBAL\Types\Type::* constant
  227. * @return QueryBuilder This QueryBuilder instance.
  228. */
  229. public function setParameter($key, $value, $type = null)
  230. {
  231. if ($type !== null) {
  232. $this->_paramTypes[$key] = $type;
  233. }
  234. $this->_params[$key] = $value;
  235. return $this;
  236. }
  237. /**
  238. * Sets a collection of query parameters for the query being constructed.
  239. *
  240. * <code>
  241. * $qb = $em->createQueryBuilder()
  242. * ->select('u')
  243. * ->from('User', 'u')
  244. * ->where('u.id = :user_id1 OR u.id = :user_id2')
  245. * ->setParameters(array(
  246. * ':user_id1' => 1,
  247. * ':user_id2' => 2
  248. * ));
  249. * </code>
  250. *
  251. * @param array $params The query parameters to set.
  252. * @return QueryBuilder This QueryBuilder instance.
  253. */
  254. public function setParameters(array $params, array $types = array())
  255. {
  256. $this->_paramTypes = $types;
  257. $this->_params = $params;
  258. return $this;
  259. }
  260. /**
  261. * Gets all defined query parameters for the query being constructed.
  262. *
  263. * @return array The currently defined query parameters.
  264. */
  265. public function getParameters()
  266. {
  267. return $this->_params;
  268. }
  269. /**
  270. * Gets a (previously set) query parameter of the query being constructed.
  271. *
  272. * @param mixed $key The key (index or name) of the bound parameter.
  273. * @return mixed The value of the bound parameter.
  274. */
  275. public function getParameter($key)
  276. {
  277. return isset($this->_params[$key]) ? $this->_params[$key] : null;
  278. }
  279. /**
  280. * Sets the position of the first result to retrieve (the "offset").
  281. *
  282. * @param integer $firstResult The first result to return.
  283. * @return QueryBuilder This QueryBuilder instance.
  284. */
  285. public function setFirstResult($firstResult)
  286. {
  287. $this->_firstResult = $firstResult;
  288. return $this;
  289. }
  290. /**
  291. * Gets the position of the first result the query object was set to retrieve (the "offset").
  292. * Returns NULL if {@link setFirstResult} was not applied to this QueryBuilder.
  293. *
  294. * @return integer The position of the first result.
  295. */
  296. public function getFirstResult()
  297. {
  298. return $this->_firstResult;
  299. }
  300. /**
  301. * Sets the maximum number of results to retrieve (the "limit").
  302. *
  303. * @param integer $maxResults The maximum number of results to retrieve.
  304. * @return QueryBuilder This QueryBuilder instance.
  305. */
  306. public function setMaxResults($maxResults)
  307. {
  308. $this->_maxResults = $maxResults;
  309. return $this;
  310. }
  311. /**
  312. * Gets the maximum number of results the query object was set to retrieve (the "limit").
  313. * Returns NULL if {@link setMaxResults} was not applied to this query builder.
  314. *
  315. * @return integer Maximum number of results.
  316. */
  317. public function getMaxResults()
  318. {
  319. return $this->_maxResults;
  320. }
  321. /**
  322. * Either appends to or replaces a single, generic query part.
  323. *
  324. * The available parts are: 'select', 'from', 'join', 'set', 'where',
  325. * 'groupBy', 'having' and 'orderBy'.
  326. *
  327. * @param string $dqlPartName
  328. * @param string $dqlPart
  329. * @param string $append
  330. * @return QueryBuilder This QueryBuilder instance.
  331. */
  332. public function add($dqlPartName, $dqlPart, $append = false)
  333. {
  334. $isMultiple = is_array($this->_dqlParts[$dqlPartName]);
  335. if ($append && $isMultiple) {
  336. $this->_dqlParts[$dqlPartName][] = $dqlPart;
  337. } else {
  338. $this->_dqlParts[$dqlPartName] = ($isMultiple) ? array($dqlPart) : $dqlPart;
  339. }
  340. $this->_state = self::STATE_DIRTY;
  341. return $this;
  342. }
  343. /**
  344. * Specifies an item that is to be returned in the query result.
  345. * Replaces any previously specified selections, if any.
  346. *
  347. * <code>
  348. * $qb = $em->createQueryBuilder()
  349. * ->select('u', 'p')
  350. * ->from('User', 'u')
  351. * ->leftJoin('u.Phonenumbers', 'p');
  352. * </code>
  353. *
  354. * @param mixed $select The selection expressions.
  355. * @return QueryBuilder This QueryBuilder instance.
  356. */
  357. public function select($select = null)
  358. {
  359. $this->_type = self::SELECT;
  360. if (empty($select)) {
  361. return $this;
  362. }
  363. $selects = is_array($select) ? $select : func_get_args();
  364. return $this->add('select', new Expr\Select($selects), false);
  365. }
  366. /**
  367. * Adds an item that is to be returned in the query result.
  368. *
  369. * <code>
  370. * $qb = $em->createQueryBuilder()
  371. * ->select('u')
  372. * ->addSelect('p')
  373. * ->from('User', 'u')
  374. * ->leftJoin('u.Phonenumbers', 'p');
  375. * </code>
  376. *
  377. * @param mixed $select The selection expression.
  378. * @return QueryBuilder This QueryBuilder instance.
  379. */
  380. public function addSelect($select = null)
  381. {
  382. $this->_type = self::SELECT;
  383. if (empty($select)) {
  384. return $this;
  385. }
  386. $selects = is_array($select) ? $select : func_get_args();
  387. return $this->add('select', new Expr\Select($selects), true);
  388. }
  389. /**
  390. * Turns the query being built into a bulk delete query that ranges over
  391. * a certain entity type.
  392. *
  393. * <code>
  394. * $qb = $em->createQueryBuilder()
  395. * ->delete('User', 'u')
  396. * ->where('u.id = :user_id');
  397. * ->setParameter(':user_id', 1);
  398. * </code>
  399. *
  400. * @param string $delete The class/type whose instances are subject to the deletion.
  401. * @param string $alias The class/type alias used in the constructed query.
  402. * @return QueryBuilder This QueryBuilder instance.
  403. */
  404. public function delete($delete = null, $alias = null)
  405. {
  406. $this->_type = self::DELETE;
  407. if ( ! $delete) {
  408. return $this;
  409. }
  410. return $this->add('from', new Expr\From($delete, $alias));
  411. }
  412. /**
  413. * Turns the query being built into a bulk update query that ranges over
  414. * a certain entity type.
  415. *
  416. * <code>
  417. * $qb = $em->createQueryBuilder()
  418. * ->update('User', 'u')
  419. * ->set('u.password', md5('password'))
  420. * ->where('u.id = ?');
  421. * </code>
  422. *
  423. * @param string $update The class/type whose instances are subject to the update.
  424. * @param string $alias The class/type alias used in the constructed query.
  425. * @return QueryBuilder This QueryBuilder instance.
  426. */
  427. public function update($update = null, $alias = null)
  428. {
  429. $this->_type = self::UPDATE;
  430. if ( ! $update) {
  431. return $this;
  432. }
  433. return $this->add('from', new Expr\From($update, $alias));
  434. }
  435. /**
  436. * Create and add a query root corresponding to the entity identified by the given alias,
  437. * forming a cartesian product with any existing query roots.
  438. *
  439. * <code>
  440. * $qb = $em->createQueryBuilder()
  441. * ->select('u')
  442. * ->from('User', 'u')
  443. * </code>
  444. *
  445. * @param string $from The class name.
  446. * @param string $alias The alias of the class.
  447. * @return QueryBuilder This QueryBuilder instance.
  448. */
  449. public function from($from, $alias)
  450. {
  451. return $this->add('from', new Expr\From($from, $alias), true);
  452. }
  453. /**
  454. * Creates and adds a join over an entity association to the query.
  455. *
  456. * The entities in the joined association will be fetched as part of the query
  457. * result if the alias used for the joined association is placed in the select
  458. * expressions.
  459. *
  460. * <code>
  461. * $qb = $em->createQueryBuilder()
  462. * ->select('u')
  463. * ->from('User', 'u')
  464. * ->join('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1');
  465. * </code>
  466. *
  467. * @param string $join The relationship to join
  468. * @param string $alias The alias of the join
  469. * @param string $conditionType The condition type constant. Either ON or WITH.
  470. * @param string $condition The condition for the join
  471. * @return QueryBuilder This QueryBuilder instance.
  472. */
  473. public function join($join, $alias, $conditionType = null, $condition = null)
  474. {
  475. return $this->innerJoin($join, $alias, $conditionType, $condition);
  476. }
  477. /**
  478. * Creates and adds a join over an entity association to the query.
  479. *
  480. * The entities in the joined association will be fetched as part of the query
  481. * result if the alias used for the joined association is placed in the select
  482. * expressions.
  483. *
  484. * [php]
  485. * $qb = $em->createQueryBuilder()
  486. * ->select('u')
  487. * ->from('User', 'u')
  488. * ->innerJoin('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1');
  489. *
  490. * @param string $join The relationship to join
  491. * @param string $alias The alias of the join
  492. * @param string $conditionType The condition type constant. Either ON or WITH.
  493. * @param string $condition The condition for the join
  494. * @return QueryBuilder This QueryBuilder instance.
  495. */
  496. public function innerJoin($join, $alias, $conditionType = null, $condition = null)
  497. {
  498. return $this->add('join', new Expr\Join(
  499. Expr\Join::INNER_JOIN, $join, $alias, $conditionType, $condition
  500. ), true);
  501. }
  502. /**
  503. * Creates and adds a left join over an entity association to the query.
  504. *
  505. * The entities in the joined association will be fetched as part of the query
  506. * result if the alias used for the joined association is placed in the select
  507. * expressions.
  508. *
  509. * <code>
  510. * $qb = $em->createQueryBuilder()
  511. * ->select('u')
  512. * ->from('User', 'u')
  513. * ->leftJoin('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1');
  514. * </code>
  515. *
  516. * @param string $join The relationship to join
  517. * @param string $alias The alias of the join
  518. * @param string $conditionType The condition type constant. Either ON or WITH.
  519. * @param string $condition The condition for the join
  520. * @return QueryBuilder This QueryBuilder instance.
  521. */
  522. public function leftJoin($join, $alias, $conditionType = null, $condition = null)
  523. {
  524. return $this->add('join', new Expr\Join(
  525. Expr\Join::LEFT_JOIN, $join, $alias, $conditionType, $condition
  526. ), true);
  527. }
  528. /**
  529. * Sets a new value for a field in a bulk update query.
  530. *
  531. * <code>
  532. * $qb = $em->createQueryBuilder()
  533. * ->update('User', 'u')
  534. * ->set('u.password', md5('password'))
  535. * ->where('u.id = ?');
  536. * </code>
  537. *
  538. * @param string $key The key/field to set.
  539. * @param string $value The value, expression, placeholder, etc.
  540. * @return QueryBuilder This QueryBuilder instance.
  541. */
  542. public function set($key, $value)
  543. {
  544. return $this->add('set', new Expr\Comparison($key, Expr\Comparison::EQ, $value), true);
  545. }
  546. /**
  547. * Specifies one or more restrictions to the query result.
  548. * Replaces any previously specified restrictions, if any.
  549. *
  550. * <code>
  551. * $qb = $em->createQueryBuilder()
  552. * ->select('u')
  553. * ->from('User', 'u')
  554. * ->where('u.id = ?');
  555. *
  556. * // You can optionally programatically build and/or expressions
  557. * $qb = $em->createQueryBuilder();
  558. *
  559. * $or = $qb->expr()->orx();
  560. * $or->add($qb->expr()->eq('u.id', 1));
  561. * $or->add($qb->expr()->eq('u.id', 2));
  562. *
  563. * $qb->update('User', 'u')
  564. * ->set('u.password', md5('password'))
  565. * ->where($or);
  566. * </code>
  567. *
  568. * @param mixed $predicates The restriction predicates.
  569. * @return QueryBuilder This QueryBuilder instance.
  570. */
  571. public function where($predicates)
  572. {
  573. if ( ! (func_num_args() == 1 && ($predicates instanceof Expr\Andx || $predicates instanceof Expr\Orx))) {
  574. $predicates = new Expr\Andx(func_get_args());
  575. }
  576. return $this->add('where', $predicates);
  577. }
  578. /**
  579. * Adds one or more restrictions to the query results, forming a logical
  580. * conjunction with any previously specified restrictions.
  581. *
  582. * <code>
  583. * $qb = $em->createQueryBuilder()
  584. * ->select('u')
  585. * ->from('User', 'u')
  586. * ->where('u.username LIKE ?')
  587. * ->andWhere('u.is_active = 1');
  588. * </code>
  589. *
  590. * @param mixed $where The query restrictions.
  591. * @return QueryBuilder This QueryBuilder instance.
  592. * @see where()
  593. */
  594. public function andWhere($where)
  595. {
  596. $where = $this->getDQLPart('where');
  597. $args = func_get_args();
  598. if ($where instanceof Expr\Andx) {
  599. $where->addMultiple($args);
  600. } else {
  601. array_unshift($args, $where);
  602. $where = new Expr\Andx($args);
  603. }
  604. return $this->add('where', $where, true);
  605. }
  606. /**
  607. * Adds one or more restrictions to the query results, forming a logical
  608. * disjunction with any previously specified restrictions.
  609. *
  610. * <code>
  611. * $qb = $em->createQueryBuilder()
  612. * ->select('u')
  613. * ->from('User', 'u')
  614. * ->where('u.id = 1')
  615. * ->orWhere('u.id = 2');
  616. * </code>
  617. *
  618. * @param mixed $where The WHERE statement
  619. * @return QueryBuilder $qb
  620. * @see where()
  621. */
  622. public function orWhere($where)
  623. {
  624. $where = $this->getDqlPart('where');
  625. $args = func_get_args();
  626. if ($where instanceof Expr\Orx) {
  627. $where->addMultiple($args);
  628. } else {
  629. array_unshift($args, $where);
  630. $where = new Expr\Orx($args);
  631. }
  632. return $this->add('where', $where, true);
  633. }
  634. /**
  635. * Specifies a grouping over the results of the query.
  636. * Replaces any previously specified groupings, if any.
  637. *
  638. * <code>
  639. * $qb = $em->createQueryBuilder()
  640. * ->select('u')
  641. * ->from('User', 'u')
  642. * ->groupBy('u.id');
  643. * </code>
  644. *
  645. * @param string $groupBy The grouping expression.
  646. * @return QueryBuilder This QueryBuilder instance.
  647. */
  648. public function groupBy($groupBy)
  649. {
  650. return $this->add('groupBy', new Expr\GroupBy(func_get_args()));
  651. }
  652. /**
  653. * Adds a grouping expression to the query.
  654. *
  655. * <code>
  656. * $qb = $em->createQueryBuilder()
  657. * ->select('u')
  658. * ->from('User', 'u')
  659. * ->groupBy('u.lastLogin');
  660. * ->addGroupBy('u.createdAt')
  661. * </code>
  662. *
  663. * @param string $groupBy The grouping expression.
  664. * @return QueryBuilder This QueryBuilder instance.
  665. */
  666. public function addGroupBy($groupBy)
  667. {
  668. return $this->add('groupBy', new Expr\GroupBy(func_get_args()), true);
  669. }
  670. /**
  671. * Specifies a restriction over the groups of the query.
  672. * Replaces any previous having restrictions, if any.
  673. *
  674. * @param mixed $having The restriction over the groups.
  675. * @return QueryBuilder This QueryBuilder instance.
  676. */
  677. public function having($having)
  678. {
  679. if ( ! (func_num_args() == 1 && ($having instanceof Expr\Andx || $having instanceof Expr\Orx))) {
  680. $having = new Expr\Andx(func_get_args());
  681. }
  682. return $this->add('having', $having);
  683. }
  684. /**
  685. * Adds a restriction over the groups of the query, forming a logical
  686. * conjunction with any existing having restrictions.
  687. *
  688. * @param mixed $having The restriction to append.
  689. * @return QueryBuilder This QueryBuilder instance.
  690. */
  691. public function andHaving($having)
  692. {
  693. $having = $this->getDqlPart('having');
  694. $args = func_get_args();
  695. if ($having instanceof Expr\Andx) {
  696. $having->addMultiple($args);
  697. } else {
  698. array_unshift($args, $having);
  699. $having = new Expr\Andx($args);
  700. }
  701. return $this->add('having', $having);
  702. }
  703. /**
  704. * Adds a restriction over the groups of the query, forming a logical
  705. * disjunction with any existing having restrictions.
  706. *
  707. * @param mixed $having The restriction to add.
  708. * @return QueryBuilder This QueryBuilder instance.
  709. */
  710. public function orHaving($having)
  711. {
  712. $having = $this->getDqlPart('having');
  713. $args = func_get_args();
  714. if ($having instanceof Expr\Orx) {
  715. $having->addMultiple($args);
  716. } else {
  717. array_unshift($args, $having);
  718. $having = new Expr\Orx($args);
  719. }
  720. return $this->add('having', $having);
  721. }
  722. /**
  723. * Specifies an ordering for the query results.
  724. * Replaces any previously specified orderings, if any.
  725. *
  726. * @param string $sort The ordering expression.
  727. * @param string $order The ordering direction.
  728. * @return QueryBuilder This QueryBuilder instance.
  729. */
  730. public function orderBy($sort, $order = null)
  731. {
  732. return $this->add('orderBy', $sort instanceof Expr\OrderBy ? $sort
  733. : new Expr\OrderBy($sort, $order));
  734. }
  735. /**
  736. * Adds an ordering to the query results.
  737. *
  738. * @param string $sort The ordering expression.
  739. * @param string $order The ordering direction.
  740. * @return QueryBuilder This QueryBuilder instance.
  741. */
  742. public function addOrderBy($sort, $order = null)
  743. {
  744. return $this->add('orderBy', new Expr\OrderBy($sort, $order), true);
  745. }
  746. /**
  747. * Get a query part by its name.
  748. *
  749. * @param string $queryPartName
  750. * @return mixed $queryPart
  751. * @todo Rename: getQueryPart (or remove?)
  752. */
  753. public function getDQLPart($queryPartName)
  754. {
  755. return $this->_dqlParts[$queryPartName];
  756. }
  757. /**
  758. * Get all query parts.
  759. *
  760. * @return array $dqlParts
  761. * @todo Rename: getQueryParts (or remove?)
  762. */
  763. public function getDQLParts()
  764. {
  765. return $this->_dqlParts;
  766. }
  767. private function _getDQLForDelete()
  768. {
  769. return 'DELETE'
  770. . $this->_getReducedDQLQueryPart('from', array('pre' => ' ', 'separator' => ', '))
  771. . $this->_getReducedDQLQueryPart('where', array('pre' => ' WHERE '))
  772. . $this->_getReducedDQLQueryPart('orderBy', array('pre' => ' ORDER BY ', 'separator' => ', '));
  773. }
  774. private function _getDQLForUpdate()
  775. {
  776. return 'UPDATE'
  777. . $this->_getReducedDQLQueryPart('from', array('pre' => ' ', 'separator' => ', '))
  778. . $this->_getReducedDQLQueryPart('set', array('pre' => ' SET ', 'separator' => ', '))
  779. . $this->_getReducedDQLQueryPart('where', array('pre' => ' WHERE '))
  780. . $this->_getReducedDQLQueryPart('orderBy', array('pre' => ' ORDER BY ', 'separator' => ', '));
  781. }
  782. private function _getDQLForSelect()
  783. {
  784. return 'SELECT'
  785. . $this->_getReducedDQLQueryPart('select', array('pre' => ' ', 'separator' => ', '))
  786. . $this->_getReducedDQLQueryPart('from', array('pre' => ' FROM ', 'separator' => ', '))
  787. . $this->_getReducedDQLQueryPart('join', array('pre' => ' ', 'separator' => ' '))
  788. . $this->_getReducedDQLQueryPart('where', array('pre' => ' WHERE '))
  789. . $this->_getReducedDQLQueryPart('groupBy', array('pre' => ' GROUP BY ', 'separator' => ', '))
  790. . $this->_getReducedDQLQueryPart('having', array('pre' => ' HAVING '))
  791. . $this->_getReducedDQLQueryPart('orderBy', array('pre' => ' ORDER BY ', 'separator' => ', '));
  792. }
  793. private function _getReducedDQLQueryPart($queryPartName, $options = array())
  794. {
  795. $queryPart = $this->getDQLPart($queryPartName);
  796. if (empty($queryPart)) {
  797. return (isset($options['empty']) ? $options['empty'] : '');
  798. }
  799. return (isset($options['pre']) ? $options['pre'] : '')
  800. . (is_array($queryPart) ? implode($options['separator'], $queryPart) : $queryPart)
  801. . (isset($options['post']) ? $options['post'] : '');
  802. }
  803. /**
  804. * Reset DQL parts
  805. *
  806. * @param array $parts
  807. * @return QueryBuilder
  808. */
  809. public function resetDQLParts($parts = null)
  810. {
  811. if (is_null($parts)) {
  812. $parts = array_keys($this->_dqlParts);
  813. }
  814. foreach ($parts as $part) {
  815. $this->resetDQLPart($part);
  816. }
  817. return $this;
  818. }
  819. /**
  820. * Reset single DQL part
  821. *
  822. * @param string $part
  823. * @return QueryBuilder;
  824. */
  825. public function resetDQLPart($part)
  826. {
  827. if (is_array($this->_dqlParts[$part])) {
  828. $this->_dqlParts[$part] = array();
  829. } else {
  830. $this->_dqlParts[$part] = null;
  831. }
  832. $this->_state = self::STATE_DIRTY;
  833. return $this;
  834. }
  835. /**
  836. * Gets a string representation of this QueryBuilder which corresponds to
  837. * the final DQL query being constructed.
  838. *
  839. * @return string The string representation of this QueryBuilder.
  840. */
  841. public function __toString()
  842. {
  843. return $this->getDQL();
  844. }
  845. /**
  846. * Deep clone of all expression objects in the DQL parts.
  847. *
  848. * @return void
  849. */
  850. public function __clone()
  851. {
  852. foreach ($this->_dqlParts AS $part => $elements) {
  853. if (is_array($this->_dqlParts[$part])) {
  854. foreach ($this->_dqlParts[$part] AS $idx => $element) {
  855. if (is_object($element)) {
  856. $this->_dqlParts[$part][$idx] = clone $element;
  857. }
  858. }
  859. } else if (\is_object($elements)) {
  860. $this->_dqlParts[$part] = clone $elements;
  861. }
  862. }
  863. }
  864. }