PageRenderTime 53ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

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

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