Query.php 80 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  5. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  6. *
  7. * Licensed under The MIT License
  8. * For full copyright and license information, please see the LICENSE.txt
  9. * Redistributions of files must retain the above copyright notice.
  10. *
  11. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  12. * @link https://cakephp.org CakePHP(tm) Project
  13. * @since 3.0.0
  14. * @license https://opensource.org/licenses/mit-license.php MIT License
  15. */
  16. namespace Cake\Database;
  17. use ArrayIterator;
  18. use Cake\Database\Exception\DatabaseException;
  19. use Cake\Database\Expression\CommonTableExpression;
  20. use Cake\Database\Expression\IdentifierExpression;
  21. use Cake\Database\Expression\OrderByExpression;
  22. use Cake\Database\Expression\OrderClauseExpression;
  23. use Cake\Database\Expression\QueryExpression;
  24. use Cake\Database\Expression\ValuesExpression;
  25. use Cake\Database\Expression\WindowExpression;
  26. use Closure;
  27. use InvalidArgumentException;
  28. use IteratorAggregate;
  29. use RuntimeException;
  30. use Stringable;
  31. use Traversable;
  32. /**
  33. * This class represents a Relational database SQL Query. A query can be of
  34. * different types like select, update, insert and delete. Exposes the methods
  35. * for dynamically constructing each query part, execute it and transform it
  36. * to a specific SQL dialect.
  37. */
  38. class Query implements ExpressionInterface, IteratorAggregate, Stringable
  39. {
  40. use TypeMapTrait;
  41. /**
  42. * @var string
  43. */
  44. public const JOIN_TYPE_INNER = 'INNER';
  45. /**
  46. * @var string
  47. */
  48. public const JOIN_TYPE_LEFT = 'LEFT';
  49. /**
  50. * @var string
  51. */
  52. public const JOIN_TYPE_RIGHT = 'RIGHT';
  53. /**
  54. * @var string
  55. */
  56. public const TYPE_SELECT = 'select';
  57. /**
  58. * @var string
  59. */
  60. public const TYPE_INSERT = 'insert';
  61. /**
  62. * @var string
  63. */
  64. public const TYPE_UPDATE = 'update';
  65. /**
  66. * @var string
  67. */
  68. public const TYPE_DELETE = 'delete';
  69. /**
  70. * Connection instance to be used to execute this query.
  71. *
  72. * @var \Cake\Database\Connection
  73. */
  74. protected Connection $_connection;
  75. /**
  76. * Type of this query (select, insert, update, delete).
  77. *
  78. * @var string
  79. */
  80. protected string $_type = 'select';
  81. /**
  82. * List of SQL parts that will be used to build this query.
  83. *
  84. * @var array<string, mixed>
  85. */
  86. protected array $_parts = [
  87. 'delete' => true,
  88. 'update' => [],
  89. 'set' => [],
  90. 'insert' => [],
  91. 'values' => [],
  92. 'with' => [],
  93. 'select' => [],
  94. 'distinct' => false,
  95. 'modifier' => [],
  96. 'from' => [],
  97. 'join' => [],
  98. 'where' => null,
  99. 'group' => [],
  100. 'having' => null,
  101. 'window' => [],
  102. 'order' => null,
  103. 'limit' => null,
  104. 'offset' => null,
  105. 'union' => [],
  106. 'epilog' => null,
  107. ];
  108. /**
  109. * The list of query clauses to traverse for generating a SELECT statement
  110. *
  111. * @var array<string>
  112. */
  113. protected array $_selectParts = [
  114. 'with', 'select', 'from', 'join', 'where', 'group', 'having', 'order', 'limit',
  115. 'offset', 'union', 'epilog',
  116. ];
  117. /**
  118. * The list of query clauses to traverse for generating an UPDATE statement
  119. *
  120. * @var array<string>
  121. */
  122. protected array $_updateParts = ['with', 'update', 'set', 'where', 'epilog'];
  123. /**
  124. * The list of query clauses to traverse for generating a DELETE statement
  125. *
  126. * @var array<string>
  127. */
  128. protected array $_deleteParts = ['with', 'delete', 'modifier', 'from', 'where', 'epilog'];
  129. /**
  130. * The list of query clauses to traverse for generating an INSERT statement
  131. *
  132. * @var array<string>
  133. */
  134. protected array $_insertParts = ['with', 'insert', 'values', 'epilog'];
  135. /**
  136. * Indicates whether internal state of this query was changed, this is used to
  137. * discard internal cached objects such as the transformed query or the reference
  138. * to the executed statement.
  139. *
  140. * @var bool
  141. */
  142. protected bool $_dirty = false;
  143. /**
  144. * A list of callback functions to be called to alter each row from resulting
  145. * statement upon retrieval. Each one of the callback function will receive
  146. * the row array as first argument.
  147. *
  148. * @var array<callable>
  149. */
  150. protected array $_resultDecorators = [];
  151. /**
  152. * @var \Cake\Database\StatementInterface|null
  153. */
  154. protected ?StatementInterface $_statement = null;
  155. /**
  156. * Result set from exeuted SELCT query.
  157. *
  158. * @var iterable|null
  159. */
  160. protected ?iterable $_results = null;
  161. /**
  162. * The object responsible for generating query placeholders and temporarily store values
  163. * associated to each of those.
  164. *
  165. * @var \Cake\Database\ValueBinder|null
  166. */
  167. protected ?ValueBinder $_valueBinder = null;
  168. /**
  169. * Instance of functions builder object used for generating arbitrary SQL functions.
  170. *
  171. * @var \Cake\Database\FunctionsBuilder|null
  172. */
  173. protected ?FunctionsBuilder $_functionsBuilder = null;
  174. /**
  175. * The Type map for fields in the select clause
  176. *
  177. * @var \Cake\Database\TypeMap|null
  178. */
  179. protected ?TypeMap $_selectTypeMap = null;
  180. /**
  181. * Tracking flag to disable casting
  182. *
  183. * @var bool
  184. */
  185. protected bool $typeCastEnabled = true;
  186. /**
  187. * Constructor.
  188. *
  189. * @param \Cake\Database\Connection $connection The connection
  190. * object to be used for transforming and executing this query
  191. */
  192. public function __construct(Connection $connection)
  193. {
  194. $this->setConnection($connection);
  195. }
  196. /**
  197. * Sets the connection instance to be used for executing and transforming this query.
  198. *
  199. * @param \Cake\Database\Connection $connection Connection instance
  200. * @return $this
  201. */
  202. public function setConnection(Connection $connection)
  203. {
  204. $this->_dirty();
  205. $this->_connection = $connection;
  206. return $this;
  207. }
  208. /**
  209. * Gets the connection instance to be used for executing and transforming this query.
  210. *
  211. * @return \Cake\Database\Connection
  212. */
  213. public function getConnection(): Connection
  214. {
  215. return $this->_connection;
  216. }
  217. /**
  218. * Compiles the SQL representation of this query and executes it using the
  219. * configured connection object. Returns the resulting statement object.
  220. *
  221. * Executing a query internally executes several steps, the first one is
  222. * letting the connection transform this object to fit its particular dialect,
  223. * this might result in generating a different Query object that will be the one
  224. * to actually be executed. Immediately after, literal values are passed to the
  225. * connection so they are bound to the query in a safe way. Finally, the resulting
  226. * statement is decorated with custom objects to execute callbacks for each row
  227. * retrieved if necessary.
  228. *
  229. * Resulting statement is traversable, so it can be used in any loop as you would
  230. * with an array.
  231. *
  232. * This method can be overridden in query subclasses to decorate behavior
  233. * around query execution.
  234. *
  235. * @return \Cake\Database\StatementInterface
  236. */
  237. public function execute(): StatementInterface
  238. {
  239. $this->_statement = $this->_results = null;
  240. $this->_statement = $this->_connection->run($this);
  241. $this->_dirty = false;
  242. return $this->_statement;
  243. }
  244. /**
  245. * Executes query and returns set of decorated results.
  246. *
  247. * The results are cached until the query is modified and marked dirty.
  248. *
  249. * @return iterable
  250. * @thows \RuntimeException When query is not a SELECT query.
  251. */
  252. public function all(): iterable
  253. {
  254. if ($this->_type !== Query::TYPE_SELECT) {
  255. throw new RuntimeException(
  256. '`all()` supports SELECT queries only. Use `execute()` to run all other queries.'
  257. );
  258. }
  259. if ($this->_results === null || $this->_dirty) {
  260. $this->_results = $this->execute()->fetchAll(StatementInterface::FETCH_TYPE_ASSOC);
  261. if ($this->_resultDecorators) {
  262. foreach ($this->_results as &$row) {
  263. foreach ($this->_resultDecorators as $decorator) {
  264. $row = $decorator($row);
  265. }
  266. }
  267. }
  268. }
  269. return $this->_results;
  270. }
  271. /**
  272. * Executes the SQL of this query and immediately closes the statement before returning the row count of records
  273. * changed.
  274. *
  275. * This method can be used with UPDATE and DELETE queries, but is not recommended for SELECT queries and is not
  276. * used to count records.
  277. *
  278. * ## Example
  279. *
  280. * ```
  281. * $rowCount = $query->update('articles')
  282. * ->set(['published'=>true])
  283. * ->where(['published'=>false])
  284. * ->rowCountAndClose();
  285. * ```
  286. *
  287. * The above example will change the published column to true for all false records, and return the number of
  288. * records that were updated.
  289. *
  290. * @return int
  291. */
  292. public function rowCountAndClose(): int
  293. {
  294. $statement = $this->execute();
  295. try {
  296. return $statement->rowCount();
  297. } finally {
  298. $statement->closeCursor();
  299. }
  300. }
  301. /**
  302. * Returns the SQL representation of this object.
  303. *
  304. * This function will compile this query to make it compatible
  305. * with the SQL dialect that is used by the connection, This process might
  306. * add, remove or alter any query part or internal expression to make it
  307. * executable in the target platform.
  308. *
  309. * The resulting query may have placeholders that will be replaced with the actual
  310. * values when the query is executed, hence it is most suitable to use with
  311. * prepared statements.
  312. *
  313. * @param \Cake\Database\ValueBinder|null $binder Value binder that generates parameter placeholders
  314. * @return string
  315. */
  316. public function sql(?ValueBinder $binder = null): string
  317. {
  318. if (!$binder) {
  319. $binder = $this->getValueBinder();
  320. $binder->resetCount();
  321. }
  322. return $this->getConnection()->getDriver()->compileQuery($this, $binder)[1];
  323. }
  324. /**
  325. * Will iterate over every specified part. Traversing functions can aggregate
  326. * results using variables in the closure or instance variables. This function
  327. * is commonly used as a way for traversing all query parts that
  328. * are going to be used for constructing a query.
  329. *
  330. * The callback will receive 2 parameters, the first one is the value of the query
  331. * part that is being iterated and the second the name of such part.
  332. *
  333. * ### Example
  334. * ```
  335. * $query->select(['title'])->from('articles')->traverse(function ($value, $clause) {
  336. * if ($clause === 'select') {
  337. * var_dump($value);
  338. * }
  339. * });
  340. * ```
  341. *
  342. * @param \Closure $callback A function or callable to be executed for each part
  343. * @return $this
  344. */
  345. public function traverse(Closure $callback)
  346. {
  347. foreach ($this->_parts as $name => $part) {
  348. $callback($part, $name);
  349. }
  350. return $this;
  351. }
  352. /**
  353. * Will iterate over the provided parts.
  354. *
  355. * Traversing functions can aggregate results using variables in the closure
  356. * or instance variables. This method can be used to traverse a subset of
  357. * query parts in order to render a SQL query.
  358. *
  359. * The callback will receive 2 parameters, the first one is the value of the query
  360. * part that is being iterated and the second the name of such part.
  361. *
  362. * ### Example
  363. *
  364. * ```
  365. * $query->select(['title'])->from('articles')->traverse(function ($value, $clause) {
  366. * if ($clause === 'select') {
  367. * var_dump($value);
  368. * }
  369. * }, ['select', 'from']);
  370. * ```
  371. *
  372. * @param callable $visitor A function or callable to be executed for each part
  373. * @param array<string> $parts The list of query parts to traverse
  374. * @return $this
  375. */
  376. public function traverseParts(callable $visitor, array $parts)
  377. {
  378. foreach ($parts as $name) {
  379. $visitor($this->_parts[$name], $name);
  380. }
  381. return $this;
  382. }
  383. /**
  384. * Adds a new common table expression (CTE) to the query.
  385. *
  386. * ### Examples:
  387. *
  388. * Common table expressions can either be passed as preconstructed expression
  389. * objects:
  390. *
  391. * ```
  392. * $cte = new \Cake\Database\Expression\CommonTableExpression(
  393. * 'cte',
  394. * $connection
  395. * ->newQuery()
  396. * ->select('*')
  397. * ->from('articles')
  398. * );
  399. *
  400. * $query->with($cte);
  401. * ```
  402. *
  403. * or returned from a closure, which will receive a new common table expression
  404. * object as the first argument, and a new blank query object as
  405. * the second argument:
  406. *
  407. * ```
  408. * $query->with(function (
  409. * \Cake\Database\Expression\CommonTableExpression $cte,
  410. * \Cake\Database\Query $query
  411. * ) {
  412. * $cteQuery = $query
  413. * ->select('*')
  414. * ->from('articles');
  415. *
  416. * return $cte
  417. * ->name('cte')
  418. * ->query($cteQuery);
  419. * });
  420. * ```
  421. *
  422. * @param \Cake\Database\Expression\CommonTableExpression|\Closure $cte The CTE to add.
  423. * @param bool $overwrite Whether to reset the list of CTEs.
  424. * @return $this
  425. */
  426. public function with(CommonTableExpression|Closure $cte, bool $overwrite = false)
  427. {
  428. if ($overwrite) {
  429. $this->_parts['with'] = [];
  430. }
  431. if ($cte instanceof Closure) {
  432. $query = $this->getConnection()->newQuery();
  433. $cte = $cte(new CommonTableExpression(), $query);
  434. if (!($cte instanceof CommonTableExpression)) {
  435. throw new RuntimeException(
  436. 'You must return a `CommonTableExpression` from a Closure passed to `with()`.'
  437. );
  438. }
  439. }
  440. $this->_parts['with'][] = $cte;
  441. $this->_dirty();
  442. return $this;
  443. }
  444. /**
  445. * Adds new fields to be returned by a `SELECT` statement when this query is
  446. * executed. Fields can be passed as an array of strings, array of expression
  447. * objects, a single expression or a single string.
  448. *
  449. * If an array is passed, keys will be used to alias fields using the value as the
  450. * real field to be aliased. It is possible to alias strings, Expression objects or
  451. * even other Query objects.
  452. *
  453. * If a callable function is passed, the returning array of the function will
  454. * be used as the list of fields.
  455. *
  456. * By default this function will append any passed argument to the list of fields
  457. * to be selected, unless the second argument is set to true.
  458. *
  459. * ### Examples:
  460. *
  461. * ```
  462. * $query->select(['id', 'title']); // Produces SELECT id, title
  463. * $query->select(['author' => 'author_id']); // Appends author: SELECT id, title, author_id as author
  464. * $query->select('id', true); // Resets the list: SELECT id
  465. * $query->select(['total' => $countQuery]); // SELECT id, (SELECT ...) AS total
  466. * $query->select(function ($query) {
  467. * return ['article_id', 'total' => $query->count('*')];
  468. * })
  469. * ```
  470. *
  471. * By default no fields are selected, if you have an instance of `Cake\ORM\Query` and try to append
  472. * fields you should also call `Cake\ORM\Query::enableAutoFields()` to select the default fields
  473. * from the table.
  474. *
  475. * @param \Cake\Database\ExpressionInterface|callable|array|string|float|int $fields fields to be added to the list.
  476. * @param bool $overwrite whether to reset fields with passed list or not
  477. * @return $this
  478. */
  479. public function select(ExpressionInterface|callable|array|string|float|int $fields = [], bool $overwrite = false)
  480. {
  481. if (!is_string($fields) && is_callable($fields)) {
  482. $fields = $fields($this);
  483. }
  484. if (!is_array($fields)) {
  485. $fields = [$fields];
  486. }
  487. if ($overwrite) {
  488. $this->_parts['select'] = $fields;
  489. } else {
  490. $this->_parts['select'] = array_merge($this->_parts['select'], $fields);
  491. }
  492. $this->_dirty();
  493. $this->_type = 'select';
  494. return $this;
  495. }
  496. /**
  497. * Adds a `DISTINCT` clause to the query to remove duplicates from the result set.
  498. * This clause can only be used for select statements.
  499. *
  500. * If you wish to filter duplicates based of those rows sharing a particular field
  501. * or set of fields, you may pass an array of fields to filter on. Beware that
  502. * this option might not be fully supported in all database systems.
  503. *
  504. * ### Examples:
  505. *
  506. * ```
  507. * // Filters products with the same name and city
  508. * $query->select(['name', 'city'])->from('products')->distinct();
  509. *
  510. * // Filters products in the same city
  511. * $query->distinct(['city']);
  512. * $query->distinct('city');
  513. *
  514. * // Filter products with the same name
  515. * $query->distinct(['name'], true);
  516. * $query->distinct('name', true);
  517. * ```
  518. *
  519. * @param \Cake\Database\ExpressionInterface|array|string|bool $on Enable/disable distinct class
  520. * or list of fields to be filtered on
  521. * @param bool $overwrite whether to reset fields with passed list or not
  522. * @return $this
  523. */
  524. public function distinct(ExpressionInterface|array|string|bool $on = [], bool $overwrite = false)
  525. {
  526. if ($on === []) {
  527. $on = true;
  528. } elseif (is_string($on)) {
  529. $on = [$on];
  530. }
  531. if (is_array($on)) {
  532. $merge = [];
  533. if (is_array($this->_parts['distinct'])) {
  534. $merge = $this->_parts['distinct'];
  535. }
  536. $on = $overwrite ? array_values($on) : array_merge($merge, array_values($on));
  537. }
  538. $this->_parts['distinct'] = $on;
  539. $this->_dirty();
  540. return $this;
  541. }
  542. /**
  543. * Adds a single or multiple `SELECT` modifiers to be used in the `SELECT`.
  544. *
  545. * By default this function will append any passed argument to the list of modifiers
  546. * to be applied, unless the second argument is set to true.
  547. *
  548. * ### Example:
  549. *
  550. * ```
  551. * // Ignore cache query in MySQL
  552. * $query->select(['name', 'city'])->from('products')->modifier('SQL_NO_CACHE');
  553. * // It will produce the SQL: SELECT SQL_NO_CACHE name, city FROM products
  554. *
  555. * // Or with multiple modifiers
  556. * $query->select(['name', 'city'])->from('products')->modifier(['HIGH_PRIORITY', 'SQL_NO_CACHE']);
  557. * // It will produce the SQL: SELECT HIGH_PRIORITY SQL_NO_CACHE name, city FROM products
  558. * ```
  559. *
  560. * @param \Cake\Database\ExpressionInterface|array|string $modifiers modifiers to be applied to the query
  561. * @param bool $overwrite whether to reset order with field list or not
  562. * @return $this
  563. */
  564. public function modifier(ExpressionInterface|array|string $modifiers, bool $overwrite = false)
  565. {
  566. $this->_dirty();
  567. if ($overwrite) {
  568. $this->_parts['modifier'] = [];
  569. }
  570. if (!is_array($modifiers)) {
  571. $modifiers = [$modifiers];
  572. }
  573. $this->_parts['modifier'] = array_merge($this->_parts['modifier'], $modifiers);
  574. return $this;
  575. }
  576. /**
  577. * Adds a single or multiple tables to be used in the FROM clause for this query.
  578. * Tables can be passed as an array of strings, array of expression
  579. * objects, a single expression or a single string.
  580. *
  581. * If an array is passed, keys will be used to alias tables using the value as the
  582. * real field to be aliased. It is possible to alias strings, ExpressionInterface objects or
  583. * even other Query objects.
  584. *
  585. * By default this function will append any passed argument to the list of tables
  586. * to be selected from, unless the second argument is set to true.
  587. *
  588. * This method can be used for select, update and delete statements.
  589. *
  590. * ### Examples:
  591. *
  592. * ```
  593. * $query->from(['p' => 'posts']); // Produces FROM posts p
  594. * $query->from('authors'); // Appends authors: FROM posts p, authors
  595. * $query->from(['products'], true); // Resets the list: FROM products
  596. * $query->from(['sub' => $countQuery]); // FROM (SELECT ...) sub
  597. * ```
  598. *
  599. * @param array|string $tables tables to be added to the list. This argument, can be
  600. * passed as an array of strings, array of expression objects, or a single string. See
  601. * the examples above for the valid call types.
  602. * @param bool $overwrite whether to reset tables with passed list or not
  603. * @return $this
  604. */
  605. public function from(array|string $tables = [], bool $overwrite = false)
  606. {
  607. $tables = (array)$tables;
  608. if ($overwrite) {
  609. $this->_parts['from'] = $tables;
  610. } else {
  611. $this->_parts['from'] = array_merge($this->_parts['from'], $tables);
  612. }
  613. $this->_dirty();
  614. return $this;
  615. }
  616. /**
  617. * Adds a single or multiple tables to be used as JOIN clauses to this query.
  618. * Tables can be passed as an array of strings, an array describing the
  619. * join parts, an array with multiple join descriptions, or a single string.
  620. *
  621. * By default this function will append any passed argument to the list of tables
  622. * to be joined, unless the third argument is set to true.
  623. *
  624. * When no join type is specified an `INNER JOIN` is used by default:
  625. * `$query->join(['authors'])` will produce `INNER JOIN authors ON 1 = 1`
  626. *
  627. * It is also possible to alias joins using the array key:
  628. * `$query->join(['a' => 'authors'])` will produce `INNER JOIN authors a ON 1 = 1`
  629. *
  630. * A join can be fully described and aliased using the array notation:
  631. *
  632. * ```
  633. * $query->join([
  634. * 'a' => [
  635. * 'table' => 'authors',
  636. * 'type' => 'LEFT',
  637. * 'conditions' => 'a.id = b.author_id'
  638. * ]
  639. * ]);
  640. * // Produces LEFT JOIN authors a ON a.id = b.author_id
  641. * ```
  642. *
  643. * You can even specify multiple joins in an array, including the full description:
  644. *
  645. * ```
  646. * $query->join([
  647. * 'a' => [
  648. * 'table' => 'authors',
  649. * 'type' => 'LEFT',
  650. * 'conditions' => 'a.id = b.author_id'
  651. * ],
  652. * 'p' => [
  653. * 'table' => 'publishers',
  654. * 'type' => 'INNER',
  655. * 'conditions' => 'p.id = b.publisher_id AND p.name = "Cake Software Foundation"'
  656. * ]
  657. * ]);
  658. * // LEFT JOIN authors a ON a.id = b.author_id
  659. * // INNER JOIN publishers p ON p.id = b.publisher_id AND p.name = "Cake Software Foundation"
  660. * ```
  661. *
  662. * ### Using conditions and types
  663. *
  664. * Conditions can be expressed, as in the examples above, using a string for comparing
  665. * columns, or string with already quoted literal values. Additionally it is
  666. * possible to use conditions expressed in arrays or expression objects.
  667. *
  668. * When using arrays for expressing conditions, it is often desirable to convert
  669. * the literal values to the correct database representation. This is achieved
  670. * using the second parameter of this function.
  671. *
  672. * ```
  673. * $query->join(['a' => [
  674. * 'table' => 'articles',
  675. * 'conditions' => [
  676. * 'a.posted >=' => new DateTime('-3 days'),
  677. * 'a.published' => true,
  678. * 'a.author_id = authors.id'
  679. * ]
  680. * ]], ['a.posted' => 'datetime', 'a.published' => 'boolean'])
  681. * ```
  682. *
  683. * ### Overwriting joins
  684. *
  685. * When creating aliased joins using the array notation, you can override
  686. * previous join definitions by using the same alias in consequent
  687. * calls to this function or you can replace all previously defined joins
  688. * with another list if the third parameter for this function is set to true.
  689. *
  690. * ```
  691. * $query->join(['alias' => 'table']); // joins table with as alias
  692. * $query->join(['alias' => 'another_table']); // joins another_table with as alias
  693. * $query->join(['something' => 'different_table'], [], true); // resets joins list
  694. * ```
  695. *
  696. * @param array<string, mixed>|string $tables list of tables to be joined in the query
  697. * @param array<string, string> $types Associative array of type names used to bind values to query
  698. * @param bool $overwrite whether to reset joins with passed list or not
  699. * @see \Cake\Database\TypeFactory
  700. * @return $this
  701. */
  702. public function join(array|string $tables, array $types = [], bool $overwrite = false)
  703. {
  704. if (is_string($tables) || isset($tables['table'])) {
  705. $tables = [$tables];
  706. }
  707. $joins = [];
  708. $i = count($this->_parts['join']);
  709. foreach ($tables as $alias => $t) {
  710. if (!is_array($t)) {
  711. $t = ['table' => $t, 'conditions' => $this->newExpr()];
  712. }
  713. if (!is_string($t['conditions']) && is_callable($t['conditions'])) {
  714. $t['conditions'] = $t['conditions']($this->newExpr(), $this);
  715. }
  716. if (!($t['conditions'] instanceof ExpressionInterface)) {
  717. $t['conditions'] = $this->newExpr()->add($t['conditions'], $types);
  718. }
  719. $alias = is_string($alias) ? $alias : null;
  720. $joins[$alias ?: $i++] = $t + ['type' => static::JOIN_TYPE_INNER, 'alias' => $alias];
  721. }
  722. if ($overwrite) {
  723. $this->_parts['join'] = $joins;
  724. } else {
  725. $this->_parts['join'] = array_merge($this->_parts['join'], $joins);
  726. }
  727. $this->_dirty();
  728. return $this;
  729. }
  730. /**
  731. * Remove a join if it has been defined.
  732. *
  733. * Useful when you are redefining joins or want to re-order
  734. * the join clauses.
  735. *
  736. * @param string $name The alias/name of the join to remove.
  737. * @return $this
  738. */
  739. public function removeJoin(string $name)
  740. {
  741. unset($this->_parts['join'][$name]);
  742. $this->_dirty();
  743. return $this;
  744. }
  745. /**
  746. * Adds a single `LEFT JOIN` clause to the query.
  747. *
  748. * This is a shorthand method for building joins via `join()`.
  749. *
  750. * The table name can be passed as a string, or as an array in case it needs to
  751. * be aliased:
  752. *
  753. * ```
  754. * // LEFT JOIN authors ON authors.id = posts.author_id
  755. * $query->leftJoin('authors', 'authors.id = posts.author_id');
  756. *
  757. * // LEFT JOIN authors a ON a.id = posts.author_id
  758. * $query->leftJoin(['a' => 'authors'], 'a.id = posts.author_id');
  759. * ```
  760. *
  761. * Conditions can be passed as strings, arrays, or expression objects. When
  762. * using arrays it is possible to combine them with the `$types` parameter
  763. * in order to define how to convert the values:
  764. *
  765. * ```
  766. * $query->leftJoin(['a' => 'articles'], [
  767. * 'a.posted >=' => new DateTime('-3 days'),
  768. * 'a.published' => true,
  769. * 'a.author_id = authors.id'
  770. * ], ['a.posted' => 'datetime', 'a.published' => 'boolean']);
  771. * ```
  772. *
  773. * See `join()` for further details on conditions and types.
  774. *
  775. * @param array<string>|string $table The table to join with
  776. * @param \Cake\Database\ExpressionInterface|array|string $conditions The conditions
  777. * to use for joining.
  778. * @param array $types a list of types associated to the conditions used for converting
  779. * values to the corresponding database representation.
  780. * @return $this
  781. */
  782. public function leftJoin(array|string $table, ExpressionInterface|array|string $conditions = [], array $types = [])
  783. {
  784. $this->join($this->_makeJoin($table, $conditions, static::JOIN_TYPE_LEFT), $types);
  785. return $this;
  786. }
  787. /**
  788. * Adds a single `RIGHT JOIN` clause to the query.
  789. *
  790. * This is a shorthand method for building joins via `join()`.
  791. *
  792. * The arguments of this method are identical to the `leftJoin()` shorthand, please refer
  793. * to that methods description for further details.
  794. *
  795. * @param array<string>|string $table The table to join with
  796. * @param \Cake\Database\ExpressionInterface|array|string $conditions The conditions
  797. * to use for joining.
  798. * @param array $types a list of types associated to the conditions used for converting
  799. * values to the corresponding database representation.
  800. * @return $this
  801. */
  802. public function rightJoin(array|string $table, ExpressionInterface|array|string $conditions = [], array $types = [])
  803. {
  804. $this->join($this->_makeJoin($table, $conditions, static::JOIN_TYPE_RIGHT), $types);
  805. return $this;
  806. }
  807. /**
  808. * Adds a single `INNER JOIN` clause to the query.
  809. *
  810. * This is a shorthand method for building joins via `join()`.
  811. *
  812. * The arguments of this method are identical to the `leftJoin()` shorthand, please refer
  813. * to that method's description for further details.
  814. *
  815. * @param array|string $table The table to join with
  816. * @param \Cake\Database\ExpressionInterface|\Closure|array|string $conditions The conditions
  817. * to use for joining.
  818. * @param array<string, string> $types a list of types associated to the conditions used for converting
  819. * values to the corresponding database representation.
  820. * @return $this
  821. */
  822. public function innerJoin(
  823. array|string $table,
  824. ExpressionInterface|Closure|array|string $conditions = [],
  825. array $types = []
  826. ) {
  827. $this->join($this->_makeJoin($table, $conditions, static::JOIN_TYPE_INNER), $types);
  828. return $this;
  829. }
  830. /**
  831. * Returns an array that can be passed to the join method describing a single join clause
  832. *
  833. * @param array<string>|string $table The table to join with
  834. * @param \Cake\Database\ExpressionInterface|\Closure|array|string $conditions The conditions
  835. * to use for joining.
  836. * @param string $type the join type to use
  837. * @return array
  838. * @psalm-suppress InvalidReturnType
  839. */
  840. protected function _makeJoin(
  841. array|string $table,
  842. ExpressionInterface|Closure|array|string $conditions,
  843. string $type
  844. ): array {
  845. $alias = $table;
  846. if (is_array($table)) {
  847. $alias = key($table);
  848. $table = current($table);
  849. }
  850. /**
  851. * @psalm-suppress InvalidArrayOffset
  852. * @psalm-suppress InvalidReturnStatement
  853. */
  854. return [
  855. $alias => [
  856. 'table' => $table,
  857. 'conditions' => $conditions,
  858. 'type' => $type,
  859. ],
  860. ];
  861. }
  862. /**
  863. * Adds a condition or set of conditions to be used in the WHERE clause for this
  864. * query. Conditions can be expressed as an array of fields as keys with
  865. * comparison operators in it, the values for the array will be used for comparing
  866. * the field to such literal. Finally, conditions can be expressed as a single
  867. * string or an array of strings.
  868. *
  869. * When using arrays, each entry will be joined to the rest of the conditions using
  870. * an `AND` operator. Consecutive calls to this function will also join the new
  871. * conditions specified using the AND operator. Additionally, values can be
  872. * expressed using expression objects which can include other query objects.
  873. *
  874. * Any conditions created with this methods can be used with any `SELECT`, `UPDATE`
  875. * and `DELETE` type of queries.
  876. *
  877. * ### Conditions using operators:
  878. *
  879. * ```
  880. * $query->where([
  881. * 'posted >=' => new DateTime('3 days ago'),
  882. * 'title LIKE' => 'Hello W%',
  883. * 'author_id' => 1,
  884. * ], ['posted' => 'datetime']);
  885. * ```
  886. *
  887. * The previous example produces:
  888. *
  889. * `WHERE posted >= 2012-01-27 AND title LIKE 'Hello W%' AND author_id = 1`
  890. *
  891. * Second parameter is used to specify what type is expected for each passed
  892. * key. Valid types can be used from the mapped with Database\Type class.
  893. *
  894. * ### Nesting conditions with conjunctions:
  895. *
  896. * ```
  897. * $query->where([
  898. * 'author_id !=' => 1,
  899. * 'OR' => ['published' => true, 'posted <' => new DateTime('now')],
  900. * 'NOT' => ['title' => 'Hello']
  901. * ], ['published' => boolean, 'posted' => 'datetime']
  902. * ```
  903. *
  904. * The previous example produces:
  905. *
  906. * `WHERE author_id = 1 AND (published = 1 OR posted < '2012-02-01') AND NOT (title = 'Hello')`
  907. *
  908. * You can nest conditions using conjunctions as much as you like. Sometimes, you
  909. * may want to define 2 different options for the same key, in that case, you can
  910. * wrap each condition inside a new array:
  911. *
  912. * `$query->where(['OR' => [['published' => false], ['published' => true]])`
  913. *
  914. * Would result in:
  915. *
  916. * `WHERE (published = false) OR (published = true)`
  917. *
  918. * Keep in mind that every time you call where() with the third param set to false
  919. * (default), it will join the passed conditions to the previous stored list using
  920. * the `AND` operator. Also, using the same array key twice in consecutive calls to
  921. * this method will not override the previous value.
  922. *
  923. * ### Using expressions objects:
  924. *
  925. * ```
  926. * $exp = $query->newExpr()->add(['id !=' => 100, 'author_id' != 1])->tieWith('OR');
  927. * $query->where(['published' => true], ['published' => 'boolean'])->where($exp);
  928. * ```
  929. *
  930. * The previous example produces:
  931. *
  932. * `WHERE (id != 100 OR author_id != 1) AND published = 1`
  933. *
  934. * Other Query objects that be used as conditions for any field.
  935. *
  936. * ### Adding conditions in multiple steps:
  937. *
  938. * You can use callable functions to construct complex expressions, functions
  939. * receive as first argument a new QueryExpression object and this query instance
  940. * as second argument. Functions must return an expression object, that will be
  941. * added the list of conditions for the query using the `AND` operator.
  942. *
  943. * ```
  944. * $query
  945. * ->where(['title !=' => 'Hello World'])
  946. * ->where(function ($exp, $query) {
  947. * $or = $exp->or(['id' => 1]);
  948. * $and = $exp->and(['id >' => 2, 'id <' => 10]);
  949. * return $or->add($and);
  950. * });
  951. * ```
  952. *
  953. * * The previous example produces:
  954. *
  955. * `WHERE title != 'Hello World' AND (id = 1 OR (id > 2 AND id < 10))`
  956. *
  957. * ### Conditions as strings:
  958. *
  959. * ```
  960. * $query->where(['articles.author_id = authors.id', 'modified IS NULL']);
  961. * ```
  962. *
  963. * The previous example produces:
  964. *
  965. * `WHERE articles.author_id = authors.id AND modified IS NULL`
  966. *
  967. * Please note that when using the array notation or the expression objects, all
  968. * *values* will be correctly quoted and transformed to the correspondent database
  969. * data type automatically for you, thus securing your application from SQL injections.
  970. * The keys however, are not treated as unsafe input, and should be validated/sanitized.
  971. *
  972. * If you use string conditions make sure that your values are correctly quoted.
  973. * The safest thing you can do is to never use string conditions.
  974. *
  975. * @param \Cake\Database\ExpressionInterface|\Closure|array|string|null $conditions The conditions to filter on.
  976. * @param array<string, string> $types Associative array of type names used to bind values to query
  977. * @param bool $overwrite whether to reset conditions with passed list or not
  978. * @see \Cake\Database\TypeFactory
  979. * @see \Cake\Database\Expression\QueryExpression
  980. * @return $this
  981. */
  982. public function where(
  983. ExpressionInterface|Closure|array|string|null $conditions = null,
  984. array $types = [],
  985. bool $overwrite = false
  986. ) {
  987. if ($overwrite) {
  988. $this->_parts['where'] = $this->newExpr();
  989. }
  990. $this->_conjugate('where', $conditions, 'AND', $types);
  991. return $this;
  992. }
  993. /**
  994. * Convenience method that adds a NOT NULL condition to the query
  995. *
  996. * @param \Cake\Database\ExpressionInterface|array|string $fields A single field or expressions or a list of them
  997. * that should be not null.
  998. * @return $this
  999. */
  1000. public function whereNotNull(ExpressionInterface|array|string $fields)
  1001. {
  1002. if (!is_array($fields)) {
  1003. $fields = [$fields];
  1004. }
  1005. $exp = $this->newExpr();
  1006. foreach ($fields as $field) {
  1007. $exp->isNotNull($field);
  1008. }
  1009. return $this->where($exp);
  1010. }
  1011. /**
  1012. * Convenience method that adds a IS NULL condition to the query
  1013. *
  1014. * @param \Cake\Database\ExpressionInterface|array|string $fields A single field or expressions or a list of them
  1015. * that should be null.
  1016. * @return $this
  1017. */
  1018. public function whereNull(ExpressionInterface|array|string $fields)
  1019. {
  1020. if (!is_array($fields)) {
  1021. $fields = [$fields];
  1022. }
  1023. $exp = $this->newExpr();
  1024. foreach ($fields as $field) {
  1025. $exp->isNull($field);
  1026. }
  1027. return $this->where($exp);
  1028. }
  1029. /**
  1030. * Adds an IN condition or set of conditions to be used in the WHERE clause for this
  1031. * query.
  1032. *
  1033. * This method does allow empty inputs in contrast to where() if you set
  1034. * 'allowEmpty' to true.
  1035. * Be careful about using it without proper sanity checks.
  1036. *
  1037. * Options:
  1038. *
  1039. * - `types` - Associative array of type names used to bind values to query
  1040. * - `allowEmpty` - Allow empty array.
  1041. *
  1042. * @param string $field Field
  1043. * @param array $values Array of values
  1044. * @param array<string, mixed> $options Options
  1045. * @return $this
  1046. */
  1047. public function whereInList(string $field, array $values, array $options = [])
  1048. {
  1049. $options += [
  1050. 'types' => [],
  1051. 'allowEmpty' => false,
  1052. ];
  1053. if ($options['allowEmpty'] && !$values) {
  1054. return $this->where('1=0');
  1055. }
  1056. return $this->where([$field . ' IN' => $values], $options['types']);
  1057. }
  1058. /**
  1059. * Adds a NOT IN condition or set of conditions to be used in the WHERE clause for this
  1060. * query.
  1061. *
  1062. * This method does allow empty inputs in contrast to where() if you set
  1063. * 'allowEmpty' to true.
  1064. * Be careful about using it without proper sanity checks.
  1065. *
  1066. * @param string $field Field
  1067. * @param array $values Array of values
  1068. * @param array<string, mixed> $options Options
  1069. * @return $this
  1070. */
  1071. public function whereNotInList(string $field, array $values, array $options = [])
  1072. {
  1073. $options += [
  1074. 'types' => [],
  1075. 'allowEmpty' => false,
  1076. ];
  1077. if ($options['allowEmpty'] && !$values) {
  1078. return $this->where([$field . ' IS NOT' => null]);
  1079. }
  1080. return $this->where([$field . ' NOT IN' => $values], $options['types']);
  1081. }
  1082. /**
  1083. * Adds a NOT IN condition or set of conditions to be used in the WHERE clause for this
  1084. * query. This also allows the field to be null with a IS NULL condition since the null
  1085. * value would cause the NOT IN condition to always fail.
  1086. *
  1087. * This method does allow empty inputs in contrast to where() if you set
  1088. * 'allowEmpty' to true.
  1089. * Be careful about using it without proper sanity checks.
  1090. *
  1091. * @param string $field Field
  1092. * @param array $values Array of values
  1093. * @param array<string, mixed> $options Options
  1094. * @return $this
  1095. */
  1096. public function whereNotInListOrNull(string $field, array $values, array $options = [])
  1097. {
  1098. $options += [
  1099. 'types' => [],
  1100. 'allowEmpty' => false,
  1101. ];
  1102. if ($options['allowEmpty'] && !$values) {
  1103. return $this->where([$field . ' IS NOT' => null]);
  1104. }
  1105. return $this->where(
  1106. [
  1107. 'OR' => [$field . ' NOT IN' => $values, $field . ' IS' => null],
  1108. ],
  1109. $options['types']
  1110. );
  1111. }
  1112. /**
  1113. * Connects any previously defined set of conditions to the provided list
  1114. * using the AND operator. This function accepts the conditions list in the same
  1115. * format as the method `where` does, hence you can use arrays, expression objects
  1116. * callback functions or strings.
  1117. *
  1118. * It is important to notice that when calling this function, any previous set
  1119. * of conditions defined for this query will be treated as a single argument for
  1120. * the AND operator. This function will not only operate the most recently defined
  1121. * condition, but all the conditions as a whole.
  1122. *
  1123. * When using an array for defining conditions, creating constraints form each
  1124. * array entry will use the same logic as with the `where()` function. This means
  1125. * that each array entry will be joined to the other using the AND operator, unless
  1126. * you nest the conditions in the array using other operator.
  1127. *
  1128. * ### Examples:
  1129. *
  1130. * ```
  1131. * $query->where(['title' => 'Hello World')->andWhere(['author_id' => 1]);
  1132. * ```
  1133. *
  1134. * Will produce:
  1135. *
  1136. * `WHERE title = 'Hello World' AND author_id = 1`
  1137. *
  1138. * ```
  1139. * $query
  1140. * ->where(['OR' => ['published' => false, 'published is NULL']])
  1141. * ->andWhere(['author_id' => 1, 'comments_count >' => 10])
  1142. * ```
  1143. *
  1144. * Produces:
  1145. *
  1146. * `WHERE (published = 0 OR published IS NULL) AND author_id = 1 AND comments_count > 10`
  1147. *
  1148. * ```
  1149. * $query
  1150. * ->where(['title' => 'Foo'])
  1151. * ->andWhere(function ($exp, $query) {
  1152. * return $exp
  1153. * ->or(['author_id' => 1])
  1154. * ->add(['author_id' => 2]);
  1155. * });
  1156. * ```
  1157. *
  1158. * Generates the following conditions:
  1159. *
  1160. * `WHERE (title = 'Foo') AND (author_id = 1 OR author_id = 2)`
  1161. *
  1162. * @param \Cake\Database\ExpressionInterface|\Closure|array|string $conditions The conditions to add with AND.
  1163. * @param array<string, string> $types Associative array of type names used to bind values to query
  1164. * @see \Cake\Database\Query::where()
  1165. * @see \Cake\Database\TypeFactory
  1166. * @return $this
  1167. */
  1168. public function andWhere(ExpressionInterface|Closure|array|string $conditions, array $types = [])
  1169. {
  1170. $this->_conjugate('where', $conditions, 'AND', $types);
  1171. return $this;
  1172. }
  1173. /**
  1174. * Adds a single or multiple fields to be used in the ORDER clause for this query.
  1175. * Fields can be passed as an array of strings, array of expression
  1176. * objects, a single expression or a single string.
  1177. *
  1178. * If an array is passed, keys will be used as the field itself and the value will
  1179. * represent the order in which such field should be ordered. When called multiple
  1180. * times with the same fields as key, the last order definition will prevail over
  1181. * the others.
  1182. *
  1183. * By default this function will append any passed argument to the list of fields
  1184. * to be selected, unless the second argument is set to true.
  1185. *
  1186. * ### Examples:
  1187. *
  1188. * ```
  1189. * $query->order(['title' => 'DESC', 'author_id' => 'ASC']);
  1190. * ```
  1191. *
  1192. * Produces:
  1193. *
  1194. * `ORDER BY title DESC, author_id ASC`
  1195. *
  1196. * ```
  1197. * $query
  1198. * ->order(['title' => $query->newExpr('DESC NULLS FIRST')])
  1199. * ->order('author_id');
  1200. * ```
  1201. *
  1202. * Will generate:
  1203. *
  1204. * `ORDER BY title DESC NULLS FIRST, author_id`
  1205. *
  1206. * ```
  1207. * $expression = $query->newExpr()->add(['id % 2 = 0']);
  1208. * $query->order($expression)->order(['title' => 'ASC']);
  1209. * ```
  1210. *
  1211. * and
  1212. *
  1213. * ```
  1214. * $query->order(function ($exp, $query) {
  1215. * return [$exp->add(['id % 2 = 0']), 'title' => 'ASC'];
  1216. * });
  1217. * ```
  1218. *
  1219. * Will both become:
  1220. *
  1221. * `ORDER BY (id %2 = 0), title ASC`
  1222. *
  1223. * Order fields/directions are not sanitized by the query builder.
  1224. * You should use an allowed list of fields/directions when passing
  1225. * in user-supplied data to `order()`.
  1226. *
  1227. * If you need to set complex expressions as order conditions, you
  1228. * should use `orderAsc()` or `orderDesc()`.
  1229. *
  1230. * @param \Cake\Database\ExpressionInterface|\Closure|array|string $fields fields to be added to the list
  1231. * @param bool $overwrite whether to reset order with field list or not
  1232. * @return $this
  1233. */
  1234. public function order(ExpressionInterface|Closure|array|string $fields, bool $overwrite = false)
  1235. {
  1236. if ($overwrite) {
  1237. $this->_parts['order'] = null;
  1238. }
  1239. if (!$fields) {
  1240. return $this;
  1241. }
  1242. if (!$this->_parts['order']) {
  1243. $this->_parts['order'] = new OrderByExpression();
  1244. }
  1245. $this->_conjugate('order', $fields, '', []);
  1246. return $this;
  1247. }
  1248. /**
  1249. * Add an ORDER BY clause with an ASC direction.
  1250. *
  1251. * This method allows you to set complex expressions
  1252. * as order conditions unlike order()
  1253. *
  1254. * Order fields are not suitable for use with user supplied data as they are
  1255. * not sanitized by the query builder.
  1256. *
  1257. * @param \Cake\Database\ExpressionInterface|\Closure|string $field The field to order on.
  1258. * @param bool $overwrite Whether to reset the order clauses.
  1259. * @return $this
  1260. */
  1261. public function orderAsc(ExpressionInterface|Closure|string $field, bool $overwrite = false)
  1262. {
  1263. if ($overwrite) {
  1264. $this->_parts['order'] = null;
  1265. }
  1266. if (!$field) {
  1267. return $this;
  1268. }
  1269. if ($field instanceof Closure) {
  1270. $field = $field($this->newExpr(), $this);
  1271. }
  1272. if (!$this->_parts['order']) {
  1273. $this->_parts['order'] = new OrderByExpression();
  1274. }
  1275. $this->_parts['order']->add(new OrderClauseExpression($field, 'ASC'));
  1276. return $this;
  1277. }
  1278. /**
  1279. * Add an ORDER BY clause with a DESC direction.
  1280. *
  1281. * This method allows you to set complex expressions
  1282. * as order conditions unlike order()
  1283. *
  1284. * Order fields are not suitable for use with user supplied data as they are
  1285. * not sanitized by the query builder.
  1286. *
  1287. * @param \Cake\Database\ExpressionInterface|\Closure|string $field The field to order on.
  1288. * @param bool $overwrite Whether to reset the order clauses.
  1289. * @return $this
  1290. */
  1291. public function orderDesc(ExpressionInterface|Closure|string $field, bool $overwrite = false)
  1292. {
  1293. if ($overwrite) {
  1294. $this->_parts['order'] = null;
  1295. }
  1296. if (!$field) {
  1297. return $this;
  1298. }
  1299. if ($field instanceof Closure) {
  1300. $field = $field($this->newExpr(), $this);
  1301. }
  1302. if (!$this->_parts['order']) {
  1303. $this->_parts['order'] = new OrderByExpression();
  1304. }
  1305. $this->_parts['order']->add(new OrderClauseExpression($field, 'DESC'));
  1306. return $this;
  1307. }
  1308. /**
  1309. * Adds a single or multiple fields to be used in the GROUP BY clause for this query.
  1310. * Fields can be passed as an array of strings, array of expression
  1311. * objects, a single expression or a single string.
  1312. *
  1313. * By default this function will append any passed argument to the list of fields
  1314. * to be grouped, unless the second argument is set to true.
  1315. *
  1316. * ### Examples:
  1317. *
  1318. * ```
  1319. * // Produces GROUP BY id, title
  1320. * $query->group(['id', 'title']);
  1321. *
  1322. * // Produces GROUP BY title
  1323. * $query->group('title');
  1324. * ```
  1325. *
  1326. * Group fields are not suitable for use with user supplied data as they are
  1327. * not sanitized by the query builder.
  1328. *
  1329. * @param \Cake\Database\ExpressionInterface|array|string $fields fields to be added to the list
  1330. * @param bool $overwrite whether to reset fields with passed list or not
  1331. * @return $this
  1332. */
  1333. public function group(ExpressionInterface|array|string $fields, bool $overwrite = false)
  1334. {
  1335. if ($overwrite) {
  1336. $this->_parts['group'] = [];
  1337. }
  1338. if (!is_array($fields)) {
  1339. $fields = [$fields];
  1340. }
  1341. $this->_parts['group'] = array_merge($this->_parts['group'], array_values($fields));
  1342. $this->_dirty();
  1343. return $this;
  1344. }
  1345. /**
  1346. * Adds a condition or set of conditions to be used in the `HAVING` clause for this
  1347. * query. This method operates in exactly the same way as the method `where()`
  1348. * does. Please refer to its documentation for an insight on how to using each
  1349. * parameter.
  1350. *
  1351. * Having fields are not suitable for use with user supplied data as they are
  1352. * not sanitized by the query builder.
  1353. *
  1354. * @param \Cake\Database\ExpressionInterface|\Closure|array|string|null $conditions The having conditions.
  1355. * @param array<string, string> $types Associative array of type names used to bind values to query
  1356. * @param bool $overwrite whether to reset conditions with passed list or not
  1357. * @see \Cake\Database\Query::where()
  1358. * @return $this
  1359. */
  1360. public function having(
  1361. ExpressionInterface|Closure|array|string|null $conditions = null,
  1362. array $types = [],
  1363. bool $overwrite = false
  1364. ) {
  1365. if ($overwrite) {
  1366. $this->_parts['having'] = $this->newExpr();
  1367. }
  1368. $this->_conjugate('having', $conditions, 'AND', $types);
  1369. return $this;
  1370. }
  1371. /**
  1372. * Connects any previously defined set of conditions to the provided list
  1373. * using the AND operator in the HAVING clause. This method operates in exactly
  1374. * the same way as the method `andWhere()` does. Please refer to its
  1375. * documentation for an insight on how to using each parameter.
  1376. *
  1377. * Having fields are not suitable for use with user supplied data as they are
  1378. * not sanitized by the query builder.
  1379. *
  1380. * @param \Cake\Database\ExpressionInterface|\Closure|array|string $conditions The AND conditions for HAVING.
  1381. * @param array<string, string> $types Associative array of type names used to bind values to query
  1382. * @see \Cake\Database\Query::andWhere()
  1383. * @return $this
  1384. */
  1385. public function andHaving(ExpressionInterface|Closure|array|string $conditions, array $types = [])
  1386. {
  1387. $this->_conjugate('having', $conditions, 'AND', $types);
  1388. return $this;
  1389. }
  1390. /**
  1391. * Adds a named window expression.
  1392. *
  1393. * You are responsible for adding windows in the order your database requires.
  1394. *
  1395. * @param string $name Window name
  1396. * @param \Cake\Database\Expression\WindowExpression|\Closure $window Window expression
  1397. * @param bool $overwrite Clear all previous query window expressions
  1398. * @return $this
  1399. */
  1400. public function window(string $name, WindowExpression|Closure $window, bool $overwrite = false)
  1401. {
  1402. if ($overwrite) {
  1403. $this->_parts['window'] = [];
  1404. }
  1405. if ($window instanceof Closure) {
  1406. $window = $window(new WindowExpression(), $this);
  1407. if (!($window instanceof WindowExpression)) {
  1408. throw new RuntimeException('You must return a `WindowExpression` from a Closure passed to `window()`.');
  1409. }
  1410. }
  1411. $this->_parts['window'][] = ['name' => new IdentifierExpression($name), 'window' => $window];
  1412. $this->_dirty();
  1413. return $this;
  1414. }
  1415. /**
  1416. * Set the page of results you want.
  1417. *
  1418. * This method provides an easier to use interface to set the limit + offset
  1419. * in the record set you want as results. If empty the limit will default to
  1420. * the existing limit clause, and if that too is empty, then `25` will be used.
  1421. *
  1422. * Pages must start at 1.
  1423. *
  1424. * @param int $num The page number you want.
  1425. * @param int|null $limit The number of rows you want in the page. If null
  1426. * the current limit clause will be used.
  1427. * @return $this
  1428. * @throws \InvalidArgumentException If page number < 1.
  1429. */
  1430. public function page(int $num, ?int $limit = null)
  1431. {
  1432. if ($num < 1) {
  1433. throw new InvalidArgumentException('Pages must start at 1.');
  1434. }
  1435. if ($limit !== null) {
  1436. $this->limit($limit);
  1437. }
  1438. $limit = $this->clause('limit');
  1439. if ($limit === null) {
  1440. $limit = 25;
  1441. $this->limit($limit);
  1442. }
  1443. $offset = ($num - 1) * $limit;
  1444. if (PHP_INT_MAX <= $offset) {
  1445. $offset = PHP_INT_MAX;
  1446. }
  1447. $this->offset((int)$offset);
  1448. return $this;
  1449. }
  1450. /**
  1451. * Sets the number of records that should be retrieved from database,
  1452. * accepts an integer or an expression object that evaluates to an integer.
  1453. * In some databases, this operation might not be supported or will require
  1454. * the query to be transformed in order to limit the result set size.
  1455. *
  1456. * ### Examples
  1457. *
  1458. * ```
  1459. * $query->limit(10) // generates LIMIT 10
  1460. * $query->limit($query->newExpr()->add(['1 + 1'])); // LIMIT (1 + 1)
  1461. * ```
  1462. *
  1463. * @param \Cake\Database\ExpressionInterface|int|null $limit number of records to be returned
  1464. * @return $this
  1465. */
  1466. public function limit(ExpressionInterface|int|null $limit)
  1467. {
  1468. $this->_dirty();
  1469. $this->_parts['limit'] = $limit;
  1470. return $this;
  1471. }
  1472. /**
  1473. * Sets the number of records that should be skipped from the original result set
  1474. * This is commonly used for paginating large results. Accepts an integer or an
  1475. * expression object that evaluates to an integer.
  1476. *
  1477. * In some databases, this operation might not be supported or will require
  1478. * the query to be transformed in order to limit the result set size.
  1479. *
  1480. * ### Examples
  1481. *
  1482. * ```
  1483. * $query->offset(10) // generates OFFSET 10
  1484. * $query->offset($query->newExpr()->add(['1 + 1'])); // OFFSET (1 + 1)
  1485. * ```
  1486. *
  1487. * @param \Cake\Database\ExpressionInterface|int|null $offset number of records to be skipped
  1488. * @return $this
  1489. */
  1490. public function offset(ExpressionInterface|int|null $offset)
  1491. {
  1492. $this->_dirty();
  1493. $this->_parts['offset'] = $offset;
  1494. return $this;
  1495. }
  1496. /**
  1497. * Adds a complete query to be used in conjunction with an UNION operator with
  1498. * this query. This is used to combine the result set of this query with the one
  1499. * that will be returned by the passed query. You can add as many queries as you
  1500. * required by calling multiple times this method with different queries.
  1501. *
  1502. * By default, the UNION operator will remove duplicate rows, if you wish to include
  1503. * every row for all queries, use unionAll().
  1504. *
  1505. * ### Examples
  1506. *
  1507. * ```
  1508. * $union = (new Query($conn))->select(['id', 'title'])->from(['a' => 'articles']);
  1509. * $query->select(['id', 'name'])->from(['d' => 'things'])->union($union);
  1510. * ```
  1511. *
  1512. * Will produce:
  1513. *
  1514. * `SELECT id, name FROM things d UNION SELECT id, title FROM articles a`
  1515. *
  1516. * @param \Cake\Database\Query|string $query full SQL query to be used in UNION operator
  1517. * @param bool $overwrite whether to reset the list of queries to be operated or not
  1518. * @return $this
  1519. */
  1520. public function union(Query|string $query, bool $overwrite = false)
  1521. {
  1522. if ($overwrite) {
  1523. $this->_parts['union'] = [];
  1524. }
  1525. $this->_parts['union'][] = [
  1526. 'all' => false,
  1527. 'query' => $query,
  1528. ];
  1529. $this->_dirty();
  1530. return $this;
  1531. }
  1532. /**
  1533. * Adds a complete query to be used in conjunction with the UNION ALL operator with
  1534. * this query. This is used to combine the result set of this query with the one
  1535. * that will be returned by the passed query. You can add as many queries as you
  1536. * required by calling multiple times this method with different queries.
  1537. *
  1538. * Unlike UNION, UNION ALL will not remove duplicate rows.
  1539. *
  1540. * ```
  1541. * $union = (new Query($conn))->select(['id', 'title'])->from(['a' => 'articles']);
  1542. * $query->select(['id', 'name'])->from(['d' => 'things'])->unionAll($union);
  1543. * ```
  1544. *
  1545. * Will produce:
  1546. *
  1547. * `SELECT id, name FROM things d UNION ALL SELECT id, title FROM articles a`
  1548. *
  1549. * @param \Cake\Database\Query|string $query full SQL query to be used in UNION operator
  1550. * @param bool $overwrite whether to reset the list of queries to be operated or not
  1551. * @return $this
  1552. */
  1553. public function unionAll(Query|string $query, bool $overwrite = false)
  1554. {
  1555. if ($overwrite) {
  1556. $this->_parts['union'] = [];
  1557. }
  1558. $this->_parts['union'][] = [
  1559. 'all' => true,
  1560. 'query' => $query,
  1561. ];
  1562. $this->_dirty();
  1563. return $this;
  1564. }
  1565. /**
  1566. * Create an insert query.
  1567. *
  1568. * Note calling this method will reset any data previously set
  1569. * with Query::values().
  1570. *
  1571. * @param array $columns The columns to insert into.
  1572. * @param array<string, string> $types A map between columns & their datatypes.
  1573. * @return $this
  1574. * @throws \RuntimeException When there are 0 columns.
  1575. */
  1576. public function insert(array $columns, array $types = [])
  1577. {
  1578. if (empty($columns)) {
  1579. throw new RuntimeException('At least 1 column is required to perform an insert.');
  1580. }
  1581. $this->_dirty();
  1582. $this->_type = 'insert';
  1583. $this->_parts['insert'][1] = $columns;
  1584. if (!$this->_parts['values']) {
  1585. $this->_parts['values'] = new ValuesExpression($columns, $this->getTypeMap()->setTypes($types));
  1586. } else {
  1587. $this->_parts['values']->setColumns($columns);
  1588. }
  1589. return $this;
  1590. }
  1591. /**
  1592. * Set the table name for insert queries.
  1593. *
  1594. * @param string $table The table name to insert into.
  1595. * @return $this
  1596. */
  1597. public function into(string $table)
  1598. {
  1599. $this->_dirty();
  1600. $this->_type = 'insert';
  1601. $this->_parts['insert'][0] = $table;
  1602. return $this;
  1603. }
  1604. /**
  1605. * Creates an expression that refers to an identifier. Identifiers are used to refer to field names and allow
  1606. * the SQL compiler to apply quotes or escape the identifier.
  1607. *
  1608. * The value is used as is, and you might be required to use aliases or include the table reference in
  1609. * the identifier. Do not use this method to inject SQL methods or logical statements.
  1610. *
  1611. * ### Example
  1612. *
  1613. * ```
  1614. * $query->newExpr()->lte('count', $query->identifier('total'));
  1615. * ```
  1616. *
  1617. * @param string $identifier The identifier for an expression
  1618. * @return \Cake\Database\ExpressionInterface
  1619. */
  1620. public function identifier(string $identifier): ExpressionInterface
  1621. {
  1622. return new IdentifierExpression($identifier);
  1623. }
  1624. /**
  1625. * Set the values for an insert query.
  1626. *
  1627. * Multi inserts can be performed by calling values() more than one time,
  1628. * or by providing an array of value sets. Additionally $data can be a Query
  1629. * instance to insert data from another SELECT statement.
  1630. *
  1631. * @param \Cake\Database\Expression\ValuesExpression|\Cake\Database\Query|array $data The data to insert.
  1632. * @return $this
  1633. * @throws \Cake\Database\Exception\DatabaseException if you try to set values before declaring columns.
  1634. * Or if you try to set values on non-insert queries.
  1635. */
  1636. public function values(ValuesExpression|Query|array $data)
  1637. {
  1638. if ($this->_type !== 'insert') {
  1639. throw new DatabaseException(
  1640. 'You cannot add values before defining columns to use.'
  1641. );
  1642. }
  1643. if (empty($this->_parts['insert'])) {
  1644. throw new DatabaseException(
  1645. 'You cannot add values before defining columns to use.'
  1646. );
  1647. }
  1648. $this->_dirty();
  1649. if ($data instanceof ValuesExpression) {
  1650. $this->_parts['values'] = $data;
  1651. return $this;
  1652. }
  1653. $this->_parts['values']->add($data);
  1654. return $this;
  1655. }
  1656. /**
  1657. * Create an update query.
  1658. *
  1659. * Can be combined with set() and where() methods to create update queries.
  1660. *
  1661. * @param \Cake\Database\ExpressionInterface|string $table The table you want to update.
  1662. * @return $this
  1663. */
  1664. public function update(ExpressionInterface|string $table)
  1665. {
  1666. $this->_dirty();
  1667. $this->_type = 'update';
  1668. $this->_parts['update'][0] = $table;
  1669. return $this;
  1670. }
  1671. /**
  1672. * Set one or many fields to update.
  1673. *
  1674. * ### Examples
  1675. *
  1676. * Passing a string:
  1677. *
  1678. * ```
  1679. * $query->update('articles')->set('title', 'The Title');
  1680. * ```
  1681. *
  1682. * Passing an array:
  1683. *
  1684. * ```
  1685. * $query->update('articles')->set(['title' => 'The Title'], ['title' => 'string']);
  1686. * ```
  1687. *
  1688. * Passing a callable:
  1689. *
  1690. * ```
  1691. * $query->update('articles')->set(function ($exp) {
  1692. * return $exp->eq('title', 'The title', 'string');
  1693. * });
  1694. * ```
  1695. *
  1696. * @param \Cake\Database\Expression\QueryExpression|\Closure|array|string $key The column name or array of keys
  1697. * + values to set. This can also be a QueryExpression containing a SQL fragment.
  1698. * It can also be a Closure, that is required to return an expression object.
  1699. * @param mixed $value The value to update $key to. Can be null if $key is an
  1700. * array or QueryExpression. When $key is an array, this parameter will be
  1701. * used as $types instead.
  1702. * @param array<string, string>|string $types The column types to treat data as.
  1703. * @return $this
  1704. */
  1705. public function set(QueryExpression|Closure|array|string $key, mixed $value = null, array|string $types = [])
  1706. {
  1707. if (empty($this->_parts['set'])) {
  1708. $this->_parts['set'] = $this->newExpr()->setConjunction(',');
  1709. }
  1710. if ($key instanceof Closure) {
  1711. $exp = $this->newExpr()->setConjunction(',');
  1712. $this->_parts['set']->add($key($exp));
  1713. return $this;
  1714. }
  1715. if (is_array($key) || $key instanceof ExpressionInterface) {
  1716. $types = (array)$value;
  1717. $this->_parts['set']->add($key, $types);
  1718. return $this;
  1719. }
  1720. if (!is_string($types)) {
  1721. $types = null;
  1722. }
  1723. $this->_parts['set']->eq($key, $value, $types);
  1724. return $this;
  1725. }
  1726. /**
  1727. * Create a delete query.
  1728. *
  1729. * Can be combined with from(), where() and other methods to
  1730. * create delete queries with specific conditions.
  1731. *
  1732. * @param string|null $table The table to use when deleting.
  1733. * @return $this
  1734. */
  1735. public function delete(?string $table = null)
  1736. {
  1737. $this->_dirty();
  1738. $this->_type = 'delete';
  1739. if ($table !== null) {
  1740. $this->from($table);
  1741. }
  1742. return $this;
  1743. }
  1744. /**
  1745. * A string or expression that will be appended to the generated query
  1746. *
  1747. * ### Examples:
  1748. * ```
  1749. * $query->select('id')->where(['author_id' => 1])->epilog('FOR UPDATE');
  1750. * $query
  1751. * ->insert('articles', ['title'])
  1752. * ->values(['author_id' => 1])
  1753. * ->epilog('RETURNING id');
  1754. * ```
  1755. *
  1756. * Epliog content is raw SQL and not suitable for use with user supplied data.
  1757. *
  1758. * @param \Cake\Database\ExpressionInterface|string|null $expression The expression to be appended
  1759. * @return $this
  1760. */
  1761. public function epilog(ExpressionInterface|string|null $expression = null)
  1762. {
  1763. $this->_dirty();
  1764. $this->_parts['epilog'] = $expression;
  1765. return $this;
  1766. }
  1767. /**
  1768. * Returns the type of this query (select, insert, update, delete)
  1769. *
  1770. * @return string
  1771. */
  1772. public function type(): string
  1773. {
  1774. return $this->_type;
  1775. }
  1776. /**
  1777. * Returns a new QueryExpression object. This is a handy function when
  1778. * building complex queries using a fluent interface. You can also override
  1779. * this function in subclasses to use a more specialized QueryExpression class
  1780. * if required.
  1781. *
  1782. * You can optionally pass a single raw SQL string or an array or expressions in
  1783. * any format accepted by \Cake\Database\Expression\QueryExpression:
  1784. *
  1785. * ```
  1786. * $expression = $query->expr(); // Returns an empty expression object
  1787. * $expression = $query->expr('Table.column = Table2.column'); // Return a raw SQL expression
  1788. * ```
  1789. *
  1790. * @param \Cake\Database\ExpressionInterface|array|string|null $rawExpression A string, array or anything you want wrapped in an expression object
  1791. * @return \Cake\Database\Expression\QueryExpression
  1792. */
  1793. public function newExpr(ExpressionInterface|array|string|null $rawExpression = null): QueryExpression
  1794. {
  1795. return $this->expr($rawExpression);
  1796. }
  1797. /**
  1798. * Returns a new QueryExpression object. This is a handy function when
  1799. * building complex queries using a fluent interface. You can also override
  1800. * this function in subclasses to use a more specialized QueryExpression class
  1801. * if required.
  1802. *
  1803. * You can optionally pass a single raw SQL string or an array or expressions in
  1804. * any format accepted by \Cake\Database\Expression\QueryExpression:
  1805. *
  1806. * ```
  1807. * $expression = $query->expr(); // Returns an empty expression object
  1808. * $expression = $query->expr('Table.column = Table2.column'); // Return a raw SQL expression
  1809. * ```
  1810. *
  1811. * @param \Cake\Database\ExpressionInterface|array|string|null $rawExpression A string, array or anything you want wrapped in an expression object
  1812. * @return \Cake\Database\Expression\QueryExpression
  1813. */
  1814. public function expr(ExpressionInterface|array|string|null $rawExpression = null): QueryExpression
  1815. {
  1816. $expression = new QueryExpression([], $this->getTypeMap());
  1817. if ($rawExpression !== null) {
  1818. $expression->add($rawExpression);
  1819. }
  1820. return $expression;
  1821. }
  1822. /**
  1823. * Returns an instance of a functions builder object that can be used for
  1824. * generating arbitrary SQL functions.
  1825. *
  1826. * ### Example:
  1827. *
  1828. * ```
  1829. * $query->func()->count('*');
  1830. * $query->func()->dateDiff(['2012-01-05', '2012-01-02'])
  1831. * ```
  1832. *
  1833. * @return \Cake\Database\FunctionsBuilder
  1834. */
  1835. public function func(): FunctionsBuilder
  1836. {
  1837. if ($this->_functionsBuilder === null) {
  1838. $this->_functionsBuilder = new FunctionsBuilder();
  1839. }
  1840. return $this->_functionsBuilder;
  1841. }
  1842. /**
  1843. * Executes this query and returns a results iterator. This function is required
  1844. * for implementing the IteratorAggregate interface and allows the query to be
  1845. * iterated without having to call all() manually, thus making it look like
  1846. * a result set instead of the query itself.
  1847. *
  1848. * @return \Traversable
  1849. */
  1850. public function getIterator(): Traversable
  1851. {
  1852. $results = $this->all();
  1853. if (is_array($results)) {
  1854. return new ArrayIterator($results);
  1855. }
  1856. return $results;
  1857. }
  1858. /**
  1859. * Returns any data that was stored in the specified clause. This is useful for
  1860. * modifying any internal part of the query and it is used by the SQL dialects
  1861. * to transform the query accordingly before it is executed. The valid clauses that
  1862. * can be retrieved are: delete, update, set, insert, values, select, distinct,
  1863. * from, join, set, where, group, having, order, limit, offset and union.
  1864. *
  1865. * The return value for each of those parts may vary. Some clauses use QueryExpression
  1866. * to internally store their state, some use arrays and others may use booleans or
  1867. * integers. This is summary of the return types for each clause.
  1868. *
  1869. * - update: string The name of the table to update
  1870. * - set: QueryExpression
  1871. * - insert: array, will return an array containing the table + columns.
  1872. * - values: ValuesExpression
  1873. * - select: array, will return empty array when no fields are set
  1874. * - distinct: boolean
  1875. * - from: array of tables
  1876. * - join: array
  1877. * - set: array
  1878. * - where: QueryExpression, returns null when not set
  1879. * - group: array
  1880. * - having: QueryExpression, returns null when not set
  1881. * - order: OrderByExpression, returns null when not set
  1882. * - limit: integer or QueryExpression, null when not set
  1883. * - offset: integer or QueryExpression, null when not set
  1884. * - union: array
  1885. *
  1886. * @param string $name name of the clause to be returned
  1887. * @return mixed
  1888. * @throws \InvalidArgumentException When the named clause does not exist.
  1889. */
  1890. public function clause(string $name): mixed
  1891. {
  1892. if (!array_key_exists($name, $this->_parts)) {
  1893. $clauses = implode(', ', array_keys($this->_parts));
  1894. throw new InvalidArgumentException("The '$name' clause is not defined. Valid clauses are: $clauses");
  1895. }
  1896. return $this->_parts[$name];
  1897. }
  1898. /**
  1899. * Registers a callback to be executed for each result that is fetched from the
  1900. * result set, the callback function will receive as first parameter an array with
  1901. * the raw data from the database for every row that is fetched and must return the
  1902. * row with any possible modifications.
  1903. *
  1904. * Callbacks will be executed lazily, if only 3 rows are fetched for database it will
  1905. * called 3 times, event though there might be more rows to be fetched in the cursor.
  1906. *
  1907. * Callbacks are stacked in the order they are registered, if you wish to reset the stack
  1908. * the call this function with the second parameter set to true.
  1909. *
  1910. * If you wish to remove all decorators from the stack, set the first parameter
  1911. * to null and the second to true.
  1912. *
  1913. * ### Example
  1914. *
  1915. * ```
  1916. * $query->decorateResults(function ($row) {
  1917. * $row['order_total'] = $row['subtotal'] + ($row['subtotal'] * $row['tax']);
  1918. * return $row;
  1919. * });
  1920. * ```
  1921. *
  1922. * @param callable|null $callback The callback to invoke when results are fetched.
  1923. * @param bool $overwrite Whether this should append or replace all existing decorators.
  1924. * @return $this
  1925. */
  1926. public function decorateResults(?callable $callback, bool $overwrite = false)
  1927. {
  1928. $this->_dirty();
  1929. if ($overwrite) {
  1930. $this->_resultDecorators = [];
  1931. }
  1932. if ($callback !== null) {
  1933. $this->_resultDecorators[] = $callback;
  1934. }
  1935. return $this;
  1936. }
  1937. /**
  1938. * This function works similar to the traverse() function, with the difference
  1939. * that it does a full depth traversal of the entire expression tree. This will execute
  1940. * the provided callback function for each ExpressionInterface object that is
  1941. * stored inside this query at any nesting depth in any part of the query.
  1942. *
  1943. * Callback will receive as first parameter the currently visited expression.
  1944. *
  1945. * @param callable $callback the function to be executed for each ExpressionInterface
  1946. * found inside this query.
  1947. * @return $this
  1948. */
  1949. public function traverseExpressions(callable $callback)
  1950. {
  1951. if (!$callback instanceof Closure) {
  1952. $callback = Closure::fromCallable($callback);
  1953. }
  1954. foreach ($this->_parts as $part) {
  1955. $this->_expressionsVisitor($part, $callback);
  1956. }
  1957. return $this;
  1958. }
  1959. /**
  1960. * Query parts traversal method used by traverseExpressions()
  1961. *
  1962. * @param mixed $expression Query expression or
  1963. * array of expressions.
  1964. * @param \Closure $callback The callback to be executed for each ExpressionInterface
  1965. * found inside this query.
  1966. * @return void
  1967. */
  1968. protected function _expressionsVisitor(mixed $expression, Closure $callback): void
  1969. {
  1970. if (is_array($expression)) {
  1971. foreach ($expression as $e) {
  1972. $this->_expressionsVisitor($e, $callback);
  1973. }
  1974. return;
  1975. }
  1976. if ($expression instanceof ExpressionInterface) {
  1977. $expression->traverse(function ($exp) use ($callback): void {
  1978. $this->_expressionsVisitor($exp, $callback);
  1979. });
  1980. if (!$expression instanceof self) {
  1981. $callback($expression);
  1982. }
  1983. }
  1984. }
  1985. /**
  1986. * Associates a query placeholder to a value and a type.
  1987. *
  1988. * ```
  1989. * $query->bind(':id', 1, 'integer');
  1990. * ```
  1991. *
  1992. * @param string|int $param placeholder to be replaced with quoted version
  1993. * of $value
  1994. * @param mixed $value The value to be bound
  1995. * @param string|int|null $type the mapped type name, used for casting when sending
  1996. * to database
  1997. * @return $this
  1998. */
  1999. public function bind(string|int $param, mixed $value, string|int|null $type = null)
  2000. {
  2001. $this->getValueBinder()->bind($param, $value, $type);
  2002. return $this;
  2003. }
  2004. /**
  2005. * Returns the currently used ValueBinder instance.
  2006. *
  2007. * A ValueBinder is responsible for generating query placeholders and temporarily
  2008. * associate values to those placeholders so that they can be passed correctly
  2009. * to the statement object.
  2010. *
  2011. * @return \Cake\Database\ValueBinder
  2012. */
  2013. public function getValueBinder(): ValueBinder
  2014. {
  2015. if ($this->_valueBinder === null) {
  2016. $this->_valueBinder = new ValueBinder();
  2017. }
  2018. return $this->_valueBinder;
  2019. }
  2020. /**
  2021. * Overwrite the current value binder
  2022. *
  2023. * A ValueBinder is responsible for generating query placeholders and temporarily
  2024. * associate values to those placeholders so that they can be passed correctly
  2025. * to the statement object.
  2026. *
  2027. * @param \Cake\Database\ValueBinder|null $binder The binder or null to disable binding.
  2028. * @return $this
  2029. */
  2030. public function setValueBinder(?ValueBinder $binder)
  2031. {
  2032. $this->_valueBinder = $binder;
  2033. return $this;
  2034. }
  2035. /**
  2036. * Sets the TypeMap class where the types for each of the fields in the
  2037. * select clause are stored.
  2038. *
  2039. * @param \Cake\Database\TypeMap $typeMap The map object to use
  2040. * @return $this
  2041. */
  2042. public function setSelectTypeMap(TypeMap $typeMap)
  2043. {
  2044. $this->_selectTypeMap = $typeMap;
  2045. $this->_dirty();
  2046. return $this;
  2047. }
  2048. /**
  2049. * Gets the TypeMap class where the types for each of the fields in the
  2050. * select clause are stored.
  2051. *
  2052. * @return \Cake\Database\TypeMap
  2053. */
  2054. public function getSelectTypeMap(): TypeMap
  2055. {
  2056. if ($this->_selectTypeMap === null) {
  2057. $this->_selectTypeMap = new TypeMap();
  2058. }
  2059. return $this->_selectTypeMap;
  2060. }
  2061. /**
  2062. * Disables result casting.
  2063. *
  2064. * When disabled, the fields will be returned as received from the database
  2065. * driver (which in most environments means they are being returned as
  2066. * strings), which can improve performance with larger datasets.
  2067. *
  2068. * @return $this
  2069. */
  2070. public function disableResultsCasting()
  2071. {
  2072. $this->typeCastEnabled = false;
  2073. return $this;
  2074. }
  2075. /**
  2076. * Enables result casting.
  2077. *
  2078. * When enabled, the fields in the results returned by this Query will be
  2079. * cast to their corresponding PHP data type.
  2080. *
  2081. * @return $this
  2082. */
  2083. public function enableResultsCasting()
  2084. {
  2085. $this->typeCastEnabled = true;
  2086. return $this;
  2087. }
  2088. /**
  2089. * Returns whether result casting is enabled/disabled.
  2090. *
  2091. * When enabled, the fields in the results returned by this Query will be
  2092. * casted to their corresponding PHP data type.
  2093. *
  2094. * When disabled, the fields will be returned as received from the database
  2095. * driver (which in most environments means they are being returned as
  2096. * strings), which can improve performance with larger datasets.
  2097. *
  2098. * @return bool
  2099. */
  2100. public function isResultsCastingEnabled(): bool
  2101. {
  2102. return $this->typeCastEnabled;
  2103. }
  2104. /**
  2105. * Helper function used to build conditions by composing QueryExpression objects.
  2106. *
  2107. * @param string $part Name of the query part to append the new part to
  2108. * @param \Cake\Database\ExpressionInterface|\Closure|array|string|null $append Expression or builder function to append.
  2109. * to append.
  2110. * @param string $conjunction type of conjunction to be used to operate part
  2111. * @param array<string, string> $types Associative array of type names used to bind values to query
  2112. * @return void
  2113. */
  2114. protected function _conjugate(
  2115. string $part,
  2116. ExpressionInterface|Closure|array|string|null $append,
  2117. string $conjunction,
  2118. array $types
  2119. ): void {
  2120. $expression = $this->_parts[$part] ?: $this->newExpr();
  2121. if (empty($append)) {
  2122. $this->_parts[$part] = $expression;
  2123. return;
  2124. }
  2125. if ($append instanceof Closure) {
  2126. $append = $append($this->newExpr(), $this);
  2127. }
  2128. if ($expression->getConjunction() === $conjunction) {
  2129. $expression->add($append, $types);
  2130. } else {
  2131. $expression = $this->newExpr()
  2132. ->setConjunction($conjunction)
  2133. ->add([$expression, $append], $types);
  2134. }
  2135. $this->_parts[$part] = $expression;
  2136. $this->_dirty();
  2137. }
  2138. /**
  2139. * Marks a query as dirty, removing any preprocessed information
  2140. * from in memory caching.
  2141. *
  2142. * @return void
  2143. */
  2144. protected function _dirty(): void
  2145. {
  2146. $this->_dirty = true;
  2147. if ($this->_statement && $this->_valueBinder) {
  2148. $this->getValueBinder()->reset();
  2149. }
  2150. }
  2151. /**
  2152. * Handles clearing iterator and cloning all expressions and value binders.
  2153. *
  2154. * @return void
  2155. */
  2156. public function __clone()
  2157. {
  2158. $this->_statement = null;
  2159. $this->_results = null;
  2160. if ($this->_valueBinder !== null) {
  2161. $this->_valueBinder = clone $this->_valueBinder;
  2162. }
  2163. if ($this->_selectTypeMap !== null) {
  2164. $this->_selectTypeMap = clone $this->_selectTypeMap;
  2165. }
  2166. foreach ($this->_parts as $name => $part) {
  2167. if (empty($part)) {
  2168. continue;
  2169. }
  2170. if (is_array($part)) {
  2171. foreach ($part as $i => $piece) {
  2172. if (is_array($piece)) {
  2173. foreach ($piece as $j => $value) {
  2174. if ($value instanceof ExpressionInterface) {
  2175. /** @psalm-suppress PossiblyUndefinedMethod */
  2176. $this->_parts[$name][$i][$j] = clone $value;
  2177. }
  2178. }
  2179. } elseif ($piece instanceof ExpressionInterface) {
  2180. /** @psalm-suppress PossiblyUndefinedMethod */
  2181. $this->_parts[$name][$i] = clone $piece;
  2182. }
  2183. }
  2184. }
  2185. if ($part instanceof ExpressionInterface) {
  2186. $this->_parts[$name] = clone $part;
  2187. }
  2188. }
  2189. }
  2190. /**
  2191. * Returns string representation of this query (complete SQL statement).
  2192. *
  2193. * @return string
  2194. */
  2195. public function __toString(): string
  2196. {
  2197. return $this->sql();
  2198. }
  2199. /**
  2200. * Returns an array that can be used to describe the internal state of this
  2201. * object.
  2202. *
  2203. * @return array<string, mixed>
  2204. */
  2205. public function __debugInfo(): array
  2206. {
  2207. try {
  2208. set_error_handler(
  2209. /** @return no-return */
  2210. function ($errno, $errstr): void {
  2211. throw new RuntimeException($errstr, $errno);
  2212. },
  2213. E_ALL
  2214. );
  2215. $sql = $this->sql();
  2216. $params = $this->getValueBinder()->bindings();
  2217. } catch (RuntimeException) {
  2218. $sql = 'SQL could not be generated for this query as it is incomplete.';
  2219. $params = [];
  2220. } finally {
  2221. restore_error_handler();
  2222. }
  2223. return [
  2224. '(help)' => 'This is a Query object, to get the results execute or iterate it.',
  2225. 'sql' => $sql,
  2226. 'params' => $params,
  2227. 'defaultTypes' => $this->getDefaultTypes(),
  2228. 'decorators' => count($this->_resultDecorators),
  2229. 'executed' => $this->_statement ? true : false,
  2230. ];
  2231. }
  2232. }