PageRenderTime 60ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Illuminate/Database/Query/Builder.php

https://github.com/jstesta/framework
PHP | 1566 lines | 574 code | 230 blank | 762 comment | 24 complexity | 605dac680d24f3b911341f1f6531a2d3 MD5 | raw file
  1. <?php namespace Illuminate\Database\Query;
  2. use Closure;
  3. use Illuminate\Support\Collection;
  4. use Illuminate\Database\ConnectionInterface;
  5. use Illuminate\Database\Query\Grammars\Grammar;
  6. use Illuminate\Database\Query\Processors\Processor;
  7. class Builder {
  8. /**
  9. * The database connection instance.
  10. *
  11. * @var \Illuminate\Database\Connection
  12. */
  13. protected $connection;
  14. /**
  15. * The database query grammar instance.
  16. *
  17. * @var \Illuminate\Database\Query\Grammars\Grammar
  18. */
  19. protected $grammar;
  20. /**
  21. * The database query post processor instance.
  22. *
  23. * @var \Illuminate\Database\Query\Processors\Processor
  24. */
  25. protected $processor;
  26. /**
  27. * The current query value bindings.
  28. *
  29. * @var array
  30. */
  31. protected $bindings = array();
  32. /**
  33. * An aggregate function and column to be run.
  34. *
  35. * @var array
  36. */
  37. public $aggregate;
  38. /**
  39. * The columns that should be returned.
  40. *
  41. * @var array
  42. */
  43. public $columns;
  44. /**
  45. * Indicates if the query returns distinct results.
  46. *
  47. * @var bool
  48. */
  49. public $distinct = false;
  50. /**
  51. * The table which the query is targeting.
  52. *
  53. * @var string
  54. */
  55. public $from;
  56. /**
  57. * The table joins for the query.
  58. *
  59. * @var array
  60. */
  61. public $joins;
  62. /**
  63. * The where constraints for the query.
  64. *
  65. * @var array
  66. */
  67. public $wheres;
  68. /**
  69. * The groupings for the query.
  70. *
  71. * @var array
  72. */
  73. public $groups;
  74. /**
  75. * The having constraints for the query.
  76. *
  77. * @var array
  78. */
  79. public $havings;
  80. /**
  81. * The orderings for the query.
  82. *
  83. * @var array
  84. */
  85. public $orders;
  86. /**
  87. * The maximum number of records to return.
  88. *
  89. * @var int
  90. */
  91. public $limit;
  92. /**
  93. * The number of records to skip.
  94. *
  95. * @var int
  96. */
  97. public $offset;
  98. /**
  99. * The query union statements.
  100. *
  101. * @var array
  102. */
  103. public $unions;
  104. /**
  105. * The key that should be used when caching the query.
  106. *
  107. * @var string
  108. */
  109. protected $cacheKey;
  110. /**
  111. * The number of minutes to cache the query.
  112. *
  113. * @var int
  114. */
  115. protected $cacheMinutes;
  116. /**
  117. * All of the available clause operators.
  118. *
  119. * @var array
  120. */
  121. protected $operators = array(
  122. '=', '<', '>', '<=', '>=', '<>', '!=',
  123. 'like', 'not like', 'between', 'ilike',
  124. );
  125. /**
  126. * Create a new query builder instance.
  127. *
  128. * @param \Illuminate\Database\ConnectionInterface $connection
  129. * @param \Illuminate\Database\Query\Grammars\Grammar $grammar
  130. * @param \Illuminate\Database\Query\Processors\Processor $processor
  131. * @return void
  132. */
  133. public function __construct(ConnectionInterface $connection,
  134. Grammar $grammar,
  135. Processor $processor)
  136. {
  137. $this->grammar = $grammar;
  138. $this->processor = $processor;
  139. $this->connection = $connection;
  140. }
  141. /**
  142. * Set the columns to be selected.
  143. *
  144. * @param array $columns
  145. * @return \Illuminate\Database\Query\Builder
  146. */
  147. public function select($columns = array('*'))
  148. {
  149. $this->columns = is_array($columns) ? $columns : func_get_args();
  150. return $this;
  151. }
  152. /**
  153. * Add a new select column to the query.
  154. *
  155. * @param mixed $column
  156. * @return \Illuminate\Database\Query\Builder
  157. */
  158. public function addSelect($column)
  159. {
  160. $column = is_array($column) ? $column : func_get_args();
  161. $this->columns = array_merge((array) $this->columns, $column);
  162. return $this;
  163. }
  164. /**
  165. * Force the query to only return distinct results.
  166. *
  167. * @return \Illuminate\Database\Query\Builder
  168. */
  169. public function distinct()
  170. {
  171. $this->distinct = true;
  172. return $this;
  173. }
  174. /**
  175. * Set the table which the query is targeting.
  176. *
  177. * @param string $table
  178. * @return \Illuminate\Database\Query\Builder
  179. */
  180. public function from($table)
  181. {
  182. $this->from = $table;
  183. return $this;
  184. }
  185. /**
  186. * Add a join clause to the query.
  187. *
  188. * @param string $table
  189. * @param string $first
  190. * @param string $operator
  191. * @param string $second
  192. * @param string $type
  193. * @return \Illuminate\Database\Query\Builder
  194. */
  195. public function join($table, $first, $operator = null, $second = null, $type = 'inner')
  196. {
  197. // If the first "column" of the join is really a Closure instance the developer
  198. // is trying to build a join with a complex "on" clause containing more than
  199. // one condition, so we'll add the join and call a Closure with the query.
  200. if ($first instanceof Closure)
  201. {
  202. $this->joins[] = new JoinClause($type, $table);
  203. call_user_func($first, end($this->joins));
  204. }
  205. // If the column is simply a string, we can assume the join simply has a basic
  206. // "on" clause with a single condition. So we will just build the join with
  207. // this simple join clauses attached to it. There is not a join callback.
  208. else
  209. {
  210. $join = new JoinClause($type, $table);
  211. $join->on($first, $operator, $second);
  212. $this->joins[] = $join;
  213. }
  214. return $this;
  215. }
  216. /**
  217. * Add a left join to the query.
  218. *
  219. * @param string $table
  220. * @param string $first
  221. * @param string $operator
  222. * @param string $second
  223. * @return \Illuminate\Database\Query\Builder
  224. */
  225. public function leftJoin($table, $first, $operator = null, $second = null)
  226. {
  227. return $this->join($table, $first, $operator, $second, 'left');
  228. }
  229. /**
  230. * Add a basic where clause to the query.
  231. *
  232. * @param string $column
  233. * @param string $operator
  234. * @param mixed $value
  235. * @param string $boolean
  236. * @return \Illuminate\Database\Query\Builder
  237. */
  238. public function where($column, $operator = null, $value = null, $boolean = 'and')
  239. {
  240. // If the columns is actually a Closure instance, we will assume the developer
  241. // wants to begin a nested where statement which is wrapped in parenthesis.
  242. // We'll add that Closure to the query then return back out immediately.
  243. if ($column instanceof Closure)
  244. {
  245. return $this->whereNested($column, $boolean);
  246. }
  247. // If the given operator is not found in the list of valid operators we will
  248. // assume that the developer is just short-cutting the '=' operators and
  249. // we will set the operators to '=' and set the values appropriately.
  250. if ( ! in_array(strtolower($operator), $this->operators, true))
  251. {
  252. list($value, $operator) = array($operator, '=');
  253. }
  254. // If the value is a Closure, it means the developer is performing an entire
  255. // sub-select within the query and we will need to compile the sub-select
  256. // within the where clause to get the appropriate query record results.
  257. if ($value instanceof Closure)
  258. {
  259. return $this->whereSub($column, $operator, $value, $boolean);
  260. }
  261. // If the value is "null", we will just assume the developer wants to add a
  262. // where null clause to the query. So, we will allow a short-cut here to
  263. // that method for convenience so the developer doesn't have to check.
  264. if (is_null($value))
  265. {
  266. return $this->whereNull($column, $boolean, $operator != '=');
  267. }
  268. // Now that we are working with just a simple query we can put the elements
  269. // in our array and add the query binding to our array of bindings that
  270. // will be bound to each SQL statements when it is finally executed.
  271. $type = 'Basic';
  272. $this->wheres[] = compact('type', 'column', 'operator', 'value', 'boolean');
  273. if ( ! $value instanceof Expression)
  274. {
  275. $this->bindings[] = $value;
  276. }
  277. return $this;
  278. }
  279. /**
  280. * Add an "or where" clause to the query.
  281. *
  282. * @param string $column
  283. * @param string $operator
  284. * @param mixed $value
  285. * @return \Illuminate\Database\Query\Builder
  286. */
  287. public function orWhere($column, $operator = null, $value = null)
  288. {
  289. return $this->where($column, $operator, $value, 'or');
  290. }
  291. /**
  292. * Add a raw where clause to the query.
  293. *
  294. * @param string $sql
  295. * @param array $bindings
  296. * @param string $boolean
  297. * @return \Illuminate\Database\Query\Builder
  298. */
  299. public function whereRaw($sql, array $bindings = array(), $boolean = 'and')
  300. {
  301. $type = 'raw';
  302. $this->wheres[] = compact('type', 'sql', 'boolean');
  303. $this->bindings = array_merge($this->bindings, $bindings);
  304. return $this;
  305. }
  306. /**
  307. * Add a raw or where clause to the query.
  308. *
  309. * @param string $sql
  310. * @param array $bindings
  311. * @return \Illuminate\Database\Query\Builder
  312. */
  313. public function orWhereRaw($sql, array $bindings = array())
  314. {
  315. return $this->whereRaw($sql, $bindings, 'or');
  316. }
  317. /**
  318. * Add a where between statement to the query.
  319. *
  320. * @param string $column
  321. * @param array $values
  322. * @param string $boolean
  323. * @return \Illuminate\Database\Query\Builder
  324. */
  325. public function whereBetween($column, array $values, $boolean = 'and')
  326. {
  327. $type = 'between';
  328. $this->wheres[] = compact('column', 'type', 'boolean');
  329. $this->bindings = array_merge($this->bindings, $values);
  330. return $this;
  331. }
  332. /**
  333. * Add an or where between statement to the query.
  334. *
  335. * @param string $column
  336. * @param array $values
  337. * @return \Illuminate\Database\Query\Builder
  338. */
  339. public function orWhereBetween($column, array $values)
  340. {
  341. return $this->whereBetween($column, $values, 'or');
  342. }
  343. /**
  344. * Add a nested where statement to the query.
  345. *
  346. * @param Closure $callback
  347. * @param string $boolean
  348. * @return \Illuminate\Database\Query\Builder
  349. */
  350. public function whereNested(Closure $callback, $boolean = 'and')
  351. {
  352. // To handle nested queries we'll actually create a brand new query instance
  353. // and pass it off to the Closure that we have. The Closure can simply do
  354. // do whatever it wants to a query then we will store it for compiling.
  355. $type = 'Nested';
  356. $query = $this->newQuery();
  357. $query->from($this->from);
  358. call_user_func($callback, $query);
  359. // Once we have let the Closure do its things, we can gather the bindings on
  360. // the nested query builder and merge them into these bindings since they
  361. // need to get extracted out of the children and assigned to the array.
  362. if (count($query->wheres))
  363. {
  364. $this->wheres[] = compact('type', 'query', 'boolean');
  365. $this->mergeBindings($query);
  366. }
  367. return $this;
  368. }
  369. /**
  370. * Add a full sub-select to the query.
  371. *
  372. * @param string $column
  373. * @param string $operator
  374. * @param Closure $callback
  375. * @param string $boolean
  376. * @return \Illuminate\Database\Query\Builder
  377. */
  378. protected function whereSub($column, $operator, Closure $callback, $boolean)
  379. {
  380. $type = 'Sub';
  381. $query = $this->newQuery();
  382. // Once we have the query instance we can simply execute it so it can add all
  383. // of the sub-select's conditions to itself, and then we can cache it off
  384. // in the array of where clauses for the "main" parent query instance.
  385. call_user_func($callback, $query);
  386. $this->wheres[] = compact('type', 'column', 'operator', 'query', 'boolean');
  387. $this->mergeBindings($query);
  388. return $this;
  389. }
  390. /**
  391. * Add an exists clause to the query.
  392. *
  393. * @param Closure $callback
  394. * @param string $boolean
  395. * @param bool $not
  396. * @return \Illuminate\Database\Query\Builder
  397. */
  398. public function whereExists(Closure $callback, $boolean = 'and', $not = false)
  399. {
  400. $type = $not ? 'NotExists' : 'Exists';
  401. $query = $this->newQuery();
  402. // Similar to the sub-select clause, we will create a new query instance so
  403. // the developer may cleanly specify the entire exists query and we will
  404. // compile the whole thing in the grammar and insert it into the SQL.
  405. call_user_func($callback, $query);
  406. $this->wheres[] = compact('type', 'operator', 'query', 'boolean');
  407. $this->mergeBindings($query);
  408. return $this;
  409. }
  410. /**
  411. * Add an or exists clause to the query.
  412. *
  413. * @param Closure $callback
  414. * @param bool $not
  415. * @return \Illuminate\Database\Query\Builder
  416. */
  417. public function orWhereExists(Closure $callback, $not = false)
  418. {
  419. return $this->whereExists($callback, 'or', $not);
  420. }
  421. /**
  422. * Add a where not exists clause to the query.
  423. *
  424. * @param Closure $calback
  425. * @param string $boolean
  426. * @return \Illuminate\Database\Query\Builder
  427. */
  428. public function whereNotExists(Closure $callback, $boolean = 'and')
  429. {
  430. return $this->whereExists($callback, $boolean, true);
  431. }
  432. /**
  433. * Add a where not exists clause to the query.
  434. *
  435. * @param Closure $calback
  436. * @return \Illuminate\Database\Query\Builder
  437. */
  438. public function orWhereNotExists(Closure $callback)
  439. {
  440. return $this->orWhereExists($callback, true);
  441. }
  442. /**
  443. * Add a "where in" clause to the query.
  444. *
  445. * @param string $column
  446. * @param mixed $values
  447. * @param string $boolean
  448. * @param bool $not
  449. * @return \Illuminate\Database\Query\Builder
  450. */
  451. public function whereIn($column, $values, $boolean = 'and', $not = false)
  452. {
  453. $type = $not ? 'NotIn' : 'In';
  454. // If the value of the where in clause is actually a Closure, we will assume that
  455. // the developer is using a full sub-select for this "in" statement, and will
  456. // execute those Closures, then we can re-construct the entire sub-selects.
  457. if ($values instanceof Closure)
  458. {
  459. return $this->whereInSub($column, $values, $boolean, $not);
  460. }
  461. $this->wheres[] = compact('type', 'column', 'values', 'boolean');
  462. $this->bindings = array_merge($this->bindings, $values);
  463. return $this;
  464. }
  465. /**
  466. * Add an "or where in" clause to the query.
  467. *
  468. * @param string $column
  469. * @param mixed $values
  470. * @return \Illuminate\Database\Query\Builder
  471. */
  472. public function orWhereIn($column, $values)
  473. {
  474. return $this->whereIn($column, $values, 'or');
  475. }
  476. /**
  477. * Add a "where not in" clause to the query.
  478. *
  479. * @param string $column
  480. * @param mixed $values
  481. * @param string $boolean
  482. * @return \Illuminate\Database\Query\Builder
  483. */
  484. public function whereNotIn($column, $values, $boolean = 'and')
  485. {
  486. return $this->whereIn($column, $values, $boolean, true);
  487. }
  488. /**
  489. * Add an "or where not in" clause to the query.
  490. *
  491. * @param string $column
  492. * @param mixed $values
  493. * @return \Illuminate\Database\Query\Builder
  494. */
  495. public function orWhereNotIn($column, $values)
  496. {
  497. return $this->whereNotIn($column, $values, 'or');
  498. }
  499. /**
  500. * Add a where in with a sub-select to the query.
  501. *
  502. * @param string $column
  503. * @param Closure $callback
  504. * @param string $boolean
  505. * @param bool $not
  506. * @return \Illuminate\Database\Query\Builder
  507. */
  508. protected function whereInSub($column, Closure $callback, $boolean, $not)
  509. {
  510. $type = $not ? 'NotInSub' : 'InSub';
  511. // To create the exists sub-select, we will actually create a query and call the
  512. // provided callback with the query so the developer may set any of the query
  513. // conditions they want for the in clause, then we'll put it in this array.
  514. call_user_func($callback, $query = $this->newQuery());
  515. $this->wheres[] = compact('type', 'column', 'query', 'boolean');
  516. $this->mergeBindings($query);
  517. return $this;
  518. }
  519. /**
  520. * Add a "where null" clause to the query.
  521. *
  522. * @param string $column
  523. * @param string $boolean
  524. * @param bool $not
  525. * @return \Illuminate\Database\Query\Builder
  526. */
  527. public function whereNull($column, $boolean = 'and', $not = false)
  528. {
  529. $type = $not ? 'NotNull' : 'Null';
  530. $this->wheres[] = compact('type', 'column', 'boolean');
  531. return $this;
  532. }
  533. /**
  534. * Add an "or where null" clause to the query.
  535. *
  536. * @param string $column
  537. * @return \Illuminate\Database\Query\Builder
  538. */
  539. public function orWhereNull($column)
  540. {
  541. return $this->whereNull($column, 'or');
  542. }
  543. /**
  544. * Add a "where not null" clause to the query.
  545. *
  546. * @param string $column
  547. * @param string $boolean
  548. * @return \Illuminate\Database\Query\Builder
  549. */
  550. public function whereNotNull($column, $boolean = 'and')
  551. {
  552. return $this->whereNull($column, $boolean, true);
  553. }
  554. /**
  555. * Add an "or where not null" clause to the query.
  556. *
  557. * @param string $column
  558. * @return \Illuminate\Database\Query\Builder
  559. */
  560. public function orWhereNotNull($column)
  561. {
  562. return $this->whereNotNull($column, 'or');
  563. }
  564. /**
  565. * Handles dynamic "where" clauses to the query.
  566. *
  567. * @param string $method
  568. * @param string $parameters
  569. * @return \Illuminate\Database\Query\Builder
  570. */
  571. public function dynamicWhere($method, $parameters)
  572. {
  573. $finder = substr($method, 5);
  574. $segments = preg_split('/(And|Or)(?=[A-Z])/', $finder, -1, PREG_SPLIT_DELIM_CAPTURE);
  575. // The connector variable will determine which connector will be used for the
  576. // query condition. We will change it as we come across new boolean values
  577. // in the dynamic method strings, which could contain a number of these.
  578. $connector = 'and';
  579. $index = 0;
  580. foreach ($segments as $segment)
  581. {
  582. // If the segment is not a boolean connector, we can assume it is a column's name
  583. // and we will add it to the query as a new constraint as a where clause, then
  584. // we can keep iterating through the dynamic method string's segments again.
  585. if ($segment != 'And' and $segment != 'Or')
  586. {
  587. $this->addDynamic($segment, $connector, $parameters, $index);
  588. $index++;
  589. }
  590. // Otherwise, we will store the connector so we know how the next where clause we
  591. // find in the query should be connected to the previous ones, meaning we will
  592. // have the proper boolean connector to connect the next where clause found.
  593. else
  594. {
  595. $connector = $segment;
  596. }
  597. }
  598. return $this;
  599. }
  600. /**
  601. * Add a single dynamic where clause statement to the query.
  602. *
  603. * @param string $segment
  604. * @param string $connector
  605. * @param array $parameters
  606. * @param int $index
  607. * @return void
  608. */
  609. protected function addDynamic($segment, $connector, $parameters, $index)
  610. {
  611. // Once we have parsed out the columns and formatted the boolean operators we
  612. // are ready to add it to this query as a where clause just like any other
  613. // clause on the query. Then we'll increment the parameter index values.
  614. $bool = strtolower($connector);
  615. $this->where(snake_case($segment), '=', $parameters[$index], $bool);
  616. }
  617. /**
  618. * Add a "group by" clause to the query.
  619. *
  620. * @param dynamic $columns
  621. * @return \Illuminate\Database\Query\Builder
  622. */
  623. public function groupBy()
  624. {
  625. $this->groups = array_merge((array) $this->groups, func_get_args());
  626. return $this;
  627. }
  628. /**
  629. * Add a "having" clause to the query.
  630. *
  631. * @param string $column
  632. * @param string $operator
  633. * @param string $value
  634. * @return \Illuminate\Database\Query\Builder
  635. */
  636. public function having($column, $operator = null, $value = null)
  637. {
  638. $type = 'basic';
  639. $this->havings[] = compact('type', 'column', 'operator', 'value');
  640. $this->bindings[] = $value;
  641. return $this;
  642. }
  643. /**
  644. * Add a raw having clause to the query.
  645. *
  646. * @param string $sql
  647. * @param array $bindings
  648. * @param string $boolean
  649. * @return \Illuminate\Database\Query\Builder
  650. */
  651. public function havingRaw($sql, array $bindings = array(), $boolean = 'and')
  652. {
  653. $type = 'raw';
  654. $this->havings[] = compact('type', 'sql', 'boolean');
  655. $this->bindings = array_merge($this->bindings, $bindings);
  656. return $this;
  657. }
  658. /**
  659. * Add a raw or having clause to the query.
  660. *
  661. * @param string $sql
  662. * @param array $bindings
  663. * @return \Illuminate\Database\Query\Builder
  664. */
  665. public function orHavingRaw($sql, array $bindings = array())
  666. {
  667. return $this->havingRaw($sql, $bindings, 'or');
  668. }
  669. /**
  670. * Add an "order by" clause to the query.
  671. *
  672. * @param string $column
  673. * @param string $direction
  674. * @return \Illuminate\Database\Query\Builder
  675. */
  676. public function orderBy($column, $direction = 'asc')
  677. {
  678. $this->orders[] = compact('column', 'direction');
  679. return $this;
  680. }
  681. /**
  682. * Set the "offset" value of the query.
  683. *
  684. * @param int $value
  685. * @return \Illuminate\Database\Query\Builder
  686. */
  687. public function skip($value)
  688. {
  689. $this->offset = $value;
  690. return $this;
  691. }
  692. /**
  693. * Set the "limit" value of the query.
  694. *
  695. * @param int $value
  696. * @return \Illuminate\Database\Query\Builder
  697. */
  698. public function take($value)
  699. {
  700. if ($value > 0) $this->limit = $value;
  701. return $this;
  702. }
  703. /**
  704. * Set the limit and offset for a given page.
  705. *
  706. * @param int $page
  707. * @param int $perPage
  708. * @return \Illuminate\Database\Query\Builder
  709. */
  710. public function forPage($page, $perPage = 15)
  711. {
  712. return $this->skip(($page - 1) * $perPage)->take($perPage);
  713. }
  714. /**
  715. * Add a union statement to the query.
  716. *
  717. * @param \Illuminate\Database\Query\Builder|\Closure $query
  718. * @param bool $all
  719. * @return \Illuminate\Database\Query\Builder
  720. */
  721. public function union($query, $all = false)
  722. {
  723. if ($query instanceof Closure)
  724. {
  725. call_user_func($query, $query = $this->newQuery());
  726. }
  727. $this->unions[] = compact('query', 'all');
  728. return $this->mergeBindings($query);
  729. }
  730. /**
  731. * Add a union all statement to the query.
  732. *
  733. * @param \Illuminate\Database\Query\Builder|\Closure $query
  734. * @return \Illuminate\Database\Query\Builder
  735. */
  736. public function unionAll($query)
  737. {
  738. return $this->union($query, true);
  739. }
  740. /**
  741. * Get the SQL representation of the query.
  742. *
  743. * @return string
  744. */
  745. public function toSql()
  746. {
  747. return $this->grammar->compileSelect($this);
  748. }
  749. /**
  750. * Indicate that the query results should be cached.
  751. *
  752. * @param int $minutes
  753. * @param string $key
  754. * @return \Illuminate\Database\Query\Builder
  755. */
  756. public function remember($minutes, $key = null)
  757. {
  758. list($this->cacheMinutes, $this->cacheKey) = array($minutes, $key);
  759. return $this;
  760. }
  761. /**
  762. * Execute a query for a single record by ID.
  763. *
  764. * @param int $id
  765. * @param array $columns
  766. * @return mixed
  767. */
  768. public function find($id, $columns = array('*'))
  769. {
  770. return $this->where('id', '=', $id)->first($columns);
  771. }
  772. /**
  773. * Pluck a single column from the database.
  774. *
  775. * @param string $column
  776. * @return mixed
  777. */
  778. public function pluck($column)
  779. {
  780. $result = (array) $this->first(array($column));
  781. return count($result) > 0 ? reset($result) : null;
  782. }
  783. /**
  784. * Execute the query and get the first result.
  785. *
  786. * @param array $columns
  787. * @return mixed
  788. */
  789. public function first($columns = array('*'))
  790. {
  791. $results = $this->take(1)->get($columns);
  792. return count($results) > 0 ? reset($results) : null;
  793. }
  794. /**
  795. * Execute the query as a "select" statement.
  796. *
  797. * @param array $columns
  798. * @return array
  799. */
  800. public function get($columns = array('*'))
  801. {
  802. if ( ! is_null($this->cacheMinutes)) return $this->getCached($columns);
  803. return $this->getFresh($columns);
  804. }
  805. /**
  806. * Execute the query as a fresh "select" statement.
  807. *
  808. * @param array $columns
  809. * @return array
  810. */
  811. public function getFresh($columns = array('*'))
  812. {
  813. if (is_null($this->columns)) $this->columns = $columns;
  814. return $this->processor->processSelect($this, $this->runSelect());
  815. }
  816. /**
  817. * Run the query as a "select" statement against the connection.
  818. *
  819. * @return array
  820. */
  821. protected function runSelect()
  822. {
  823. return $this->connection->select($this->toSql(), $this->bindings);
  824. }
  825. /**
  826. * Execute the query as a cached "select" statement.
  827. *
  828. * @param array $columns
  829. * @return array
  830. */
  831. public function getCached($columns = array('*'))
  832. {
  833. list($key, $minutes) = $this->getCacheInfo();
  834. // If the query is requested ot be cached, we will cache it using a unique key
  835. // for this database connection and query statement, including the bindings
  836. // that are used on this query, providing great convenience when caching.
  837. $cache = $this->connection->getCacheManager();
  838. $callback = $this->getCacheCallback($columns);
  839. return $cache->remember($key, $minutes, $callback);
  840. }
  841. /**
  842. * Get the cache key and cache minutes as an array.
  843. *
  844. * @return array
  845. */
  846. protected function getCacheInfo()
  847. {
  848. return array($this->getCacheKey(), $this->cacheMinutes);
  849. }
  850. /**
  851. * Get a unique cache key for the complete query.
  852. *
  853. * @return string
  854. */
  855. public function getCacheKey()
  856. {
  857. return $this->cacheKey ?: $this->generateCacheKey();
  858. }
  859. /**
  860. * Generate the unique cache key for the query.
  861. *
  862. * @return string
  863. */
  864. public function generateCacheKey()
  865. {
  866. $name = $this->connection->getName();
  867. return md5($name.$this->toSql().serialize($this->bindings));
  868. }
  869. /**
  870. * Get the Closure callback used when caching queries.
  871. *
  872. * @param array $columns
  873. * @return \Closure
  874. */
  875. protected function getCacheCallback($columns)
  876. {
  877. $me = $this;
  878. return function() use ($me, $columns) { return $me->getFresh($columns); };
  879. }
  880. /**
  881. * Get an array with the values of a given column.
  882. *
  883. * @param string $column
  884. * @param string $key
  885. * @return array
  886. */
  887. public function lists($column, $key = null)
  888. {
  889. $columns = $this->getListSelect($column, $key);
  890. // First we will just get all of the column values for the record result set
  891. // then we can associate those values with the column if it was specified
  892. // otherwise we can just give these values back without a specific key.
  893. $results = new Collection($this->get($columns));
  894. $values = $results->fetch($columns[0])->all();
  895. // If a key was specified and we have results, we will go ahead and combine
  896. // the values with the keys of all of the records so that the values can
  897. // be accessed by the key of the rows instead of simply being numeric.
  898. if ( ! is_null($key) and count($results) > 0)
  899. {
  900. $keys = $results->fetch($key)->all();
  901. return array_combine($keys, $values);
  902. }
  903. return $values;
  904. }
  905. /**
  906. * Get the columns that should be used in a list array.
  907. *
  908. * @param string $column
  909. * @param string $key
  910. * @return array
  911. */
  912. protected function getListSelect($column, $key)
  913. {
  914. $select = is_null($key) ? array($column) : array($column, $key);
  915. // If the selected column contains a "dot", we will remove it so that the list
  916. // operation can run normally. Specifying the table is not needed, since we
  917. // really want the names of the columns as it is in this resulting array.
  918. if (($dot = strpos($select[0], '.')) !== false)
  919. {
  920. $select[0] = substr($select[0], $dot + 1);
  921. }
  922. return $select;
  923. }
  924. /**
  925. * Concatenate values of a given column as a string.
  926. *
  927. * @param string $column
  928. * @param string $glue
  929. * @return string
  930. */
  931. public function implode($column, $glue = null)
  932. {
  933. if (is_null($glue)) return implode($this->lists($column));
  934. return implode($glue, $this->lists($column));
  935. }
  936. /**
  937. * Get a paginator for the "select" statement.
  938. *
  939. * @param int $perPage
  940. * @param array $columns
  941. * @return \Illuminate\Pagination\Paginator
  942. */
  943. public function paginate($perPage = 15, $columns = array('*'))
  944. {
  945. $paginator = $this->connection->getPaginator();
  946. if (isset($this->groups))
  947. {
  948. return $this->groupedPaginate($paginator, $perPage, $columns);
  949. }
  950. else
  951. {
  952. return $this->ungroupedPaginate($paginator, $perPage, $columns);
  953. }
  954. }
  955. /**
  956. * Create a paginator for a grouped pagination statement.
  957. *
  958. * @param \Illuminate\Pagination\Environment $paginator
  959. * @param int $perPage
  960. * @param array $columns
  961. * @return \Illuminate\Pagination\Paginator
  962. */
  963. protected function groupedPaginate($paginator, $perPage, $columns)
  964. {
  965. $results = $this->get($columns);
  966. return $this->buildRawPaginator($paginator, $results, $perPage);
  967. }
  968. /**
  969. * Build a paginator instance from a raw result array.
  970. *
  971. * @param \Illuminate\Pagination\Environment $paginator
  972. * @param array $results
  973. * @param int $perPage
  974. * @return \Illuminate\Pagination\Paginator
  975. */
  976. public function buildRawPaginator($paginator, $results, $perPage)
  977. {
  978. // For queries which have a group by, we will actually retrieve the entire set
  979. // of rows from the table and "slice" them via PHP. This is inefficient and
  980. // the developer must be aware of this behavior; however, it's an option.
  981. $start = ($paginator->getCurrentPage() - 1) * $perPage;
  982. $sliced = array_slice($results, $start, $perPage);
  983. return $paginator->make($sliced, count($results), $perPage);
  984. }
  985. /**
  986. * Create a paginator for an un-grouped pagination statement.
  987. *
  988. * @param \Illuminate\Pagination\Environment $paginator
  989. * @param int $perPage
  990. * @param array $columns
  991. * @return \Illuminate\Pagination\Paginator
  992. */
  993. protected function ungroupedPaginate($paginator, $perPage, $columns)
  994. {
  995. $total = $this->getPaginationCount();
  996. // Once we have the total number of records to be paginated, we can grab the
  997. // current page and the result array. Then we are ready to create a brand
  998. // new Paginator instances for the results which will create the links.
  999. $page = $paginator->getCurrentPage();
  1000. $results = $this->forPage($page, $perPage)->get($columns);
  1001. return $paginator->make($results, $total, $perPage);
  1002. }
  1003. /**
  1004. * Get the count of the total records for pagination.
  1005. *
  1006. * @return int
  1007. */
  1008. public function getPaginationCount()
  1009. {
  1010. list($orders, $this->orders) = array($this->orders, null);
  1011. // Because some database engines may throw errors if we leave the ordering
  1012. // statements on the query, we will "back them up" and remove them from
  1013. // the query. Once we have the count we will put them back onto this.
  1014. $total = $this->count();
  1015. $this->orders = $orders;
  1016. return $total;
  1017. }
  1018. /**
  1019. * Determine if any rows exist for the current query.
  1020. *
  1021. * @return bool
  1022. */
  1023. public function exists()
  1024. {
  1025. return $this->count() > 0;
  1026. }
  1027. /**
  1028. * Retrieve the "count" result of the query.
  1029. *
  1030. * @param string $column
  1031. * @return int
  1032. */
  1033. public function count($column = '*')
  1034. {
  1035. return $this->aggregate(__FUNCTION__, array($column));
  1036. }
  1037. /**
  1038. * Retrieve the minimum value of a given column.
  1039. *
  1040. * @param string $column
  1041. * @return mixed
  1042. */
  1043. public function min($column)
  1044. {
  1045. return $this->aggregate(__FUNCTION__, array($column));
  1046. }
  1047. /**
  1048. * Retrieve the maximum value of a given column.
  1049. *
  1050. * @param string $column
  1051. * @return mixed
  1052. */
  1053. public function max($column)
  1054. {
  1055. return $this->aggregate(__FUNCTION__, array($column));
  1056. }
  1057. /**
  1058. * Retrieve the sum of the values of a given column.
  1059. *
  1060. * @param string $column
  1061. * @return mixed
  1062. */
  1063. public function sum($column)
  1064. {
  1065. return $this->aggregate(__FUNCTION__, array($column));
  1066. }
  1067. /**
  1068. * Retrieve the average of the values of a given column.
  1069. *
  1070. * @param string $column
  1071. * @return mixed
  1072. */
  1073. public function avg($column)
  1074. {
  1075. return $this->aggregate(__FUNCTION__, array($column));
  1076. }
  1077. /**
  1078. * Execute an aggregate function on the database.
  1079. *
  1080. * @param string $function
  1081. * @param array $columns
  1082. * @return mixed
  1083. */
  1084. public function aggregate($function, $columns = array('*'))
  1085. {
  1086. $this->aggregate = compact('function', 'columns');
  1087. $results = $this->get($columns);
  1088. // Once we have executed the query, we will reset the aggregate property so
  1089. // that more select queries can be executed against the database without
  1090. // the aggregate value getting in the way when the grammar builds it.
  1091. $this->columns = null; $this->aggregate = null;
  1092. if (isset($results[0]))
  1093. {
  1094. $result = (array) $results[0];
  1095. return $result['aggregate'];
  1096. }
  1097. }
  1098. /**
  1099. * Insert a new record into the database.
  1100. *
  1101. * @param array $values
  1102. * @return bool
  1103. */
  1104. public function insert(array $values)
  1105. {
  1106. // Since every insert gets treated like a batch insert, we will make sure the
  1107. // bindings are structured in a way that is convenient for building these
  1108. // inserts statements by verifying the elements are actually an array.
  1109. if ( ! is_array(reset($values)))
  1110. {
  1111. $values = array($values);
  1112. }
  1113. $bindings = array();
  1114. // We'll treat every insert like a batch insert so we can easily insert each
  1115. // of the records into the database consistently. This will make it much
  1116. // easier on the grammars to just handle one type of record insertion.
  1117. foreach ($values as $record)
  1118. {
  1119. $bindings = array_merge($bindings, array_values($record));
  1120. }
  1121. $sql = $this->grammar->compileInsert($this, $values);
  1122. // Once we have compiled the insert statement's SQL we can execute it on the
  1123. // connection and return a result as a boolean success indicator as that
  1124. // is the same type of result returned by the raw connection instance.
  1125. $bindings = $this->cleanBindings($bindings);
  1126. return $this->connection->insert($sql, $bindings);
  1127. }
  1128. /**
  1129. * Insert a new record and get the value of the primary key.
  1130. *
  1131. * @param array $values
  1132. * @param string $sequence
  1133. * @return int
  1134. */
  1135. public function insertGetId(array $values, $sequence = null)
  1136. {
  1137. $sql = $this->grammar->compileInsertGetId($this, $values, $sequence);
  1138. $values = $this->cleanBindings($values);
  1139. return $this->processor->processInsertGetId($this, $sql, $values, $sequence);
  1140. }
  1141. /**
  1142. * Update a record in the database.
  1143. *
  1144. * @param array $values
  1145. * @return int
  1146. */
  1147. public function update(array $values)
  1148. {
  1149. $bindings = array_values(array_merge($values, $this->bindings));
  1150. $sql = $this->grammar->compileUpdate($this, $values);
  1151. return $this->connection->update($sql, $this->cleanBindings($bindings));
  1152. }
  1153. /**
  1154. * Increment a column's value by a given amount.
  1155. *
  1156. * @param string $column
  1157. * @param int $amount
  1158. * @param array $extra
  1159. * @return int
  1160. */
  1161. public function increment($column, $amount = 1, array $extra = array())
  1162. {
  1163. $wrapped = $this->grammar->wrap($column);
  1164. $columns = array_merge(array($column => $this->raw("$wrapped + $amount")), $extra);
  1165. return $this->update($columns);
  1166. }
  1167. /**
  1168. * Decrement a column's value by a given amount.
  1169. *
  1170. * @param string $column
  1171. * @param int $amount
  1172. * @param array $extra
  1173. * @return int
  1174. */
  1175. public function decrement($column, $amount = 1, array $extra = array())
  1176. {
  1177. $wrapped = $this->grammar->wrap($column);
  1178. $columns = array_merge(array($column => $this->raw("$wrapped - $amount")), $extra);
  1179. return $this->update($columns);
  1180. }
  1181. /**
  1182. * Delete a record from the database.
  1183. *
  1184. * @param mixed $id
  1185. * @return int
  1186. */
  1187. public function delete($id = null)
  1188. {
  1189. // If an ID is passed to the method, we will set the where clause to check
  1190. // the ID to allow developers to simply and quickly remove a single row
  1191. // from their database without manually specifying the where clauses.
  1192. if ( ! is_null($id)) $this->where('id', '=', $id);
  1193. $sql = $this->grammar->compileDelete($this);
  1194. return $this->connection->delete($sql, $this->bindings);
  1195. }
  1196. /**
  1197. * Run a truncate statement on the table.
  1198. *
  1199. * @return void
  1200. */
  1201. public function truncate()
  1202. {
  1203. foreach ($this->grammar->compileTruncate($this) as $sql => $bindings)
  1204. {
  1205. $this->connection->statement($sql, $bindings);
  1206. }
  1207. }
  1208. /**
  1209. * Get a new instance of the query builder.
  1210. *
  1211. * @return \Illuminate\Database\Query\Builder
  1212. */
  1213. public function newQuery()
  1214. {
  1215. return new Builder($this->connection, $this->grammar, $this->processor);
  1216. }
  1217. /**
  1218. * Merge an array of where clauses and bindings.
  1219. *
  1220. * @param array $wheres
  1221. * @param array $bindings
  1222. * @return void
  1223. */
  1224. public function mergeWheres($wheres, $bindings)
  1225. {
  1226. $this->wheres = array_merge($this->wheres, (array) $wheres);
  1227. $this->bindings = array_values(array_merge($this->bindings, (array) $bindings));
  1228. }
  1229. /**
  1230. * Get a copy of the where clauses and bindings in an array.
  1231. *
  1232. * @return array
  1233. */
  1234. public function getAndResetWheres()
  1235. {
  1236. $values = array($this->wheres, $this->bindings);
  1237. list($this->wheres, $this->bindings) = array(null, array());
  1238. return $values;
  1239. }
  1240. /**
  1241. * Remove all of the expressions from a list of bindings.
  1242. *
  1243. * @param array $bindings
  1244. * @return array
  1245. */
  1246. protected function cleanBindings(array $bindings)
  1247. {
  1248. return array_values(array_filter($bindings, function($binding)
  1249. {
  1250. return ! $binding instanceof Expression;
  1251. }));
  1252. }
  1253. /**
  1254. * Create a raw database expression.
  1255. *
  1256. * @param mixed $value
  1257. * @return \Illuminate\Database\Query\Expression
  1258. */
  1259. public function raw($value)
  1260. {
  1261. return $this->connection->raw($value);
  1262. }
  1263. /**
  1264. * Get the current query value bindings.
  1265. *
  1266. * @return array
  1267. */
  1268. public function getBindings()
  1269. {
  1270. return $this->bindings;
  1271. }
  1272. /**
  1273. * Set the bindings on the query builder.
  1274. *
  1275. * @param array $bindings
  1276. * @return void
  1277. */
  1278. public function setBindings(array $bindings)
  1279. {
  1280. $this->bindings = $bindings;
  1281. }
  1282. /**
  1283. * Merge an array of bindings into our bindings.
  1284. *
  1285. * @param \Illuminate\Database\Query\Builder $query
  1286. * @return \Illuminate\Database\Query\Builder
  1287. */
  1288. public function mergeBindings(Builder $query)
  1289. {
  1290. $this->bindings = array_values(array_merge($this->bindings, $query->bindings));
  1291. return $this;
  1292. }
  1293. /**
  1294. * Get the database connection instance.
  1295. *
  1296. * @return \Illuminate\Database\ConnectionInterface
  1297. */
  1298. public function getConnection()
  1299. {
  1300. return $this->connection;
  1301. }
  1302. /**
  1303. * Get the database query processor instance.
  1304. *
  1305. * @return \Illuminate\Database\Query\Processors\Processor
  1306. */
  1307. public function getProcessor()
  1308. {
  1309. return $this->processor;
  1310. }
  1311. /**
  1312. * Get the query grammar instance.
  1313. *
  1314. * @return \Illuminate\Database\Grammar
  1315. */
  1316. public function getGrammar()
  1317. {
  1318. return $this->grammar;
  1319. }
  1320. /**
  1321. * Handle dynamic method calls into the method.
  1322. *
  1323. * @param string $method
  1324. * @param array $parameters
  1325. * @return mixed
  1326. */
  1327. public function __call($method, $parameters)
  1328. {
  1329. if (starts_with($method, 'where'))
  1330. {
  1331. return $this->dynamicWhere($method, $parameters);
  1332. }
  1333. $className = get_class($this);
  1334. throw new \BadMethodCallException("Call to undefined method {$className}::{$method}()");
  1335. }
  1336. }