PageRenderTime 40ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/classes/database/query/builder/select.php

http://github.com/fuel/core
PHP | 524 lines | 232 code | 76 blank | 216 comment | 17 complexity | 059bbd3d4dd5b77fb24c33ea953664c1 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * Fuel is a fast, lightweight, community driven PHP 5.4+ framework.
  4. *
  5. * @package Fuel
  6. * @version 1.9-dev
  7. * @author Fuel Development Team
  8. * @license MIT License
  9. * @copyright 2010 - 2019 Fuel Development Team
  10. * @copyright 2008 - 2009 Kohana Team
  11. * @link https://fuelphp.com
  12. */
  13. namespace Fuel\Core;
  14. class Database_Query_Builder_Select extends \Database_Query_Builder_Where
  15. {
  16. /**
  17. * @var array $_select columns to select
  18. */
  19. protected $_select = array();
  20. /**
  21. * @var bool $_distinct whether to select distinct values
  22. */
  23. protected $_distinct = false;
  24. /**
  25. * @var array $_from table name
  26. */
  27. protected $_from = array();
  28. /**
  29. * @var array $_join join objects
  30. */
  31. protected $_join = array();
  32. /**
  33. * @var array $_group_by group by clauses
  34. */
  35. protected $_group_by = array();
  36. /**
  37. * @var array $_having having clauses
  38. */
  39. protected $_having = array();
  40. /**
  41. * @var integer $_offset offset
  42. */
  43. protected $_offset = null;
  44. /**
  45. * @var Database_Query_Builder_Join $_last_join last join statement
  46. */
  47. protected $_last_join;
  48. /**
  49. * Sets the initial columns to select from.
  50. *
  51. * @param array $columns column list
  52. */
  53. public function __construct(array $columns = null)
  54. {
  55. if ( ! empty($columns))
  56. {
  57. // Set the initial columns
  58. $this->_select = $columns;
  59. }
  60. // Start the query with no actual SQL statement
  61. parent::__construct('', \DB::SELECT);
  62. }
  63. /**
  64. * Enables or disables selecting only unique columns using "SELECT DISTINCT"
  65. *
  66. * @param boolean $value enable or disable distinct columns
  67. * @return $this
  68. */
  69. public function distinct($value = true)
  70. {
  71. $this->_distinct = (bool) $value;
  72. return $this;
  73. }
  74. /**
  75. * Choose the columns to select from.
  76. *
  77. * @param mixed $columns column name or array($column, $alias) or object
  78. * @param ...
  79. *
  80. * @return $this
  81. */
  82. public function select($columns = null)
  83. {
  84. $columns = func_get_args();
  85. $this->_select = array_merge($this->_select, $columns);
  86. return $this;
  87. }
  88. /**
  89. * Choose the columns to select from, using an array.
  90. *
  91. * @param array $columns list of column names or aliases
  92. * @param bool $reset if true, don't merge but overwrite
  93. *
  94. * @return $this
  95. */
  96. public function select_array(array $columns, $reset = false)
  97. {
  98. $this->_select = $reset ? $columns : array_merge($this->_select, $columns);
  99. return $this;
  100. }
  101. /**
  102. * Choose the tables to select "FROM ..."
  103. *
  104. * @param mixed $tables table name or array($table, $alias)
  105. * @param ...
  106. *
  107. * @return $this
  108. */
  109. public function from($tables)
  110. {
  111. $tables = func_get_args();
  112. $this->_from = array_merge($this->_from, $tables);
  113. return $this;
  114. }
  115. /**
  116. * Adds addition tables to "JOIN ...".
  117. *
  118. * @param mixed $table column name or array($column, $alias)
  119. * @param string $type join type (LEFT, RIGHT, INNER, etc)
  120. *
  121. * @return $this
  122. */
  123. public function join($table, $type = NULL)
  124. {
  125. $this->_join[] = $this->_last_join = new \Database_Query_Builder_Join($table, $type);
  126. return $this;
  127. }
  128. /**
  129. * Adds "ON ..." conditions for the last created JOIN statement.
  130. *
  131. * @param mixed $c1 column name or array($column, $alias) or object
  132. * @param string $op logic operator
  133. * @param mixed $c2 column name or array($column, $alias) or object
  134. *
  135. * @return $this
  136. */
  137. public function on($c1, $op, $c2)
  138. {
  139. $this->_last_join->on($c1, $op, $c2);
  140. return $this;
  141. }
  142. /**
  143. * Adds "AND ON ..." conditions for the last created JOIN statement.
  144. *
  145. * @param mixed $c1 column name or array($column, $alias) or object
  146. * @param string $op logic operator
  147. * @param mixed $c2 column name or array($column, $alias) or object
  148. *
  149. * @return $this
  150. */
  151. public function and_on($c1, $op, $c2)
  152. {
  153. $this->_last_join->and_on($c1, $op, $c2);
  154. return $this;
  155. }
  156. /**
  157. * Adds "OR ON ..." conditions for the last created JOIN statement.
  158. *
  159. * @param mixed $c1 column name or array($column, $alias) or object
  160. * @param string $op logic operator
  161. * @param mixed $c2 column name or array($column, $alias) or object
  162. *
  163. * @return $this
  164. */
  165. public function or_on($c1, $op, $c2)
  166. {
  167. $this->_last_join->or_on($c1, $op, $c2);
  168. return $this;
  169. }
  170. /**
  171. * Adds an opening bracket the last created JOIN statement.
  172. *
  173. * @return $this
  174. */
  175. public function on_open()
  176. {
  177. $this->_last_join->on_open();
  178. return $this;
  179. }
  180. /**
  181. * Adds a closing bracket for the last created JOIN statement.
  182. *
  183. * @return $this
  184. */
  185. public function on_close()
  186. {
  187. $this->_last_join->on_close();
  188. return $this;
  189. }
  190. /**
  191. * Creates a "GROUP BY ..." filter.
  192. *
  193. * @param mixed $columns column name or array($column, $column) or object
  194. * @param ...
  195. *
  196. * @return $this
  197. */
  198. public function group_by($columns)
  199. {
  200. $columns = func_get_args();
  201. foreach($columns as $idx => $column)
  202. {
  203. // if an array of columns is passed, flatten it
  204. if (is_array($column))
  205. {
  206. foreach($column as $c)
  207. {
  208. $columns[] = $c;
  209. }
  210. unset($columns[$idx]);
  211. }
  212. }
  213. $this->_group_by = array_merge($this->_group_by, $columns);
  214. return $this;
  215. }
  216. /**
  217. * Alias of and_having()
  218. *
  219. * @param mixed $column column name or array($column, $alias) or object
  220. * @param string $op logic operator
  221. * @param mixed $value column value
  222. *
  223. * @return $this
  224. */
  225. public function having($column, $op = null, $value = null)
  226. {
  227. return call_fuel_func_array(array($this, 'and_having'), func_get_args());
  228. }
  229. /**
  230. * Creates a new "AND HAVING" condition for the query.
  231. *
  232. * @param mixed $column column name or array($column, $alias) or object
  233. * @param string $op logic operator
  234. * @param mixed $value column value
  235. *
  236. * @return $this
  237. */
  238. public function and_having($column, $op = null, $value = null)
  239. {
  240. if($column instanceof \Closure)
  241. {
  242. $this->and_having_open();
  243. $column($this);
  244. $this->and_having_close();
  245. return $this;
  246. }
  247. if(func_num_args() === 2)
  248. {
  249. $value = $op;
  250. $op = '=';
  251. }
  252. $this->_having[] = array('AND' => array($column, $op, $value));
  253. return $this;
  254. }
  255. /**
  256. * Creates a new "OR HAVING" condition for the query.
  257. *
  258. * @param mixed $column column name or array($column, $alias) or object
  259. * @param string $op logic operator
  260. * @param mixed $value column value
  261. *
  262. * @return $this
  263. */
  264. public function or_having($column, $op = null, $value = null)
  265. {
  266. if($column instanceof \Closure)
  267. {
  268. $this->or_having_open();
  269. $column($this);
  270. $this->or_having_close();
  271. return $this;
  272. }
  273. if(func_num_args() === 2)
  274. {
  275. $value = $op;
  276. $op = '=';
  277. }
  278. $this->_having[] = array('OR' => array($column, $op, $value));
  279. return $this;
  280. }
  281. /**
  282. * Alias of and_having_open()
  283. *
  284. * @return $this
  285. */
  286. public function having_open()
  287. {
  288. return $this->and_having_open();
  289. }
  290. /**
  291. * Opens a new "AND HAVING (...)" grouping.
  292. *
  293. * @return $this
  294. */
  295. public function and_having_open()
  296. {
  297. $this->_having[] = array('AND' => '(');
  298. return $this;
  299. }
  300. /**
  301. * Opens a new "OR HAVING (...)" grouping.
  302. *
  303. * @return $this
  304. */
  305. public function or_having_open()
  306. {
  307. $this->_having[] = array('OR' => '(');
  308. return $this;
  309. }
  310. /**
  311. * Closes an open "AND HAVING (...)" grouping.
  312. *
  313. * @return $this
  314. */
  315. public function having_close()
  316. {
  317. return $this->and_having_close();
  318. }
  319. /**
  320. * Closes an open "AND HAVING (...)" grouping.
  321. *
  322. * @return $this
  323. */
  324. public function and_having_close()
  325. {
  326. $this->_having[] = array('AND' => ')');
  327. return $this;
  328. }
  329. /**
  330. * Closes an open "OR HAVING (...)" grouping.
  331. *
  332. * @return $this
  333. */
  334. public function or_having_close()
  335. {
  336. $this->_having[] = array('OR' => ')');
  337. return $this;
  338. }
  339. /**
  340. * Start returning results after "OFFSET ..."
  341. *
  342. * @param integer $number starting result number
  343. *
  344. * @return $this
  345. */
  346. public function offset($number)
  347. {
  348. $this->_offset = (int) $number;
  349. return $this;
  350. }
  351. /**
  352. * Compile the SQL query and return it.
  353. *
  354. * @param mixed $db Database_Connection instance or instance name
  355. *
  356. * @return string
  357. */
  358. public function compile($db = null)
  359. {
  360. if ( ! $db instanceof \Database_Connection)
  361. {
  362. // Get the database instance
  363. $db = $this->_connection ?: \Database_Connection::instance($db);
  364. }
  365. // Callback to quote identifiers
  366. $quote_ident = array($db, 'quote_identifier');
  367. // Callback to quote tables
  368. $quote_table = array($db, 'quote_table');
  369. // Start a selection query
  370. $query = 'SELECT ';
  371. if ($this->_distinct === TRUE)
  372. {
  373. // Select only unique results
  374. $query .= 'DISTINCT ';
  375. }
  376. if (empty($this->_select))
  377. {
  378. // Select all columns
  379. $query .= '*';
  380. }
  381. else
  382. {
  383. // Select all columns
  384. $query .= implode(', ', array_unique(array_map($quote_ident, $this->_select)));
  385. }
  386. if ( ! empty($this->_from))
  387. {
  388. // Set tables to select from
  389. $query .= ' FROM '.implode(', ', array_unique(array_map($quote_table, $this->_from)));
  390. }
  391. if ( ! empty($this->_join))
  392. {
  393. // Add tables to join
  394. $query .= ' '.$this->_compile_join($db, $this->_join);
  395. }
  396. if ( ! empty($this->_where))
  397. {
  398. // Add selection conditions
  399. $query .= ' WHERE '.$this->_compile_conditions($db, $this->_where);
  400. }
  401. if ( ! empty($this->_group_by))
  402. {
  403. // Add sorting
  404. $query .= ' GROUP BY '.implode(', ', array_map($quote_ident, $this->_group_by));
  405. }
  406. if ( ! empty($this->_having))
  407. {
  408. // Add filtering conditions
  409. $query .= ' HAVING '.$this->_compile_conditions($db, $this->_having);
  410. }
  411. if ( ! empty($this->_order_by))
  412. {
  413. // Add sorting
  414. $query .= ' '.$this->_compile_order_by($db, $this->_order_by);
  415. }
  416. if ($this->_limit !== NULL)
  417. {
  418. // Add limiting
  419. $query .= ' LIMIT '.$this->_limit;
  420. }
  421. if ($this->_offset !== NULL)
  422. {
  423. // Add offsets
  424. $query .= ' OFFSET '.$this->_offset;
  425. }
  426. return $query;
  427. }
  428. /**
  429. * Reset the query parameters
  430. * @return $this
  431. */
  432. public function reset()
  433. {
  434. $this->_select = array();
  435. $this->_from = array();
  436. $this->_join = array();
  437. $this->_where = array();
  438. $this->_group_by = array();
  439. $this->_having = array();
  440. $this->_order_by = array();
  441. $this->_distinct = false;
  442. $this->_limit = null;
  443. $this->_offset = null;
  444. $this->_last_join = null;
  445. $this->_parameters = array();
  446. return $this;
  447. }
  448. }