You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1224 lines
32 KiB

3 years ago
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  6. * @author Daniel Kesselberg <mail@danielkesselberg.de>
  7. * @author Joas Schilling <coding@schilljs.com>
  8. * @author Lukas Reschke <lukas@statuscode.ch>
  9. * @author Robin Appelman <robin@icewind.nl>
  10. * @author Roeland Jago Douma <roeland@famdouma.nl>
  11. * @author Thomas Müller <thomas.mueller@tmit.eu>
  12. *
  13. * @license AGPL-3.0
  14. *
  15. * This code is free software: you can redistribute it and/or modify
  16. * it under the terms of the GNU Affero General Public License, version 3,
  17. * as published by the Free Software Foundation.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU Affero General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU Affero General Public License, version 3,
  25. * along with this program. If not, see <http://www.gnu.org/licenses/>
  26. *
  27. */
  28. namespace OC\DB\QueryBuilder;
  29. use Doctrine\DBAL\Platforms\MySqlPlatform;
  30. use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
  31. use Doctrine\DBAL\Platforms\SqlitePlatform;
  32. use OC\DB\OracleConnection;
  33. use OC\DB\QueryBuilder\ExpressionBuilder\ExpressionBuilder;
  34. use OC\DB\QueryBuilder\ExpressionBuilder\MySqlExpressionBuilder;
  35. use OC\DB\QueryBuilder\ExpressionBuilder\OCIExpressionBuilder;
  36. use OC\DB\QueryBuilder\ExpressionBuilder\PgSqlExpressionBuilder;
  37. use OC\DB\QueryBuilder\ExpressionBuilder\SqliteExpressionBuilder;
  38. use OC\DB\QueryBuilder\FunctionBuilder\FunctionBuilder;
  39. use OC\DB\QueryBuilder\FunctionBuilder\OCIFunctionBuilder;
  40. use OC\DB\QueryBuilder\FunctionBuilder\PgSqlFunctionBuilder;
  41. use OC\DB\QueryBuilder\FunctionBuilder\SqliteFunctionBuilder;
  42. use OC\SystemConfig;
  43. use OCP\DB\QueryBuilder\IParameter;
  44. use OCP\DB\QueryBuilder\IQueryBuilder;
  45. use OCP\DB\QueryBuilder\IQueryFunction;
  46. use OCP\IDBConnection;
  47. use OCP\ILogger;
  48. class QueryBuilder implements IQueryBuilder {
  49. /** @var \OCP\IDBConnection */
  50. private $connection;
  51. /** @var SystemConfig */
  52. private $systemConfig;
  53. /** @var ILogger */
  54. private $logger;
  55. /** @var \Doctrine\DBAL\Query\QueryBuilder */
  56. private $queryBuilder;
  57. /** @var QuoteHelper */
  58. private $helper;
  59. /** @var bool */
  60. private $automaticTablePrefix = true;
  61. /** @var string */
  62. protected $lastInsertedTable;
  63. /**
  64. * Initializes a new QueryBuilder.
  65. *
  66. * @param IDBConnection $connection
  67. * @param SystemConfig $systemConfig
  68. * @param ILogger $logger
  69. */
  70. public function __construct(IDBConnection $connection, SystemConfig $systemConfig, ILogger $logger) {
  71. $this->connection = $connection;
  72. $this->systemConfig = $systemConfig;
  73. $this->logger = $logger;
  74. $this->queryBuilder = new \Doctrine\DBAL\Query\QueryBuilder($this->connection);
  75. $this->helper = new QuoteHelper();
  76. }
  77. /**
  78. * Enable/disable automatic prefixing of table names with the oc_ prefix
  79. *
  80. * @param bool $enabled If set to true table names will be prefixed with the
  81. * owncloud database prefix automatically.
  82. * @since 8.2.0
  83. */
  84. public function automaticTablePrefix($enabled) {
  85. $this->automaticTablePrefix = (bool) $enabled;
  86. }
  87. /**
  88. * Gets an ExpressionBuilder used for object-oriented construction of query expressions.
  89. * This producer method is intended for convenient inline usage. Example:
  90. *
  91. * <code>
  92. * $qb = $conn->getQueryBuilder()
  93. * ->select('u')
  94. * ->from('users', 'u')
  95. * ->where($qb->expr()->eq('u.id', 1));
  96. * </code>
  97. *
  98. * For more complex expression construction, consider storing the expression
  99. * builder object in a local variable.
  100. *
  101. * @return \OCP\DB\QueryBuilder\IExpressionBuilder
  102. */
  103. public function expr() {
  104. if ($this->connection instanceof OracleConnection) {
  105. return new OCIExpressionBuilder($this->connection, $this);
  106. } elseif ($this->connection->getDatabasePlatform() instanceof PostgreSqlPlatform) {
  107. return new PgSqlExpressionBuilder($this->connection, $this);
  108. } elseif ($this->connection->getDatabasePlatform() instanceof MySqlPlatform) {
  109. return new MySqlExpressionBuilder($this->connection, $this);
  110. } elseif ($this->connection->getDatabasePlatform() instanceof SqlitePlatform) {
  111. return new SqliteExpressionBuilder($this->connection, $this);
  112. } else {
  113. return new ExpressionBuilder($this->connection, $this);
  114. }
  115. }
  116. /**
  117. * Gets an FunctionBuilder used for object-oriented construction of query functions.
  118. * This producer method is intended for convenient inline usage. Example:
  119. *
  120. * <code>
  121. * $qb = $conn->getQueryBuilder()
  122. * ->select('u')
  123. * ->from('users', 'u')
  124. * ->where($qb->fun()->md5('u.id'));
  125. * </code>
  126. *
  127. * For more complex function construction, consider storing the function
  128. * builder object in a local variable.
  129. *
  130. * @return \OCP\DB\QueryBuilder\IFunctionBuilder
  131. */
  132. public function func() {
  133. if ($this->connection instanceof OracleConnection) {
  134. return new OCIFunctionBuilder($this->helper);
  135. } elseif ($this->connection->getDatabasePlatform() instanceof SqlitePlatform) {
  136. return new SqliteFunctionBuilder($this->helper);
  137. } elseif ($this->connection->getDatabasePlatform() instanceof PostgreSqlPlatform) {
  138. return new PgSqlFunctionBuilder($this->helper);
  139. } else {
  140. return new FunctionBuilder($this->helper);
  141. }
  142. }
  143. /**
  144. * Gets the type of the currently built query.
  145. *
  146. * @return integer
  147. */
  148. public function getType() {
  149. return $this->queryBuilder->getType();
  150. }
  151. /**
  152. * Gets the associated DBAL Connection for this query builder.
  153. *
  154. * @return \OCP\IDBConnection
  155. */
  156. public function getConnection() {
  157. return $this->connection;
  158. }
  159. /**
  160. * Gets the state of this query builder instance.
  161. *
  162. * @return integer Either QueryBuilder::STATE_DIRTY or QueryBuilder::STATE_CLEAN.
  163. */
  164. public function getState() {
  165. return $this->queryBuilder->getState();
  166. }
  167. /**
  168. * Executes this query using the bound parameters and their types.
  169. *
  170. * Uses {@see Connection::executeQuery} for select statements and {@see Connection::executeUpdate}
  171. * for insert, update and delete statements.
  172. *
  173. * @return \Doctrine\DBAL\Driver\Statement|int
  174. */
  175. public function execute() {
  176. if ($this->systemConfig->getValue('log_query', false)) {
  177. $params = [];
  178. foreach ($this->getParameters() as $placeholder => $value) {
  179. if (is_array($value)) {
  180. $params[] = $placeholder . ' => (\'' . implode('\', \'', $value) . '\')';
  181. } else {
  182. $params[] = $placeholder . ' => \'' . $value . '\'';
  183. }
  184. }
  185. if (empty($params)) {
  186. $this->logger->debug('DB QueryBuilder: \'{query}\'', [
  187. 'query' => $this->getSQL(),
  188. 'app' => 'core',
  189. ]);
  190. } else {
  191. $this->logger->debug('DB QueryBuilder: \'{query}\' with parameters: {params}', [
  192. 'query' => $this->getSQL(),
  193. 'params' => implode(', ', $params),
  194. 'app' => 'core',
  195. ]);
  196. }
  197. }
  198. return $this->queryBuilder->execute();
  199. }
  200. /**
  201. * Gets the complete SQL string formed by the current specifications of this QueryBuilder.
  202. *
  203. * <code>
  204. * $qb = $conn->getQueryBuilder()
  205. * ->select('u')
  206. * ->from('User', 'u')
  207. * echo $qb->getSQL(); // SELECT u FROM User u
  208. * </code>
  209. *
  210. * @return string The SQL query string.
  211. */
  212. public function getSQL() {
  213. return $this->queryBuilder->getSQL();
  214. }
  215. /**
  216. * Sets a query parameter for the query being constructed.
  217. *
  218. * <code>
  219. * $qb = $conn->getQueryBuilder()
  220. * ->select('u')
  221. * ->from('users', 'u')
  222. * ->where('u.id = :user_id')
  223. * ->setParameter(':user_id', 1);
  224. * </code>
  225. *
  226. * @param string|integer $key The parameter position or name.
  227. * @param mixed $value The parameter value.
  228. * @param string|null|int $type One of the IQueryBuilder::PARAM_* constants.
  229. *
  230. * @return $this This QueryBuilder instance.
  231. */
  232. public function setParameter($key, $value, $type = null) {
  233. $this->queryBuilder->setParameter($key, $value, $type);
  234. return $this;
  235. }
  236. /**
  237. * Sets a collection of query parameters for the query being constructed.
  238. *
  239. * <code>
  240. * $qb = $conn->getQueryBuilder()
  241. * ->select('u')
  242. * ->from('users', 'u')
  243. * ->where('u.id = :user_id1 OR u.id = :user_id2')
  244. * ->setParameters(array(
  245. * ':user_id1' => 1,
  246. * ':user_id2' => 2
  247. * ));
  248. * </code>
  249. *
  250. * @param array $params The query parameters to set.
  251. * @param array $types The query parameters types to set.
  252. *
  253. * @return $this This QueryBuilder instance.
  254. */
  255. public function setParameters(array $params, array $types = []) {
  256. $this->queryBuilder->setParameters($params, $types);
  257. return $this;
  258. }
  259. /**
  260. * Gets all defined query parameters for the query being constructed indexed by parameter index or name.
  261. *
  262. * @return array The currently defined query parameters indexed by parameter index or name.
  263. */
  264. public function getParameters() {
  265. return $this->queryBuilder->getParameters();
  266. }
  267. /**
  268. * Gets a (previously set) query parameter of the query being constructed.
  269. *
  270. * @param mixed $key The key (index or name) of the bound parameter.
  271. *
  272. * @return mixed The value of the bound parameter.
  273. */
  274. public function getParameter($key) {
  275. return $this->queryBuilder->getParameter($key);
  276. }
  277. /**
  278. * Gets all defined query parameter types for the query being constructed indexed by parameter index or name.
  279. *
  280. * @return array The currently defined query parameter types indexed by parameter index or name.
  281. */
  282. public function getParameterTypes() {
  283. return $this->queryBuilder->getParameterTypes();
  284. }
  285. /**
  286. * Gets a (previously set) query parameter type of the query being constructed.
  287. *
  288. * @param mixed $key The key (index or name) of the bound parameter type.
  289. *
  290. * @return mixed The value of the bound parameter type.
  291. */
  292. public function getParameterType($key) {
  293. return $this->queryBuilder->getParameterType($key);
  294. }
  295. /**
  296. * Sets the position of the first result to retrieve (the "offset").
  297. *
  298. * @param integer $firstResult The first result to return.
  299. *
  300. * @return $this This QueryBuilder instance.
  301. */
  302. public function setFirstResult($firstResult) {
  303. $this->queryBuilder->setFirstResult($firstResult);
  304. return $this;
  305. }
  306. /**
  307. * Gets the position of the first result the query object was set to retrieve (the "offset").
  308. * Returns NULL if {@link setFirstResult} was not applied to this QueryBuilder.
  309. *
  310. * @return integer The position of the first result.
  311. */
  312. public function getFirstResult() {
  313. return $this->queryBuilder->getFirstResult();
  314. }
  315. /**
  316. * Sets the maximum number of results to retrieve (the "limit").
  317. *
  318. * NOTE: Setting max results to "0" will cause mixed behaviour. While most
  319. * of the databases will just return an empty result set, Oracle will return
  320. * all entries.
  321. *
  322. * @param integer $maxResults The maximum number of results to retrieve.
  323. *
  324. * @return $this This QueryBuilder instance.
  325. */
  326. public function setMaxResults($maxResults) {
  327. $this->queryBuilder->setMaxResults($maxResults);
  328. return $this;
  329. }
  330. /**
  331. * Gets the maximum number of results the query object was set to retrieve (the "limit").
  332. * Returns NULL if {@link setMaxResults} was not applied to this query builder.
  333. *
  334. * @return integer The maximum number of results.
  335. */
  336. public function getMaxResults() {
  337. return $this->queryBuilder->getMaxResults();
  338. }
  339. /**
  340. * Specifies an item that is to be returned in the query result.
  341. * Replaces any previously specified selections, if any.
  342. *
  343. * <code>
  344. * $qb = $conn->getQueryBuilder()
  345. * ->select('u.id', 'p.id')
  346. * ->from('users', 'u')
  347. * ->leftJoin('u', 'phonenumbers', 'p', 'u.id = p.user_id');
  348. * </code>
  349. *
  350. * @param mixed ...$selects The selection expressions.
  351. *
  352. * '@return $this This QueryBuilder instance.
  353. */
  354. public function select(...$selects) {
  355. if (count($selects) === 1 && is_array($selects[0])) {
  356. $selects = $selects[0];
  357. }
  358. $this->queryBuilder->select(
  359. $this->helper->quoteColumnNames($selects)
  360. );
  361. return $this;
  362. }
  363. /**
  364. * Specifies an item that is to be returned with a different name in the query result.
  365. *
  366. * <code>
  367. * $qb = $conn->getQueryBuilder()
  368. * ->selectAlias('u.id', 'user_id')
  369. * ->from('users', 'u')
  370. * ->leftJoin('u', 'phonenumbers', 'p', 'u.id = p.user_id');
  371. * </code>
  372. *
  373. * @param mixed $select The selection expressions.
  374. * @param string $alias The column alias used in the constructed query.
  375. *
  376. * @return $this This QueryBuilder instance.
  377. */
  378. public function selectAlias($select, $alias) {
  379. $this->queryBuilder->addSelect(
  380. $this->helper->quoteColumnName($select) . ' AS ' . $this->helper->quoteColumnName($alias)
  381. );
  382. return $this;
  383. }
  384. /**
  385. * Specifies an item that is to be returned uniquely in the query result.
  386. *
  387. * <code>
  388. * $qb = $conn->getQueryBuilder()
  389. * ->selectDistinct('type')
  390. * ->from('users');
  391. * </code>
  392. *
  393. * @param mixed $select The selection expressions.
  394. *
  395. * @return $this This QueryBuilder instance.
  396. */
  397. public function selectDistinct($select) {
  398. $this->queryBuilder->addSelect(
  399. 'DISTINCT ' . $this->helper->quoteColumnName($select)
  400. );
  401. return $this;
  402. }
  403. /**
  404. * Adds an item that is to be returned in the query result.
  405. *
  406. * <code>
  407. * $qb = $conn->getQueryBuilder()
  408. * ->select('u.id')
  409. * ->addSelect('p.id')
  410. * ->from('users', 'u')
  411. * ->leftJoin('u', 'phonenumbers', 'u.id = p.user_id');
  412. * </code>
  413. *
  414. * @param mixed ...$selects The selection expression.
  415. *
  416. * @return $this This QueryBuilder instance.
  417. */
  418. public function addSelect(...$selects) {
  419. if (count($selects) === 1 && is_array($selects[0])) {
  420. $selects = $selects[0];
  421. }
  422. $this->queryBuilder->addSelect(
  423. $this->helper->quoteColumnNames($selects)
  424. );
  425. return $this;
  426. }
  427. /**
  428. * Turns the query being built into a bulk delete query that ranges over
  429. * a certain table.
  430. *
  431. * <code>
  432. * $qb = $conn->getQueryBuilder()
  433. * ->delete('users', 'u')
  434. * ->where('u.id = :user_id');
  435. * ->setParameter(':user_id', 1);
  436. * </code>
  437. *
  438. * @param string $delete The table whose rows are subject to the deletion.
  439. * @param string $alias The table alias used in the constructed query.
  440. *
  441. * @return $this This QueryBuilder instance.
  442. */
  443. public function delete($delete = null, $alias = null) {
  444. $this->queryBuilder->delete(
  445. $this->getTableName($delete),
  446. $alias
  447. );
  448. return $this;
  449. }
  450. /**
  451. * Turns the query being built into a bulk update query that ranges over
  452. * a certain table
  453. *
  454. * <code>
  455. * $qb = $conn->getQueryBuilder()
  456. * ->update('users', 'u')
  457. * ->set('u.password', md5('password'))
  458. * ->where('u.id = ?');
  459. * </code>
  460. *
  461. * @param string $update The table whose rows are subject to the update.
  462. * @param string $alias The table alias used in the constructed query.
  463. *
  464. * @return $this This QueryBuilder instance.
  465. */
  466. public function update($update = null, $alias = null) {
  467. $this->queryBuilder->update(
  468. $this->getTableName($update),
  469. $alias
  470. );
  471. return $this;
  472. }
  473. /**
  474. * Turns the query being built into an insert query that inserts into
  475. * a certain table
  476. *
  477. * <code>
  478. * $qb = $conn->getQueryBuilder()
  479. * ->insert('users')
  480. * ->values(
  481. * array(
  482. * 'name' => '?',
  483. * 'password' => '?'
  484. * )
  485. * );
  486. * </code>
  487. *
  488. * @param string $insert The table into which the rows should be inserted.
  489. *
  490. * @return $this This QueryBuilder instance.
  491. */
  492. public function insert($insert = null) {
  493. $this->queryBuilder->insert(
  494. $this->getTableName($insert)
  495. );
  496. $this->lastInsertedTable = $insert;
  497. return $this;
  498. }
  499. /**
  500. * Creates and adds a query root corresponding to the table identified by the
  501. * given alias, forming a cartesian product with any existing query roots.
  502. *
  503. * <code>
  504. * $qb = $conn->getQueryBuilder()
  505. * ->select('u.id')
  506. * ->from('users', 'u')
  507. * </code>
  508. *
  509. * @param string $from The table.
  510. * @param string|null $alias The alias of the table.
  511. *
  512. * @return $this This QueryBuilder instance.
  513. */
  514. public function from($from, $alias = null) {
  515. $this->queryBuilder->from(
  516. $this->getTableName($from),
  517. $this->quoteAlias($alias)
  518. );
  519. return $this;
  520. }
  521. /**
  522. * Creates and adds a join to the query.
  523. *
  524. * <code>
  525. * $qb = $conn->getQueryBuilder()
  526. * ->select('u.name')
  527. * ->from('users', 'u')
  528. * ->join('u', 'phonenumbers', 'p', 'p.is_primary = 1');
  529. * </code>
  530. *
  531. * @param string $fromAlias The alias that points to a from clause.
  532. * @param string $join The table name to join.
  533. * @param string $alias The alias of the join table.
  534. * @param string $condition The condition for the join.
  535. *
  536. * @return $this This QueryBuilder instance.
  537. */
  538. public function join($fromAlias, $join, $alias, $condition = null) {
  539. $this->queryBuilder->join(
  540. $this->quoteAlias($fromAlias),
  541. $this->getTableName($join),
  542. $this->quoteAlias($alias),
  543. $condition
  544. );
  545. return $this;
  546. }
  547. /**
  548. * Creates and adds a join to the query.
  549. *
  550. * <code>
  551. * $qb = $conn->getQueryBuilder()
  552. * ->select('u.name')
  553. * ->from('users', 'u')
  554. * ->innerJoin('u', 'phonenumbers', 'p', 'p.is_primary = 1');
  555. * </code>
  556. *
  557. * @param string $fromAlias The alias that points to a from clause.
  558. * @param string $join The table name to join.
  559. * @param string $alias The alias of the join table.
  560. * @param string $condition The condition for the join.
  561. *
  562. * @return $this This QueryBuilder instance.
  563. */
  564. public function innerJoin($fromAlias, $join, $alias, $condition = null) {
  565. $this->queryBuilder->innerJoin(
  566. $this->quoteAlias($fromAlias),
  567. $this->getTableName($join),
  568. $this->quoteAlias($alias),
  569. $condition
  570. );
  571. return $this;
  572. }
  573. /**
  574. * Creates and adds a left join to the query.
  575. *
  576. * <code>
  577. * $qb = $conn->getQueryBuilder()
  578. * ->select('u.name')
  579. * ->from('users', 'u')
  580. * ->leftJoin('u', 'phonenumbers', 'p', 'p.is_primary = 1');
  581. * </code>
  582. *
  583. * @param string $fromAlias The alias that points to a from clause.
  584. * @param string $join The table name to join.
  585. * @param string $alias The alias of the join table.
  586. * @param string $condition The condition for the join.
  587. *
  588. * @return $this This QueryBuilder instance.
  589. */
  590. public function leftJoin($fromAlias, $join, $alias, $condition = null) {
  591. $this->queryBuilder->leftJoin(
  592. $this->quoteAlias($fromAlias),
  593. $this->getTableName($join),
  594. $this->quoteAlias($alias),
  595. $condition
  596. );
  597. return $this;
  598. }
  599. /**
  600. * Creates and adds a right join to the query.
  601. *
  602. * <code>
  603. * $qb = $conn->getQueryBuilder()
  604. * ->select('u.name')
  605. * ->from('users', 'u')
  606. * ->rightJoin('u', 'phonenumbers', 'p', 'p.is_primary = 1');
  607. * </code>
  608. *
  609. * @param string $fromAlias The alias that points to a from clause.
  610. * @param string $join The table name to join.
  611. * @param string $alias The alias of the join table.
  612. * @param string $condition The condition for the join.
  613. *
  614. * @return $this This QueryBuilder instance.
  615. */
  616. public function rightJoin($fromAlias, $join, $alias, $condition = null) {
  617. $this->queryBuilder->rightJoin(
  618. $this->quoteAlias($fromAlias),
  619. $this->getTableName($join),
  620. $this->quoteAlias($alias),
  621. $condition
  622. );
  623. return $this;
  624. }
  625. /**
  626. * Sets a new value for a column in a bulk update query.
  627. *
  628. * <code>
  629. * $qb = $conn->getQueryBuilder()
  630. * ->update('users', 'u')
  631. * ->set('u.password', md5('password'))
  632. * ->where('u.id = ?');
  633. * </code>
  634. *
  635. * @param string $key The column to set.
  636. * @param IParameter|string $value The value, expression, placeholder, etc.
  637. *
  638. * @return $this This QueryBuilder instance.
  639. */
  640. public function set($key, $value) {
  641. $this->queryBuilder->set(
  642. $this->helper->quoteColumnName($key),
  643. $this->helper->quoteColumnName($value)
  644. );
  645. return $this;
  646. }
  647. /**
  648. * Specifies one or more restrictions to the query result.
  649. * Replaces any previously specified restrictions, if any.
  650. *
  651. * <code>
  652. * $qb = $conn->getQueryBuilder()
  653. * ->select('u.name')
  654. * ->from('users', 'u')
  655. * ->where('u.id = ?');
  656. *
  657. * // You can optionally programatically build and/or expressions
  658. * $qb = $conn->getQueryBuilder();
  659. *
  660. * $or = $qb->expr()->orx();
  661. * $or->add($qb->expr()->eq('u.id', 1));
  662. * $or->add($qb->expr()->eq('u.id', 2));
  663. *
  664. * $qb->update('users', 'u')
  665. * ->set('u.password', md5('password'))
  666. * ->where($or);
  667. * </code>
  668. *
  669. * @param mixed ...$predicates The restriction predicates.
  670. *
  671. * @return $this This QueryBuilder instance.
  672. */
  673. public function where(...$predicates) {
  674. call_user_func_array(
  675. [$this->queryBuilder, 'where'],
  676. $predicates
  677. );
  678. return $this;
  679. }
  680. /**
  681. * Adds one or more restrictions to the query results, forming a logical
  682. * conjunction with any previously specified restrictions.
  683. *
  684. * <code>
  685. * $qb = $conn->getQueryBuilder()
  686. * ->select('u')
  687. * ->from('users', 'u')
  688. * ->where('u.username LIKE ?')
  689. * ->andWhere('u.is_active = 1');
  690. * </code>
  691. *
  692. * @param mixed ...$where The query restrictions.
  693. *
  694. * @return $this This QueryBuilder instance.
  695. *
  696. * @see where()
  697. */
  698. public function andWhere(...$where) {
  699. call_user_func_array(
  700. [$this->queryBuilder, 'andWhere'],
  701. $where
  702. );
  703. return $this;
  704. }
  705. /**
  706. * Adds one or more restrictions to the query results, forming a logical
  707. * disjunction with any previously specified restrictions.
  708. *
  709. * <code>
  710. * $qb = $conn->getQueryBuilder()
  711. * ->select('u.name')
  712. * ->from('users', 'u')
  713. * ->where('u.id = 1')
  714. * ->orWhere('u.id = 2');
  715. * </code>
  716. *
  717. * @param mixed ...$where The WHERE statement.
  718. *
  719. * @return $this This QueryBuilder instance.
  720. *
  721. * @see where()
  722. */
  723. public function orWhere(...$where) {
  724. call_user_func_array(
  725. [$this->queryBuilder, 'orWhere'],
  726. $where
  727. );
  728. return $this;
  729. }
  730. /**
  731. * Specifies a grouping over the results of the query.
  732. * Replaces any previously specified groupings, if any.
  733. *
  734. * <code>
  735. * $qb = $conn->getQueryBuilder()
  736. * ->select('u.name')
  737. * ->from('users', 'u')
  738. * ->groupBy('u.id');
  739. * </code>
  740. *
  741. * @param mixed ...$groupBys The grouping expression.
  742. *
  743. * @return $this This QueryBuilder instance.
  744. */
  745. public function groupBy(...$groupBys) {
  746. if (count($groupBys) === 1 && is_array($groupBys[0])) {
  747. $groupBys = $groupBys[0];
  748. }
  749. call_user_func_array(
  750. [$this->queryBuilder, 'groupBy'],
  751. $this->helper->quoteColumnNames($groupBys)
  752. );
  753. return $this;
  754. }
  755. /**
  756. * Adds a grouping expression to the query.
  757. *
  758. * <code>
  759. * $qb = $conn->getQueryBuilder()
  760. * ->select('u.name')
  761. * ->from('users', 'u')
  762. * ->groupBy('u.lastLogin');
  763. * ->addGroupBy('u.createdAt')
  764. * </code>
  765. *
  766. * @param mixed ...$groupBy The grouping expression.
  767. *
  768. * @return $this This QueryBuilder instance.
  769. */
  770. public function addGroupBy(...$groupBys) {
  771. if (count($groupBys) === 1 && is_array($groupBys[0])) {
  772. $$groupBys = $groupBys[0];
  773. }
  774. call_user_func_array(
  775. [$this->queryBuilder, 'addGroupBy'],
  776. $this->helper->quoteColumnNames($groupBys)
  777. );
  778. return $this;
  779. }
  780. /**
  781. * Sets a value for a column in an insert query.
  782. *
  783. * <code>
  784. * $qb = $conn->getQueryBuilder()
  785. * ->insert('users')
  786. * ->values(
  787. * array(
  788. * 'name' => '?'
  789. * )
  790. * )
  791. * ->setValue('password', '?');
  792. * </code>
  793. *
  794. * @param string $column The column into which the value should be inserted.
  795. * @param string $value The value that should be inserted into the column.
  796. *
  797. * @return $this This QueryBuilder instance.
  798. */
  799. public function setValue($column, $value) {
  800. $this->queryBuilder->setValue(
  801. $this->helper->quoteColumnName($column),
  802. $value
  803. );
  804. return $this;
  805. }
  806. /**
  807. * Specifies values for an insert query indexed by column names.
  808. * Replaces any previous values, if any.
  809. *
  810. * <code>
  811. * $qb = $conn->getQueryBuilder()
  812. * ->insert('users')
  813. * ->values(
  814. * array(
  815. * 'name' => '?',
  816. * 'password' => '?'
  817. * )
  818. * );
  819. * </code>
  820. *
  821. * @param array $values The values to specify for the insert query indexed by column names.
  822. *
  823. * @return $this This QueryBuilder instance.
  824. */
  825. public function values(array $values) {
  826. $quotedValues = [];
  827. foreach ($values as $key => $value) {
  828. $quotedValues[$this->helper->quoteColumnName($key)] = $value;
  829. }
  830. $this->queryBuilder->values($quotedValues);
  831. return $this;
  832. }
  833. /**
  834. * Specifies a restriction over the groups of the query.
  835. * Replaces any previous having restrictions, if any.
  836. *
  837. * @param mixed ...$having The restriction over the groups.
  838. *
  839. * @return $this This QueryBuilder instance.
  840. */
  841. public function having(...$having) {
  842. call_user_func_array(
  843. [$this->queryBuilder, 'having'],
  844. $having
  845. );
  846. return $this;
  847. }
  848. /**
  849. * Adds a restriction over the groups of the query, forming a logical
  850. * conjunction with any existing having restrictions.
  851. *
  852. * @param mixed ...$having The restriction to append.
  853. *
  854. * @return $this This QueryBuilder instance.
  855. */
  856. public function andHaving(...$having) {
  857. call_user_func_array(
  858. [$this->queryBuilder, 'andHaving'],
  859. $having
  860. );
  861. return $this;
  862. }
  863. /**
  864. * Adds a restriction over the groups of the query, forming a logical
  865. * disjunction with any existing having restrictions.
  866. *
  867. * @param mixed ...$having The restriction to add.
  868. *
  869. * @return $this This QueryBuilder instance.
  870. */
  871. public function orHaving(...$having) {
  872. call_user_func_array(
  873. [$this->queryBuilder, 'orHaving'],
  874. $having
  875. );
  876. return $this;
  877. }
  878. /**
  879. * Specifies an ordering for the query results.
  880. * Replaces any previously specified orderings, if any.
  881. *
  882. * @param string $sort The ordering expression.
  883. * @param string $order The ordering direction.
  884. *
  885. * @return $this This QueryBuilder instance.
  886. */
  887. public function orderBy($sort, $order = null) {
  888. $this->queryBuilder->orderBy(
  889. $this->helper->quoteColumnName($sort),
  890. $order
  891. );
  892. return $this;
  893. }
  894. /**
  895. * Adds an ordering to the query results.
  896. *
  897. * @param string $sort The ordering expression.
  898. * @param string $order The ordering direction.
  899. *
  900. * @return $this This QueryBuilder instance.
  901. */
  902. public function addOrderBy($sort, $order = null) {
  903. $this->queryBuilder->addOrderBy(
  904. $this->helper->quoteColumnName($sort),
  905. $order
  906. );
  907. return $this;
  908. }
  909. /**
  910. * Gets a query part by its name.
  911. *
  912. * @param string $queryPartName
  913. *
  914. * @return mixed
  915. */
  916. public function getQueryPart($queryPartName) {
  917. return $this->queryBuilder->getQueryPart($queryPartName);
  918. }
  919. /**
  920. * Gets all query parts.
  921. *
  922. * @return array
  923. */
  924. public function getQueryParts() {
  925. return $this->queryBuilder->getQueryParts();
  926. }
  927. /**
  928. * Resets SQL parts.
  929. *
  930. * @param array|null $queryPartNames
  931. *
  932. * @return $this This QueryBuilder instance.
  933. */
  934. public function resetQueryParts($queryPartNames = null) {
  935. $this->queryBuilder->resetQueryParts($queryPartNames);
  936. return $this;
  937. }
  938. /**
  939. * Resets a single SQL part.
  940. *
  941. * @param string $queryPartName
  942. *
  943. * @return $this This QueryBuilder instance.
  944. */
  945. public function resetQueryPart($queryPartName) {
  946. $this->queryBuilder->resetQueryPart($queryPartName);
  947. return $this;
  948. }
  949. /**
  950. * Creates a new named parameter and bind the value $value to it.
  951. *
  952. * This method provides a shortcut for PDOStatement::bindValue
  953. * when using prepared statements.
  954. *
  955. * The parameter $value specifies the value that you want to bind. If
  956. * $placeholder is not provided bindValue() will automatically create a
  957. * placeholder for you. An automatic placeholder will be of the name
  958. * ':dcValue1', ':dcValue2' etc.
  959. *
  960. * For more information see {@link http://php.net/pdostatement-bindparam}
  961. *
  962. * Example:
  963. * <code>
  964. * $value = 2;
  965. * $q->eq( 'id', $q->bindValue( $value ) );
  966. * $stmt = $q->executeQuery(); // executed with 'id = 2'
  967. * </code>
  968. *
  969. * @license New BSD License
  970. * @link http://www.zetacomponents.org
  971. *
  972. * @param mixed $value
  973. * @param mixed $type
  974. * @param string $placeHolder The name to bind with. The string must start with a colon ':'.
  975. *
  976. * @return IParameter the placeholder name used.
  977. */
  978. public function createNamedParameter($value, $type = IQueryBuilder::PARAM_STR, $placeHolder = null) {
  979. return new Parameter($this->queryBuilder->createNamedParameter($value, $type, $placeHolder));
  980. }
  981. /**
  982. * Creates a new positional parameter and bind the given value to it.
  983. *
  984. * Attention: If you are using positional parameters with the query builder you have
  985. * to be very careful to bind all parameters in the order they appear in the SQL
  986. * statement , otherwise they get bound in the wrong order which can lead to serious
  987. * bugs in your code.
  988. *
  989. * Example:
  990. * <code>
  991. * $qb = $conn->getQueryBuilder();
  992. * $qb->select('u.*')
  993. * ->from('users', 'u')
  994. * ->where('u.username = ' . $qb->createPositionalParameter('Foo', IQueryBuilder::PARAM_STR))
  995. * ->orWhere('u.username = ' . $qb->createPositionalParameter('Bar', IQueryBuilder::PARAM_STR))
  996. * </code>
  997. *
  998. * @param mixed $value
  999. * @param integer $type
  1000. *
  1001. * @return IParameter
  1002. */
  1003. public function createPositionalParameter($value, $type = IQueryBuilder::PARAM_STR) {
  1004. return new Parameter($this->queryBuilder->createPositionalParameter($value, $type));
  1005. }
  1006. /**
  1007. * Creates a new parameter
  1008. *
  1009. * Example:
  1010. * <code>
  1011. * $qb = $conn->getQueryBuilder();
  1012. * $qb->select('u.*')
  1013. * ->from('users', 'u')
  1014. * ->where('u.username = ' . $qb->createParameter('name'))
  1015. * ->setParameter('name', 'Bar', IQueryBuilder::PARAM_STR))
  1016. * </code>
  1017. *
  1018. * @param string $name
  1019. *
  1020. * @return IParameter
  1021. */
  1022. public function createParameter($name) {
  1023. return new Parameter(':' . $name);
  1024. }
  1025. /**
  1026. * Creates a new function
  1027. *
  1028. * Attention: Column names inside the call have to be quoted before hand
  1029. *
  1030. * Example:
  1031. * <code>
  1032. * $qb = $conn->getQueryBuilder();
  1033. * $qb->select($qb->createFunction('COUNT(*)'))
  1034. * ->from('users', 'u')
  1035. * echo $qb->getSQL(); // SELECT COUNT(*) FROM `users` u
  1036. * </code>
  1037. * <code>
  1038. * $qb = $conn->getQueryBuilder();
  1039. * $qb->select($qb->createFunction('COUNT(`column`)'))
  1040. * ->from('users', 'u')
  1041. * echo $qb->getSQL(); // SELECT COUNT(`column`) FROM `users` u
  1042. * </code>
  1043. *
  1044. * @param string $call
  1045. *
  1046. * @return IQueryFunction
  1047. */
  1048. public function createFunction($call) {
  1049. return new QueryFunction($call);
  1050. }
  1051. /**
  1052. * Used to get the id of the last inserted element
  1053. * @return int
  1054. * @throws \BadMethodCallException When being called before an insert query has been run.
  1055. */
  1056. public function getLastInsertId() {
  1057. if ($this->getType() === \Doctrine\DBAL\Query\QueryBuilder::INSERT && $this->lastInsertedTable) {
  1058. // lastInsertId() needs the prefix but no quotes
  1059. $table = $this->prefixTableName($this->lastInsertedTable);
  1060. return (int) $this->connection->lastInsertId($table);
  1061. }
  1062. throw new \BadMethodCallException('Invalid call to getLastInsertId without using insert() before.');
  1063. }
  1064. /**
  1065. * Returns the table name quoted and with database prefix as needed by the implementation
  1066. *
  1067. * @param string $table
  1068. * @return string
  1069. */
  1070. public function getTableName($table) {
  1071. if ($table instanceof IQueryFunction) {
  1072. return (string) $table;
  1073. }
  1074. $table = $this->prefixTableName($table);
  1075. return $this->helper->quoteColumnName($table);
  1076. }
  1077. /**
  1078. * Returns the table name with database prefix as needed by the implementation
  1079. *
  1080. * @param string $table
  1081. * @return string
  1082. */
  1083. protected function prefixTableName($table) {
  1084. if ($this->automaticTablePrefix === false || strpos($table, '*PREFIX*') === 0) {
  1085. return $table;
  1086. }
  1087. return '*PREFIX*' . $table;
  1088. }
  1089. /**
  1090. * Returns the column name quoted and with table alias prefix as needed by the implementation
  1091. *
  1092. * @param string $column
  1093. * @param string $tableAlias
  1094. * @return string
  1095. */
  1096. public function getColumnName($column, $tableAlias = '') {
  1097. if ($tableAlias !== '') {
  1098. $tableAlias .= '.';
  1099. }
  1100. return $this->helper->quoteColumnName($tableAlias . $column);
  1101. }
  1102. /**
  1103. * Returns the column name quoted and with table alias prefix as needed by the implementation
  1104. *
  1105. * @param string $alias
  1106. * @return string
  1107. */
  1108. public function quoteAlias($alias) {
  1109. if ($alias === '' || $alias === null) {
  1110. return $alias;
  1111. }
  1112. return $this->helper->quoteColumnName($alias);
  1113. }
  1114. }