|
|
@@ -14,11 +14,9 @@
|
|
|
*/
|
|
|
namespace Cake\ORM;
|
|
|
|
|
|
-use Cake\Collection\Iterator\MapReduce;
|
|
|
use Cake\Database\Query as DatabaseQuery;
|
|
|
-use Cake\Event\Event;
|
|
|
+use Cake\Datasource\QueryTrait;
|
|
|
use Cake\ORM\EagerLoader;
|
|
|
-use Cake\ORM\QueryCacher;
|
|
|
use Cake\ORM\Table;
|
|
|
|
|
|
/**
|
|
|
@@ -30,6 +28,8 @@ use Cake\ORM\Table;
|
|
|
*/
|
|
|
class Query extends DatabaseQuery {
|
|
|
|
|
|
+ use QueryTrait;
|
|
|
+
|
|
|
/**
|
|
|
* Indicates that the operation should append to the list
|
|
|
*
|
|
|
@@ -52,13 +52,6 @@ class Query extends DatabaseQuery {
|
|
|
const OVERWRITE = true;
|
|
|
|
|
|
/**
|
|
|
- * Instance of a table object this query is bound to
|
|
|
- *
|
|
|
- * @var \Cake\ORM\Table
|
|
|
- */
|
|
|
- protected $_repository;
|
|
|
-
|
|
|
-/**
|
|
|
* Whether the user select any fields before being executed, this is used
|
|
|
* to determined if any fields should be automatically be selected.
|
|
|
*
|
|
|
@@ -67,16 +60,6 @@ class Query extends DatabaseQuery {
|
|
|
protected $_hasFields;
|
|
|
|
|
|
/**
|
|
|
- * A ResultSet.
|
|
|
- *
|
|
|
- * When set, query execution will be bypassed.
|
|
|
- *
|
|
|
- * @var Cake\ORM\ResultSet
|
|
|
- * @see setResult()
|
|
|
- */
|
|
|
- protected $_results;
|
|
|
-
|
|
|
-/**
|
|
|
* Boolean for tracking whether or not buffered results
|
|
|
* are enabled.
|
|
|
*
|
|
|
@@ -85,22 +68,6 @@ class Query extends DatabaseQuery {
|
|
|
protected $_useBufferedResults = true;
|
|
|
|
|
|
/**
|
|
|
- * List of map-reduce routines that should be applied over the query
|
|
|
- * result
|
|
|
- *
|
|
|
- * @var array
|
|
|
- */
|
|
|
- protected $_mapReduce = [];
|
|
|
-
|
|
|
-/**
|
|
|
- * List of formatter classes or callbacks that will post-process the
|
|
|
- * results when fetched
|
|
|
- *
|
|
|
- * @var array
|
|
|
- */
|
|
|
- protected $_formatters = [];
|
|
|
-
|
|
|
-/**
|
|
|
* Holds any custom options passed using applyOptions that could not be processed
|
|
|
* by any method in this class.
|
|
|
*
|
|
|
@@ -116,13 +83,6 @@ class Query extends DatabaseQuery {
|
|
|
protected $_hydrate = true;
|
|
|
|
|
|
/**
|
|
|
- * A query cacher instance if this query has caching enabled.
|
|
|
- *
|
|
|
- * @var Cake\ORM\QueryCacher
|
|
|
- */
|
|
|
- protected $_cache;
|
|
|
-
|
|
|
-/**
|
|
|
* A callable function that can be used to calculate the total amount of
|
|
|
* records this query will match when not using `limit`
|
|
|
*
|
|
|
@@ -154,24 +114,6 @@ class Query extends DatabaseQuery {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Returns the default table object that will be used by this query,
|
|
|
- * that is, the table that will appear in the from clause.
|
|
|
- *
|
|
|
- * When called with a Table argument, the default table object will be set
|
|
|
- * and this query object will be returned for chaining.
|
|
|
- *
|
|
|
- * @param \Cake\ORM\Table $table The default table object to use
|
|
|
- * @return \Cake\ORM\Table|Query
|
|
|
- */
|
|
|
- public function repository(Table $table = null) {
|
|
|
- if ($table === null) {
|
|
|
- return $this->_repository;
|
|
|
- }
|
|
|
- $this->_repository = $table;
|
|
|
- return $this;
|
|
|
- }
|
|
|
-
|
|
|
-/**
|
|
|
* Hints this object to associate the correct types when casting conditions
|
|
|
* for the database. This is done by extracting the field types from the schema
|
|
|
* associated to the passed table object. This prevents the user from repeating
|
|
|
@@ -399,151 +341,6 @@ class Query extends DatabaseQuery {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Set the result set for a query.
|
|
|
- *
|
|
|
- * Setting the resultset of a query will make execute() a no-op. Instead
|
|
|
- * of executing the SQL query and fetching results, the ResultSet provided to this
|
|
|
- * method will be returned.
|
|
|
- *
|
|
|
- * This method is most useful when combined with results stored in a persistent cache.
|
|
|
- *
|
|
|
- * @param Cake\ORM\ResultSet $results The results this query should return.
|
|
|
- * @return Query The query instance.
|
|
|
- */
|
|
|
- public function setResult($results) {
|
|
|
- $this->_results = $results;
|
|
|
- return $this;
|
|
|
- }
|
|
|
-
|
|
|
-/**
|
|
|
- * Enable result caching for this query.
|
|
|
- *
|
|
|
- * If a query has caching enabled, it will do the following when executed:
|
|
|
- *
|
|
|
- * - Check the cache for $key. If there are results no SQL will be executed.
|
|
|
- * Instead the cached results will be returned.
|
|
|
- * - When the cached data is stale/missing the result set will be cached as the query
|
|
|
- * is executed.
|
|
|
- *
|
|
|
- * ## Usage
|
|
|
- *
|
|
|
- * {{{
|
|
|
- * // Simple string key + config
|
|
|
- * $query->cache('my_key', 'db_results');
|
|
|
- *
|
|
|
- * // Function to generate key.
|
|
|
- * $query->cache(function($q) {
|
|
|
- * $key = serialize($q->clause('select'));
|
|
|
- * $key .= serialize($q->clause('where'));
|
|
|
- * return md5($key);
|
|
|
- * });
|
|
|
- *
|
|
|
- * // Using a pre-built cache engine.
|
|
|
- * $query->cache('my_key', $engine);
|
|
|
- *
|
|
|
- *
|
|
|
- * // Disable caching
|
|
|
- * $query->cache(false);
|
|
|
- * }}}
|
|
|
- *
|
|
|
- * @param false|string|Closure $key Either the cache key or a function to generate the cache key.
|
|
|
- * When using a function, this query instance will be supplied as an argument.
|
|
|
- * @param string|CacheEngine $config Either the name of the cache config to use, or
|
|
|
- * a cache config instance.
|
|
|
- * @return Query The query instance.
|
|
|
- * @throws \RuntimeException When you attempt to cache a non-select query.
|
|
|
- */
|
|
|
- public function cache($key, $config = 'default') {
|
|
|
- if ($this->_type !== 'select' && $this->_type !== null) {
|
|
|
- throw new \RuntimeException('You cannot cache the results of non-select queries.');
|
|
|
- }
|
|
|
- if ($key === false) {
|
|
|
- $this->_cache = null;
|
|
|
- return $this;
|
|
|
- }
|
|
|
- $this->_cache = new QueryCacher($key, $config);
|
|
|
- return $this;
|
|
|
- }
|
|
|
-
|
|
|
-/**
|
|
|
- * Executes this query and returns a results iterator. This function is required
|
|
|
- * for implementing the IteratorAggregate interface and allows the query to be
|
|
|
- * iterated without having to call execute() manually, thus making it look like
|
|
|
- * a result set instead of the query itself.
|
|
|
- *
|
|
|
- * @return Iterator
|
|
|
- */
|
|
|
- public function getIterator() {
|
|
|
- return $this->all();
|
|
|
- }
|
|
|
-
|
|
|
-/**
|
|
|
- * Fetch the results for this query.
|
|
|
- *
|
|
|
- * Compiles the SQL representation of this query and executes it using the
|
|
|
- * provided connection object. Returns a ResultSet iterator object.
|
|
|
- *
|
|
|
- * ResultSet is a travesable object that implements the methods found
|
|
|
- * on Cake\Collection\Collection.
|
|
|
- *
|
|
|
- * @return Cake\ORM\ResultCollectionTrait
|
|
|
- * @throws RuntimeException if this method is called on a non-select Query.
|
|
|
- */
|
|
|
- public function all() {
|
|
|
- if ($this->_type !== 'select' && $this->_type !== null) {
|
|
|
- throw new \RuntimeException(
|
|
|
- 'You cannot call all() on a non-select query. Use execute() instead.'
|
|
|
- );
|
|
|
- }
|
|
|
- return $this->getResults();
|
|
|
- }
|
|
|
-
|
|
|
-/**
|
|
|
- * Get the result set for this query.
|
|
|
- *
|
|
|
- * Will return either the results set through setResult(), or execute the underlying statement
|
|
|
- * and return the ResultSet object ready for streaming of results.
|
|
|
- *
|
|
|
- * @return Cake\ORM\ResultCollectionTrait
|
|
|
- */
|
|
|
- public function getResults() {
|
|
|
- if (isset($this->_results)) {
|
|
|
- return $this->_results;
|
|
|
- }
|
|
|
-
|
|
|
- $table = $this->repository();
|
|
|
- $event = new Event('Model.beforeFind', $table, [$this, $this->_options, true]);
|
|
|
- $table->getEventManager()->dispatch($event);
|
|
|
-
|
|
|
- if (isset($this->_results)) {
|
|
|
- return $this->_results;
|
|
|
- }
|
|
|
-
|
|
|
- if ($this->_cache) {
|
|
|
- $results = $this->_cache->fetch($this);
|
|
|
- }
|
|
|
- if (!isset($results)) {
|
|
|
- $results = $this->_decorateResults(
|
|
|
- new ResultSet($this, $this->execute())
|
|
|
- );
|
|
|
- if ($this->_cache) {
|
|
|
- $this->_cache->store($this, $results);
|
|
|
- }
|
|
|
- }
|
|
|
- $this->_results = $results;
|
|
|
- return $this->_results;
|
|
|
- }
|
|
|
-
|
|
|
-/**
|
|
|
- * Returns an array representation of the results after executing the query.
|
|
|
- *
|
|
|
- * @return array
|
|
|
- */
|
|
|
- public function toArray() {
|
|
|
- return $this->all()->toArray();
|
|
|
- }
|
|
|
-
|
|
|
-/**
|
|
|
* Returns a key => value array representing a single aliased field
|
|
|
* that can be passed directly to the select() method.
|
|
|
* The key will contain the alias and the value the actual field name.
|
|
|
@@ -681,109 +478,6 @@ class Query extends DatabaseQuery {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Register a new MapReduce routine to be executed on top of the database results
|
|
|
- * Both the mapper and caller callable should be invokable objects.
|
|
|
- *
|
|
|
- * The MapReduce routing will only be run when the query is executed and the first
|
|
|
- * result is attempted to be fetched.
|
|
|
- *
|
|
|
- * If the first argument is set to null, it will return the list of previously
|
|
|
- * registered map reduce routines.
|
|
|
- *
|
|
|
- * If the third argument is set to true, it will erase previous map reducers
|
|
|
- * and replace it with the arguments passed.
|
|
|
- *
|
|
|
- * @param callable $mapper
|
|
|
- * @param callable $reducer
|
|
|
- * @param boolean $overwrite
|
|
|
- * @return Cake\ORM\Query|array
|
|
|
- * @see Cake\Collection\Iterator\MapReduce for details on how to use emit data to the map reducer.
|
|
|
- */
|
|
|
- public function mapReduce(callable $mapper = null, callable $reducer = null, $overwrite = false) {
|
|
|
- if ($overwrite) {
|
|
|
- $this->_mapReduce = [];
|
|
|
- }
|
|
|
- if ($mapper === null) {
|
|
|
- return $this->_mapReduce;
|
|
|
- }
|
|
|
- $this->_mapReduce[] = compact('mapper', 'reducer');
|
|
|
- return $this;
|
|
|
- }
|
|
|
-
|
|
|
-/**
|
|
|
- * Registers a new formatter callback function that is to be executed when trying
|
|
|
- * to fetch the results from the database.
|
|
|
- *
|
|
|
- * Formatting callbacks will get a first parameter, a `ResultSetDecorator`, that
|
|
|
- * can be traversed and modified at will. As for the second parameter, the
|
|
|
- * formatting callback will receive this query instance.
|
|
|
- *
|
|
|
- * Callbacks are required to return an iterator object, which will be used as
|
|
|
- * the return value for this query's result. Formatter functions are applied
|
|
|
- * after all the `MapReduce` routines for this query have been executed.
|
|
|
- *
|
|
|
- * If the first argument is set to null, it will return the list of previously
|
|
|
- * registered map reduce routines.
|
|
|
- *
|
|
|
- * If the second argument is set to true, it will erase previous formatters
|
|
|
- * and replace them with the passed first argument.
|
|
|
- *
|
|
|
- * ### Example:
|
|
|
- *
|
|
|
- * {{{
|
|
|
- * //Return all results from the table indexed by id
|
|
|
- * $query->select(['id', 'name'])->formatResults(function($results, $query) {
|
|
|
- * return $results->indexBy('id');
|
|
|
- * });
|
|
|
- *
|
|
|
- * //Add a new column to the ResultSet
|
|
|
- * $query->select(['name', 'birth_date'])->formatResults(function($results, $query) {
|
|
|
- * return $results->map(function($row) {
|
|
|
- * $row['age'] = $row['birth_date']->diff(new DateTime)->y;
|
|
|
- * return $row;
|
|
|
- * });
|
|
|
- * });
|
|
|
- * }}}
|
|
|
- *
|
|
|
- * @param callable $formatter
|
|
|
- * @param boolean|integer $mode
|
|
|
- * @return Cake\ORM\Query|array
|
|
|
- */
|
|
|
- public function formatResults(callable $formatter = null, $mode = self::APPEND) {
|
|
|
- if ($mode === self::OVERWRITE) {
|
|
|
- $this->_formatters = [];
|
|
|
- }
|
|
|
- if ($formatter === null) {
|
|
|
- return $this->_formatters;
|
|
|
- }
|
|
|
-
|
|
|
- if ($mode === self::PREPEND) {
|
|
|
- array_unshift($this->_formatters, $formatter);
|
|
|
- return $this;
|
|
|
- }
|
|
|
-
|
|
|
- $this->_formatters[] = $formatter;
|
|
|
- return $this;
|
|
|
- }
|
|
|
-
|
|
|
-/**
|
|
|
- * Returns the first result out of executing this query, if the query has not been
|
|
|
- * executed before, it will set the limit clause to 1 for performance reasons.
|
|
|
- *
|
|
|
- * ### Example:
|
|
|
- *
|
|
|
- * `$singleUser = $query->select(['id', 'username'])->first();`
|
|
|
- *
|
|
|
- * @return mixed the first result from the ResultSet
|
|
|
- */
|
|
|
- public function first() {
|
|
|
- if ($this->_dirty) {
|
|
|
- $this->limit(1);
|
|
|
- }
|
|
|
- return $this->all()->first();
|
|
|
- }
|
|
|
-
|
|
|
-/**
|
|
|
* Return the COUNT(*) for for the query.
|
|
|
*
|
|
|
* @return integer
|
|
|
@@ -860,32 +554,6 @@ class Query extends DatabaseQuery {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Decorates the ResultSet iterator with MapReduce routines
|
|
|
- *
|
|
|
- * @param Cake\ORM\ResultCollectionTrait $result Original results
|
|
|
- * @return Cake\ORM\ResultCollectionTrait
|
|
|
- */
|
|
|
- protected function _decorateResults($result) {
|
|
|
- foreach ($this->_mapReduce as $functions) {
|
|
|
- $result = new MapReduce($result, $functions['mapper'], $functions['reducer']);
|
|
|
- }
|
|
|
-
|
|
|
- if (!empty($this->_mapReduce)) {
|
|
|
- $result = new ResultSetDecorator($result);
|
|
|
- }
|
|
|
-
|
|
|
- foreach ($this->_formatters as $formatter) {
|
|
|
- $result = $formatter($result, $this);
|
|
|
- }
|
|
|
-
|
|
|
- if (!empty($this->_formatters) && !($result instanceof ResultSetDecorator)) {
|
|
|
- $result = new ResultSetDecorator($result);
|
|
|
- }
|
|
|
-
|
|
|
- return $result;
|
|
|
- }
|
|
|
-
|
|
|
-/**
|
|
|
* Auxiliary function used to wrap the original statement from the driver with
|
|
|
* any registered callbacks. This will also setup the correct statement class
|
|
|
* in order to eager load deep associations.
|
|
|
@@ -1031,7 +699,7 @@ class Query extends DatabaseQuery {
|
|
|
*/
|
|
|
public function __call($method, $arguments) {
|
|
|
if ($this->type() === 'select') {
|
|
|
- $resultSetClass = __NAMESPACE__ . '\ResultSetDecorator';
|
|
|
+ $resultSetClass = 'Cake\Datasource\ResultSetDecorator';
|
|
|
if (in_array($method, get_class_methods($resultSetClass))) {
|
|
|
$results = $this->all();
|
|
|
return call_user_func_array([$results, $method], $arguments);
|