Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like Query often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Query, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
31 | class Query implements ExpressionInterface, IteratorAggregate |
||
32 | { |
||
33 | |||
34 | use TypeMapTrait; |
||
35 | |||
36 | /** |
||
37 | * Connection instance to be used to execute this query. |
||
38 | * |
||
39 | * @var \Cake\Datasource\ConnectionInterface |
||
40 | */ |
||
41 | protected $_connection; |
||
42 | |||
43 | /** |
||
44 | * Type of this query (select, insert, update, delete). |
||
45 | * |
||
46 | * @var string |
||
47 | */ |
||
48 | protected $_type = 'select'; |
||
49 | |||
50 | /** |
||
51 | * List of SQL parts that will be used to build this query. |
||
52 | * |
||
53 | * @var array |
||
54 | */ |
||
55 | protected $_parts = [ |
||
56 | 'delete' => true, |
||
57 | 'update' => [], |
||
58 | 'set' => [], |
||
59 | 'insert' => [], |
||
60 | 'values' => [], |
||
61 | 'select' => [], |
||
62 | 'distinct' => false, |
||
63 | 'modifier' => [], |
||
64 | 'from' => [], |
||
65 | 'join' => [], |
||
66 | 'where' => null, |
||
67 | 'group' => [], |
||
68 | 'having' => null, |
||
69 | 'order' => null, |
||
70 | 'limit' => null, |
||
71 | 'offset' => null, |
||
72 | 'union' => [], |
||
73 | 'epilog' => null |
||
74 | ]; |
||
75 | |||
76 | /** |
||
77 | * Indicates whether internal state of this query was changed, this is used to |
||
78 | * discard internal cached objects such as the transformed query or the reference |
||
79 | * to the executed statement. |
||
80 | * |
||
81 | * @var bool |
||
82 | */ |
||
83 | protected $_dirty = false; |
||
84 | |||
85 | /** |
||
86 | * A list of callback functions to be called to alter each row from resulting |
||
87 | * statement upon retrieval. Each one of the callback function will receive |
||
88 | * the row array as first argument. |
||
89 | * |
||
90 | * @var array |
||
91 | */ |
||
92 | protected $_resultDecorators = []; |
||
93 | |||
94 | /** |
||
95 | * Statement object resulting from executing this query. |
||
96 | * |
||
97 | * @var \Cake\Database\StatementInterface |
||
98 | */ |
||
99 | protected $_iterator; |
||
100 | |||
101 | /** |
||
102 | * The object responsible for generating query placeholders and temporarily store values |
||
103 | * associated to each of those. |
||
104 | * |
||
105 | * @var ValueBinder |
||
106 | */ |
||
107 | protected $_valueBinder; |
||
108 | |||
109 | /** |
||
110 | * Instance of functions builder object used for generating arbitrary SQL functions. |
||
111 | * |
||
112 | * @var FunctionsBuilder |
||
113 | */ |
||
114 | protected $_functionsBuilder; |
||
115 | |||
116 | /** |
||
117 | * Boolean for tracking whether or not buffered results |
||
118 | * are enabled. |
||
119 | * |
||
120 | * @var bool |
||
121 | */ |
||
122 | protected $_useBufferedResults = true; |
||
123 | |||
124 | /** |
||
125 | * Constructor. |
||
126 | * |
||
127 | * @param \Cake\Datasource\ConnectionInterface $connection The connection |
||
128 | * object to be used for transforming and executing this query |
||
129 | */ |
||
130 | public function __construct($connection) |
||
134 | |||
135 | /** |
||
136 | * Sets the connection instance to be used for executing and transforming this query |
||
137 | * When called with a null argument, it will return the current connection instance. |
||
138 | * |
||
139 | * @param \Cake\Datasource\ConnectionInterface $connection instance |
||
140 | * @return $this|\Cake\Datasource\ConnectionInterface |
||
141 | */ |
||
142 | public function connection($connection = null) |
||
143 | { |
||
144 | if ($connection === null) { |
||
145 | return $this->_connection; |
||
146 | } |
||
147 | $this->_dirty(); |
||
148 | $this->_connection = $connection; |
||
149 | return $this; |
||
150 | } |
||
151 | |||
152 | /** |
||
153 | * Compiles the SQL representation of this query and executes it using the |
||
154 | * configured connection object. Returns the resulting statement object. |
||
155 | * |
||
156 | * Executing a query internally executes several steps, the first one is |
||
157 | * letting the connection transform this object to fit its particular dialect, |
||
158 | * this might result in generating a different Query object that will be the one |
||
159 | * to actually be executed. Immediately after, literal values are passed to the |
||
160 | * connection so they are bound to the query in a safe way. Finally, the resulting |
||
161 | * statement is decorated with custom objects to execute callbacks for each row |
||
162 | * retrieved if necessary. |
||
163 | * |
||
164 | * Resulting statement is traversable, so it can be used in any loop as you would |
||
165 | * with an array. |
||
166 | * |
||
167 | * This method can be overridden in query subclasses to decorate behavior |
||
168 | * around query execution. |
||
169 | * |
||
170 | * @return \Cake\Database\StatementInterface |
||
171 | */ |
||
172 | public function execute() |
||
173 | { |
||
174 | $statement = $this->_connection->run($this); |
||
175 | $this->_iterator = $this->_decorateStatement($statement); |
||
176 | $this->_dirty = false; |
||
177 | return $this->_iterator; |
||
178 | } |
||
179 | |||
180 | /** |
||
181 | * Returns the SQL representation of this object. |
||
182 | * |
||
183 | * This function will compile this query to make it compatible |
||
184 | * with the SQL dialect that is used by the connection, This process might |
||
185 | * add, remove or alter any query part or internal expression to make it |
||
186 | * executable in the target platform. |
||
187 | * |
||
188 | * The resulting query may have placeholders that will be replaced with the actual |
||
189 | * values when the query is executed, hence it is most suitable to use with |
||
190 | * prepared statements. |
||
191 | * |
||
192 | * @param \Cake\Database\ValueBinder $generator A placeholder object that will hold |
||
193 | * associated values for expressions |
||
194 | * @return string |
||
195 | */ |
||
196 | public function sql(ValueBinder $generator = null) |
||
197 | { |
||
198 | if (!$generator) { |
||
199 | $generator = $this->valueBinder(); |
||
200 | $generator->resetCount(); |
||
|
|||
201 | } |
||
202 | |||
203 | return $this->connection()->compileQuery($this, $generator); |
||
204 | } |
||
205 | |||
206 | /** |
||
207 | * Will iterate over every specified part. Traversing functions can aggregate |
||
208 | * results using variables in the closure or instance variables. This function |
||
209 | * is commonly used as a way for traversing all query parts that |
||
210 | * are going to be used for constructing a query. |
||
211 | * |
||
212 | * The callback will receive 2 parameters, the first one is the value of the query |
||
213 | * part that is being iterated and the second the name of such part. |
||
214 | * |
||
215 | * ### Example: |
||
216 | * ``` |
||
217 | * $query->select(['title'])->from('articles')->traverse(function ($value, $clause) { |
||
218 | * if ($clause === 'select') { |
||
219 | * var_dump($value); |
||
220 | * } |
||
221 | * }, ['select', 'from']); |
||
222 | * ``` |
||
223 | * |
||
224 | * @param callable $visitor a function or callable to be executed for each part |
||
225 | * @param array $parts the query clauses to traverse |
||
226 | * @return $this |
||
227 | */ |
||
228 | public function traverse(callable $visitor, array $parts = []) |
||
229 | { |
||
230 | $parts = $parts ?: array_keys($this->_parts); |
||
231 | foreach ($parts as $name) { |
||
232 | $visitor($this->_parts[$name], $name); |
||
233 | } |
||
234 | return $this; |
||
235 | } |
||
236 | |||
237 | /** |
||
238 | * Adds new fields to be returned by a SELECT statement when this query is |
||
239 | * executed. Fields can be passed as an array of strings, array of expression |
||
240 | * objects, a single expression or a single string. |
||
241 | * |
||
242 | * If an array is passed, keys will be used to alias fields using the value as the |
||
243 | * real field to be aliased. It is possible to alias strings, Expression objects or |
||
244 | * even other Query objects. |
||
245 | * |
||
246 | * If a callable function is passed, the returning array of the function will |
||
247 | * be used as the list of fields. |
||
248 | * |
||
249 | * By default this function will append any passed argument to the list of fields |
||
250 | * to be selected, unless the second argument is set to true. |
||
251 | * |
||
252 | * ### Examples: |
||
253 | * |
||
254 | * ``` |
||
255 | * $query->select(['id', 'title']); // Produces SELECT id, title |
||
256 | * $query->select(['author' => 'author_id']); // Appends author: SELECT id, title, author_id as author |
||
257 | * $query->select('id', true); // Resets the list: SELECT id |
||
258 | * $query->select(['total' => $countQuery]); // SELECT id, (SELECT ...) AS total |
||
259 | * $query->select(function ($query) { |
||
260 | * return ['article_id', 'total' => $query->count('*')]; |
||
261 | * }) |
||
262 | * ``` |
||
263 | * |
||
264 | * By default no fields are selected, if you have an instance of `Cake\ORM\Query` and try to append |
||
265 | * fields you should also call `Cake\ORM\Query::autoFields()` to select the default fields |
||
266 | * from the table. |
||
267 | * |
||
268 | * @param array|ExpressionInterface|string|callable $fields fields to be added to the list. |
||
269 | * @param bool $overwrite whether to reset fields with passed list or not |
||
270 | * @return $this |
||
271 | */ |
||
272 | public function select($fields = [], $overwrite = false) |
||
273 | { |
||
274 | if (!is_string($fields) && is_callable($fields)) { |
||
275 | $fields = $fields($this); |
||
276 | } |
||
277 | |||
278 | if (!is_array($fields)) { |
||
279 | $fields = [$fields]; |
||
280 | } |
||
281 | |||
282 | View Code Duplication | if ($overwrite) { |
|
283 | $this->_parts['select'] = $fields; |
||
284 | } else { |
||
285 | $this->_parts['select'] = array_merge($this->_parts['select'], $fields); |
||
286 | } |
||
287 | |||
288 | $this->_dirty(); |
||
289 | $this->_type = 'select'; |
||
290 | return $this; |
||
291 | } |
||
292 | |||
293 | /** |
||
294 | * Adds a DISTINCT clause to the query to remove duplicates from the result set. |
||
295 | * This clause can only be used for select statements. |
||
296 | * |
||
297 | * If you wish to filter duplicates based of those rows sharing a particular field |
||
298 | * or set of fields, you may pass an array of fields to filter on. Beware that |
||
299 | * this option might not be fully supported in all database systems. |
||
300 | * |
||
301 | * ### Examples: |
||
302 | * |
||
303 | * ``` |
||
304 | * // Filters products with the same name and city |
||
305 | * $query->select(['name', 'city'])->from('products')->distinct(); |
||
306 | * |
||
307 | * // Filters products in the same city |
||
308 | * $query->distinct(['city']); |
||
309 | * $query->distinct('city'); |
||
310 | * |
||
311 | * // Filter products with the same name |
||
312 | * $query->distinct(['name'], true); |
||
313 | * $query->distinct('name', true); |
||
314 | * ``` |
||
315 | * |
||
316 | * @param array|ExpressionInterface|string|bool $on Enable/disable distinct class |
||
317 | * or list of fields to be filtered on |
||
318 | * @param bool $overwrite whether to reset fields with passed list or not |
||
319 | * @return $this |
||
320 | */ |
||
321 | public function distinct($on = [], $overwrite = false) |
||
322 | { |
||
323 | if ($on === []) { |
||
324 | $on = true; |
||
325 | } elseif (is_string($on)) { |
||
326 | $on = [$on]; |
||
327 | } |
||
328 | |||
329 | if (is_array($on)) { |
||
330 | $merge = []; |
||
331 | if (is_array($this->_parts['distinct'])) { |
||
332 | $merge = $this->_parts['distinct']; |
||
333 | } |
||
334 | $on = ($overwrite) ? array_values($on) : array_merge($merge, array_values($on)); |
||
335 | } |
||
336 | |||
337 | $this->_parts['distinct'] = $on; |
||
338 | $this->_dirty(); |
||
339 | return $this; |
||
340 | } |
||
341 | |||
342 | /** |
||
343 | * Adds a single or multiple SELECT modifiers to be used in the SELECT. |
||
344 | * |
||
345 | * By default this function will append any passed argument to the list of modifiers |
||
346 | * to be applied, unless the second argument is set to true. |
||
347 | * |
||
348 | * ### Example: |
||
349 | * |
||
350 | * ``` |
||
351 | * // Ignore cache query in MySQL |
||
352 | * $query->select(['name', 'city'])->from('products')->modifier('SQL_NO_CACHE'); |
||
353 | * // It will produce the SQL: SELECT SQL_NO_CACHE name, city FROM products |
||
354 | * |
||
355 | * // Or with multiple modifiers |
||
356 | * $query->select(['name', 'city'])->from('products')->modifier(['HIGH_PRIORITY', 'SQL_NO_CACHE']); |
||
357 | * // It will produce the SQL: SELECT HIGH_PRIORITY SQL_NO_CACHE name, city FROM products |
||
358 | * ``` |
||
359 | * |
||
360 | * @param array|ExpressionInterface|string $modifiers modifiers to be applied to the query |
||
361 | * @param bool $overwrite whether to reset order with field list or not |
||
362 | * @return $this |
||
363 | */ |
||
364 | public function modifier($modifiers, $overwrite = false) |
||
365 | { |
||
366 | $this->_dirty(); |
||
367 | if ($overwrite) { |
||
368 | $this->_parts['modifier'] = []; |
||
369 | } |
||
370 | $this->_parts['modifier'] = array_merge($this->_parts['modifier'], (array)$modifiers); |
||
371 | return $this; |
||
372 | } |
||
373 | |||
374 | /** |
||
375 | * Adds a single or multiple tables to be used in the FROM clause for this query. |
||
376 | * Tables can be passed as an array of strings, array of expression |
||
377 | * objects, a single expression or a single string. |
||
378 | * |
||
379 | * If an array is passed, keys will be used to alias tables using the value as the |
||
380 | * real field to be aliased. It is possible to alias strings, ExpressionInterface objects or |
||
381 | * even other Query objects. |
||
382 | * |
||
383 | * By default this function will append any passed argument to the list of tables |
||
384 | * to be selected from, unless the second argument is set to true. |
||
385 | * |
||
386 | * This method can be used for select, update and delete statements. |
||
387 | * |
||
388 | * ### Examples: |
||
389 | * |
||
390 | * ``` |
||
391 | * $query->from(['p' => 'posts']); // Produces FROM posts p |
||
392 | * $query->from('authors'); // Appends authors: FROM posts p, authors |
||
393 | * $query->select(['products'], true); // Resets the list: FROM products |
||
394 | * $query->select(['sub' => $countQuery]); // FROM (SELECT ...) sub |
||
395 | * ``` |
||
396 | * |
||
397 | * @param array|ExpressionInterface|string $tables tables to be added to the list |
||
398 | * @param bool $overwrite whether to reset tables with passed list or not |
||
399 | * @return $this |
||
400 | */ |
||
401 | public function from($tables = [], $overwrite = false) |
||
420 | |||
421 | /** |
||
422 | * Adds a single or multiple tables to be used as JOIN clauses to this query. |
||
423 | * Tables can be passed as an array of strings, an array describing the |
||
424 | * join parts, an array with multiple join descriptions, or a single string. |
||
425 | * |
||
426 | * By default this function will append any passed argument to the list of tables |
||
427 | * to be joined, unless the third argument is set to true. |
||
428 | * |
||
429 | * When no join type is specified an INNER JOIN is used by default: |
||
430 | * `$query->join(['authors'])` will produce `INNER JOIN authors ON 1 = 1` |
||
431 | * |
||
432 | * It is also possible to alias joins using the array key: |
||
433 | * `$query->join(['a' => 'authors'])`` will produce `INNER JOIN authors a ON 1 = 1` |
||
434 | * |
||
435 | * A join can be fully described and aliased using the array notation: |
||
436 | * |
||
437 | * ``` |
||
438 | * $query->join([ |
||
439 | * 'a' => [ |
||
440 | * 'table' => 'authors', |
||
441 | * 'type' => 'LEFT', |
||
442 | * 'conditions' => 'a.id = b.author_id' |
||
443 | * ] |
||
444 | * ]); |
||
445 | * // Produces LEFT JOIN authors a ON a.id = b.author_id |
||
446 | * ``` |
||
447 | * |
||
448 | * You can even specify multiple joins in an array, including the full description: |
||
449 | * |
||
450 | * ``` |
||
451 | * $query->join([ |
||
452 | * 'a' => [ |
||
453 | * 'table' => 'authors', |
||
454 | * 'type' => 'LEFT', |
||
455 | * 'conditions' => 'a.id = b.author_id' |
||
456 | * ], |
||
457 | * 'p' => [ |
||
458 | * 'table' => 'publishers', |
||
459 | * 'type' => 'INNER', |
||
460 | * 'conditions' => 'p.id = b.publisher_id AND p.name = "Cake Software Foundation"' |
||
461 | * ] |
||
462 | * ]); |
||
463 | * // LEFT JOIN authors a ON a.id = b.author_id |
||
464 | * // INNER JOIN publishers p ON p.id = b.publisher_id AND p.name = "Cake Software Foundation" |
||
465 | * ``` |
||
466 | * |
||
467 | * ### Using conditions and types |
||
468 | * |
||
469 | * Conditions can be expressed, as in the examples above, using a string for comparing |
||
470 | * columns, or string with already quoted literal values. Additionally it is |
||
471 | * possible to use conditions expressed in arrays or expression objects. |
||
472 | * |
||
473 | * When using arrays for expressing conditions, it is often desirable to convert |
||
474 | * the literal values to the correct database representation. This is achieved |
||
475 | * using the second parameter of this function. |
||
476 | * |
||
477 | * ``` |
||
478 | * $query->join(['a' => [ |
||
479 | * 'table' => 'articles', |
||
480 | * 'conditions' => [ |
||
481 | * 'a.posted >=' => new DateTime('-3 days'), |
||
482 | * 'a.published' => true, |
||
483 | * 'a.author_id = authors.id' |
||
484 | * ] |
||
485 | * ]], ['a.posted' => 'datetime', 'a.published' => 'boolean']) |
||
486 | * ``` |
||
487 | * |
||
488 | * ### Overwriting joins |
||
489 | * |
||
490 | * When creating aliased joins using the array notation, you can override |
||
491 | * previous join definitions by using the same alias in consequent |
||
492 | * calls to this function or you can replace all previously defined joins |
||
493 | * with another list if the third parameter for this function is set to true. |
||
494 | * |
||
495 | * ``` |
||
496 | * $query->join(['alias' => 'table']); // joins table with as alias |
||
497 | * $query->join(['alias' => 'another_table']); // joins another_table with as alias |
||
498 | * $query->join(['something' => 'different_table'], [], true); // resets joins list |
||
499 | * ``` |
||
500 | * |
||
501 | * @param array|string|null $tables list of tables to be joined in the query |
||
502 | * @param array $types associative array of type names used to bind values to query |
||
503 | * @param bool $overwrite whether to reset joins with passed list or not |
||
504 | * @see \Cake\Database\Type |
||
505 | * @return $this |
||
506 | */ |
||
507 | public function join($tables = null, $types = [], $overwrite = false) |
||
508 | { |
||
509 | if ($tables === null) { |
||
510 | return $this->_parts['join']; |
||
511 | } |
||
512 | |||
513 | if (is_string($tables) || isset($tables['table'])) { |
||
514 | $tables = [$tables]; |
||
515 | } |
||
516 | |||
517 | $joins = []; |
||
518 | $i = count($this->_parts['join']); |
||
519 | foreach ($tables as $alias => $t) { |
||
520 | if (!is_array($t)) { |
||
521 | $t = ['table' => $t, 'conditions' => $this->newExpr()]; |
||
522 | } |
||
523 | |||
524 | if (!is_string($t['conditions']) && is_callable($t['conditions'])) { |
||
525 | $t['conditions'] = $t['conditions']($this->newExpr(), $this); |
||
526 | } |
||
527 | |||
528 | if (!($t['conditions'] instanceof ExpressionInterface)) { |
||
529 | $t['conditions'] = $this->newExpr()->add($t['conditions'], $types); |
||
530 | } |
||
531 | $alias = is_string($alias) ? $alias : null; |
||
532 | $joins[$alias ?: $i++] = $t + ['type' => 'INNER', 'alias' => $alias]; |
||
533 | } |
||
534 | |||
535 | View Code Duplication | if ($overwrite) { |
|
536 | $this->_parts['join'] = $joins; |
||
537 | } else { |
||
538 | $this->_parts['join'] = array_merge($this->_parts['join'], $joins); |
||
539 | } |
||
540 | |||
541 | $this->_dirty(); |
||
542 | return $this; |
||
543 | } |
||
544 | |||
545 | /** |
||
546 | * Remove a join if it has been defined. |
||
547 | * |
||
548 | * Useful when you are redefining joins or want to re-order |
||
549 | * the join clauses. |
||
550 | * |
||
551 | * @param string $name The alias/name of the join to remove. |
||
552 | * @return $this |
||
553 | */ |
||
554 | public function removeJoin($name) |
||
555 | { |
||
556 | unset($this->_parts['join'][$name]); |
||
557 | $this->_dirty(); |
||
558 | return $this; |
||
559 | } |
||
560 | |||
561 | /** |
||
562 | * Adds a single LEFT JOIN clause to the query. |
||
563 | * |
||
564 | * This is a shorthand method for building joins via `join()`. |
||
565 | * |
||
566 | * The table name can be passed as a string, or as an array in case it needs to |
||
567 | * be aliased: |
||
568 | * |
||
569 | * ``` |
||
570 | * // LEFT JOIN authors ON authors.id = posts.author_id |
||
571 | * $query->leftJoin('authors', 'authors.id = posts.author_id'); |
||
572 | * |
||
573 | * // LEFT JOIN authors a ON a.id = posts.author_id |
||
574 | * $query->leftJoin(['a' => 'authors'], 'a.id = posts.author_id'); |
||
575 | * ``` |
||
576 | * |
||
577 | * Conditions can be passed as strings, arrays, or expression objects. When |
||
578 | * using arrays it is possible to combine them with the `$types` parameter |
||
579 | * in order to define how to convert the values: |
||
580 | * |
||
581 | * ``` |
||
582 | * $query->leftJoin(['a' => 'articles'], [ |
||
583 | * 'a.posted >=' => new DateTime('-3 days'), |
||
584 | * 'a.published' => true, |
||
585 | * 'a.author_id = authors.id' |
||
586 | * ], ['a.posted' => 'datetime', 'a.published' => 'boolean']); |
||
587 | * ``` |
||
588 | * |
||
589 | * See `join()` for further details on conditions and types. |
||
590 | * |
||
591 | * @param string|array $table The table to join with |
||
592 | * @param string|array|\Cake\Database\ExpressionInterface $conditions The conditions |
||
593 | * to use for joining. |
||
594 | * @param array $types a list of types associated to the conditions used for converting |
||
595 | * values to the corresponding database representation. |
||
596 | * @return $this |
||
597 | */ |
||
598 | public function leftJoin($table, $conditions = [], $types = []) |
||
602 | |||
603 | /** |
||
604 | * Adds a single RIGHT JOIN clause to the query. |
||
605 | * |
||
606 | * This is a shorthand method for building joins via `join()`. |
||
607 | * |
||
608 | * The arguments of this method are identical to the `leftJoin()` shorthand, please refer |
||
609 | * to that methods description for further details. |
||
610 | * |
||
611 | * @param string|array $table The table to join with |
||
612 | * @param string|array|\Cake\Database\ExpressionInterface $conditions The conditions |
||
613 | * to use for joining. |
||
614 | * @param array $types a list of types associated to the conditions used for converting |
||
615 | * values to the corresponding database representation. |
||
616 | * @return $this |
||
617 | */ |
||
618 | public function rightJoin($table, $conditions = [], $types = []) |
||
622 | |||
623 | /** |
||
624 | * Adds a single INNER JOIN clause to the query. |
||
625 | * |
||
626 | * This is a shorthand method for building joins via `join()`. |
||
627 | * |
||
628 | * The arguments of this method are identical to the `leftJoin()` shorthand, please refer |
||
629 | * to that methods description for further details. |
||
630 | * |
||
631 | * @param string|array $table The table to join with |
||
632 | * @param string|array|\Cake\Database\ExpressionInterface $conditions The conditions |
||
633 | * to use for joining. |
||
634 | * @param array $types a list of types associated to the conditions used for converting |
||
635 | * values to the corresponding database representation. |
||
636 | * @return $this |
||
637 | */ |
||
638 | public function innerJoin($table, $conditions = [], $types = []) |
||
642 | |||
643 | /** |
||
644 | * Returns an array that can be passed to the join method describing a single join clause |
||
645 | * |
||
646 | * @param string|array $table The table to join with |
||
647 | * @param string|array|\Cake\Database\ExpressionInterface $conditions The conditions |
||
648 | * to use for joining. |
||
649 | * @param string $type the join type to use |
||
650 | * @return array |
||
651 | */ |
||
652 | protected function _makeJoin($table, $conditions, $type) |
||
653 | { |
||
654 | $alias = $table; |
||
655 | |||
656 | if (is_array($table)) { |
||
657 | $alias = key($table); |
||
658 | $table = current($table); |
||
659 | } |
||
660 | |||
661 | return [ |
||
662 | $alias => [ |
||
663 | 'table' => $table, |
||
664 | 'conditions' => $conditions, |
||
665 | 'type' => $type |
||
666 | ] |
||
667 | ]; |
||
668 | } |
||
669 | |||
670 | /** |
||
671 | * Adds a condition or set of conditions to be used in the WHERE clause for this |
||
672 | * query. Conditions can be expressed as an array of fields as keys with |
||
673 | * comparison operators in it, the values for the array will be used for comparing |
||
674 | * the field to such literal. Finally, conditions can be expressed as a single |
||
675 | * string or an array of strings. |
||
676 | * |
||
677 | * When using arrays, each entry will be joined to the rest of the conditions using |
||
678 | * an AND operator. Consecutive calls to this function will also join the new |
||
679 | * conditions specified using the AND operator. Additionally, values can be |
||
680 | * expressed using expression objects which can include other query objects. |
||
681 | * |
||
682 | * Any conditions created with this methods can be used with any SELECT, UPDATE |
||
683 | * and DELETE type of queries. |
||
684 | * |
||
685 | * ### Conditions using operators: |
||
686 | * |
||
687 | * ``` |
||
688 | * $query->where([ |
||
689 | * 'posted >=' => new DateTime('3 days ago'), |
||
690 | * 'title LIKE' => 'Hello W%', |
||
691 | * 'author_id' => 1, |
||
692 | * ], ['posted' => 'datetime']); |
||
693 | * ``` |
||
694 | * |
||
695 | * The previous example produces: |
||
696 | * |
||
697 | * `WHERE posted >= 2012-01-27 AND title LIKE 'Hello W%' AND author_id = 1` |
||
698 | * |
||
699 | * Second parameter is used to specify what type is expected for each passed |
||
700 | * key. Valid types can be used from the mapped with Database\Type class. |
||
701 | * |
||
702 | * ### Nesting conditions with conjunctions: |
||
703 | * |
||
704 | * ``` |
||
705 | * $query->where([ |
||
706 | * 'author_id !=' => 1, |
||
707 | * 'OR' => ['published' => true, 'posted <' => new DateTime('now')], |
||
708 | * 'NOT' => ['title' => 'Hello'] |
||
709 | * ], ['published' => boolean, 'posted' => 'datetime'] |
||
710 | * ``` |
||
711 | * |
||
712 | * The previous example produces: |
||
713 | * |
||
714 | * `WHERE author_id = 1 AND (published = 1 OR posted < '2012-02-01') AND NOT (title = 'Hello')` |
||
715 | * |
||
716 | * You can nest conditions using conjunctions as much as you like. Sometimes, you |
||
717 | * may want to define 2 different options for the same key, in that case, you can |
||
718 | * wrap each condition inside a new array: |
||
719 | * |
||
720 | * `$query->where(['OR' => [['published' => false], ['published' => true]])` |
||
721 | * |
||
722 | * Keep in mind that every time you call where() with the third param set to false |
||
723 | * (default), it will join the passed conditions to the previous stored list using |
||
724 | * the AND operator. Also, using the same array key twice in consecutive calls to |
||
725 | * this method will not override the previous value. |
||
726 | * |
||
727 | * ### Using expressions objects: |
||
728 | * |
||
729 | * ``` |
||
730 | * $exp = $query->newExpr()->add(['id !=' => 100, 'author_id' != 1])->type('OR'); |
||
731 | * $query->where(['published' => true], ['published' => 'boolean'])->where($exp); |
||
732 | * ``` |
||
733 | * |
||
734 | * The previous example produces: |
||
735 | * |
||
736 | * `WHERE (id != 100 OR author_id != 1) AND published = 1` |
||
737 | * |
||
738 | * Other Query objects that be used as conditions for any field. |
||
739 | * |
||
740 | * ### Adding conditions in multiple steps: |
||
741 | * |
||
742 | * You can use callable functions to construct complex expressions, functions |
||
743 | * receive as first argument a new QueryExpression object and this query instance |
||
744 | * as second argument. Functions must return an expression object, that will be |
||
745 | * added the list of conditions for the query using the AND operator. |
||
746 | * |
||
747 | * ``` |
||
748 | * $query |
||
749 | * ->where(['title !=' => 'Hello World']) |
||
750 | * ->where(function ($exp, $query) { |
||
751 | * $or = $exp->or_(['id' => 1]); |
||
752 | * $and = $exp->and_(['id >' => 2, 'id <' => 10]); |
||
753 | * return $or->add($and); |
||
754 | * }); |
||
755 | * ``` |
||
756 | * |
||
757 | * * The previous example produces: |
||
758 | * |
||
759 | * `WHERE title != 'Hello World' AND (id = 1 OR (id > 2 AND id < 10))` |
||
760 | * |
||
761 | * ### Conditions as strings: |
||
762 | * |
||
763 | * ``` |
||
764 | * $query->where(['articles.author_id = authors.id', 'modified IS NULL']); |
||
765 | * ``` |
||
766 | * |
||
767 | * The previous example produces: |
||
768 | * |
||
769 | * `WHERE articles.author_id = authors.id AND modified IS NULL` |
||
770 | * |
||
771 | * Please note that when using the array notation or the expression objects, all |
||
772 | * values will be correctly quoted and transformed to the correspondent database |
||
773 | * data type automatically for you, thus securing your application from SQL injections. |
||
774 | * If you use string conditions make sure that your values are correctly quoted. |
||
775 | * The safest thing you can do is to never use string conditions. |
||
776 | * |
||
777 | * @param string|array|\Cake\Database\ExpressionInterface|callback|null $conditions The conditions to filter on. |
||
778 | * @param array $types associative array of type names used to bind values to query |
||
779 | * @param bool $overwrite whether to reset conditions with passed list or not |
||
780 | * @see \Cake\Database\Type |
||
781 | * @see \Cake\Database\Expression\QueryExpression |
||
782 | * @return $this |
||
783 | */ |
||
784 | View Code Duplication | public function where($conditions = null, $types = [], $overwrite = false) |
|
785 | { |
||
786 | if ($overwrite) { |
||
787 | $this->_parts['where'] = $this->newExpr(); |
||
788 | } |
||
789 | $this->_conjugate('where', $conditions, 'AND', $types); |
||
790 | return $this; |
||
791 | } |
||
792 | |||
793 | /** |
||
794 | * Connects any previously defined set of conditions to the provided list |
||
795 | * using the AND operator. This function accepts the conditions list in the same |
||
796 | * format as the method `where` does, hence you can use arrays, expression objects |
||
797 | * callback functions or strings. |
||
798 | * |
||
799 | * It is important to notice that when calling this function, any previous set |
||
800 | * of conditions defined for this query will be treated as a single argument for |
||
801 | * the AND operator. This function will not only operate the most recently defined |
||
802 | * condition, but all the conditions as a whole. |
||
803 | * |
||
804 | * When using an array for defining conditions, creating constraints form each |
||
805 | * array entry will use the same logic as with the `where()` function. This means |
||
806 | * that each array entry will be joined to the other using the AND operator, unless |
||
807 | * you nest the conditions in the array using other operator. |
||
808 | * |
||
809 | * ### Examples: |
||
810 | * |
||
811 | * ``` |
||
812 | * $query->where(['title' => 'Hello World')->andWhere(['author_id' => 1]); |
||
813 | * ``` |
||
814 | * |
||
815 | * Will produce: |
||
816 | * |
||
817 | * `WHERE title = 'Hello World' AND author_id = 1` |
||
818 | * |
||
819 | * ``` |
||
820 | * $query |
||
821 | * ->where(['OR' => ['published' => false, 'published is NULL']]) |
||
822 | * ->andWhere(['author_id' => 1, 'comments_count >' => 10]) |
||
823 | * ``` |
||
824 | * |
||
825 | * Produces: |
||
826 | * |
||
827 | * `WHERE (published = 0 OR published IS NULL) AND author_id = 1 AND comments_count > 10` |
||
828 | * |
||
829 | * ``` |
||
830 | * $query |
||
831 | * ->where(['title' => 'Foo']) |
||
832 | * ->andWhere(function ($exp, $query) { |
||
833 | * return $exp |
||
834 | * ->add(['author_id' => 1]) |
||
835 | * ->or_(['author_id' => 2]); |
||
836 | * }); |
||
837 | * ``` |
||
838 | * |
||
839 | * Generates the following conditions: |
||
840 | * |
||
841 | * `WHERE (title = 'Foo') AND (author_id = 1 OR author_id = 2)` |
||
842 | * |
||
843 | * @param string|array|ExpressionInterface|callback $conditions The conditions to add with AND. |
||
844 | * @param array $types associative array of type names used to bind values to query |
||
845 | * @see \Cake\Database\Query::where() |
||
846 | * @see \Cake\Database\Type |
||
847 | * @return $this |
||
848 | */ |
||
849 | public function andWhere($conditions, $types = []) |
||
850 | { |
||
851 | $this->_conjugate('where', $conditions, 'AND', $types); |
||
852 | return $this; |
||
853 | } |
||
854 | |||
855 | /** |
||
856 | * Connects any previously defined set of conditions to the provided list |
||
857 | * using the OR operator. This function accepts the conditions list in the same |
||
858 | * format as the method `where` does, hence you can use arrays, expression objects |
||
859 | * callback functions or strings. |
||
860 | * |
||
861 | * It is important to notice that when calling this function, any previous set |
||
862 | * of conditions defined for this query will be treated as a single argument for |
||
863 | * the OR operator. This function will not only operate the most recently defined |
||
864 | * condition, but all the conditions as a whole. |
||
865 | * |
||
866 | * When using an array for defining conditions, creating constraints form each |
||
867 | * array entry will use the same logic as with the `where()` function. This means |
||
868 | * that each array entry will be joined to the other using the OR operator, unless |
||
869 | * you nest the conditions in the array using other operator. |
||
870 | * |
||
871 | * ### Examples: |
||
872 | * |
||
873 | * ``` |
||
874 | * $query->where(['title' => 'Hello World')->orWhere(['title' => 'Foo']); |
||
875 | * ``` |
||
876 | * |
||
877 | * Will produce: |
||
878 | * |
||
879 | * `WHERE title = 'Hello World' OR title = 'Foo'` |
||
880 | * |
||
881 | * ``` |
||
882 | * $query |
||
883 | * ->where(['OR' => ['published' => false, 'published is NULL']]) |
||
884 | * ->orWhere(['author_id' => 1, 'comments_count >' => 10]) |
||
885 | * ``` |
||
886 | * |
||
887 | * Produces: |
||
888 | * |
||
889 | * `WHERE (published = 0 OR published IS NULL) OR (author_id = 1 AND comments_count > 10)` |
||
890 | * |
||
891 | * ``` |
||
892 | * $query |
||
893 | * ->where(['title' => 'Foo']) |
||
894 | * ->orWhere(function ($exp, $query) { |
||
895 | * return $exp |
||
896 | * ->add(['author_id' => 1]) |
||
897 | * ->or_(['author_id' => 2]); |
||
898 | * }); |
||
899 | * ``` |
||
900 | * |
||
901 | * Generates the following conditions: |
||
902 | * |
||
903 | * `WHERE (title = 'Foo') OR (author_id = 1 OR author_id = 2)` |
||
904 | * |
||
905 | * @param string|array|ExpressionInterface|callback $conditions The conditions to add with OR. |
||
906 | * @param array $types associative array of type names used to bind values to query |
||
907 | * @see \Cake\Database\Query::where() |
||
908 | * @see \Cake\Database\Type |
||
909 | * @return $this |
||
910 | */ |
||
911 | public function orWhere($conditions, $types = []) |
||
912 | { |
||
913 | $this->_conjugate('where', $conditions, 'OR', $types); |
||
914 | return $this; |
||
915 | } |
||
916 | |||
917 | /** |
||
918 | * Adds a single or multiple fields to be used in the ORDER clause for this query. |
||
919 | * Fields can be passed as an array of strings, array of expression |
||
920 | * objects, a single expression or a single string. |
||
921 | * |
||
922 | * If an array is passed, keys will be used as the field itself and the value will |
||
923 | * represent the order in which such field should be ordered. When called multiple |
||
924 | * times with the same fields as key, the last order definition will prevail over |
||
925 | * the others. |
||
926 | * |
||
927 | * By default this function will append any passed argument to the list of fields |
||
928 | * to be selected, unless the second argument is set to true. |
||
929 | * |
||
930 | * ### Examples: |
||
931 | * |
||
932 | * ``` |
||
933 | * $query->order(['title' => 'DESC', 'author_id' => 'ASC']); |
||
934 | * ``` |
||
935 | * |
||
936 | * Produces: |
||
937 | * |
||
938 | * `ORDER BY title DESC, author_id ASC` |
||
939 | * |
||
940 | * ``` |
||
941 | * $query->order(['title' => 'DESC NULLS FIRST'])->order('author_id'); |
||
942 | * ``` |
||
943 | * |
||
944 | * Will generate: |
||
945 | * |
||
946 | * `ORDER BY title DESC NULLS FIRST, author_id` |
||
947 | * |
||
948 | * ``` |
||
949 | * $expression = $query->newExpr()->add(['id % 2 = 0']); |
||
950 | * $query->order($expression)->order(['title' => 'ASC']); |
||
951 | * ``` |
||
952 | * |
||
953 | * Will become: |
||
954 | * |
||
955 | * `ORDER BY (id %2 = 0), title ASC` |
||
956 | * |
||
957 | * If you need to set complex expressions as order conditions, you |
||
958 | * should use `orderAsc()` or `orderDesc()`. |
||
959 | * |
||
960 | * @param array|\Cake\Database\ExpressionInterface|string $fields fields to be added to the list |
||
961 | * @param bool $overwrite whether to reset order with field list or not |
||
962 | * @return $this |
||
963 | */ |
||
964 | View Code Duplication | public function order($fields, $overwrite = false) |
|
980 | |||
981 | /** |
||
982 | * Add an ORDER BY clause with an ASC direction. |
||
983 | * |
||
984 | * This method allows you to set complex expressions |
||
985 | * as order conditions unlike order() |
||
986 | * |
||
987 | * @param string|\Cake\Database\Expression\QueryExpression $field The field to order on. |
||
988 | * @param bool $overwrite Whether or not to reset the order clauses. |
||
989 | * @return $this |
||
990 | */ |
||
991 | View Code Duplication | public function orderAsc($field, $overwrite = false) |
|
1006 | |||
1007 | /** |
||
1008 | * Add an ORDER BY clause with an ASC direction. |
||
1009 | * |
||
1010 | * This method allows you to set complex expressions |
||
1011 | * as order conditions unlike order() |
||
1012 | * |
||
1013 | * @param string|\Cake\Database\Expression\QueryExpression $field The field to order on. |
||
1014 | * @param bool $overwrite Whether or not to reset the order clauses. |
||
1015 | * @return $this |
||
1016 | */ |
||
1017 | View Code Duplication | public function orderDesc($field, $overwrite = false) |
|
1032 | |||
1033 | /** |
||
1034 | * Adds a single or multiple fields to be used in the GROUP BY clause for this query. |
||
1035 | * Fields can be passed as an array of strings, array of expression |
||
1036 | * objects, a single expression or a single string. |
||
1037 | * |
||
1038 | * By default this function will append any passed argument to the list of fields |
||
1039 | * to be grouped, unless the second argument is set to true. |
||
1040 | * |
||
1041 | * ### Examples: |
||
1042 | * |
||
1043 | * ``` |
||
1044 | * // Produces GROUP BY id, title |
||
1045 | * $query->group(['id', 'title']); |
||
1046 | * |
||
1047 | * // Produces GROUP BY title |
||
1048 | * $query->group('title'); |
||
1049 | * ``` |
||
1050 | * |
||
1051 | * @param array|ExpressionInterface|string $fields fields to be added to the list |
||
1052 | * @param bool $overwrite whether to reset fields with passed list or not |
||
1053 | * @return $this |
||
1054 | */ |
||
1055 | public function group($fields, $overwrite = false) |
||
1056 | { |
||
1057 | if ($overwrite) { |
||
1058 | $this->_parts['group'] = []; |
||
1059 | } |
||
1060 | |||
1061 | if (!is_array($fields)) { |
||
1062 | $fields = [$fields]; |
||
1063 | } |
||
1064 | |||
1065 | $this->_parts['group'] = array_merge($this->_parts['group'], array_values($fields)); |
||
1066 | $this->_dirty(); |
||
1067 | return $this; |
||
1068 | } |
||
1069 | |||
1070 | /** |
||
1071 | * Adds a condition or set of conditions to be used in the HAVING clause for this |
||
1072 | * query. This method operates in exactly the same way as the method `where()` |
||
1073 | * does. Please refer to its documentation for an insight on how to using each |
||
1074 | * parameter. |
||
1075 | * |
||
1076 | * @param string|array|ExpressionInterface|callback $conditions The having conditions. |
||
1077 | * @param array $types associative array of type names used to bind values to query |
||
1078 | * @param bool $overwrite whether to reset conditions with passed list or not |
||
1079 | * @see \Cake\Database\Query::where() |
||
1080 | * @return $this |
||
1081 | */ |
||
1082 | View Code Duplication | public function having($conditions = null, $types = [], $overwrite = false) |
|
1083 | { |
||
1084 | if ($overwrite) { |
||
1085 | $this->_parts['having'] = $this->newExpr(); |
||
1086 | } |
||
1087 | $this->_conjugate('having', $conditions, 'AND', $types); |
||
1088 | return $this; |
||
1089 | } |
||
1090 | |||
1091 | /** |
||
1092 | * Connects any previously defined set of conditions to the provided list |
||
1093 | * using the AND operator in the HAVING clause. This method operates in exactly |
||
1094 | * the same way as the method `andWhere()` does. Please refer to its |
||
1095 | * documentation for an insight on how to using each parameter. |
||
1096 | * |
||
1097 | * @param string|array|ExpressionInterface|callback $conditions The AND conditions for HAVING. |
||
1098 | * @param array $types associative array of type names used to bind values to query |
||
1099 | * @see \Cake\Database\Query::andWhere() |
||
1100 | * @return $this |
||
1101 | */ |
||
1102 | public function andHaving($conditions, $types = []) |
||
1103 | { |
||
1104 | $this->_conjugate('having', $conditions, 'AND', $types); |
||
1105 | return $this; |
||
1106 | } |
||
1107 | |||
1108 | /** |
||
1109 | * Connects any previously defined set of conditions to the provided list |
||
1110 | * using the OR operator in the HAVING clause. This method operates in exactly |
||
1111 | * the same way as the method `orWhere()` does. Please refer to its |
||
1112 | * documentation for an insight on how to using each parameter. |
||
1113 | * |
||
1114 | * @param string|array|ExpressionInterface|callback $conditions The OR conditions for HAVING. |
||
1115 | * @param array $types associative array of type names used to bind values to query. |
||
1116 | * @see \Cake\Database\Query::orWhere() |
||
1117 | * @return $this |
||
1118 | */ |
||
1119 | public function orHaving($conditions, $types = []) |
||
1120 | { |
||
1121 | $this->_conjugate('having', $conditions, 'OR', $types); |
||
1122 | return $this; |
||
1123 | } |
||
1124 | |||
1125 | /** |
||
1126 | * Set the page of results you want. |
||
1127 | * |
||
1128 | * This method provides an easier to use interface to set the limit + offset |
||
1129 | * in the record set you want as results. If empty the limit will default to |
||
1130 | * the existing limit clause, and if that too is empty, then `25` will be used. |
||
1131 | * |
||
1132 | * Pages should start at 1. |
||
1133 | * |
||
1134 | * @param int $num The page number you want. |
||
1135 | * @param int $limit The number of rows you want in the page. If null |
||
1136 | * the current limit clause will be used. |
||
1137 | * @return $this |
||
1138 | */ |
||
1139 | public function page($num, $limit = null) |
||
1156 | |||
1157 | /** |
||
1158 | * Sets the number of records that should be retrieved from database, |
||
1159 | * accepts an integer or an expression object that evaluates to an integer. |
||
1160 | * In some databases, this operation might not be supported or will require |
||
1161 | * the query to be transformed in order to limit the result set size. |
||
1162 | * |
||
1163 | * ### Examples |
||
1164 | * |
||
1165 | * ``` |
||
1166 | * $query->limit(10) // generates LIMIT 10 |
||
1167 | * $query->limit($query->newExpr()->add(['1 + 1'])); // LIMIT (1 + 1) |
||
1168 | * ``` |
||
1169 | * |
||
1170 | * @param int|ExpressionInterface $num number of records to be returned |
||
1171 | * @return $this |
||
1172 | */ |
||
1173 | View Code Duplication | public function limit($num) |
|
1182 | |||
1183 | /** |
||
1184 | * Sets the number of records that should be skipped from the original result set |
||
1185 | * This is commonly used for paginating large results. Accepts an integer or an |
||
1186 | * expression object that evaluates to an integer. |
||
1187 | * |
||
1188 | * In some databases, this operation might not be supported or will require |
||
1189 | * the query to be transformed in order to limit the result set size. |
||
1190 | * |
||
1191 | * ### Examples |
||
1192 | * |
||
1193 | * ``` |
||
1194 | * $query->offset(10) // generates OFFSET 10 |
||
1195 | * $query->offset($query->newExpr()->add(['1 + 1'])); // OFFSET (1 + 1) |
||
1196 | * ``` |
||
1197 | * |
||
1198 | * @param int|ExpressionInterface $num number of records to be skipped |
||
1199 | * @return $this |
||
1200 | */ |
||
1201 | View Code Duplication | public function offset($num) |
|
1210 | |||
1211 | /** |
||
1212 | * Adds a complete query to be used in conjunction with an UNION operator with |
||
1213 | * this query. This is used to combine the result set of this query with the one |
||
1214 | * that will be returned by the passed query. You can add as many queries as you |
||
1215 | * required by calling multiple times this method with different queries. |
||
1216 | * |
||
1217 | * By default, the UNION operator will remove duplicate rows, if you wish to include |
||
1218 | * every row for all queries, use unionAll(). |
||
1219 | * |
||
1220 | * ### Examples |
||
1221 | * |
||
1222 | * ``` |
||
1223 | * $union = (new Query($conn))->select(['id', 'title'])->from(['a' => 'articles']); |
||
1224 | * $query->select(['id', 'name'])->from(['d' => 'things'])->union($union); |
||
1225 | * ``` |
||
1226 | * |
||
1227 | * Will produce: |
||
1228 | * |
||
1229 | * `SELECT id, name FROM things d UNION SELECT id, title FROM articles a` |
||
1230 | * |
||
1231 | * @param string|Query $query full SQL query to be used in UNION operator |
||
1232 | * @param bool $overwrite whether to reset the list of queries to be operated or not |
||
1233 | * @return $this |
||
1234 | */ |
||
1235 | View Code Duplication | public function union($query, $overwrite = false) |
|
1247 | |||
1248 | /** |
||
1249 | * Adds a complete query to be used in conjunction with the UNION ALL operator with |
||
1250 | * this query. This is used to combine the result set of this query with the one |
||
1251 | * that will be returned by the passed query. You can add as many queries as you |
||
1252 | * required by calling multiple times this method with different queries. |
||
1253 | * |
||
1254 | * Unlike UNION, UNION ALL will not remove duplicate rows. |
||
1255 | * |
||
1256 | * ``` |
||
1257 | * $union = (new Query($conn))->select(['id', 'title'])->from(['a' => 'articles']); |
||
1258 | * $query->select(['id', 'name'])->from(['d' => 'things'])->unionAll($union); |
||
1259 | * ``` |
||
1260 | * |
||
1261 | * Will produce: |
||
1262 | * |
||
1263 | * `SELECT id, name FROM things d UNION ALL SELECT id, title FROM articles a` |
||
1264 | * |
||
1265 | * @param string|Query $query full SQL query to be used in UNION operator |
||
1266 | * @param bool $overwrite whether to reset the list of queries to be operated or not |
||
1267 | * @return $this |
||
1268 | */ |
||
1269 | View Code Duplication | public function unionAll($query, $overwrite = false) |
|
1281 | |||
1282 | /** |
||
1283 | * Create an insert query. |
||
1284 | * |
||
1285 | * Note calling this method will reset any data previously set |
||
1286 | * with Query::values(). |
||
1287 | * |
||
1288 | * @param array $columns The columns to insert into. |
||
1289 | * @param array $types A map between columns & their datatypes. |
||
1290 | * @return $this |
||
1291 | * @throws \RuntimeException When there are 0 columns. |
||
1292 | */ |
||
1293 | public function insert(array $columns, array $types = []) |
||
1308 | |||
1309 | /** |
||
1310 | * Set the table name for insert queries. |
||
1311 | * |
||
1312 | * @param string $table The table name to insert into. |
||
1313 | * @return $this |
||
1314 | */ |
||
1315 | View Code Duplication | public function into($table) |
|
1322 | |||
1323 | /** |
||
1324 | * Set the values for an insert query. |
||
1325 | * |
||
1326 | * Multi inserts can be performed by calling values() more than one time, |
||
1327 | * or by providing an array of value sets. Additionally $data can be a Query |
||
1328 | * instance to insert data from another SELECT statement. |
||
1329 | * |
||
1330 | * @param array|Query $data The data to insert. |
||
1331 | * @return $this |
||
1332 | * @throws \Cake\Database\Exception if you try to set values before declaring columns. |
||
1333 | * Or if you try to set values on non-insert queries. |
||
1334 | */ |
||
1335 | public function values($data) |
||
1357 | |||
1358 | /** |
||
1359 | * Create an update query. |
||
1360 | * |
||
1361 | * Can be combined with set() and where() methods to create update queries. |
||
1362 | * |
||
1363 | * @param string $table The table you want to update. |
||
1364 | * @return $this |
||
1365 | */ |
||
1366 | View Code Duplication | public function update($table) |
|
1373 | |||
1374 | /** |
||
1375 | * Set one or many fields to update. |
||
1376 | * |
||
1377 | * ### Examples |
||
1378 | * |
||
1379 | * Passing a string: |
||
1380 | * |
||
1381 | * ``` |
||
1382 | * $query->update('articles')->set('title', 'The Title'); |
||
1383 | * ``` |
||
1384 | * |
||
1385 | * Passing an array: |
||
1386 | * |
||
1387 | * ``` |
||
1388 | * $query->update('articles')->set(['title' => 'The Title'], ['title' => 'string']); |
||
1389 | * ``` |
||
1390 | * |
||
1391 | * Passing a callable: |
||
1392 | * |
||
1393 | * ``` |
||
1394 | * $query->update('articles')->set(function ($exp) { |
||
1395 | * return $exp->eq('title', 'The title', 'string'); |
||
1396 | * }); |
||
1397 | * ``` |
||
1398 | * |
||
1399 | * @param string|array|callable|QueryExpression $key The column name or array of keys |
||
1400 | * + values to set. This can also be a QueryExpression containing a SQL fragment. |
||
1401 | * It can also be a callable, that is required to return an expression object. |
||
1402 | * @param mixed $value The value to update $key to. Can be null if $key is an |
||
1403 | * array or QueryExpression. When $key is an array, this parameter will be |
||
1404 | * used as $types instead. |
||
1405 | * @param array $types The column types to treat data as. |
||
1406 | * @return $this |
||
1407 | */ |
||
1408 | public function set($key, $value = null, $types = []) |
||
1433 | |||
1434 | /** |
||
1435 | * Create a delete query. |
||
1436 | * |
||
1437 | * Can be combined with from(), where() and other methods to |
||
1438 | * create delete queries with specific conditions. |
||
1439 | * |
||
1440 | * @param string $table The table to use when deleting. |
||
1441 | * @return $this |
||
1442 | */ |
||
1443 | public function delete($table = null) |
||
1452 | |||
1453 | /** |
||
1454 | * A string or expression that will be appended to the generated query |
||
1455 | * |
||
1456 | * ### Examples: |
||
1457 | * ``` |
||
1458 | * $query->select('id')->where(['author_id' => 1])->epilog('FOR UPDATE'); |
||
1459 | * $query |
||
1460 | * ->insert('articles', ['title']) |
||
1461 | * ->values(['author_id' => 1]) |
||
1462 | * ->epilog('RETURNING id'); |
||
1463 | * ``` |
||
1464 | * |
||
1465 | * @param string|\Cake\Database\Expression\QueryExpression $expression The expression to be appended |
||
1466 | * @return $this |
||
1467 | */ |
||
1468 | public function epilog($expression = null) |
||
1474 | |||
1475 | /** |
||
1476 | * Returns the type of this query (select, insert, update, delete) |
||
1477 | * |
||
1478 | * @return string |
||
1479 | */ |
||
1480 | public function type() |
||
1484 | |||
1485 | /** |
||
1486 | * Returns a new QueryExpression object. This is a handy function when |
||
1487 | * building complex queries using a fluent interface. You can also override |
||
1488 | * this function in subclasses to use a more specialized QueryExpression class |
||
1489 | * if required. |
||
1490 | * |
||
1491 | * You can optionally pass a single raw SQL string or an array or expressions in |
||
1492 | * any format accepted by \Cake\Database\Expression\QueryExpression: |
||
1493 | * |
||
1494 | * ``` |
||
1495 | * $expression = $query->newExpr(); // Returns an empty expression object |
||
1496 | * $expression = $query->newExpr('Table.column = Table2.column'); // Return a raw SQL expression |
||
1497 | * ``` |
||
1498 | * |
||
1499 | * @param mixed $rawExpression A string, array or anything you want wrapped in an expression object |
||
1500 | * @return \Cake\Database\Expression\QueryExpression |
||
1501 | */ |
||
1502 | public function newExpr($rawExpression = null) |
||
1512 | |||
1513 | /** |
||
1514 | * Returns an instance of a functions builder object that can be used for |
||
1515 | * generating arbitrary SQL functions. |
||
1516 | * |
||
1517 | * ### Example: |
||
1518 | * |
||
1519 | * ``` |
||
1520 | * $query->func()->count('*'); |
||
1521 | * $query->func()->dateDiff(['2012-01-05', '2012-01-02']) |
||
1522 | * ``` |
||
1523 | * |
||
1524 | * @return \Cake\Database\FunctionsBuilder |
||
1525 | */ |
||
1526 | public function func() |
||
1533 | |||
1534 | /** |
||
1535 | * Executes this query and returns a results iterator. This function is required |
||
1536 | * for implementing the IteratorAggregate interface and allows the query to be |
||
1537 | * iterated without having to call execute() manually, thus making it look like |
||
1538 | * a result set instead of the query itself. |
||
1539 | * |
||
1540 | * @return \Iterator |
||
1541 | */ |
||
1542 | public function getIterator() |
||
1549 | |||
1550 | /** |
||
1551 | * Returns any data that was stored in the specified clause. This is useful for |
||
1552 | * modifying any internal part of the query and it is used by the SQL dialects |
||
1553 | * to transform the query accordingly before it is executed. The valid clauses that |
||
1554 | * can be retrieved are: delete, update, set, insert, values, select, distinct, |
||
1555 | * from, join, set, where, group, having, order, limit, offset and union. |
||
1556 | * |
||
1557 | * The return value for each of those parts may vary. Some clauses use QueryExpression |
||
1558 | * to internally store their state, some use arrays and others may use booleans or |
||
1559 | * integers. This is summary of the return types for each clause. |
||
1560 | * |
||
1561 | * - update: string The name of the table to update |
||
1562 | * - set: QueryExpression |
||
1563 | * - insert: array, will return an array containing the table + columns. |
||
1564 | * - values: ValuesExpression |
||
1565 | * - select: array, will return empty array when no fields are set |
||
1566 | * - distinct: boolean |
||
1567 | * - from: array of tables |
||
1568 | * - join: array |
||
1569 | * - set: array |
||
1570 | * - where: QueryExpression, returns null when not set |
||
1571 | * - group: array |
||
1572 | * - having: QueryExpression, returns null when not set |
||
1573 | * - order: OrderByExpression, returns null when not set |
||
1574 | * - limit: integer or QueryExpression, null when not set |
||
1575 | * - offset: integer or QueryExpression, null when not set |
||
1576 | * - union: array |
||
1577 | * |
||
1578 | * @param string $name name of the clause to be returned |
||
1579 | * @return mixed |
||
1580 | */ |
||
1581 | public function clause($name) |
||
1585 | |||
1586 | /** |
||
1587 | * Registers a callback to be executed for each result that is fetched from the |
||
1588 | * result set, the callback function will receive as first parameter an array with |
||
1589 | * the raw data from the database for every row that is fetched and must return the |
||
1590 | * row with any possible modifications. |
||
1591 | * |
||
1592 | * Callbacks will be executed lazily, if only 3 rows are fetched for database it will |
||
1593 | * called 3 times, event though there might be more rows to be fetched in the cursor. |
||
1594 | * |
||
1595 | * Callbacks are stacked in the order they are registered, if you wish to reset the stack |
||
1596 | * the call this function with the second parameter set to true. |
||
1597 | * |
||
1598 | * If you wish to remove all decorators from the stack, set the first parameter |
||
1599 | * to null and the second to true. |
||
1600 | * |
||
1601 | * ### Example |
||
1602 | * |
||
1603 | * ``` |
||
1604 | * $query->decorateResults(function ($row) { |
||
1605 | * $row['order_total'] = $row['subtotal'] + ($row['subtotal'] * $row['tax']); |
||
1606 | * return $row; |
||
1607 | * }); |
||
1608 | * ``` |
||
1609 | * |
||
1610 | * @param null|callable $callback The callback to invoke when results are fetched. |
||
1611 | * @param bool $overwrite Whether or not this should append or replace all existing decorators. |
||
1612 | * @return $this |
||
1613 | */ |
||
1614 | public function decorateResults($callback, $overwrite = false) |
||
1626 | |||
1627 | /** |
||
1628 | * This function works similar to the traverse() function, with the difference |
||
1629 | * that it does a full depth traversal of the entire expression tree. This will execute |
||
1630 | * the provided callback function for each ExpressionInterface object that is |
||
1631 | * stored inside this query at any nesting depth in any part of the query. |
||
1632 | * |
||
1633 | * Callback will receive as first parameter the currently visited expression. |
||
1634 | * |
||
1635 | * @param callable $callback the function to be executed for each ExpressionInterface |
||
1636 | * found inside this query. |
||
1637 | * @return $this|null |
||
1638 | */ |
||
1639 | public function traverseExpressions(callable $callback) |
||
1659 | |||
1660 | /** |
||
1661 | * Associates a query placeholder to a value and a type. |
||
1662 | * |
||
1663 | * If type is expressed as "atype[]" (note braces) then it will cause the |
||
1664 | * placeholder to be re-written dynamically so if the value is an array, it |
||
1665 | * will create as many placeholders as values are in it. For example "string[]" |
||
1666 | * will create several placeholders of type string. |
||
1667 | * |
||
1668 | * @param string|int $param placeholder to be replaced with quoted version |
||
1669 | * of $value |
||
1670 | * @param mixed $value The value to be bound |
||
1671 | * @param string|int $type the mapped type name, used for casting when sending |
||
1672 | * to database |
||
1673 | * @return $this |
||
1674 | */ |
||
1675 | public function bind($param, $value, $type = 'string') |
||
1680 | |||
1681 | /** |
||
1682 | * Returns the currently used ValueBinder instance. If a value is passed, |
||
1683 | * it will be set as the new instance to be used. |
||
1684 | * |
||
1685 | * A ValueBinder is responsible for generating query placeholders and temporarily |
||
1686 | * associate values to those placeholders so that they can be passed correctly |
||
1687 | * statement object. |
||
1688 | * |
||
1689 | * @param \Cake\Database\ValueBinder $binder new instance to be set. If no value is passed the |
||
1690 | * default one will be returned |
||
1691 | * @return $this|\Cake\Database\ValueBinder |
||
1692 | */ |
||
1693 | public function valueBinder($binder = null) |
||
1704 | |||
1705 | /** |
||
1706 | * Enable/Disable buffered results. |
||
1707 | * |
||
1708 | * When enabled the results returned by this Query will be |
||
1709 | * buffered. This enables you to iterate a result set multiple times, or |
||
1710 | * both cache and iterate it. |
||
1711 | * |
||
1712 | * When disabled it will consume less memory as fetched results are not |
||
1713 | * remembered for future iterations. |
||
1714 | * |
||
1715 | * If called with no arguments, it will return whether or not buffering is |
||
1716 | * enabled. |
||
1717 | * |
||
1718 | * @param bool|null $enable whether or not to enable buffering |
||
1719 | * @return bool|$this |
||
1720 | */ |
||
1721 | public function bufferResults($enable = null) |
||
1731 | |||
1732 | /** |
||
1733 | * Auxiliary function used to wrap the original statement from the driver with |
||
1734 | * any registered callbacks. |
||
1735 | * |
||
1736 | * @param \Cake\Database\StatementInterface $statement to be decorated |
||
1737 | * @return \Cake\Database\Statement\CallbackStatement |
||
1738 | */ |
||
1739 | protected function _decorateStatement($statement) |
||
1746 | |||
1747 | /** |
||
1748 | * Helper function used to build conditions by composing QueryExpression objects. |
||
1749 | * |
||
1750 | * @param string $part Name of the query part to append the new part to |
||
1751 | * @param string|null|array|ExpressionInterface|callback $append Expression or builder function to append. |
||
1752 | * @param string $conjunction type of conjunction to be used to operate part |
||
1753 | * @param array $types associative array of type names used to bind values to query |
||
1754 | * @return void |
||
1755 | */ |
||
1756 | protected function _conjugate($part, $append, $conjunction, $types) |
||
1779 | |||
1780 | /** |
||
1781 | * Marks a query as dirty, removing any preprocessed information |
||
1782 | * from in memory caching. |
||
1783 | * |
||
1784 | * @return void |
||
1785 | */ |
||
1786 | protected function _dirty() |
||
1794 | |||
1795 | /** |
||
1796 | * Do a deep clone on this object. |
||
1797 | * |
||
1798 | * Will clone all of the expression objects used in |
||
1799 | * each of the clauses, as well as the valueBinder. |
||
1800 | * |
||
1801 | * @return void |
||
1802 | */ |
||
1803 | public function __clone() |
||
1825 | |||
1826 | /** |
||
1827 | * Returns string representation of this query (complete SQL statement). |
||
1828 | * |
||
1829 | * @return string |
||
1830 | */ |
||
1831 | public function __toString() |
||
1835 | |||
1836 | /** |
||
1837 | * Returns an array that can be used to describe the internal state of this |
||
1838 | * object. |
||
1839 | * |
||
1840 | * @return array |
||
1841 | */ |
||
1842 | public function __debugInfo() |
||
1853 | } |
||
1854 |
It seems like the method you are trying to call exists only in some of the possible types.
Let’s take a look at an example:
Available Fixes
Add an additional type-check:
Only allow a single type to be passed if the variable comes from a parameter: