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: