/lib/Doctrine/ORM/Query/Expr.php

https://github.com/adrienbrault/doctrine2 · PHP · 652 lines · 237 code · 45 blank · 370 comment · 7 complexity · 76039a5a9100571d4ebdc86c12b54bde MD5 · raw file

  1. <?php
  2. declare(strict_types=1);
  3. namespace Doctrine\ORM\Query;
  4. /**
  5. * This class is used to generate DQL expressions via a set of PHP static functions.
  6. * @todo Rename: ExpressionBuilder
  7. */
  8. class Expr
  9. {
  10. /**
  11. * Creates a conjunction of the given boolean expressions.
  12. *
  13. * Example:
  14. *
  15. * [php]
  16. * // (u.type = ?1) AND (u.role = ?2)
  17. * $expr->andX($expr->eq('u.type', ':1'), $expr->eq('u.role', ':2'));
  18. *
  19. * @param Expr\Comparison|Expr\Func|Expr\Orx $x Optional clause. Defaults to null, but requires at least one
  20. * defined when converting to string.
  21. *
  22. * @return Expr\Andx
  23. */
  24. public function andX($x = null)
  25. {
  26. return new Expr\Andx(func_get_args());
  27. }
  28. /**
  29. * Creates a disjunction of the given boolean expressions.
  30. *
  31. * Example:
  32. *
  33. * [php]
  34. * // (u.type = ?1) OR (u.role = ?2)
  35. * $q->where($q->expr()->orX('u.type = ?1', 'u.role = ?2'));
  36. *
  37. * @param mixed $x Optional clause. Defaults to null, but requires
  38. * at least one defined when converting to string.
  39. *
  40. * @return Expr\Orx
  41. */
  42. public function orX($x = null)
  43. {
  44. return new Expr\Orx(func_get_args());
  45. }
  46. /**
  47. * Creates an ASCending order expression.
  48. *
  49. * @param mixed $expr
  50. *
  51. * @return Expr\OrderBy
  52. */
  53. public function asc($expr)
  54. {
  55. return new Expr\OrderBy($expr, 'ASC');
  56. }
  57. /**
  58. * Creates a DESCending order expression.
  59. *
  60. * @param mixed $expr
  61. *
  62. * @return Expr\OrderBy
  63. */
  64. public function desc($expr)
  65. {
  66. return new Expr\OrderBy($expr, 'DESC');
  67. }
  68. /**
  69. * Creates an equality comparison expression with the given arguments.
  70. *
  71. * First argument is considered the left expression and the second is the right expression.
  72. * When converted to string, it will generated a <left expr> = <right expr>. Example:
  73. *
  74. * [php]
  75. * // u.id = ?1
  76. * $expr->eq('u.id', '?1');
  77. *
  78. * @param mixed $x Left expression.
  79. * @param mixed $y Right expression.
  80. *
  81. * @return Expr\Comparison
  82. */
  83. public function eq($x, $y)
  84. {
  85. return new Expr\Comparison($x, Expr\Comparison::EQ, $y);
  86. }
  87. /**
  88. * Creates an instance of Expr\Comparison, with the given arguments.
  89. * First argument is considered the left expression and the second is the right expression.
  90. * When converted to string, it will generated a <left expr> <> <right expr>. Example:
  91. *
  92. * [php]
  93. * // u.id <> ?1
  94. * $q->where($q->expr()->neq('u.id', '?1'));
  95. *
  96. * @param mixed $x Left expression.
  97. * @param mixed $y Right expression.
  98. *
  99. * @return Expr\Comparison
  100. */
  101. public function neq($x, $y)
  102. {
  103. return new Expr\Comparison($x, Expr\Comparison::NEQ, $y);
  104. }
  105. /**
  106. * Creates an instance of Expr\Comparison, with the given arguments.
  107. * First argument is considered the left expression and the second is the right expression.
  108. * When converted to string, it will generated a <left expr> < <right expr>. Example:
  109. *
  110. * [php]
  111. * // u.id < ?1
  112. * $q->where($q->expr()->lt('u.id', '?1'));
  113. *
  114. * @param mixed $x Left expression.
  115. * @param mixed $y Right expression.
  116. *
  117. * @return Expr\Comparison
  118. */
  119. public function lt($x, $y)
  120. {
  121. return new Expr\Comparison($x, Expr\Comparison::LT, $y);
  122. }
  123. /**
  124. * Creates an instance of Expr\Comparison, with the given arguments.
  125. * First argument is considered the left expression and the second is the right expression.
  126. * When converted to string, it will generated a <left expr> <= <right expr>. Example:
  127. *
  128. * [php]
  129. * // u.id <= ?1
  130. * $q->where($q->expr()->lte('u.id', '?1'));
  131. *
  132. * @param mixed $x Left expression.
  133. * @param mixed $y Right expression.
  134. *
  135. * @return Expr\Comparison
  136. */
  137. public function lte($x, $y)
  138. {
  139. return new Expr\Comparison($x, Expr\Comparison::LTE, $y);
  140. }
  141. /**
  142. * Creates an instance of Expr\Comparison, with the given arguments.
  143. * First argument is considered the left expression and the second is the right expression.
  144. * When converted to string, it will generated a <left expr> > <right expr>. Example:
  145. *
  146. * [php]
  147. * // u.id > ?1
  148. * $q->where($q->expr()->gt('u.id', '?1'));
  149. *
  150. * @param mixed $x Left expression.
  151. * @param mixed $y Right expression.
  152. *
  153. * @return Expr\Comparison
  154. */
  155. public function gt($x, $y)
  156. {
  157. return new Expr\Comparison($x, Expr\Comparison::GT, $y);
  158. }
  159. /**
  160. * Creates an instance of Expr\Comparison, with the given arguments.
  161. * First argument is considered the left expression and the second is the right expression.
  162. * When converted to string, it will generated a <left expr> >= <right expr>. Example:
  163. *
  164. * [php]
  165. * // u.id >= ?1
  166. * $q->where($q->expr()->gte('u.id', '?1'));
  167. *
  168. * @param mixed $x Left expression.
  169. * @param mixed $y Right expression.
  170. *
  171. * @return Expr\Comparison
  172. */
  173. public function gte($x, $y)
  174. {
  175. return new Expr\Comparison($x, Expr\Comparison::GTE, $y);
  176. }
  177. /**
  178. * Creates an instance of AVG() function, with the given argument.
  179. *
  180. * @param mixed $x Argument to be used in AVG() function.
  181. *
  182. * @return Expr\Func
  183. */
  184. public function avg($x)
  185. {
  186. return new Expr\Func('AVG', [$x]);
  187. }
  188. /**
  189. * Creates an instance of MAX() function, with the given argument.
  190. *
  191. * @param mixed $x Argument to be used in MAX() function.
  192. *
  193. * @return Expr\Func
  194. */
  195. public function max($x)
  196. {
  197. return new Expr\Func('MAX', [$x]);
  198. }
  199. /**
  200. * Creates an instance of MIN() function, with the given argument.
  201. *
  202. * @param mixed $x Argument to be used in MIN() function.
  203. *
  204. * @return Expr\Func
  205. */
  206. public function min($x)
  207. {
  208. return new Expr\Func('MIN', [$x]);
  209. }
  210. /**
  211. * Creates an instance of COUNT() function, with the given argument.
  212. *
  213. * @param mixed $x Argument to be used in COUNT() function.
  214. *
  215. * @return Expr\Func
  216. */
  217. public function count($x)
  218. {
  219. return new Expr\Func('COUNT', [$x]);
  220. }
  221. /**
  222. * Creates an instance of COUNT(DISTINCT) function, with the given argument.
  223. *
  224. * @param mixed $x Argument to be used in COUNT(DISTINCT) function.
  225. *
  226. * @return string
  227. */
  228. public function countDistinct($x)
  229. {
  230. return 'COUNT(DISTINCT ' . implode(', ', func_get_args()) . ')';
  231. }
  232. /**
  233. * Creates an instance of EXISTS() function, with the given DQL Subquery.
  234. *
  235. * @param mixed $subquery DQL Subquery to be used in EXISTS() function.
  236. *
  237. * @return Expr\Func
  238. */
  239. public function exists($subquery)
  240. {
  241. return new Expr\Func('EXISTS', [$subquery]);
  242. }
  243. /**
  244. * Creates an instance of ALL() function, with the given DQL Subquery.
  245. *
  246. * @param mixed $subquery DQL Subquery to be used in ALL() function.
  247. *
  248. * @return Expr\Func
  249. */
  250. public function all($subquery)
  251. {
  252. return new Expr\Func('ALL', [$subquery]);
  253. }
  254. /**
  255. * Creates a SOME() function expression with the given DQL subquery.
  256. *
  257. * @param mixed $subquery DQL Subquery to be used in SOME() function.
  258. *
  259. * @return Expr\Func
  260. */
  261. public function some($subquery)
  262. {
  263. return new Expr\Func('SOME', [$subquery]);
  264. }
  265. /**
  266. * Creates an ANY() function expression with the given DQL subquery.
  267. *
  268. * @param mixed $subquery DQL Subquery to be used in ANY() function.
  269. *
  270. * @return Expr\Func
  271. */
  272. public function any($subquery)
  273. {
  274. return new Expr\Func('ANY', [$subquery]);
  275. }
  276. /**
  277. * Creates a negation expression of the given restriction.
  278. *
  279. * @param mixed $restriction Restriction to be used in NOT() function.
  280. *
  281. * @return Expr\Func
  282. */
  283. public function not($restriction)
  284. {
  285. return new Expr\Func('NOT', [$restriction]);
  286. }
  287. /**
  288. * Creates an ABS() function expression with the given argument.
  289. *
  290. * @param mixed $x Argument to be used in ABS() function.
  291. *
  292. * @return Expr\Func
  293. */
  294. public function abs($x)
  295. {
  296. return new Expr\Func('ABS', [$x]);
  297. }
  298. /**
  299. * Creates a product mathematical expression with the given arguments.
  300. *
  301. * First argument is considered the left expression and the second is the right expression.
  302. * When converted to string, it will generated a <left expr> * <right expr>. Example:
  303. *
  304. * [php]
  305. * // u.salary * u.percentAnnualSalaryIncrease
  306. * $q->expr()->prod('u.salary', 'u.percentAnnualSalaryIncrease')
  307. *
  308. * @param mixed $x Left expression.
  309. * @param mixed $y Right expression.
  310. *
  311. * @return Expr\Math
  312. */
  313. public function prod($x, $y)
  314. {
  315. return new Expr\Math($x, '*', $y);
  316. }
  317. /**
  318. * Creates a difference mathematical expression with the given arguments.
  319. * First argument is considered the left expression and the second is the right expression.
  320. * When converted to string, it will generated a <left expr> - <right expr>. Example:
  321. *
  322. * [php]
  323. * // u.monthlySubscriptionCount - 1
  324. * $q->expr()->diff('u.monthlySubscriptionCount', '1')
  325. *
  326. * @param mixed $x Left expression.
  327. * @param mixed $y Right expression.
  328. *
  329. * @return Expr\Math
  330. */
  331. public function diff($x, $y)
  332. {
  333. return new Expr\Math($x, '-', $y);
  334. }
  335. /**
  336. * Creates a sum mathematical expression with the given arguments.
  337. * First argument is considered the left expression and the second is the right expression.
  338. * When converted to string, it will generated a <left expr> + <right expr>. Example:
  339. *
  340. * [php]
  341. * // u.numChildren + 1
  342. * $q->expr()->sum('u.numChildren', '1')
  343. *
  344. * @param mixed $x Left expression.
  345. * @param mixed $y Right expression.
  346. *
  347. * @return Expr\Math
  348. */
  349. public function sum($x, $y)
  350. {
  351. return new Expr\Math($x, '+', $y);
  352. }
  353. /**
  354. * Creates a quotient mathematical expression with the given arguments.
  355. * First argument is considered the left expression and the second is the right expression.
  356. * When converted to string, it will generated a <left expr> / <right expr>. Example:
  357. *
  358. * [php]
  359. * // u.total / u.period
  360. * $expr->quot('u.total', 'u.period')
  361. *
  362. * @param mixed $x Left expression.
  363. * @param mixed $y Right expression.
  364. *
  365. * @return Expr\Math
  366. */
  367. public function quot($x, $y)
  368. {
  369. return new Expr\Math($x, '/', $y);
  370. }
  371. /**
  372. * Creates a SQRT() function expression with the given argument.
  373. *
  374. * @param mixed $x Argument to be used in SQRT() function.
  375. *
  376. * @return Expr\Func
  377. */
  378. public function sqrt($x)
  379. {
  380. return new Expr\Func('SQRT', [$x]);
  381. }
  382. /**
  383. * Creates an IN() expression with the given arguments.
  384. *
  385. * @param string $x Field in string format to be restricted by IN() function.
  386. * @param mixed $y Argument to be used in IN() function.
  387. *
  388. * @return Expr\Func
  389. */
  390. public function in($x, $y)
  391. {
  392. if (is_array($y)) {
  393. foreach ($y as &$literal) {
  394. if (! ($literal instanceof Expr\Literal)) {
  395. $literal = $this->quoteLiteral($literal);
  396. }
  397. }
  398. }
  399. return new Expr\Func($x . ' IN', (array) $y);
  400. }
  401. /**
  402. * Creates a NOT IN() expression with the given arguments.
  403. *
  404. * @param string $x Field in string format to be restricted by NOT IN() function.
  405. * @param mixed $y Argument to be used in NOT IN() function.
  406. *
  407. * @return Expr\Func
  408. */
  409. public function notIn($x, $y)
  410. {
  411. if (is_array($y)) {
  412. foreach ($y as &$literal) {
  413. if (! ($literal instanceof Expr\Literal)) {
  414. $literal = $this->quoteLiteral($literal);
  415. }
  416. }
  417. }
  418. return new Expr\Func($x . ' NOT IN', (array) $y);
  419. }
  420. /**
  421. * Creates an IS NULL expression with the given arguments.
  422. *
  423. * @param string $x Field in string format to be restricted by IS NULL.
  424. *
  425. * @return string
  426. */
  427. public function isNull($x)
  428. {
  429. return $x . ' IS NULL';
  430. }
  431. /**
  432. * Creates an IS NOT NULL expression with the given arguments.
  433. *
  434. * @param string $x Field in string format to be restricted by IS NOT NULL.
  435. *
  436. * @return string
  437. */
  438. public function isNotNull($x)
  439. {
  440. return $x . ' IS NOT NULL';
  441. }
  442. /**
  443. * Creates a LIKE() comparison expression with the given arguments.
  444. *
  445. * @param string $x Field in string format to be inspected by LIKE() comparison.
  446. * @param mixed $y Argument to be used in LIKE() comparison.
  447. *
  448. * @return Expr\Comparison
  449. */
  450. public function like($x, $y)
  451. {
  452. return new Expr\Comparison($x, 'LIKE', $y);
  453. }
  454. /**
  455. * Creates a NOT LIKE() comparison expression with the given arguments.
  456. *
  457. * @param string $x Field in string format to be inspected by LIKE() comparison.
  458. * @param mixed $y Argument to be used in LIKE() comparison.
  459. *
  460. * @return Expr\Comparison
  461. */
  462. public function notLike($x, $y)
  463. {
  464. return new Expr\Comparison($x, 'NOT LIKE', $y);
  465. }
  466. /**
  467. * Creates a CONCAT() function expression with the given arguments.
  468. *
  469. * @param mixed $x First argument to be used in CONCAT() function.
  470. * @param mixed $y,... Other arguments to be used in CONCAT() function.
  471. *
  472. * @return Expr\Func
  473. */
  474. public function concat($x, $y)
  475. {
  476. return new Expr\Func('CONCAT', func_get_args());
  477. }
  478. /**
  479. * Creates a SUBSTRING() function expression with the given arguments.
  480. *
  481. * @param mixed $x Argument to be used as string to be cropped by SUBSTRING() function.
  482. * @param int $from Initial offset to start cropping string. May accept negative values.
  483. * @param int|null $len Length of crop. May accept negative values.
  484. *
  485. * @return Expr\Func
  486. */
  487. public function substring($x, $from, $len = null)
  488. {
  489. $args = [$x, $from];
  490. if ($len !== null) {
  491. $args[] = $len;
  492. }
  493. return new Expr\Func('SUBSTRING', $args);
  494. }
  495. /**
  496. * Creates a LOWER() function expression with the given argument.
  497. *
  498. * @param mixed $x Argument to be used in LOWER() function.
  499. *
  500. * @return Expr\Func A LOWER function expression.
  501. */
  502. public function lower($x)
  503. {
  504. return new Expr\Func('LOWER', [$x]);
  505. }
  506. /**
  507. * Creates an UPPER() function expression with the given argument.
  508. *
  509. * @param mixed $x Argument to be used in UPPER() function.
  510. *
  511. * @return Expr\Func An UPPER function expression.
  512. */
  513. public function upper($x)
  514. {
  515. return new Expr\Func('UPPER', [$x]);
  516. }
  517. /**
  518. * Creates a LENGTH() function expression with the given argument.
  519. *
  520. * @param mixed $x Argument to be used as argument of LENGTH() function.
  521. *
  522. * @return Expr\Func A LENGTH function expression.
  523. */
  524. public function length($x)
  525. {
  526. return new Expr\Func('LENGTH', [$x]);
  527. }
  528. /**
  529. * Creates a literal expression of the given argument.
  530. *
  531. * @param mixed $literal Argument to be converted to literal.
  532. *
  533. * @return Expr\Literal
  534. */
  535. public function literal($literal)
  536. {
  537. return new Expr\Literal($this->quoteLiteral($literal));
  538. }
  539. /**
  540. * Quotes a literal value, if necessary, according to the DQL syntax.
  541. *
  542. * @param mixed $literal The literal value.
  543. *
  544. * @return string
  545. */
  546. private function quoteLiteral($literal)
  547. {
  548. if (is_numeric($literal) && ! is_string($literal)) {
  549. return (string) $literal;
  550. } elseif (is_bool($literal)) {
  551. return $literal ? 'true' : 'false';
  552. }
  553. return "'" . str_replace("'", "''", $literal) . "'";
  554. }
  555. /**
  556. * Creates an instance of BETWEEN() function, with the given argument.
  557. *
  558. * @param mixed $val Valued to be inspected by range values.
  559. * @param int|string $x Starting range value to be used in BETWEEN() function.
  560. * @param int|string $y End point value to be used in BETWEEN() function.
  561. *
  562. * @return Expr\Func A BETWEEN expression.
  563. */
  564. public function between($val, $x, $y)
  565. {
  566. return $val . ' BETWEEN ' . $x . ' AND ' . $y;
  567. }
  568. /**
  569. * Creates an instance of TRIM() function, with the given argument.
  570. *
  571. * @param mixed $x Argument to be used as argument of TRIM() function.
  572. *
  573. * @return Expr\Func a TRIM expression.
  574. */
  575. public function trim($x)
  576. {
  577. return new Expr\Func('TRIM', $x);
  578. }
  579. /**
  580. * Creates an instance of MEMBER OF function, with the given arguments.
  581. *
  582. * @param string $x Value to be checked
  583. * @param string $y Value to be checked against
  584. *
  585. * @return Expr\Comparison
  586. */
  587. public function isMemberOf($x, $y)
  588. {
  589. return new Expr\Comparison($x, 'MEMBER OF', $y);
  590. }
  591. /**
  592. * Creates an instance of INSTANCE OF function, with the given arguments.
  593. *
  594. * @param string $x Value to be checked
  595. * @param string $y Value to be checked against
  596. *
  597. * @return Expr\Comparison
  598. */
  599. public function isInstanceOf($x, $y)
  600. {
  601. return new Expr\Comparison($x, 'INSTANCE OF', $y);
  602. }
  603. }