query.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884
  1. <?php namespace Laravel\Database;
  2. use Closure;
  3. use Laravel\Database;
  4. use Laravel\Paginator;
  5. use Laravel\Database\Query\Grammars\Postgres;
  6. use Laravel\Database\Query\Grammars\SQLServer;
  7. class Query {
  8. /**
  9. * The database connection.
  10. *
  11. * @var Connection
  12. */
  13. public $connection;
  14. /**
  15. * The query grammar instance.
  16. *
  17. * @var Query\Grammars\Grammar
  18. */
  19. public $grammar;
  20. /**
  21. * The SELECT clause.
  22. *
  23. * @var array
  24. */
  25. public $selects;
  26. /**
  27. * The aggregating column and function.
  28. *
  29. * @var array
  30. */
  31. public $aggregate;
  32. /**
  33. * Indicates if the query should return distinct results.
  34. *
  35. * @var bool
  36. */
  37. public $distinct = false;
  38. /**
  39. * The table name.
  40. *
  41. * @var string
  42. */
  43. public $from;
  44. /**
  45. * The table joins.
  46. *
  47. * @var array
  48. */
  49. public $joins;
  50. /**
  51. * The WHERE clauses.
  52. *
  53. * @var array
  54. */
  55. public $wheres;
  56. /**
  57. * The GROUP BY clauses.
  58. *
  59. * @var array
  60. */
  61. public $groupings;
  62. /**
  63. * The HAVING clauses.
  64. *
  65. * @var array
  66. */
  67. public $havings;
  68. /**
  69. * The ORDER BY clauses.
  70. *
  71. * @var array
  72. */
  73. public $orderings;
  74. /**
  75. * The LIMIT value.
  76. *
  77. * @var int
  78. */
  79. public $limit;
  80. /**
  81. * The OFFSET value.
  82. *
  83. * @var int
  84. */
  85. public $offset;
  86. /**
  87. * The query value bindings.
  88. *
  89. * @var array
  90. */
  91. public $bindings = array();
  92. /**
  93. * Create a new query instance.
  94. *
  95. * @param Connection $connection
  96. * @param Grammar $grammar
  97. * @param string $table
  98. * @return void
  99. */
  100. public function __construct(Connection $connection, Query\Grammars\Grammar $grammar, $table)
  101. {
  102. $this->from = $table;
  103. $this->grammar = $grammar;
  104. $this->connection = $connection;
  105. }
  106. /**
  107. * Force the query to return distinct results.
  108. *
  109. * @return Query
  110. */
  111. public function distinct()
  112. {
  113. $this->distinct = true;
  114. return $this;
  115. }
  116. /**
  117. * Add an array of columns to the SELECT clause.
  118. *
  119. * @param array $columns
  120. * @return Query
  121. */
  122. public function select($columns = array('*'))
  123. {
  124. $this->selects = (array) $columns;
  125. return $this;
  126. }
  127. /**
  128. * Add a join clause to the query.
  129. *
  130. * @param string $table
  131. * @param string $column1
  132. * @param string $operator
  133. * @param string $column2
  134. * @param string $type
  135. * @return Query
  136. */
  137. public function join($table, $column1, $operator = null, $column2 = null, $type = 'INNER')
  138. {
  139. // If the "column" is really an instance of a Closure, the developer is
  140. // trying to create a join with a complex "ON" clause. So, we will add
  141. // the join, and then call the Closure with the join/
  142. if ($column1 instanceof Closure)
  143. {
  144. $this->joins[] = new Query\Join($type, $table);
  145. call_user_func($column1, end($this->joins));
  146. }
  147. // If the column is just a string, we can assume that the join just
  148. // has a simple on clause, and we'll create the join instance and
  149. // add the clause automatically for the develoepr.
  150. else
  151. {
  152. $join = new Query\Join($type, $table);
  153. $join->on($column1, $operator, $column2);
  154. $this->joins[] = $join;
  155. }
  156. return $this;
  157. }
  158. /**
  159. * Add a left join to the query.
  160. *
  161. * @param string $table
  162. * @param string $column1
  163. * @param string $operator
  164. * @param string $column2
  165. * @return Query
  166. */
  167. public function left_join($table, $column1, $operator = null, $column2 = null)
  168. {
  169. return $this->join($table, $column1, $operator, $column2, 'LEFT');
  170. }
  171. /**
  172. * Reset the where clause to its initial state.
  173. *
  174. * @return void
  175. */
  176. public function reset_where()
  177. {
  178. list($this->wheres, $this->bindings) = array(array(), array());
  179. }
  180. /**
  181. * Add a raw where condition to the query.
  182. *
  183. * @param string $where
  184. * @param array $bindings
  185. * @param string $connector
  186. * @return Query
  187. */
  188. public function raw_where($where, $bindings = array(), $connector = 'AND')
  189. {
  190. $this->wheres[] = array('type' => 'where_raw', 'connector' => $connector, 'sql' => $where);
  191. $this->bindings = array_merge($this->bindings, $bindings);
  192. return $this;
  193. }
  194. /**
  195. * Add a raw or where condition to the query.
  196. *
  197. * @param string $where
  198. * @param array $bindings
  199. * @return Query
  200. */
  201. public function raw_or_where($where, $bindings = array())
  202. {
  203. return $this->raw_where($where, $bindings, 'OR');
  204. }
  205. /**
  206. * Add a where condition to the query.
  207. *
  208. * @param string $column
  209. * @param string $operator
  210. * @param mixed $value
  211. * @param string $connector
  212. * @return Query
  213. */
  214. public function where($column, $operator = null, $value = null, $connector = 'AND')
  215. {
  216. // If a Closure is passed into the method, it means a nested where
  217. // clause is being initiated, so we will take a different course
  218. // of action than when the statement is just a simple where.
  219. if ($column instanceof Closure)
  220. {
  221. return $this->where_nested($column, $connector);
  222. }
  223. $type = 'where';
  224. $this->wheres[] = compact('type', 'column', 'operator', 'value', 'connector');
  225. $this->bindings[] = $value;
  226. return $this;
  227. }
  228. /**
  229. * Add an or where condition to the query.
  230. *
  231. * @param string $column
  232. * @param string $operator
  233. * @param mixed $value
  234. * @return Query
  235. */
  236. public function or_where($column, $operator = null, $value = null)
  237. {
  238. return $this->where($column, $operator, $value, 'OR');
  239. }
  240. /**
  241. * Add an or where condition for the primary key to the query.
  242. *
  243. * @param mixed $value
  244. * @return Query
  245. */
  246. public function or_where_id($value)
  247. {
  248. return $this->or_where('id', '=', $value);
  249. }
  250. /**
  251. * Add a where in condition to the query.
  252. *
  253. * @param string $column
  254. * @param array $values
  255. * @param string $connector
  256. * @param bool $not
  257. * @return Query
  258. */
  259. public function where_in($column, $values, $connector = 'AND', $not = false)
  260. {
  261. $type = ($not) ? 'where_not_in' : 'where_in';
  262. $this->wheres[] = compact('type', 'column', 'values', 'connector');
  263. $this->bindings = array_merge($this->bindings, $values);
  264. return $this;
  265. }
  266. /**
  267. * Add an or where in condition to the query.
  268. *
  269. * @param string $column
  270. * @param array $values
  271. * @return Query
  272. */
  273. public function or_where_in($column, $values)
  274. {
  275. return $this->where_in($column, $values, 'OR');
  276. }
  277. /**
  278. * Add a where not in condition to the query.
  279. *
  280. * @param string $column
  281. * @param array $values
  282. * @param string $connector
  283. * @return Query
  284. */
  285. public function where_not_in($column, $values, $connector = 'AND')
  286. {
  287. return $this->where_in($column, $values, $connector, true);
  288. }
  289. /**
  290. * Add an or where not in condition to the query.
  291. *
  292. * @param string $column
  293. * @param array $values
  294. * @return Query
  295. */
  296. public function or_where_not_in($column, $values)
  297. {
  298. return $this->where_not_in($column, $values, 'OR');
  299. }
  300. /**
  301. * Add a where null condition to the query.
  302. *
  303. * @param string $column
  304. * @param string $connector
  305. * @param bool $not
  306. * @return Query
  307. */
  308. public function where_null($column, $connector = 'AND', $not = false)
  309. {
  310. $type = ($not) ? 'where_not_null' : 'where_null';
  311. $this->wheres[] = compact('type', 'column', 'connector');
  312. return $this;
  313. }
  314. /**
  315. * Add an or where null condition to the query.
  316. *
  317. * @param string $column
  318. * @return Query
  319. */
  320. public function or_where_null($column)
  321. {
  322. return $this->where_null($column, 'OR');
  323. }
  324. /**
  325. * Add a where not null condition to the query.
  326. *
  327. * @param string $column
  328. * @param string $connector
  329. * @return Query
  330. */
  331. public function where_not_null($column, $connector = 'AND')
  332. {
  333. return $this->where_null($column, $connector, true);
  334. }
  335. /**
  336. * Add an or where not null condition to the query.
  337. *
  338. * @param string $column
  339. * @return Query
  340. */
  341. public function or_where_not_null($column)
  342. {
  343. return $this->where_not_null($column, 'OR');
  344. }
  345. /**
  346. * Add a nested where condition to the query.
  347. *
  348. * @param Closure $callback
  349. * @param string $connector
  350. * @return Query
  351. */
  352. public function where_nested($callback, $connector = 'AND')
  353. {
  354. $type = 'where_nested';
  355. // To handle a nested where statement, we will actually instantiate a new
  356. // Query instance and run the callback over that instance, which will
  357. // allow the developer to have a fresh query instance
  358. $query = new Query($this->connection, $this->grammar, $this->from);
  359. call_user_func($callback, $query);
  360. // Once the callback has been run on the query, we will store the nested
  361. // query instance on the where clause array so that it's passed to the
  362. // query's query grammar instance when building.
  363. if ($query->wheres !== null)
  364. {
  365. $this->wheres[] = compact('type', 'query', 'connector');
  366. }
  367. $this->bindings = array_merge($this->bindings, $query->bindings);
  368. return $this;
  369. }
  370. /**
  371. * Add dynamic where conditions to the query.
  372. *
  373. * @param string $method
  374. * @param array $parameters
  375. * @return Query
  376. */
  377. private function dynamic_where($method, $parameters)
  378. {
  379. $finder = substr($method, 6);
  380. $flags = PREG_SPLIT_DELIM_CAPTURE;
  381. $segments = preg_split('/(_and_|_or_)/i', $finder, -1, $flags);
  382. // The connector variable will determine which connector will be used
  383. // for the condition. We'll change it as we come across new boolean
  384. // connectors in the dynamic method string.
  385. //
  386. // The index variable helps us get the correct parameter value for
  387. // the where condition. We increment it each time we add another
  388. // condition to the query's where clause.
  389. $connector = 'AND';
  390. $index = 0;
  391. foreach ($segments as $segment)
  392. {
  393. // If the segment is not a boolean connector, we can assume it it is
  394. // a column name, and we'll add it to the query as a new constraint
  395. // of the query's where clause and keep iterating the segments.
  396. if ($segment != '_and_' and $segment != '_or_')
  397. {
  398. $this->where($segment, '=', $parameters[$index], $connector);
  399. $index++;
  400. }
  401. // Otherwise, we will store the connector so we know how the next
  402. // where clause we find in the query should be connected to the
  403. // previous one and will add it when we find the next one.
  404. else
  405. {
  406. $connector = trim(strtoupper($segment), '_');
  407. }
  408. }
  409. return $this;
  410. }
  411. /**
  412. * Add a grouping to the query.
  413. *
  414. * @param string $column
  415. * @return Query
  416. */
  417. public function group_by($column)
  418. {
  419. $this->groupings[] = $column;
  420. return $this;
  421. }
  422. /**
  423. * Add a having to the query.
  424. *
  425. * @param string $column
  426. * @param string $operator
  427. * @param mixed $value
  428. */
  429. public function having($column, $operator, $value)
  430. {
  431. $this->havings[] = compact('column', 'operator', 'value');
  432. $this->bindings[] = $value;
  433. return $this;
  434. }
  435. /**
  436. * Add an ordering to the query.
  437. *
  438. * @param string $column
  439. * @param string $direction
  440. * @return Query
  441. */
  442. public function order_by($column, $direction = 'asc')
  443. {
  444. $this->orderings[] = compact('column', 'direction');
  445. return $this;
  446. }
  447. /**
  448. * Set the query offset.
  449. *
  450. * @param int $value
  451. * @return Query
  452. */
  453. public function skip($value)
  454. {
  455. $this->offset = $value;
  456. return $this;
  457. }
  458. /**
  459. * Set the query limit.
  460. *
  461. * @param int $value
  462. * @return Query
  463. */
  464. public function take($value)
  465. {
  466. $this->limit = $value;
  467. return $this;
  468. }
  469. /**
  470. * Set the query limit and offset for a given page.
  471. *
  472. * @param int $page
  473. * @param int $per_page
  474. * @return Query
  475. */
  476. public function for_page($page, $per_page)
  477. {
  478. return $this->skip(($page - 1) * $per_page)->take($per_page);
  479. }
  480. /**
  481. * Find a record by the primary key.
  482. *
  483. * @param int $id
  484. * @param array $columns
  485. * @return object
  486. */
  487. public function find($id, $columns = array('*'))
  488. {
  489. return $this->where('id', '=', $id)->first($columns);
  490. }
  491. /**
  492. * Execute the query as a SELECT statement and return a single column.
  493. *
  494. * @param string $column
  495. * @return mixed
  496. */
  497. public function only($column)
  498. {
  499. $sql = $this->grammar->select($this->select(array($column)));
  500. return $this->connection->only($sql, $this->bindings);
  501. }
  502. /**
  503. * Execute the query as a SELECT statement and return the first result.
  504. *
  505. * @param array $columns
  506. * @return mixed
  507. */
  508. public function first($columns = array('*'))
  509. {
  510. $columns = (array) $columns;
  511. // Since we only need the first result, we'll go ahead and set the
  512. // limit clause to 1, since this will be much faster than getting
  513. // all of the rows and then only returning the first.
  514. $results = $this->take(1)->get($columns);
  515. return (count($results) > 0) ? $results[0] : null;
  516. }
  517. /**
  518. * Get an array with the values of a given column.
  519. *
  520. * @param string $column
  521. * @param string $key
  522. * @return array
  523. */
  524. public function lists($column, $key = null)
  525. {
  526. $columns = (is_null($key)) ? array($column) : array($column, $key);
  527. $results = $this->get($columns);
  528. // First we will get the array of values for the requested column.
  529. // Of course, this array will simply have numeric keys. After we
  530. // have this array we will determine if we need to key the array
  531. // by another column from the result set.
  532. $values = array_map(function($row) use ($column)
  533. {
  534. return $row->$column;
  535. }, $results);
  536. // If a key was provided, we will extract an array of keys and
  537. // set the keys on the array of values using the array_combine
  538. // function provided by PHP, which should give us the proper
  539. // array form to return from the method.
  540. if ( ! is_null($key))
  541. {
  542. return array_combine(array_map(function($row) use ($key)
  543. {
  544. return $row->$key;
  545. }, $results), $values);
  546. }
  547. return $values;
  548. }
  549. /**
  550. * Execute the query as a SELECT statement.
  551. *
  552. * @param array $columns
  553. * @return array
  554. */
  555. public function get($columns = array('*'))
  556. {
  557. if (is_null($this->selects)) $this->select($columns);
  558. $sql = $this->grammar->select($this);
  559. $results = $this->connection->query($sql, $this->bindings);
  560. // If the query has an offset and we are using the SQL Server grammar,
  561. // we need to spin through the results and remove the "rownum" from
  562. // each of the objects since there is no "offset".
  563. if ($this->offset > 0 and $this->grammar instanceof SQLServer)
  564. {
  565. array_walk($results, function($result)
  566. {
  567. unset($result->rownum);
  568. });
  569. }
  570. // Reset the SELECT clause so more queries can be performed using
  571. // the same instance. This is helpful for getting aggregates and
  572. // then getting actual results from the query.
  573. $this->selects = null;
  574. return $results;
  575. }
  576. /**
  577. * Get an aggregate value.
  578. *
  579. * @param string $aggregator
  580. * @param array $columns
  581. * @return mixed
  582. */
  583. public function aggregate($aggregator, $columns)
  584. {
  585. // We'll set the aggregate value so the grammar does not try to compile
  586. // a SELECT clause on the query. If an aggregator is present, it's own
  587. // grammar function will be used to build the SQL syntax.
  588. $this->aggregate = compact('aggregator', 'columns');
  589. $sql = $this->grammar->select($this);
  590. $result = $this->connection->only($sql, $this->bindings);
  591. // Reset the aggregate so more queries can be performed using the same
  592. // instance. This is helpful for getting aggregates and then getting
  593. // actual results from the query such as during paging.
  594. $this->aggregate = null;
  595. return $result;
  596. }
  597. /**
  598. * Get the paginated query results as a Paginator instance.
  599. *
  600. * @param int $per_page
  601. * @param array $columns
  602. * @return Paginator
  603. */
  604. public function paginate($per_page = 20, $columns = array('*'))
  605. {
  606. // Because some database engines may throw errors if we leave orderings
  607. // on the query when retrieving the total number of records, we'll drop
  608. // all of the ordreings and put them back on the query.
  609. list($orderings, $this->orderings) = array($this->orderings, null);
  610. $total = $this->count(reset($columns));
  611. $page = Paginator::page($total, $per_page);
  612. $this->orderings = $orderings;
  613. // Now we're ready to get the actual pagination results from the table
  614. // using the for_page and get methods. The "for_page" method provides
  615. // a convenient way to set the paging limit and offset.
  616. $results = $this->for_page($page, $per_page)->get($columns);
  617. return Paginator::make($results, $total, $per_page);
  618. }
  619. /**
  620. * Insert an array of values into the database table.
  621. *
  622. * @param array $values
  623. * @return bool
  624. */
  625. public function insert($values)
  626. {
  627. // Force every insert to be treated like a batch insert to make creating
  628. // the binding array simpler since we can just spin through the inserted
  629. // rows as if there/ was more than one every time.
  630. if ( ! is_array(reset($values))) $values = array($values);
  631. $bindings = array();
  632. // We need to merge the the insert values into the array of the query
  633. // bindings so that they will be bound to the PDO statement when it
  634. // is executed by the database connection.
  635. foreach ($values as $value)
  636. {
  637. $bindings = array_merge($bindings, array_values($value));
  638. }
  639. $sql = $this->grammar->insert($this, $values);
  640. return $this->connection->query($sql, $bindings);
  641. }
  642. /**
  643. * Insert an array of values into the database table and return the ID.
  644. *
  645. * @param array $values
  646. * @param string $column
  647. * @return int
  648. */
  649. public function insert_get_id($values, $column = 'id')
  650. {
  651. $sql = $this->grammar->insert_get_id($this, $values, $column);
  652. $result = $this->connection->query($sql, array_values($values));
  653. if ($this->grammar instanceof Postgres)
  654. {
  655. return (int) $result[0]->$column;
  656. }
  657. else
  658. {
  659. return (int) $this->connection->pdo->lastInsertId();
  660. }
  661. }
  662. /**
  663. * Increment the value of a column by a given amount.
  664. *
  665. * @param string $column
  666. * @param int $amount
  667. * @return int
  668. */
  669. public function increment($column, $amount = 1)
  670. {
  671. return $this->adjust($column, $amount, ' + ');
  672. }
  673. /**
  674. * Decrement the value of a column by a given amount.
  675. *
  676. * @param string $column
  677. * @param int $amount
  678. * @return int
  679. */
  680. public function decrement($column, $amount = 1)
  681. {
  682. return $this->adjust($column, $amount, ' - ');
  683. }
  684. /**
  685. * Adjust the value of a column up or down by a given amount.
  686. *
  687. * @param string $column
  688. * @param int $amount
  689. * @param string $operator
  690. * @return int
  691. */
  692. protected function adjust($column, $amount, $operator)
  693. {
  694. $wrapped = $this->grammar->wrap($column);
  695. // To make the adjustment to the column, we'll wrap the expression in an
  696. // Expression instance, which forces the adjustment to be injected into
  697. // the query as a string instead of bound.
  698. $value = Database::raw($wrapped.$operator.$amount);
  699. return $this->update(array($column => $value));
  700. }
  701. /**
  702. * Update an array of values in the database table.
  703. *
  704. * @param array $values
  705. * @return int
  706. */
  707. public function update($values)
  708. {
  709. // For update statements, we need to merge the bindings such that the update
  710. // values occur before the where bindings in the array since the sets will
  711. // precede any of the where clauses in the SQL syntax that is generated.
  712. $bindings = array_merge(array_values($values), $this->bindings);
  713. $sql = $this->grammar->update($this, $values);
  714. return $this->connection->query($sql, $bindings);
  715. }
  716. /**
  717. * Execute the query as a DELETE statement.
  718. *
  719. * Optionally, an ID may be passed to the method do delete a specific row.
  720. *
  721. * @param int $id
  722. * @return int
  723. */
  724. public function delete($id = null)
  725. {
  726. // If an ID is given to the method, we'll set the where clause to
  727. // match on the value of the ID. This allows the developer to
  728. // quickly delete a row by its primary key value.
  729. if ( ! is_null($id))
  730. {
  731. $this->where('id', '=', $id);
  732. }
  733. $sql = $this->grammar->delete($this);
  734. return $this->connection->query($sql, $this->bindings);
  735. }
  736. /**
  737. * Magic Method for handling dynamic functions.
  738. *
  739. * This method handles calls to aggregates as well as dynamic where clauses.
  740. */
  741. public function __call($method, $parameters)
  742. {
  743. if (strpos($method, 'where_') === 0)
  744. {
  745. return $this->dynamic_where($method, $parameters, $this);
  746. }
  747. // All of the aggregate methods are handled by a single method, so we'll
  748. // catch them all here and then pass them off to the agregate method
  749. // instead of creating methods for each one of them.
  750. if (in_array($method, array('count', 'min', 'max', 'avg', 'sum')))
  751. {
  752. if (count($parameters) == 0) $parameters[0] = '*';
  753. return $this->aggregate(strtoupper($method), (array) $parameters[0]);
  754. }
  755. throw new \Exception("Method [$method] is not defined on the Query class.");
  756. }
  757. }