query.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867
  1. <?php namespace Laravel\Database;
  2. use Closure;
  3. use Laravel\Database;
  4. use 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 = is_array($columns) ? $columns : 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 developer.
  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 nested constraints 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. call_user_func($callback, $this);
  355. return $this;
  356. }
  357. /**
  358. * Add dynamic where conditions to the query.
  359. *
  360. * @param string $method
  361. * @param array $parameters
  362. * @return Query
  363. */
  364. private function dynamic_where($method, $parameters)
  365. {
  366. $finder = substr($method, 6);
  367. $flags = PREG_SPLIT_DELIM_CAPTURE;
  368. $segments = preg_split('/(_and_|_or_)/i', $finder, -1, $flags);
  369. // The connector variable will determine which connector will be used
  370. // for the condition. We'll change it as we come across new boolean
  371. // connectors in the dynamic method string.
  372. //
  373. // The index variable helps us get the correct parameter value for
  374. // the where condition. We increment it each time we add another
  375. // condition to the query's where clause.
  376. $connector = 'AND';
  377. $index = 0;
  378. foreach ($segments as $segment)
  379. {
  380. // If the segment is not a boolean connector, we can assume it is
  381. // a column name, and we'll add it to the query as a new constraint
  382. // of the query's where clause and keep iterating the segments.
  383. if ($segment != '_and_' and $segment != '_or_')
  384. {
  385. $this->where($segment, '=', $parameters[$index], $connector);
  386. $index++;
  387. }
  388. // Otherwise, we will store the connector so we know how the next
  389. // where clause we find in the query should be connected to the
  390. // previous one and will add it when we find the next one.
  391. else
  392. {
  393. $connector = trim(strtoupper($segment), '_');
  394. }
  395. }
  396. return $this;
  397. }
  398. /**
  399. * Add a grouping to the query.
  400. *
  401. * @param string $column
  402. * @return Query
  403. */
  404. public function group_by($column)
  405. {
  406. $this->groupings[] = $column;
  407. return $this;
  408. }
  409. /**
  410. * Add a having to the query.
  411. *
  412. * @param string $column
  413. * @param string $operator
  414. * @param mixed $value
  415. */
  416. public function having($column, $operator, $value)
  417. {
  418. $this->havings[] = compact('column', 'operator', 'value');
  419. $this->bindings[] = $value;
  420. return $this;
  421. }
  422. /**
  423. * Add an ordering to the query.
  424. *
  425. * @param string $column
  426. * @param string $direction
  427. * @return Query
  428. */
  429. public function order_by($column, $direction = 'asc')
  430. {
  431. $this->orderings[] = compact('column', 'direction');
  432. return $this;
  433. }
  434. /**
  435. * Set the query offset.
  436. *
  437. * @param int $value
  438. * @return Query
  439. */
  440. public function skip($value)
  441. {
  442. $this->offset = $value;
  443. return $this;
  444. }
  445. /**
  446. * Set the query limit.
  447. *
  448. * @param int $value
  449. * @return Query
  450. */
  451. public function take($value)
  452. {
  453. $this->limit = $value;
  454. return $this;
  455. }
  456. /**
  457. * Set the query limit and offset for a given page.
  458. *
  459. * @param int $page
  460. * @param int $per_page
  461. * @return Query
  462. */
  463. public function for_page($page, $per_page)
  464. {
  465. return $this->skip(($page - 1) * $per_page)->take($per_page);
  466. }
  467. /**
  468. * Find a record by the primary key.
  469. *
  470. * @param int $id
  471. * @param array $columns
  472. * @return object
  473. */
  474. public function find($id, $columns = array('*'))
  475. {
  476. return $this->where('id', '=', $id)->first($columns);
  477. }
  478. /**
  479. * Execute the query as a SELECT statement and return a single column.
  480. *
  481. * @param string $column
  482. * @return mixed
  483. */
  484. public function only($column)
  485. {
  486. $sql = $this->grammar->select($this->select(array($column)));
  487. return $this->connection->only($sql, $this->bindings);
  488. }
  489. /**
  490. * Execute the query as a SELECT statement and return the first result.
  491. *
  492. * @param array $columns
  493. * @return mixed
  494. */
  495. public function first($columns = array('*'))
  496. {
  497. $columns = (array) $columns;
  498. // Since we only need the first result, we'll go ahead and set the
  499. // limit clause to 1, since this will be much faster than getting
  500. // all of the rows and then only returning the first.
  501. $results = $this->take(1)->get($columns);
  502. return (count($results) > 0) ? $results[0] : null;
  503. }
  504. /**
  505. * Get an array with the values of a given column.
  506. *
  507. * @param string $column
  508. * @param string $key
  509. * @return array
  510. */
  511. public function lists($column, $key = null)
  512. {
  513. $columns = (is_null($key)) ? array($column) : array($column, $key);
  514. $results = $this->get($columns);
  515. // First we will get the array of values for the requested column.
  516. // Of course, this array will simply have numeric keys. After we
  517. // have this array we will determine if we need to key the array
  518. // by another column from the result set.
  519. $values = array_map(function($row) use ($column)
  520. {
  521. return $row->$column;
  522. }, $results);
  523. // If a key was provided, we will extract an array of keys and
  524. // set the keys on the array of values using the array_combine
  525. // function provided by PHP, which should give us the proper
  526. // array form to return from the method.
  527. if ( ! is_null($key))
  528. {
  529. return array_combine(array_map(function($row) use ($key)
  530. {
  531. return $row->$key;
  532. }, $results), $values);
  533. }
  534. return $values;
  535. }
  536. /**
  537. * Execute the query as a SELECT statement.
  538. *
  539. * @param array $columns
  540. * @return array
  541. */
  542. public function get($columns = array('*'))
  543. {
  544. if (is_null($this->selects)) $this->select($columns);
  545. $sql = $this->grammar->select($this);
  546. $results = $this->connection->query($sql, $this->bindings);
  547. // If the query has an offset and we are using the SQL Server grammar,
  548. // we need to spin through the results and remove the "rownum" from
  549. // each of the objects since there is no "offset".
  550. if ($this->offset > 0 and $this->grammar instanceof SQLServer)
  551. {
  552. array_walk($results, function($result)
  553. {
  554. unset($result->rownum);
  555. });
  556. }
  557. // Reset the SELECT clause so more queries can be performed using
  558. // the same instance. This is helpful for getting aggregates and
  559. // then getting actual results from the query.
  560. $this->selects = null;
  561. return $results;
  562. }
  563. /**
  564. * Get an aggregate value.
  565. *
  566. * @param string $aggregator
  567. * @param array $columns
  568. * @return mixed
  569. */
  570. public function aggregate($aggregator, $columns)
  571. {
  572. // We'll set the aggregate value so the grammar does not try to compile
  573. // a SELECT clause on the query. If an aggregator is present, its own
  574. // grammar function will be used to build the SQL syntax.
  575. $this->aggregate = compact('aggregator', 'columns');
  576. $sql = $this->grammar->select($this);
  577. $result = $this->connection->only($sql, $this->bindings);
  578. // Reset the aggregate so more queries can be performed using the same
  579. // instance. This is helpful for getting aggregates and then getting
  580. // actual results from the query such as during paging.
  581. $this->aggregate = null;
  582. return $result;
  583. }
  584. /**
  585. * Get the paginated query results as a Paginator instance.
  586. *
  587. * @param int $per_page
  588. * @param array $columns
  589. * @return Paginator
  590. */
  591. public function paginate($per_page = 20, $columns = array('*'))
  592. {
  593. // Because some database engines may throw errors if we leave orderings
  594. // on the query when retrieving the total number of records, we'll drop
  595. // all of the orderings and put them back on the query.
  596. list($orderings, $this->orderings) = array($this->orderings, null);
  597. $total = $this->count(reset($columns));
  598. $page = Paginator::page($total, $per_page);
  599. $this->orderings = $orderings;
  600. // Now we're ready to get the actual pagination results from the table
  601. // using the for_page and get methods. The "for_page" method provides
  602. // a convenient way to set the paging limit and offset.
  603. $results = $this->for_page($page, $per_page)->get($columns);
  604. return Paginator::make($results, $total, $per_page);
  605. }
  606. /**
  607. * Insert an array of values into the database table.
  608. *
  609. * @param array $values
  610. * @return bool
  611. */
  612. public function insert($values)
  613. {
  614. // Force every insert to be treated like a batch insert to make creating
  615. // the binding array simpler since we can just spin through the inserted
  616. // rows as if there was more than one every time.
  617. if ( ! is_array(reset($values))) $values = array($values);
  618. $bindings = array();
  619. // We need to merge the insert values into the array of the query
  620. // bindings so that they will be bound to the PDO statement when it
  621. // is executed by the database connection.
  622. foreach ($values as $value)
  623. {
  624. $bindings = array_merge($bindings, array_values($value));
  625. }
  626. $sql = $this->grammar->insert($this, $values);
  627. return $this->connection->query($sql, $bindings);
  628. }
  629. /**
  630. * Insert an array of values into the database table and return the ID.
  631. *
  632. * @param array $values
  633. * @param string $column
  634. * @return int
  635. */
  636. public function insert_get_id($values, $column = 'id')
  637. {
  638. $sql = $this->grammar->insert_get_id($this, $values, $column);
  639. $result = $this->connection->query($sql, array_values($values));
  640. if ($this->grammar instanceof Postgres)
  641. {
  642. return (int) $result[0]->$column;
  643. }
  644. else
  645. {
  646. return (int) $this->connection->pdo->lastInsertId();
  647. }
  648. }
  649. /**
  650. * Increment the value of a column by a given amount.
  651. *
  652. * @param string $column
  653. * @param int $amount
  654. * @return int
  655. */
  656. public function increment($column, $amount = 1)
  657. {
  658. return $this->adjust($column, $amount, ' + ');
  659. }
  660. /**
  661. * Decrement the value of a column by a given amount.
  662. *
  663. * @param string $column
  664. * @param int $amount
  665. * @return int
  666. */
  667. public function decrement($column, $amount = 1)
  668. {
  669. return $this->adjust($column, $amount, ' - ');
  670. }
  671. /**
  672. * Adjust the value of a column up or down by a given amount.
  673. *
  674. * @param string $column
  675. * @param int $amount
  676. * @param string $operator
  677. * @return int
  678. */
  679. protected function adjust($column, $amount, $operator)
  680. {
  681. $wrapped = $this->grammar->wrap($column);
  682. // To make the adjustment to the column, we'll wrap the expression in an
  683. // Expression instance, which forces the adjustment to be injected into
  684. // the query as a string instead of bound.
  685. $value = Database::raw($wrapped.$operator.$amount);
  686. return $this->update(array($column => $value));
  687. }
  688. /**
  689. * Update an array of values in the database table.
  690. *
  691. * @param array $values
  692. * @return int
  693. */
  694. public function update($values)
  695. {
  696. // For update statements, we need to merge the bindings such that the update
  697. // values occur before the where bindings in the array since the sets will
  698. // precede any of the where clauses in the SQL syntax that is generated.
  699. $bindings = array_merge(array_values($values), $this->bindings);
  700. $sql = $this->grammar->update($this, $values);
  701. return $this->connection->query($sql, $bindings);
  702. }
  703. /**
  704. * Execute the query as a DELETE statement.
  705. *
  706. * Optionally, an ID may be passed to the method to delete a specific row.
  707. *
  708. * @param int $id
  709. * @return int
  710. */
  711. public function delete($id = null)
  712. {
  713. // If an ID is given to the method, we'll set the where clause to
  714. // match on the value of the ID. This allows the developer to
  715. // quickly delete a row by its primary key value.
  716. if ( ! is_null($id))
  717. {
  718. $this->where('id', '=', $id);
  719. }
  720. $sql = $this->grammar->delete($this);
  721. return $this->connection->query($sql, $this->bindings);
  722. }
  723. /**
  724. * Magic Method for handling dynamic functions.
  725. *
  726. * This method handles calls to aggregates as well as dynamic where clauses.
  727. */
  728. public function __call($method, $parameters)
  729. {
  730. if (strpos($method, 'where_') === 0)
  731. {
  732. return $this->dynamic_where($method, $parameters, $this);
  733. }
  734. // All of the aggregate methods are handled by a single method, so we'll
  735. // catch them all here and then pass them off to the aggregate method
  736. // instead of creating methods for each one of them.
  737. if (in_array($method, array('count', 'min', 'max', 'avg', 'sum')))
  738. {
  739. if (count($parameters) == 0) $parameters[0] = '*';
  740. return $this->aggregate(strtoupper($method), (array) $parameters[0]);
  741. }
  742. throw new \Exception("Method [$method] is not defined on the Query class.");
  743. }
  744. }