Query.php 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345
  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://www.yiiframework.com/license/
  6. */
  7. namespace yii\db;
  8. use Yii;
  9. use yii\base\Component;
  10. use yii\base\InvalidArgumentException;
  11. use yii\helpers\ArrayHelper;
  12. use yii\base\InvalidConfigException;
  13. /**
  14. * Query represents a SELECT SQL statement in a way that is independent of DBMS.
  15. *
  16. * Query provides a set of methods to facilitate the specification of different clauses
  17. * in a SELECT statement. These methods can be chained together.
  18. *
  19. * By calling [[createCommand()]], we can get a [[Command]] instance which can be further
  20. * used to perform/execute the DB query against a database.
  21. *
  22. * For example,
  23. *
  24. * ```php
  25. * $query = new Query;
  26. * // compose the query
  27. * $query->select('id, name')
  28. * ->from('user')
  29. * ->limit(10);
  30. * // build and execute the query
  31. * $rows = $query->all();
  32. * // alternatively, you can create DB command and execute it
  33. * $command = $query->createCommand();
  34. * // $command->sql returns the actual SQL
  35. * $rows = $command->queryAll();
  36. * ```
  37. *
  38. * Query internally uses the [[QueryBuilder]] class to generate the SQL statement.
  39. *
  40. * A more detailed usage guide on how to work with Query can be found in the [guide article on Query Builder](guide:db-query-builder).
  41. *
  42. * @property string[] $tablesUsedInFrom Table names indexed by aliases. This property is read-only.
  43. *
  44. * @author Qiang Xue <qiang.xue@gmail.com>
  45. * @author Carsten Brandt <mail@cebe.cc>
  46. * @since 2.0
  47. */
  48. class Query extends Component implements QueryInterface, ExpressionInterface
  49. {
  50. use QueryTrait;
  51. /**
  52. * @var array the columns being selected. For example, `['id', 'name']`.
  53. * This is used to construct the SELECT clause in a SQL statement. If not set, it means selecting all columns.
  54. * @see select()
  55. */
  56. public $select;
  57. /**
  58. * @var string additional option that should be appended to the 'SELECT' keyword. For example,
  59. * in MySQL, the option 'SQL_CALC_FOUND_ROWS' can be used.
  60. */
  61. public $selectOption;
  62. /**
  63. * @var bool whether to select distinct rows of data only. If this is set true,
  64. * the SELECT clause would be changed to SELECT DISTINCT.
  65. */
  66. public $distinct;
  67. /**
  68. * @var array the table(s) to be selected from. For example, `['user', 'post']`.
  69. * This is used to construct the FROM clause in a SQL statement.
  70. * @see from()
  71. */
  72. public $from;
  73. /**
  74. * @var array how to group the query results. For example, `['company', 'department']`.
  75. * This is used to construct the GROUP BY clause in a SQL statement.
  76. */
  77. public $groupBy;
  78. /**
  79. * @var array how to join with other tables. Each array element represents the specification
  80. * of one join which has the following structure:
  81. *
  82. * ```php
  83. * [$joinType, $tableName, $joinCondition]
  84. * ```
  85. *
  86. * For example,
  87. *
  88. * ```php
  89. * [
  90. * ['INNER JOIN', 'user', 'user.id = author_id'],
  91. * ['LEFT JOIN', 'team', 'team.id = team_id'],
  92. * ]
  93. * ```
  94. */
  95. public $join;
  96. /**
  97. * @var string|array|ExpressionInterface the condition to be applied in the GROUP BY clause.
  98. * It can be either a string or an array. Please refer to [[where()]] on how to specify the condition.
  99. */
  100. public $having;
  101. /**
  102. * @var array this is used to construct the UNION clause(s) in a SQL statement.
  103. * Each array element is an array of the following structure:
  104. *
  105. * - `query`: either a string or a [[Query]] object representing a query
  106. * - `all`: boolean, whether it should be `UNION ALL` or `UNION`
  107. */
  108. public $union;
  109. /**
  110. * @var array list of query parameter values indexed by parameter placeholders.
  111. * For example, `[':name' => 'Dan', ':age' => 31]`.
  112. */
  113. public $params = [];
  114. /**
  115. * @var int|true the default number of seconds that query results can remain valid in cache.
  116. * Use 0 to indicate that the cached data will never expire.
  117. * Use a negative number to indicate that query cache should not be used.
  118. * Use boolean `true` to indicate that [[Connection::queryCacheDuration]] should be used.
  119. * @see cache()
  120. * @since 2.0.14
  121. */
  122. public $queryCacheDuration;
  123. /**
  124. * @var \yii\caching\Dependency the dependency to be associated with the cached query result for this query
  125. * @see cache()
  126. * @since 2.0.14
  127. */
  128. public $queryCacheDependency;
  129. /**
  130. * Creates a DB command that can be used to execute this query.
  131. * @param Connection $db the database connection used to generate the SQL statement.
  132. * If this parameter is not given, the `db` application component will be used.
  133. * @return Command the created DB command instance.
  134. */
  135. public function createCommand($db = null)
  136. {
  137. if ($db === null) {
  138. $db = Yii::$app->getDb();
  139. }
  140. list($sql, $params) = $db->getQueryBuilder()->build($this);
  141. $command = $db->createCommand($sql, $params);
  142. $this->setCommandCache($command);
  143. return $command;
  144. }
  145. /**
  146. * Prepares for building SQL.
  147. * This method is called by [[QueryBuilder]] when it starts to build SQL from a query object.
  148. * You may override this method to do some final preparation work when converting a query into a SQL statement.
  149. * @param QueryBuilder $builder
  150. * @return $this a prepared query instance which will be used by [[QueryBuilder]] to build the SQL
  151. */
  152. public function prepare($builder)
  153. {
  154. return $this;
  155. }
  156. /**
  157. * Starts a batch query.
  158. *
  159. * A batch query supports fetching data in batches, which can keep the memory usage under a limit.
  160. * This method will return a [[BatchQueryResult]] object which implements the [[\Iterator]] interface
  161. * and can be traversed to retrieve the data in batches.
  162. *
  163. * For example,
  164. *
  165. * ```php
  166. * $query = (new Query)->from('user');
  167. * foreach ($query->batch() as $rows) {
  168. * // $rows is an array of 100 or fewer rows from user table
  169. * }
  170. * ```
  171. *
  172. * @param int $batchSize the number of records to be fetched in each batch.
  173. * @param Connection $db the database connection. If not set, the "db" application component will be used.
  174. * @return BatchQueryResult the batch query result. It implements the [[\Iterator]] interface
  175. * and can be traversed to retrieve the data in batches.
  176. */
  177. public function batch($batchSize = 100, $db = null)
  178. {
  179. return Yii::createObject([
  180. 'class' => BatchQueryResult::className(),
  181. 'query' => $this,
  182. 'batchSize' => $batchSize,
  183. 'db' => $db,
  184. 'each' => false,
  185. ]);
  186. }
  187. /**
  188. * Starts a batch query and retrieves data row by row.
  189. *
  190. * This method is similar to [[batch()]] except that in each iteration of the result,
  191. * only one row of data is returned. For example,
  192. *
  193. * ```php
  194. * $query = (new Query)->from('user');
  195. * foreach ($query->each() as $row) {
  196. * }
  197. * ```
  198. *
  199. * @param int $batchSize the number of records to be fetched in each batch.
  200. * @param Connection $db the database connection. If not set, the "db" application component will be used.
  201. * @return BatchQueryResult the batch query result. It implements the [[\Iterator]] interface
  202. * and can be traversed to retrieve the data in batches.
  203. */
  204. public function each($batchSize = 100, $db = null)
  205. {
  206. return Yii::createObject([
  207. 'class' => BatchQueryResult::className(),
  208. 'query' => $this,
  209. 'batchSize' => $batchSize,
  210. 'db' => $db,
  211. 'each' => true,
  212. ]);
  213. }
  214. /**
  215. * Executes the query and returns all results as an array.
  216. * @param Connection $db the database connection used to generate the SQL statement.
  217. * If this parameter is not given, the `db` application component will be used.
  218. * @return array the query results. If the query results in nothing, an empty array will be returned.
  219. */
  220. public function all($db = null)
  221. {
  222. if ($this->emulateExecution) {
  223. return [];
  224. }
  225. $rows = $this->createCommand($db)->queryAll();
  226. return $this->populate($rows);
  227. }
  228. /**
  229. * Converts the raw query results into the format as specified by this query.
  230. * This method is internally used to convert the data fetched from database
  231. * into the format as required by this query.
  232. * @param array $rows the raw query result from database
  233. * @return array the converted query result
  234. */
  235. public function populate($rows)
  236. {
  237. if ($this->indexBy === null) {
  238. return $rows;
  239. }
  240. $result = [];
  241. foreach ($rows as $row) {
  242. $result[ArrayHelper::getValue($row, $this->indexBy)] = $row;
  243. }
  244. return $result;
  245. }
  246. /**
  247. * Executes the query and returns a single row of result.
  248. * @param Connection $db the database connection used to generate the SQL statement.
  249. * If this parameter is not given, the `db` application component will be used.
  250. * @return array|bool the first row (in terms of an array) of the query result. False is returned if the query
  251. * results in nothing.
  252. */
  253. public function one($db = null)
  254. {
  255. if ($this->emulateExecution) {
  256. return false;
  257. }
  258. return $this->createCommand($db)->queryOne();
  259. }
  260. /**
  261. * Returns the query result as a scalar value.
  262. * The value returned will be the first column in the first row of the query results.
  263. * @param Connection $db the database connection used to generate the SQL statement.
  264. * If this parameter is not given, the `db` application component will be used.
  265. * @return string|null|false the value of the first column in the first row of the query result.
  266. * False is returned if the query result is empty.
  267. */
  268. public function scalar($db = null)
  269. {
  270. if ($this->emulateExecution) {
  271. return null;
  272. }
  273. return $this->createCommand($db)->queryScalar();
  274. }
  275. /**
  276. * Executes the query and returns the first column of the result.
  277. * @param Connection $db the database connection used to generate the SQL statement.
  278. * If this parameter is not given, the `db` application component will be used.
  279. * @return array the first column of the query result. An empty array is returned if the query results in nothing.
  280. */
  281. public function column($db = null)
  282. {
  283. if ($this->emulateExecution) {
  284. return [];
  285. }
  286. if ($this->indexBy === null) {
  287. return $this->createCommand($db)->queryColumn();
  288. }
  289. if (is_string($this->indexBy) && is_array($this->select) && count($this->select) === 1) {
  290. if (strpos($this->indexBy, '.') === false && count($tables = $this->getTablesUsedInFrom()) > 0) {
  291. $this->select[] = key($tables) . '.' . $this->indexBy;
  292. } else {
  293. $this->select[] = $this->indexBy;
  294. }
  295. }
  296. $rows = $this->createCommand($db)->queryAll();
  297. $results = [];
  298. foreach ($rows as $row) {
  299. $value = reset($row);
  300. if ($this->indexBy instanceof \Closure) {
  301. $results[call_user_func($this->indexBy, $row)] = $value;
  302. } else {
  303. $results[$row[$this->indexBy]] = $value;
  304. }
  305. }
  306. return $results;
  307. }
  308. /**
  309. * Returns the number of records.
  310. * @param string $q the COUNT expression. Defaults to '*'.
  311. * Make sure you properly [quote](guide:db-dao#quoting-table-and-column-names) column names in the expression.
  312. * @param Connection $db the database connection used to generate the SQL statement.
  313. * If this parameter is not given (or null), the `db` application component will be used.
  314. * @return int|string number of records. The result may be a string depending on the
  315. * underlying database engine and to support integer values higher than a 32bit PHP integer can handle.
  316. */
  317. public function count($q = '*', $db = null)
  318. {
  319. if ($this->emulateExecution) {
  320. return 0;
  321. }
  322. return $this->queryScalar("COUNT($q)", $db);
  323. }
  324. /**
  325. * Returns the sum of the specified column values.
  326. * @param string $q the column name or expression.
  327. * Make sure you properly [quote](guide:db-dao#quoting-table-and-column-names) column names in the expression.
  328. * @param Connection $db the database connection used to generate the SQL statement.
  329. * If this parameter is not given, the `db` application component will be used.
  330. * @return mixed the sum of the specified column values.
  331. */
  332. public function sum($q, $db = null)
  333. {
  334. if ($this->emulateExecution) {
  335. return 0;
  336. }
  337. return $this->queryScalar("SUM($q)", $db);
  338. }
  339. /**
  340. * Returns the average of the specified column values.
  341. * @param string $q the column name or expression.
  342. * Make sure you properly [quote](guide:db-dao#quoting-table-and-column-names) column names in the expression.
  343. * @param Connection $db the database connection used to generate the SQL statement.
  344. * If this parameter is not given, the `db` application component will be used.
  345. * @return mixed the average of the specified column values.
  346. */
  347. public function average($q, $db = null)
  348. {
  349. if ($this->emulateExecution) {
  350. return 0;
  351. }
  352. return $this->queryScalar("AVG($q)", $db);
  353. }
  354. /**
  355. * Returns the minimum of the specified column values.
  356. * @param string $q the column name or expression.
  357. * Make sure you properly [quote](guide:db-dao#quoting-table-and-column-names) column names in the expression.
  358. * @param Connection $db the database connection used to generate the SQL statement.
  359. * If this parameter is not given, the `db` application component will be used.
  360. * @return mixed the minimum of the specified column values.
  361. */
  362. public function min($q, $db = null)
  363. {
  364. return $this->queryScalar("MIN($q)", $db);
  365. }
  366. /**
  367. * Returns the maximum of the specified column values.
  368. * @param string $q the column name or expression.
  369. * Make sure you properly [quote](guide:db-dao#quoting-table-and-column-names) column names in the expression.
  370. * @param Connection $db the database connection used to generate the SQL statement.
  371. * If this parameter is not given, the `db` application component will be used.
  372. * @return mixed the maximum of the specified column values.
  373. */
  374. public function max($q, $db = null)
  375. {
  376. return $this->queryScalar("MAX($q)", $db);
  377. }
  378. /**
  379. * Returns a value indicating whether the query result contains any row of data.
  380. * @param Connection $db the database connection used to generate the SQL statement.
  381. * If this parameter is not given, the `db` application component will be used.
  382. * @return bool whether the query result contains any row of data.
  383. */
  384. public function exists($db = null)
  385. {
  386. if ($this->emulateExecution) {
  387. return false;
  388. }
  389. $command = $this->createCommand($db);
  390. $params = $command->params;
  391. $command->setSql($command->db->getQueryBuilder()->selectExists($command->getSql()));
  392. $command->bindValues($params);
  393. return (bool) $command->queryScalar();
  394. }
  395. /**
  396. * Queries a scalar value by setting [[select]] first.
  397. * Restores the value of select to make this query reusable.
  398. * @param string|ExpressionInterface $selectExpression
  399. * @param Connection|null $db
  400. * @return bool|string
  401. */
  402. protected function queryScalar($selectExpression, $db)
  403. {
  404. if ($this->emulateExecution) {
  405. return null;
  406. }
  407. if (
  408. !$this->distinct
  409. && empty($this->groupBy)
  410. && empty($this->having)
  411. && empty($this->union)
  412. ) {
  413. $select = $this->select;
  414. $order = $this->orderBy;
  415. $limit = $this->limit;
  416. $offset = $this->offset;
  417. $this->select = [$selectExpression];
  418. $this->orderBy = null;
  419. $this->limit = null;
  420. $this->offset = null;
  421. $command = $this->createCommand($db);
  422. $this->select = $select;
  423. $this->orderBy = $order;
  424. $this->limit = $limit;
  425. $this->offset = $offset;
  426. return $command->queryScalar();
  427. }
  428. $command = (new self())
  429. ->select([$selectExpression])
  430. ->from(['c' => $this])
  431. ->createCommand($db);
  432. $this->setCommandCache($command);
  433. return $command->queryScalar();
  434. }
  435. /**
  436. * Returns table names used in [[from]] indexed by aliases.
  437. * Both aliases and names are enclosed into {{ and }}.
  438. * @return string[] table names indexed by aliases
  439. * @throws \yii\base\InvalidConfigException
  440. * @since 2.0.12
  441. */
  442. public function getTablesUsedInFrom()
  443. {
  444. if (empty($this->from)) {
  445. return [];
  446. }
  447. if (is_array($this->from)) {
  448. $tableNames = $this->from;
  449. } elseif (is_string($this->from)) {
  450. $tableNames = preg_split('/\s*,\s*/', trim($this->from), -1, PREG_SPLIT_NO_EMPTY);
  451. } elseif ($this->from instanceof Expression) {
  452. $tableNames = [$this->from];
  453. } else {
  454. throw new InvalidConfigException(gettype($this->from) . ' in $from is not supported.');
  455. }
  456. return $this->cleanUpTableNames($tableNames);
  457. }
  458. /**
  459. * Clean up table names and aliases
  460. * Both aliases and names are enclosed into {{ and }}.
  461. * @param array $tableNames non-empty array
  462. * @return string[] table names indexed by aliases
  463. * @since 2.0.14
  464. */
  465. protected function cleanUpTableNames($tableNames)
  466. {
  467. $cleanedUpTableNames = [];
  468. foreach ($tableNames as $alias => $tableName) {
  469. if (is_string($tableName) && !is_string($alias)) {
  470. $pattern = <<<PATTERN
  471. ~
  472. ^
  473. \s*
  474. (
  475. (?:['"`\[]|{{)
  476. .*?
  477. (?:['"`\]]|}})
  478. |
  479. \(.*?\)
  480. |
  481. .*?
  482. )
  483. (?:
  484. (?:
  485. \s+
  486. (?:as)?
  487. \s*
  488. )
  489. (
  490. (?:['"`\[]|{{)
  491. .*?
  492. (?:['"`\]]|}})
  493. |
  494. .*?
  495. )
  496. )?
  497. \s*
  498. $
  499. ~iux
  500. PATTERN;
  501. if (preg_match($pattern, $tableName, $matches)) {
  502. if (isset($matches[2])) {
  503. list(, $tableName, $alias) = $matches;
  504. } else {
  505. $tableName = $alias = $matches[1];
  506. }
  507. }
  508. }
  509. if ($tableName instanceof Expression) {
  510. if (!is_string($alias)) {
  511. throw new InvalidArgumentException('To use Expression in from() method, pass it in array format with alias.');
  512. }
  513. $cleanedUpTableNames[$this->ensureNameQuoted($alias)] = $tableName;
  514. } elseif ($tableName instanceof self) {
  515. $cleanedUpTableNames[$this->ensureNameQuoted($alias)] = $tableName;
  516. } else {
  517. $cleanedUpTableNames[$this->ensureNameQuoted($alias)] = $this->ensureNameQuoted($tableName);
  518. }
  519. }
  520. return $cleanedUpTableNames;
  521. }
  522. /**
  523. * Ensures name is wrapped with {{ and }}
  524. * @param string $name
  525. * @return string
  526. */
  527. private function ensureNameQuoted($name)
  528. {
  529. $name = str_replace(["'", '"', '`', '[', ']'], '', $name);
  530. if ($name && !preg_match('/^{{.*}}$/', $name)) {
  531. return '{{' . $name . '}}';
  532. }
  533. return $name;
  534. }
  535. /**
  536. * Sets the SELECT part of the query.
  537. * @param string|array|ExpressionInterface $columns the columns to be selected.
  538. * Columns can be specified in either a string (e.g. "id, name") or an array (e.g. ['id', 'name']).
  539. * Columns can be prefixed with table names (e.g. "user.id") and/or contain column aliases (e.g. "user.id AS user_id").
  540. * The method will automatically quote the column names unless a column contains some parenthesis
  541. * (which means the column contains a DB expression). A DB expression may also be passed in form of
  542. * an [[ExpressionInterface]] object.
  543. *
  544. * Note that if you are selecting an expression like `CONCAT(first_name, ' ', last_name)`, you should
  545. * use an array to specify the columns. Otherwise, the expression may be incorrectly split into several parts.
  546. *
  547. * When the columns are specified as an array, you may also use array keys as the column aliases (if a column
  548. * does not need alias, do not use a string key).
  549. *
  550. * Starting from version 2.0.1, you may also select sub-queries as columns by specifying each such column
  551. * as a `Query` instance representing the sub-query.
  552. *
  553. * @param string $option additional option that should be appended to the 'SELECT' keyword. For example,
  554. * in MySQL, the option 'SQL_CALC_FOUND_ROWS' can be used.
  555. * @return $this the query object itself
  556. */
  557. public function select($columns, $option = null)
  558. {
  559. $this->select = $this->normalizeSelect($columns);
  560. $this->selectOption = $option;
  561. return $this;
  562. }
  563. /**
  564. * Add more columns to the SELECT part of the query.
  565. *
  566. * Note, that if [[select]] has not been specified before, you should include `*` explicitly
  567. * if you want to select all remaining columns too:
  568. *
  569. * ```php
  570. * $query->addSelect(["*", "CONCAT(first_name, ' ', last_name) AS full_name"])->one();
  571. * ```
  572. *
  573. * @param string|array|ExpressionInterface $columns the columns to add to the select. See [[select()]] for more
  574. * details about the format of this parameter.
  575. * @return $this the query object itself
  576. * @see select()
  577. */
  578. public function addSelect($columns)
  579. {
  580. if ($this->select === null) {
  581. return $this->select($columns);
  582. }
  583. if (!is_array($this->select)) {
  584. $this->select = $this->normalizeSelect($this->select);
  585. }
  586. $this->select = array_merge($this->select, $this->normalizeSelect($columns));
  587. return $this;
  588. }
  589. /**
  590. * Normalizes the SELECT columns passed to [[select()]] or [[addSelect()]].
  591. *
  592. * @param string|array|ExpressionInterface $columns
  593. * @return array
  594. * @since 2.0.21
  595. */
  596. protected function normalizeSelect($columns)
  597. {
  598. if ($columns instanceof ExpressionInterface) {
  599. $columns = [$columns];
  600. } elseif (!is_array($columns)) {
  601. $columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY);
  602. }
  603. $select = [];
  604. foreach ($columns as $columnAlias => $columnDefinition) {
  605. if (is_string($columnAlias)) {
  606. // Already in the normalized format, good for them
  607. $select[$columnAlias] = $columnDefinition;
  608. continue;
  609. }
  610. if (is_string($columnDefinition)) {
  611. if (
  612. preg_match('/^(.*?)(?i:\s+as\s+|\s+)([\w\-_\.]+)$/', $columnDefinition, $matches) &&
  613. !preg_match('/^\d+$/', $matches[2]) &&
  614. strpos($matches[2], '.') === false
  615. ) {
  616. // Using "columnName as alias" or "columnName alias" syntax
  617. $select[$matches[2]] = $matches[1];
  618. continue;
  619. }
  620. if (strpos($columnDefinition, '(') === false) {
  621. // Normal column name, just alias it to itself to ensure it's not selected twice
  622. $select[$columnDefinition] = $columnDefinition;
  623. continue;
  624. }
  625. }
  626. // Either a string calling a function, DB expression, or sub-query
  627. $select[] = $columnDefinition;
  628. }
  629. return $select;
  630. }
  631. /**
  632. * Returns unique column names excluding duplicates.
  633. * Columns to be removed:
  634. * - if column definition already present in SELECT part with same alias
  635. * - if column definition without alias already present in SELECT part without alias too
  636. * @param array $columns the columns to be merged to the select.
  637. * @since 2.0.14
  638. * @deprecated in 2.0.21
  639. */
  640. protected function getUniqueColumns($columns)
  641. {
  642. $unaliasedColumns = $this->getUnaliasedColumnsFromSelect();
  643. $result = [];
  644. foreach ($columns as $columnAlias => $columnDefinition) {
  645. if (!$columnDefinition instanceof Query) {
  646. if (is_string($columnAlias)) {
  647. $existsInSelect = isset($this->select[$columnAlias]) && $this->select[$columnAlias] === $columnDefinition;
  648. if ($existsInSelect) {
  649. continue;
  650. }
  651. } elseif (is_int($columnAlias)) {
  652. $existsInSelect = in_array($columnDefinition, $unaliasedColumns, true);
  653. $existsInResultSet = in_array($columnDefinition, $result, true);
  654. if ($existsInSelect || $existsInResultSet) {
  655. continue;
  656. }
  657. }
  658. }
  659. $result[$columnAlias] = $columnDefinition;
  660. }
  661. return $result;
  662. }
  663. /**
  664. * @return array List of columns without aliases from SELECT statement.
  665. * @since 2.0.14
  666. * @deprecated in 2.0.21
  667. */
  668. protected function getUnaliasedColumnsFromSelect()
  669. {
  670. $result = [];
  671. if (is_array($this->select)) {
  672. foreach ($this->select as $name => $value) {
  673. if (is_int($name)) {
  674. $result[] = $value;
  675. }
  676. }
  677. }
  678. return array_unique($result);
  679. }
  680. /**
  681. * Sets the value indicating whether to SELECT DISTINCT or not.
  682. * @param bool $value whether to SELECT DISTINCT or not.
  683. * @return $this the query object itself
  684. */
  685. public function distinct($value = true)
  686. {
  687. $this->distinct = $value;
  688. return $this;
  689. }
  690. /**
  691. * Sets the FROM part of the query.
  692. * @param string|array|ExpressionInterface $tables the table(s) to be selected from. This can be either a string (e.g. `'user'`)
  693. * or an array (e.g. `['user', 'profile']`) specifying one or several table names.
  694. * Table names can contain schema prefixes (e.g. `'public.user'`) and/or table aliases (e.g. `'user u'`).
  695. * The method will automatically quote the table names unless it contains some parenthesis
  696. * (which means the table is given as a sub-query or DB expression).
  697. *
  698. * When the tables are specified as an array, you may also use the array keys as the table aliases
  699. * (if a table does not need alias, do not use a string key).
  700. *
  701. * Use a Query object to represent a sub-query. In this case, the corresponding array key will be used
  702. * as the alias for the sub-query.
  703. *
  704. * To specify the `FROM` part in plain SQL, you may pass an instance of [[ExpressionInterface]].
  705. *
  706. * Here are some examples:
  707. *
  708. * ```php
  709. * // SELECT * FROM `user` `u`, `profile`;
  710. * $query = (new \yii\db\Query)->from(['u' => 'user', 'profile']);
  711. *
  712. * // SELECT * FROM (SELECT * FROM `user` WHERE `active` = 1) `activeusers`;
  713. * $subquery = (new \yii\db\Query)->from('user')->where(['active' => true])
  714. * $query = (new \yii\db\Query)->from(['activeusers' => $subquery]);
  715. *
  716. * // subquery can also be a string with plain SQL wrapped in parenthesis
  717. * // SELECT * FROM (SELECT * FROM `user` WHERE `active` = 1) `activeusers`;
  718. * $subquery = "(SELECT * FROM `user` WHERE `active` = 1)";
  719. * $query = (new \yii\db\Query)->from(['activeusers' => $subquery]);
  720. * ```
  721. *
  722. * @return $this the query object itself
  723. */
  724. public function from($tables)
  725. {
  726. if ($tables instanceof ExpressionInterface) {
  727. $tables = [$tables];
  728. }
  729. if (is_string($tables)) {
  730. $tables = preg_split('/\s*,\s*/', trim($tables), -1, PREG_SPLIT_NO_EMPTY);
  731. }
  732. $this->from = $tables;
  733. return $this;
  734. }
  735. /**
  736. * Sets the WHERE part of the query.
  737. *
  738. * The method requires a `$condition` parameter, and optionally a `$params` parameter
  739. * specifying the values to be bound to the query.
  740. *
  741. * The `$condition` parameter should be either a string (e.g. `'id=1'`) or an array.
  742. *
  743. * {@inheritdoc}
  744. *
  745. * @param string|array|ExpressionInterface $condition the conditions that should be put in the WHERE part.
  746. * @param array $params the parameters (name => value) to be bound to the query.
  747. * @return $this the query object itself
  748. * @see andWhere()
  749. * @see orWhere()
  750. * @see QueryInterface::where()
  751. */
  752. public function where($condition, $params = [])
  753. {
  754. $this->where = $condition;
  755. $this->addParams($params);
  756. return $this;
  757. }
  758. /**
  759. * Adds an additional WHERE condition to the existing one.
  760. * The new condition and the existing one will be joined using the `AND` operator.
  761. * @param string|array|ExpressionInterface $condition the new WHERE condition. Please refer to [[where()]]
  762. * on how to specify this parameter.
  763. * @param array $params the parameters (name => value) to be bound to the query.
  764. * @return $this the query object itself
  765. * @see where()
  766. * @see orWhere()
  767. */
  768. public function andWhere($condition, $params = [])
  769. {
  770. if ($this->where === null) {
  771. $this->where = $condition;
  772. } elseif (is_array($this->where) && isset($this->where[0]) && strcasecmp($this->where[0], 'and') === 0) {
  773. $this->where[] = $condition;
  774. } else {
  775. $this->where = ['and', $this->where, $condition];
  776. }
  777. $this->addParams($params);
  778. return $this;
  779. }
  780. /**
  781. * Adds an additional WHERE condition to the existing one.
  782. * The new condition and the existing one will be joined using the `OR` operator.
  783. * @param string|array|ExpressionInterface $condition the new WHERE condition. Please refer to [[where()]]
  784. * on how to specify this parameter.
  785. * @param array $params the parameters (name => value) to be bound to the query.
  786. * @return $this the query object itself
  787. * @see where()
  788. * @see andWhere()
  789. */
  790. public function orWhere($condition, $params = [])
  791. {
  792. if ($this->where === null) {
  793. $this->where = $condition;
  794. } else {
  795. $this->where = ['or', $this->where, $condition];
  796. }
  797. $this->addParams($params);
  798. return $this;
  799. }
  800. /**
  801. * Adds a filtering condition for a specific column and allow the user to choose a filter operator.
  802. *
  803. * It adds an additional WHERE condition for the given field and determines the comparison operator
  804. * based on the first few characters of the given value.
  805. * The condition is added in the same way as in [[andFilterWhere]] so [[isEmpty()|empty values]] are ignored.
  806. * The new condition and the existing one will be joined using the `AND` operator.
  807. *
  808. * The comparison operator is intelligently determined based on the first few characters in the given value.
  809. * In particular, it recognizes the following operators if they appear as the leading characters in the given value:
  810. *
  811. * - `<`: the column must be less than the given value.
  812. * - `>`: the column must be greater than the given value.
  813. * - `<=`: the column must be less than or equal to the given value.
  814. * - `>=`: the column must be greater than or equal to the given value.
  815. * - `<>`: the column must not be the same as the given value.
  816. * - `=`: the column must be equal to the given value.
  817. * - If none of the above operators is detected, the `$defaultOperator` will be used.
  818. *
  819. * @param string $name the column name.
  820. * @param string $value the column value optionally prepended with the comparison operator.
  821. * @param string $defaultOperator The operator to use, when no operator is given in `$value`.
  822. * Defaults to `=`, performing an exact match.
  823. * @return $this The query object itself
  824. * @since 2.0.8
  825. */
  826. public function andFilterCompare($name, $value, $defaultOperator = '=')
  827. {
  828. if (preg_match('/^(<>|>=|>|<=|<|=)/', $value, $matches)) {
  829. $operator = $matches[1];
  830. $value = substr($value, strlen($operator));
  831. } else {
  832. $operator = $defaultOperator;
  833. }
  834. return $this->andFilterWhere([$operator, $name, $value]);
  835. }
  836. /**
  837. * Appends a JOIN part to the query.
  838. * The first parameter specifies what type of join it is.
  839. * @param string $type the type of join, such as INNER JOIN, LEFT JOIN.
  840. * @param string|array $table the table to be joined.
  841. *
  842. * Use a string to represent the name of the table to be joined.
  843. * The table name can contain a schema prefix (e.g. 'public.user') and/or table alias (e.g. 'user u').
  844. * The method will automatically quote the table name unless it contains some parenthesis
  845. * (which means the table is given as a sub-query or DB expression).
  846. *
  847. * Use an array to represent joining with a sub-query. The array must contain only one element.
  848. * The value must be a [[Query]] object representing the sub-query while the corresponding key
  849. * represents the alias for the sub-query.
  850. *
  851. * @param string|array $on the join condition that should appear in the ON part.
  852. * Please refer to [[where()]] on how to specify this parameter.
  853. *
  854. * Note that the array format of [[where()]] is designed to match columns to values instead of columns to columns, so
  855. * the following would **not** work as expected: `['post.author_id' => 'user.id']`, it would
  856. * match the `post.author_id` column value against the string `'user.id'`.
  857. * It is recommended to use the string syntax here which is more suited for a join:
  858. *
  859. * ```php
  860. * 'post.author_id = user.id'
  861. * ```
  862. *
  863. * @param array $params the parameters (name => value) to be bound to the query.
  864. * @return $this the query object itself
  865. */
  866. public function join($type, $table, $on = '', $params = [])
  867. {
  868. $this->join[] = [$type, $table, $on];
  869. return $this->addParams($params);
  870. }
  871. /**
  872. * Appends an INNER JOIN part to the query.
  873. * @param string|array $table the table to be joined.
  874. *
  875. * Use a string to represent the name of the table to be joined.
  876. * The table name can contain a schema prefix (e.g. 'public.user') and/or table alias (e.g. 'user u').
  877. * The method will automatically quote the table name unless it contains some parenthesis
  878. * (which means the table is given as a sub-query or DB expression).
  879. *
  880. * Use an array to represent joining with a sub-query. The array must contain only one element.
  881. * The value must be a [[Query]] object representing the sub-query while the corresponding key
  882. * represents the alias for the sub-query.
  883. *
  884. * @param string|array $on the join condition that should appear in the ON part.
  885. * Please refer to [[join()]] on how to specify this parameter.
  886. * @param array $params the parameters (name => value) to be bound to the query.
  887. * @return $this the query object itself
  888. */
  889. public function innerJoin($table, $on = '', $params = [])
  890. {
  891. $this->join[] = ['INNER JOIN', $table, $on];
  892. return $this->addParams($params);
  893. }
  894. /**
  895. * Appends a LEFT OUTER JOIN part to the query.
  896. * @param string|array $table the table to be joined.
  897. *
  898. * Use a string to represent the name of the table to be joined.
  899. * The table name can contain a schema prefix (e.g. 'public.user') and/or table alias (e.g. 'user u').
  900. * The method will automatically quote the table name unless it contains some parenthesis
  901. * (which means the table is given as a sub-query or DB expression).
  902. *
  903. * Use an array to represent joining with a sub-query. The array must contain only one element.
  904. * The value must be a [[Query]] object representing the sub-query while the corresponding key
  905. * represents the alias for the sub-query.
  906. *
  907. * @param string|array $on the join condition that should appear in the ON part.
  908. * Please refer to [[join()]] on how to specify this parameter.
  909. * @param array $params the parameters (name => value) to be bound to the query
  910. * @return $this the query object itself
  911. */
  912. public function leftJoin($table, $on = '', $params = [])
  913. {
  914. $this->join[] = ['LEFT JOIN', $table, $on];
  915. return $this->addParams($params);
  916. }
  917. /**
  918. * Appends a RIGHT OUTER JOIN part to the query.
  919. * @param string|array $table the table to be joined.
  920. *
  921. * Use a string to represent the name of the table to be joined.
  922. * The table name can contain a schema prefix (e.g. 'public.user') and/or table alias (e.g. 'user u').
  923. * The method will automatically quote the table name unless it contains some parenthesis
  924. * (which means the table is given as a sub-query or DB expression).
  925. *
  926. * Use an array to represent joining with a sub-query. The array must contain only one element.
  927. * The value must be a [[Query]] object representing the sub-query while the corresponding key
  928. * represents the alias for the sub-query.
  929. *
  930. * @param string|array $on the join condition that should appear in the ON part.
  931. * Please refer to [[join()]] on how to specify this parameter.
  932. * @param array $params the parameters (name => value) to be bound to the query
  933. * @return $this the query object itself
  934. */
  935. public function rightJoin($table, $on = '', $params = [])
  936. {
  937. $this->join[] = ['RIGHT JOIN', $table, $on];
  938. return $this->addParams($params);
  939. }
  940. /**
  941. * Sets the GROUP BY part of the query.
  942. * @param string|array|ExpressionInterface $columns the columns to be grouped by.
  943. * Columns can be specified in either a string (e.g. "id, name") or an array (e.g. ['id', 'name']).
  944. * The method will automatically quote the column names unless a column contains some parenthesis
  945. * (which means the column contains a DB expression).
  946. *
  947. * Note that if your group-by is an expression containing commas, you should always use an array
  948. * to represent the group-by information. Otherwise, the method will not be able to correctly determine
  949. * the group-by columns.
  950. *
  951. * Since version 2.0.7, an [[ExpressionInterface]] object can be passed to specify the GROUP BY part explicitly in plain SQL.
  952. * Since version 2.0.14, an [[ExpressionInterface]] object can be passed as well.
  953. * @return $this the query object itself
  954. * @see addGroupBy()
  955. */
  956. public function groupBy($columns)
  957. {
  958. if ($columns instanceof ExpressionInterface) {
  959. $columns = [$columns];
  960. } elseif (!is_array($columns)) {
  961. $columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY);
  962. }
  963. $this->groupBy = $columns;
  964. return $this;
  965. }
  966. /**
  967. * Adds additional group-by columns to the existing ones.
  968. * @param string|array|ExpressionInterface $columns additional columns to be grouped by.
  969. * Columns can be specified in either a string (e.g. "id, name") or an array (e.g. ['id', 'name']).
  970. * The method will automatically quote the column names unless a column contains some parenthesis
  971. * (which means the column contains a DB expression).
  972. *
  973. * Note that if your group-by is an expression containing commas, you should always use an array
  974. * to represent the group-by information. Otherwise, the method will not be able to correctly determine
  975. * the group-by columns.
  976. *
  977. * Since version 2.0.7, an [[Expression]] object can be passed to specify the GROUP BY part explicitly in plain SQL.
  978. * Since version 2.0.14, an [[ExpressionInterface]] object can be passed as well.
  979. * @return $this the query object itself
  980. * @see groupBy()
  981. */
  982. public function addGroupBy($columns)
  983. {
  984. if ($columns instanceof ExpressionInterface) {
  985. $columns = [$columns];
  986. } elseif (!is_array($columns)) {
  987. $columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY);
  988. }
  989. if ($this->groupBy === null) {
  990. $this->groupBy = $columns;
  991. } else {
  992. $this->groupBy = array_merge($this->groupBy, $columns);
  993. }
  994. return $this;
  995. }
  996. /**
  997. * Sets the HAVING part of the query.
  998. * @param string|array|ExpressionInterface $condition the conditions to be put after HAVING.
  999. * Please refer to [[where()]] on how to specify this parameter.
  1000. * @param array $params the parameters (name => value) to be bound to the query.
  1001. * @return $this the query object itself
  1002. * @see andHaving()
  1003. * @see orHaving()
  1004. */
  1005. public function having($condition, $params = [])
  1006. {
  1007. $this->having = $condition;
  1008. $this->addParams($params);
  1009. return $this;
  1010. }
  1011. /**
  1012. * Adds an additional HAVING condition to the existing one.
  1013. * The new condition and the existing one will be joined using the `AND` operator.
  1014. * @param string|array|ExpressionInterface $condition the new HAVING condition. Please refer to [[where()]]
  1015. * on how to specify this parameter.
  1016. * @param array $params the parameters (name => value) to be bound to the query.
  1017. * @return $this the query object itself
  1018. * @see having()
  1019. * @see orHaving()
  1020. */
  1021. public function andHaving($condition, $params = [])
  1022. {
  1023. if ($this->having === null) {
  1024. $this->having = $condition;
  1025. } else {
  1026. $this->having = ['and', $this->having, $condition];
  1027. }
  1028. $this->addParams($params);
  1029. return $this;
  1030. }
  1031. /**
  1032. * Adds an additional HAVING condition to the existing one.
  1033. * The new condition and the existing one will be joined using the `OR` operator.
  1034. * @param string|array|ExpressionInterface $condition the new HAVING condition. Please refer to [[where()]]
  1035. * on how to specify this parameter.
  1036. * @param array $params the parameters (name => value) to be bound to the query.
  1037. * @return $this the query object itself
  1038. * @see having()
  1039. * @see andHaving()
  1040. */
  1041. public function orHaving($condition, $params = [])
  1042. {
  1043. if ($this->having === null) {
  1044. $this->having = $condition;
  1045. } else {
  1046. $this->having = ['or', $this->having, $condition];
  1047. }
  1048. $this->addParams($params);
  1049. return $this;
  1050. }
  1051. /**
  1052. * Sets the HAVING part of the query but ignores [[isEmpty()|empty operands]].
  1053. *
  1054. * This method is similar to [[having()]]. The main difference is that this method will
  1055. * remove [[isEmpty()|empty query operands]]. As a result, this method is best suited
  1056. * for building query conditions based on filter values entered by users.
  1057. *
  1058. * The following code shows the difference between this method and [[having()]]:
  1059. *
  1060. * ```php
  1061. * // HAVING `age`=:age
  1062. * $query->filterHaving(['name' => null, 'age' => 20]);
  1063. * // HAVING `age`=:age
  1064. * $query->having(['age' => 20]);
  1065. * // HAVING `name` IS NULL AND `age`=:age
  1066. * $query->having(['name' => null, 'age' => 20]);
  1067. * ```
  1068. *
  1069. * Note that unlike [[having()]], you cannot pass binding parameters to this method.
  1070. *
  1071. * @param array $condition the conditions that should be put in the HAVING part.
  1072. * See [[having()]] on how to specify this parameter.
  1073. * @return $this the query object itself
  1074. * @see having()
  1075. * @see andFilterHaving()
  1076. * @see orFilterHaving()
  1077. * @since 2.0.11
  1078. */
  1079. public function filterHaving(array $condition)
  1080. {
  1081. $condition = $this->filterCondition($condition);
  1082. if ($condition !== []) {
  1083. $this->having($condition);
  1084. }
  1085. return $this;
  1086. }
  1087. /**
  1088. * Adds an additional HAVING condition to the existing one but ignores [[isEmpty()|empty operands]].
  1089. * The new condition and the existing one will be joined using the `AND` operator.
  1090. *
  1091. * This method is similar to [[andHaving()]]. The main difference is that this method will
  1092. * remove [[isEmpty()|empty query operands]]. As a result, this method is best suited
  1093. * for building query conditions based on filter values entered by users.
  1094. *
  1095. * @param array $condition the new HAVING condition. Please refer to [[having()]]
  1096. * on how to specify this parameter.
  1097. * @return $this the query object itself
  1098. * @see filterHaving()
  1099. * @see orFilterHaving()
  1100. * @since 2.0.11
  1101. */
  1102. public function andFilterHaving(array $condition)
  1103. {
  1104. $condition = $this->filterCondition($condition);
  1105. if ($condition !== []) {
  1106. $this->andHaving($condition);
  1107. }
  1108. return $this;
  1109. }
  1110. /**
  1111. * Adds an additional HAVING condition to the existing one but ignores [[isEmpty()|empty operands]].
  1112. * The new condition and the existing one will be joined using the `OR` operator.
  1113. *
  1114. * This method is similar to [[orHaving()]]. The main difference is that this method will
  1115. * remove [[isEmpty()|empty query operands]]. As a result, this method is best suited
  1116. * for building query conditions based on filter values entered by users.
  1117. *
  1118. * @param array $condition the new HAVING condition. Please refer to [[having()]]
  1119. * on how to specify this parameter.
  1120. * @return $this the query object itself
  1121. * @see filterHaving()
  1122. * @see andFilterHaving()
  1123. * @since 2.0.11
  1124. */
  1125. public function orFilterHaving(array $condition)
  1126. {
  1127. $condition = $this->filterCondition($condition);
  1128. if ($condition !== []) {
  1129. $this->orHaving($condition);
  1130. }
  1131. return $this;
  1132. }
  1133. /**
  1134. * Appends a SQL statement using UNION operator.
  1135. * @param string|Query $sql the SQL statement to be appended using UNION
  1136. * @param bool $all TRUE if using UNION ALL and FALSE if using UNION
  1137. * @return $this the query object itself
  1138. */
  1139. public function union($sql, $all = false)
  1140. {
  1141. $this->union[] = ['query' => $sql, 'all' => $all];
  1142. return $this;
  1143. }
  1144. /**
  1145. * Sets the parameters to be bound to the query.
  1146. * @param array $params list of query parameter values indexed by parameter placeholders.
  1147. * For example, `[':name' => 'Dan', ':age' => 31]`.
  1148. * @return $this the query object itself
  1149. * @see addParams()
  1150. */
  1151. public function params($params)
  1152. {
  1153. $this->params = $params;
  1154. return $this;
  1155. }
  1156. /**
  1157. * Adds additional parameters to be bound to the query.
  1158. * @param array $params list of query parameter values indexed by parameter placeholders.
  1159. * For example, `[':name' => 'Dan', ':age' => 31]`.
  1160. * @return $this the query object itself
  1161. * @see params()
  1162. */
  1163. public function addParams($params)
  1164. {
  1165. if (!empty($params)) {
  1166. if (empty($this->params)) {
  1167. $this->params = $params;
  1168. } else {
  1169. foreach ($params as $name => $value) {
  1170. if (is_int($name)) {
  1171. $this->params[] = $value;
  1172. } else {
  1173. $this->params[$name] = $value;
  1174. }
  1175. }
  1176. }
  1177. }
  1178. return $this;
  1179. }
  1180. /**
  1181. * Enables query cache for this Query.
  1182. * @param int|true $duration the number of seconds that query results can remain valid in cache.
  1183. * Use 0 to indicate that the cached data will never expire.
  1184. * Use a negative number to indicate that query cache should not be used.
  1185. * Use boolean `true` to indicate that [[Connection::queryCacheDuration]] should be used.
  1186. * Defaults to `true`.
  1187. * @param \yii\caching\Dependency $dependency the cache dependency associated with the cached result.
  1188. * @return $this the Query object itself
  1189. * @since 2.0.14
  1190. */
  1191. public function cache($duration = true, $dependency = null)
  1192. {
  1193. $this->queryCacheDuration = $duration;
  1194. $this->queryCacheDependency = $dependency;
  1195. return $this;
  1196. }
  1197. /**
  1198. * Disables query cache for this Query.
  1199. * @return $this the Query object itself
  1200. * @since 2.0.14
  1201. */
  1202. public function noCache()
  1203. {
  1204. $this->queryCacheDuration = -1;
  1205. return $this;
  1206. }
  1207. /**
  1208. * Sets $command cache, if this query has enabled caching.
  1209. *
  1210. * @param Command $command
  1211. * @return Command
  1212. * @since 2.0.14
  1213. */
  1214. protected function setCommandCache($command)
  1215. {
  1216. if ($this->queryCacheDuration !== null || $this->queryCacheDependency !== null) {
  1217. $duration = $this->queryCacheDuration === true ? null : $this->queryCacheDuration;
  1218. $command->cache($duration, $this->queryCacheDependency);
  1219. }
  1220. return $command;
  1221. }
  1222. /**
  1223. * Creates a new Query object and copies its property values from an existing one.
  1224. * The properties being copies are the ones to be used by query builders.
  1225. * @param Query $from the source query object
  1226. * @return Query the new Query object
  1227. */
  1228. public static function create($from)
  1229. {
  1230. return new self([
  1231. 'where' => $from->where,
  1232. 'limit' => $from->limit,
  1233. 'offset' => $from->offset,
  1234. 'orderBy' => $from->orderBy,
  1235. 'indexBy' => $from->indexBy,
  1236. 'select' => $from->select,
  1237. 'selectOption' => $from->selectOption,
  1238. 'distinct' => $from->distinct,
  1239. 'from' => $from->from,
  1240. 'groupBy' => $from->groupBy,
  1241. 'join' => $from->join,
  1242. 'having' => $from->having,
  1243. 'union' => $from->union,
  1244. 'params' => $from->params,
  1245. ]);
  1246. }
  1247. /**
  1248. * Returns the SQL representation of Query
  1249. * @return string
  1250. */
  1251. public function __toString()
  1252. {
  1253. return serialize($this);
  1254. }
  1255. }