query.php 20 KB

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