Query.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  11. * @link http://cakephp.org CakePHP(tm) Project
  12. * @since 3.0.0
  13. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\ORM;
  16. use Cake\Database\Query as DatabaseQuery;
  17. use Cake\Database\ValueBinder;
  18. use Cake\Datasource\QueryTrait;
  19. use Cake\ORM\EagerLoader;
  20. use Cake\ORM\ResultSet;
  21. use Cake\ORM\Table;
  22. use JsonSerializable;
  23. /**
  24. * Extends the base Query class to provide new methods related to association
  25. * loading, automatic fields selection, automatic type casting and to wrap results
  26. * into a specific iterator that will be responsible for hydrating results if
  27. * required.
  28. *
  29. */
  30. class Query extends DatabaseQuery implements JsonSerializable {
  31. use QueryTrait {
  32. cache as private _cache;
  33. all as private _all;
  34. _decorateResults as private _applyDecorators;
  35. __call as private _call;
  36. }
  37. /**
  38. * Indicates that the operation should append to the list
  39. *
  40. * @var int
  41. */
  42. const APPEND = 0;
  43. /**
  44. * Indicates that the operation should prepend to the list
  45. *
  46. * @var int
  47. */
  48. const PREPEND = 1;
  49. /**
  50. * Indicates that the operation should overwrite the list
  51. *
  52. * @var bool
  53. */
  54. const OVERWRITE = true;
  55. /**
  56. * Whether the user select any fields before being executed, this is used
  57. * to determined if any fields should be automatically be selected.
  58. *
  59. * @var bool
  60. */
  61. protected $_hasFields;
  62. /**
  63. * Tracks whether or not the original query should include
  64. * fields from the top level table.
  65. *
  66. * @var bool
  67. */
  68. protected $_autoFields;
  69. /**
  70. * Boolean for tracking whether or not buffered results
  71. * are enabled.
  72. *
  73. * @var bool
  74. */
  75. protected $_useBufferedResults = true;
  76. /**
  77. * Whether to hydrate results into entity objects
  78. *
  79. * @var bool
  80. */
  81. protected $_hydrate = true;
  82. /**
  83. * A callable function that can be used to calculate the total amount of
  84. * records this query will match when not using `limit`
  85. *
  86. * @var callable
  87. */
  88. protected $_counter;
  89. /**
  90. * Instance of a class responsible for storing association containments and
  91. * for eager loading them when this query is executed
  92. *
  93. * @var \Cake\ORM\EagerLoader
  94. */
  95. protected $_eagerLoader;
  96. /**
  97. * True if the beforeFind event has already been triggered for this query
  98. *
  99. * @var bool
  100. */
  101. protected $_beforeFindFired = false;
  102. /**
  103. * Constructor
  104. *
  105. * @param \Cake\Database\Connection $connection The connection object
  106. * @param \Cake\ORM\Table $table The table this query is starting on
  107. */
  108. public function __construct($connection, $table) {
  109. parent::__construct($connection);
  110. $this->repository($table);
  111. if ($this->_repository) {
  112. $this->addDefaultTypes($this->_repository);
  113. }
  114. }
  115. /**
  116. * Hints this object to associate the correct types when casting conditions
  117. * for the database. This is done by extracting the field types from the schema
  118. * associated to the passed table object. This prevents the user from repeating
  119. * himself when specifying conditions.
  120. *
  121. * This method returns the same query object for chaining.
  122. *
  123. * @param \Cake\ORM\Table $table The table to pull types from
  124. * @return $this
  125. */
  126. public function addDefaultTypes(Table $table) {
  127. $alias = $table->alias();
  128. $schema = $table->schema();
  129. $fields = [];
  130. foreach ($schema->columns() as $f) {
  131. $fields[$f] = $fields[$alias . '.' . $f] = $schema->columnType($f);
  132. }
  133. $this->defaultTypes($fields);
  134. return $this;
  135. }
  136. /**
  137. * Sets the instance of the eager loader class to use for loading associations
  138. * and storing containments. If called with no arguments, it will return the
  139. * currently configured instance.
  140. *
  141. * @param \Cake\ORM\EagerLoader $instance The eager loader to use. Pass null
  142. * to get the current eagerloader.
  143. * @return \Cake\ORM\EagerLoader|$this
  144. */
  145. public function eagerLoader(EagerLoader $instance = null) {
  146. if ($instance === null) {
  147. if ($this->_eagerLoader === null) {
  148. $this->_eagerLoader = new EagerLoader;
  149. }
  150. return $this->_eagerLoader;
  151. }
  152. $this->_eagerLoader = $instance;
  153. return $this;
  154. }
  155. /**
  156. * Sets the list of associations that should be eagerly loaded along with this
  157. * query. The list of associated tables passed must have been previously set as
  158. * associations using the Table API.
  159. *
  160. * ### Example:
  161. *
  162. * {{{
  163. * // Bring articles' author information
  164. * $query->contain('Author');
  165. *
  166. * // Also bring the category and tags associated to each article
  167. * $query->contain(['Category', 'Tag']);
  168. * }}}
  169. *
  170. * Associations can be arbitrarily nested using dot notation or nested arrays,
  171. * this allows this object to calculate joins or any additional queries that
  172. * must be executed to bring the required associated data.
  173. *
  174. * ### Example:
  175. *
  176. * {{{
  177. * // Eager load the product info, and for each product load other 2 associations
  178. * $query->contain(['Product' => ['Manufacturer', 'Distributor']);
  179. *
  180. * // Which is equivalent to calling
  181. * $query->contain(['Products.Manufactures', 'Products.Distributors']);
  182. *
  183. * // For an author query, load his region, state and country
  184. * $query->contain('Regions.States.Countries');
  185. * }}}
  186. *
  187. * It is possible to control the conditions and fields selected for each of the
  188. * contained associations:
  189. *
  190. * ### Example:
  191. *
  192. * {{{
  193. * $query->contain(['Tags' => function ($q) {
  194. * return $q->where(['Tags.is_popular' => true]);
  195. * }]);
  196. *
  197. * $query->contain(['Products.Manufactures' => function ($q) {
  198. * return $q->select(['name'])->where(['Manufactures.active' => true]);
  199. * }]);
  200. * }}}
  201. *
  202. * Each association might define special options when eager loaded, the allowed
  203. * options that can be set per association are:
  204. *
  205. * - foreignKey: Used to set a different field to match both tables, if set to false
  206. * no join conditions will be generated automatically
  207. * - fields: An array with the fields that should be fetched from the association
  208. * - queryBuilder: Equivalent to passing a callable instead of an options array
  209. *
  210. * ### Example:
  211. *
  212. * {{{
  213. * // Set options for the hasMany articles that will be eagerly loaded for an author
  214. * $query->contain([
  215. * 'Articles' => [
  216. * 'fields' => ['title', 'author_id']
  217. * ]
  218. * ]);
  219. * }}}
  220. *
  221. * When containing associations, it is important to include foreign key columns.
  222. * Failing to do so will trigger exceptions.
  223. *
  224. * {{{
  225. * // Use special join conditions for getting an author's hasMany 'likes'
  226. * $query->contain([
  227. * 'Likes' => [
  228. * 'foreignKey' => false,
  229. * 'queryBuilder' => function ($q) {
  230. * return $q->where(...); // Add full filtering conditions
  231. * }
  232. * ]
  233. * ]);
  234. * }}}
  235. *
  236. * If called with no arguments, this function will return an array with
  237. * with the list of previously configured associations to be contained in the
  238. * result.
  239. *
  240. * If called with an empty first argument and $override is set to true, the
  241. * previous list will be emptied.
  242. *
  243. * @param array|string $associations list of table aliases to be queried
  244. * @param bool $override whether override previous list with the one passed
  245. * defaults to merging previous list with the new one.
  246. * @return array|$this
  247. */
  248. public function contain($associations = null, $override = false) {
  249. if (empty($associations) && $override) {
  250. $this->_eagerLoader = null;
  251. }
  252. $result = $this->eagerLoader()->contain($associations);
  253. if ($associations !== null || $override) {
  254. $this->_dirty();
  255. }
  256. if ($associations === null) {
  257. return $result;
  258. }
  259. return $this;
  260. }
  261. /**
  262. * Adds filtering conditions to this query to only bring rows that have a relation
  263. * to another from an associated table, based on conditions in the associated table.
  264. *
  265. * This function will add entries in the `contain` graph.
  266. *
  267. * ### Example:
  268. *
  269. * {{{
  270. * // Bring only articles that were tagged with 'cake'
  271. * $query->matching('Tags', function ($q) {
  272. * return $q->where(['name' => 'cake']);
  273. * );
  274. * }}}
  275. *
  276. * It is possible to filter by deep associations by using dot notation:
  277. *
  278. * ### Example:
  279. *
  280. * {{{
  281. * // Bring only articles that were commented by 'markstory'
  282. * $query->matching('Comments.Users', function ($q) {
  283. * return $q->where(['username' => 'markstory']);
  284. * );
  285. * }}}
  286. *
  287. * As this function will create `INNER JOIN`, you might want to consider
  288. * calling `distinct` on this query as you might get duplicate rows if
  289. * your conditions don't filter them already. This might be the case, for example,
  290. * of the same user commenting more than once in the same article.
  291. *
  292. * ### Example:
  293. *
  294. * {{{
  295. * // Bring unique articles that were commented by 'markstory'
  296. * $query->distinct(['Articles.id'])
  297. * ->matching('Comments.Users', function ($q) {
  298. * return $q->where(['username' => 'markstory']);
  299. * );
  300. * }}}
  301. *
  302. * Please note that the query passed to the closure will only accept calling
  303. * `select`, `where`, `andWhere` and `orWhere` on it. If you wish to
  304. * add more complex clauses you can do it directly in the main query.
  305. *
  306. * @param string $assoc The association to filter by
  307. * @param callable $builder a function that will receive a pre-made query object
  308. * that can be used to add custom conditions or selecting some fields
  309. * @return $this
  310. */
  311. public function matching($assoc, callable $builder = null) {
  312. $this->eagerLoader()->matching($assoc, $builder);
  313. $this->_dirty();
  314. return $this;
  315. }
  316. /**
  317. * Enable/Disable buffered results.
  318. *
  319. * When enabled the ResultSet returned by this Query will be
  320. * buffered. This enables you to iterate a ResultSet multiple times, or
  321. * both cache and iterate the ResultSet.
  322. *
  323. * When disabled it will consume less memory as fetched results are not
  324. * remembered in the ResultSet.
  325. *
  326. * If called with no arguments, it will return whether or not buffering is
  327. * enabled.
  328. *
  329. * @param bool $enable whether or not to enable buffering
  330. * @return bool|$this
  331. */
  332. public function bufferResults($enable = null) {
  333. if ($enable === null) {
  334. return $this->_useBufferedResults;
  335. }
  336. $this->_dirty();
  337. $this->_useBufferedResults = (bool)$enable;
  338. return $this;
  339. }
  340. /**
  341. * Returns a key => value array representing a single aliased field
  342. * that can be passed directly to the select() method.
  343. * The key will contain the alias and the value the actual field name.
  344. *
  345. * If the field is already aliased, then it will not be changed.
  346. * If no $alias is passed, the default table for this query will be used.
  347. *
  348. * @param string $field The field to alias
  349. * @param string $alias the alias used to prefix the field
  350. * @return array
  351. */
  352. public function aliasField($field, $alias = null) {
  353. $namespaced = strpos($field, '.') !== false;
  354. $aliasedField = $field;
  355. if ($namespaced) {
  356. list($alias, $field) = explode('.', $field);
  357. }
  358. if (!$alias) {
  359. $alias = $this->repository()->alias();
  360. }
  361. $key = sprintf('%s__%s', $alias, $field);
  362. if (!$namespaced) {
  363. $aliasedField = $alias . '.' . $field;
  364. }
  365. return [$key => $aliasedField];
  366. }
  367. /**
  368. * Runs `aliasField()` for each field in the provided list and returns
  369. * the result under a single array.
  370. *
  371. * @param array $fields The fields to alias
  372. * @param string $defaultAlias The default alias
  373. * @return array
  374. */
  375. public function aliasFields($fields, $defaultAlias = null) {
  376. $aliased = [];
  377. foreach ($fields as $alias => $field) {
  378. if (is_numeric($alias) && is_string($field)) {
  379. $aliased += $this->aliasField($field, $defaultAlias);
  380. continue;
  381. }
  382. $aliased[$alias] = $field;
  383. }
  384. return $aliased;
  385. }
  386. /**
  387. * Populates or adds parts to current query clauses using an array.
  388. * This is handy for passing all query clauses at once. The option array accepts:
  389. *
  390. * - fields: Maps to the select method
  391. * - conditions: Maps to the where method
  392. * - limit: Maps to the limit method
  393. * - order: Maps to the order method
  394. * - offset: Maps to the offset method
  395. * - group: Maps to the group method
  396. * - having: Maps to the having method
  397. * - contain: Maps to the contain options for eager loading
  398. * - join: Maps to the join method
  399. * - page: Maps to the page method
  400. *
  401. * ### Example:
  402. *
  403. * {{{
  404. * $query->applyOptions([
  405. * 'fields' => ['id', 'name'],
  406. * 'conditions' => [
  407. * 'created >=' => '2013-01-01'
  408. * ],
  409. * 'limit' => 10
  410. * ]);
  411. * }}}
  412. *
  413. * Is equivalent to:
  414. *
  415. * {{{
  416. * $query
  417. * ->select(['id', 'name'])
  418. * ->where(['created >=' => '2013-01-01'])
  419. * ->limit(10)
  420. * }}}
  421. *
  422. * @param array $options list of query clauses to apply new parts to.
  423. * @return $this
  424. */
  425. public function applyOptions(array $options) {
  426. $valid = [
  427. 'fields' => 'select',
  428. 'conditions' => 'where',
  429. 'join' => 'join',
  430. 'order' => 'order',
  431. 'limit' => 'limit',
  432. 'offset' => 'offset',
  433. 'group' => 'group',
  434. 'having' => 'having',
  435. 'contain' => 'contain',
  436. 'page' => 'page',
  437. ];
  438. ksort($options);
  439. foreach ($options as $option => $values) {
  440. if (isset($valid[$option]) && isset($values)) {
  441. $this->{$valid[$option]}($values);
  442. } else {
  443. $this->_options[$option] = $values;
  444. }
  445. }
  446. return $this;
  447. }
  448. /**
  449. * Creates a copy of this current query, triggers beforeFind and resets some state.
  450. *
  451. * The following state will be cleared:
  452. *
  453. * - autoFields
  454. * - limit
  455. * - offset
  456. * - map/reduce functions
  457. * - result formatters
  458. * - order
  459. * - containments
  460. *
  461. * This method creates query clones that are useful when working with subqueries.
  462. *
  463. * @return \Cake\ORM\Query
  464. */
  465. public function cleanCopy() {
  466. $query = clone $this;
  467. $query->triggerBeforeFind();
  468. $query->autoFields(false);
  469. $query->limit(null);
  470. $query->order([], true);
  471. $query->offset(null);
  472. $query->mapReduce(null, null, true);
  473. $query->formatResults(null, true);
  474. return $query;
  475. }
  476. /**
  477. * Returns the COUNT(*) for the query.
  478. *
  479. * @return int
  480. */
  481. public function count() {
  482. $query = $this->cleanCopy();
  483. $counter = $this->_counter;
  484. if ($counter) {
  485. $query->counter(null);
  486. return (int)$counter($query);
  487. }
  488. $count = ['count' => $query->func()->count('*')];
  489. $complex = count($query->clause('group')) || $query->clause('distinct');
  490. $complex = $complex || count($query->clause('union'));
  491. if (!$complex) {
  492. $statement = $query
  493. ->select($count, true)
  494. ->autoFields(false)
  495. ->execute();
  496. } else {
  497. $statement = $this->connection()->newQuery()
  498. ->select($count)
  499. ->from(['count_source' => $query])
  500. ->execute();
  501. }
  502. $result = $statement->fetch('assoc')['count'];
  503. $statement->closeCursor();
  504. return (int)$result;
  505. }
  506. /**
  507. * Registers a callable function that will be executed when the `count` method in
  508. * this query is called. The return value for the function will be set as the
  509. * return value of the `count` method.
  510. *
  511. * This is particularly useful when you need to optimize a query for returning the
  512. * count, for example removing unnecessary joins, removing group by or just return
  513. * an estimated number of rows.
  514. *
  515. * The callback will receive as first argument a clone of this query and not this
  516. * query itself.
  517. *
  518. * @param callable $counter The counter value
  519. * @return $this
  520. */
  521. public function counter($counter) {
  522. $this->_counter = $counter;
  523. return $this;
  524. }
  525. /**
  526. * Toggle hydrating entities.
  527. *
  528. * If set to false array results will be returned
  529. *
  530. * @param bool|null $enable Use a boolean to set the hydration mode.
  531. * Null will fetch the current hydration mode.
  532. * @return bool|$this A boolean when reading, and $this when setting the mode.
  533. */
  534. public function hydrate($enable = null) {
  535. if ($enable === null) {
  536. return $this->_hydrate;
  537. }
  538. $this->_dirty();
  539. $this->_hydrate = (bool)$enable;
  540. return $this;
  541. }
  542. /**
  543. * {@inheritDoc}
  544. *
  545. * @return $this
  546. * @throws \RuntimeException When you attempt to cache a non-select query.
  547. */
  548. public function cache($key, $config = 'default') {
  549. if ($this->_type !== 'select' && $this->_type !== null) {
  550. throw new \RuntimeException('You cannot cache the results of non-select queries.');
  551. }
  552. return $this->_cache($key, $config);
  553. }
  554. /**
  555. * {@inheritDoc}
  556. *
  557. * @throws \RuntimeException if this method is called on a non-select Query.
  558. */
  559. public function all() {
  560. if ($this->_type !== 'select' && $this->_type !== null) {
  561. throw new \RuntimeException(
  562. 'You cannot call all() on a non-select query. Use execute() instead.'
  563. );
  564. }
  565. return $this->_all();
  566. }
  567. /**
  568. * Trigger the beforeFind event on the query's repository object.
  569. *
  570. * Will not trigger more than once, and only for select queries.
  571. *
  572. * @return void
  573. */
  574. public function triggerBeforeFind() {
  575. if (!$this->_beforeFindFired && $this->_type === 'select') {
  576. $table = $this->repository();
  577. $table->dispatchEvent('Model.beforeFind', [$this, $this->_options, !$this->eagerLoaded()]);
  578. $this->_beforeFindFired = true;
  579. }
  580. }
  581. /**
  582. * {@inheritDoc}
  583. */
  584. public function sql(ValueBinder $binder = null) {
  585. $this->triggerBeforeFind();
  586. $this->_transformQuery();
  587. $sql = parent::sql($binder);
  588. return $sql;
  589. }
  590. /**
  591. * Executes this query and returns a ResultSet object containing the results.
  592. * This will also setup the correct statement class in order to eager load deep
  593. * associations.
  594. *
  595. * @return \Cake\ORM\ResultSet
  596. */
  597. protected function _execute() {
  598. $this->triggerBeforeFind();
  599. if ($this->_results) {
  600. $decorator = $this->_decoratorClass();
  601. return new $decorator($this->_results);
  602. }
  603. $statement = $this->eagerLoader()->loadExternal($this, $this->execute());
  604. return new ResultSet($this, $statement);
  605. }
  606. /**
  607. * Applies some defaults to the query object before it is executed.
  608. *
  609. * Specifically add the FROM clause, adds default table fields if none are
  610. * specified and applies the joins required to eager load associations defined
  611. * using `contain`
  612. *
  613. * @see \Cake\Database\Query::execute()
  614. * @return $this
  615. */
  616. protected function _transformQuery() {
  617. if (!$this->_dirty) {
  618. return;
  619. }
  620. if ($this->_type === 'select') {
  621. if (empty($this->_parts['from'])) {
  622. $this->from([$this->_repository->alias() => $this->_repository->table()]);
  623. }
  624. $this->_addDefaultFields();
  625. $this->eagerLoader()->attachAssociations($this, $this->_repository, !$this->_hasFields);
  626. }
  627. }
  628. /**
  629. * Inspects if there are any set fields for selecting, otherwise adds all
  630. * the fields for the default table.
  631. *
  632. * @return void
  633. */
  634. protected function _addDefaultFields() {
  635. $select = $this->clause('select');
  636. $this->_hasFields = true;
  637. if (!count($select) || $this->_autoFields === true) {
  638. $this->_hasFields = false;
  639. $this->select($this->repository()->schema()->columns());
  640. $select = $this->clause('select');
  641. }
  642. $aliased = $this->aliasFields($select, $this->repository()->alias());
  643. $this->select($aliased, true);
  644. }
  645. /**
  646. * Apply custom finds to against an existing query object.
  647. *
  648. * Allows custom find methods to be combined and applied to each other.
  649. *
  650. * {{{
  651. * $table->find('all')->find('recent');
  652. * }}}
  653. *
  654. * The above is an example of stacking multiple finder methods onto
  655. * a single query.
  656. *
  657. * @param string $finder The finder method to use.
  658. * @param array $options The options for the finder.
  659. * @return $this Returns a modified query.
  660. * @see \Cake\ORM\Table::find()
  661. */
  662. public function find($finder, array $options = []) {
  663. return $this->repository()->callFinder($finder, $this, $options);
  664. }
  665. /**
  666. * Marks a query as dirty, removing any preprocessed information
  667. * from in memory caching such as previous results
  668. *
  669. * @return void
  670. */
  671. protected function _dirty() {
  672. $this->_results = null;
  673. parent::_dirty();
  674. }
  675. /**
  676. * Create an update query.
  677. *
  678. * This changes the query type to be 'update'.
  679. * Can be combined with set() and where() methods to create update queries.
  680. *
  681. * @param string $table Unused parameter.
  682. * @return $this
  683. */
  684. public function update($table = null) {
  685. $table = $this->repository()->table();
  686. return parent::update($table);
  687. }
  688. /**
  689. * Create a delete query.
  690. *
  691. * This changes the query type to be 'delete'.
  692. * Can be combined with the where() method to create delete queries.
  693. *
  694. * @param string $table Unused parameter.
  695. * @return $this
  696. */
  697. public function delete($table = null) {
  698. $repo = $this->repository();
  699. $this->from([$repo->alias() => $repo->table()]);
  700. return parent::delete();
  701. }
  702. /**
  703. * Create an insert query.
  704. *
  705. * This changes the query type to be 'insert'.
  706. * Note calling this method will reset any data previously set
  707. * with Query::values()
  708. *
  709. * Can be combined with the where() method to create delete queries.
  710. *
  711. * @param array $columns The columns to insert into.
  712. * @param array $types A map between columns & their datatypes.
  713. * @return $this
  714. */
  715. public function insert(array $columns, array $types = []) {
  716. $table = $this->repository()->table();
  717. $this->into($table);
  718. return parent::insert($columns, $types);
  719. }
  720. /**
  721. * {@inheritDoc}
  722. *
  723. * @throws \BadMethodCallException if the method is called for a non-select query
  724. */
  725. public function __call($method, $arguments) {
  726. if ($this->type() === 'select') {
  727. return $this->_call($method, $arguments);
  728. }
  729. throw new \BadMethodCallException(
  730. sprintf('Cannot call method "%s" on a "%s" query', $method, $this->type())
  731. );
  732. }
  733. /**
  734. * {@inheritDoc}
  735. */
  736. public function __debugInfo() {
  737. return parent::__debugInfo() + [
  738. 'hydrate' => $this->_hydrate,
  739. 'buffered' => $this->_useBufferedResults,
  740. 'formatters' => count($this->_formatters),
  741. 'mapReducers' => count($this->_mapReduce),
  742. 'contain' => $this->contain(),
  743. 'extraOptions' => $this->_options,
  744. 'repository' => $this->_repository
  745. ];
  746. }
  747. /**
  748. * Executes the query and converts the result set into JSON.
  749. *
  750. * Part of JsonSerializable interface.
  751. *
  752. * @return \Cake\Datasource\ResultSetInterface The data to convert to JSON.
  753. */
  754. public function jsonSerialize() {
  755. return $this->all();
  756. }
  757. /**
  758. * Get/Set whether or not the ORM should automatically append fields.
  759. *
  760. * By default calling select() will disable auto-fields. You can re-enable
  761. * auto-fields with this method.
  762. *
  763. * @param bool $value The value to set or null to read the current value.
  764. * @return bool|$this Either the current value or the query object.
  765. */
  766. public function autoFields($value = null) {
  767. if ($value === null) {
  768. return $this->_autoFields;
  769. }
  770. $this->_autoFields = (bool)$value;
  771. return $this;
  772. }
  773. /**
  774. * Decorates the results iterator with MapReduce routines and formatters
  775. *
  776. * @param \Traversable $result Original results
  777. * @return \Cake\Datasource\ResultSetInterface
  778. */
  779. protected function _decorateResults($result) {
  780. $result = $this->_applyDecorators($result);
  781. if (!($result instanceof ResultSet) && $this->bufferResults()) {
  782. $class = $this->_decoratorClass();
  783. $result = new $class($result->buffered());
  784. }
  785. return $result;
  786. }
  787. }