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

https://github.com/woxxy/FoolFuuka · PHP · 426 lines · 201 code · 71 blank · 154 comment · 16 complexity · 4ecc05d938a637742a1a24cc50d60210 MD5 · raw file

  1. <?php
  2. /**
  3. * Database query builder for SELECT statements.
  4. *
  5. * @package Fuel/Database
  6. * @category Query
  7. * @author Kohana Team
  8. * @copyright (c) 2008-2009 Kohana Team
  9. * @license http://kohanaphp.com/license
  10. */
  11. namespace Fuel\Core;
  12. class Database_Query_Builder_Select extends \Database_Query_Builder_Where
  13. {
  14. // SELECT ...
  15. protected $_select = array();
  16. // DISTINCT
  17. protected $_distinct = FALSE;
  18. // FROM ...
  19. protected $_from = array();
  20. // JOIN ...
  21. protected $_join = array();
  22. // GROUP BY ...
  23. protected $_group_by = array();
  24. // HAVING ...
  25. protected $_having = array();
  26. // OFFSET ...
  27. protected $_offset = NULL;
  28. // The last JOIN statement created
  29. protected $_last_join;
  30. /**
  31. * Sets the initial columns to select from.
  32. *
  33. * @param array column list
  34. * @return void
  35. */
  36. public function __construct(array $columns = NULL)
  37. {
  38. if ( ! empty($columns))
  39. {
  40. // Set the initial columns
  41. $this->_select = $columns;
  42. }
  43. // Start the query with no actual SQL statement
  44. parent::__construct('', \DB::SELECT);
  45. }
  46. /**
  47. * Enables or disables selecting only unique columns using "SELECT DISTINCT"
  48. *
  49. * @param boolean enable or disable distinct columns
  50. * @return $this
  51. */
  52. public function distinct($value = true)
  53. {
  54. $this->_distinct = (bool) $value;
  55. return $this;
  56. }
  57. /**
  58. * Choose the columns to select from.
  59. *
  60. * @param mixed column name or array($column, $alias) or object
  61. * @param ...
  62. * @return $this
  63. */
  64. public function select($columns = NULL)
  65. {
  66. $columns = func_get_args();
  67. $this->_select = array_merge($this->_select, $columns);
  68. return $this;
  69. }
  70. /**
  71. * Choose the columns to select from, using an array.
  72. *
  73. * @param array list of column names or aliases
  74. * @return $this
  75. */
  76. public function select_array(array $columns)
  77. {
  78. $this->_select = array_merge($this->_select, $columns);
  79. return $this;
  80. }
  81. /**
  82. * Choose the tables to select "FROM ..."
  83. *
  84. * @param mixed table name or array($table, $alias) or object
  85. * @param ...
  86. * @return $this
  87. */
  88. public function from($tables)
  89. {
  90. $tables = func_get_args();
  91. $this->_from = array_merge($this->_from, $tables);
  92. return $this;
  93. }
  94. /**
  95. * Adds addition tables to "JOIN ...".
  96. *
  97. * @param mixed column name or array($column, $alias) or object
  98. * @param string join type (LEFT, RIGHT, INNER, etc)
  99. * @return $this
  100. */
  101. public function join($table, $type = NULL)
  102. {
  103. $this->_join[] = $this->_last_join = new \Database_Query_Builder_Join($table, $type);
  104. return $this;
  105. }
  106. /**
  107. * Adds "ON ..." conditions for the last created JOIN statement.
  108. *
  109. * @param mixed column name or array($column, $alias) or object
  110. * @param string logic operator
  111. * @param mixed column name or array($column, $alias) or object
  112. * @return $this
  113. */
  114. public function on($c1, $op, $c2)
  115. {
  116. $this->_last_join->on($c1, $op, $c2);
  117. return $this;
  118. }
  119. /**
  120. * Creates a "GROUP BY ..." filter.
  121. *
  122. * @param mixed column name or array($column, $alias) or object
  123. * @param ...
  124. * @return $this
  125. */
  126. public function group_by($columns)
  127. {
  128. $columns = func_get_args();
  129. $this->_group_by = array_merge($this->_group_by, $columns);
  130. return $this;
  131. }
  132. /**
  133. * Alias of and_having()
  134. *
  135. * @param mixed column name or array($column, $alias) or object
  136. * @param string logic operator
  137. * @param mixed column value
  138. * @return $this
  139. */
  140. public function having($column, $op = null, $value = NULL)
  141. {
  142. return call_user_func_array(array($this, 'and_having'), func_get_args());
  143. }
  144. /**
  145. * Creates a new "AND HAVING" condition for the query.
  146. *
  147. * @param mixed column name or array($column, $alias) or object
  148. * @param string logic operator
  149. * @param mixed column value
  150. * @return $this
  151. */
  152. public function and_having($column, $op = null, $value = null)
  153. {
  154. if($column instanceof \Closure)
  155. {
  156. $this->and_having_open();
  157. $column($this);
  158. $this->and_having_close();
  159. return $this;
  160. }
  161. if(func_num_args() === 2)
  162. {
  163. $value = $op;
  164. $op = '=';
  165. }
  166. $this->_having[] = array('AND' => array($column, $op, $value));
  167. return $this;
  168. }
  169. /**
  170. * Creates a new "OR HAVING" condition for the query.
  171. *
  172. * @param mixed column name or array($column, $alias) or object
  173. * @param string logic operator
  174. * @param mixed column value
  175. * @return $this
  176. */
  177. public function or_having($column, $op = null, $value = null)
  178. {
  179. if($column instanceof \Closure)
  180. {
  181. $this->or_having_open();
  182. $column($this);
  183. $this->or_having_close();
  184. return $this;
  185. }
  186. if(func_num_args() === 2)
  187. {
  188. $value = $op;
  189. $op = '=';
  190. }
  191. $this->_having[] = array('OR' => array($column, $op, $value));
  192. return $this;
  193. }
  194. /**
  195. * Alias of and_having_open()
  196. *
  197. * @return $this
  198. */
  199. public function having_open()
  200. {
  201. return $this->and_having_open();
  202. }
  203. /**
  204. * Opens a new "AND HAVING (...)" grouping.
  205. *
  206. * @return $this
  207. */
  208. public function and_having_open()
  209. {
  210. $this->_having[] = array('AND' => '(');
  211. return $this;
  212. }
  213. /**
  214. * Opens a new "OR HAVING (...)" grouping.
  215. *
  216. * @return $this
  217. */
  218. public function or_having_open()
  219. {
  220. $this->_having[] = array('OR' => '(');
  221. return $this;
  222. }
  223. /**
  224. * Closes an open "AND HAVING (...)" grouping.
  225. *
  226. * @return $this
  227. */
  228. public function having_close()
  229. {
  230. return $this->and_having_close();
  231. }
  232. /**
  233. * Closes an open "AND HAVING (...)" grouping.
  234. *
  235. * @return $this
  236. */
  237. public function and_having_close()
  238. {
  239. $this->_having[] = array('AND' => ')');
  240. return $this;
  241. }
  242. /**
  243. * Closes an open "OR HAVING (...)" grouping.
  244. *
  245. * @return $this
  246. */
  247. public function or_having_close()
  248. {
  249. $this->_having[] = array('OR' => ')');
  250. return $this;
  251. }
  252. /**
  253. * Start returning results after "OFFSET ..."
  254. *
  255. * @param integer starting result number
  256. * @return $this
  257. */
  258. public function offset($number)
  259. {
  260. $this->_offset = (int) $number;
  261. return $this;
  262. }
  263. /**
  264. * Compile the SQL query and return it.
  265. *
  266. * @param mixed Database instance or instance name
  267. * @return string
  268. */
  269. public function compile($db = null)
  270. {
  271. if ( ! $db instanceof \Database_Connection)
  272. {
  273. // Get the database instance
  274. $db = \Database_Connection::instance($db);
  275. }
  276. // Callback to quote identifiers
  277. $quote_ident = array($db, 'quote_identifier');
  278. // Callback to quote tables
  279. $quote_table = array($db, 'quote_table');
  280. // Start a selection query
  281. $query = 'SELECT ';
  282. if ($this->_distinct === TRUE)
  283. {
  284. // Select only unique results
  285. $query .= 'DISTINCT ';
  286. }
  287. if (empty($this->_select))
  288. {
  289. // Select all columns
  290. $query .= '*';
  291. }
  292. else
  293. {
  294. // Select all columns
  295. $query .= implode(', ', array_unique(array_map($quote_ident, $this->_select)));
  296. }
  297. if ( ! empty($this->_from))
  298. {
  299. // Set tables to select from
  300. $query .= ' FROM '.implode(', ', array_unique(array_map($quote_table, $this->_from)));
  301. }
  302. if ( ! empty($this->_join))
  303. {
  304. // Add tables to join
  305. $query .= ' '.$this->_compile_join($db, $this->_join);
  306. }
  307. if ( ! empty($this->_where))
  308. {
  309. // Add selection conditions
  310. $query .= ' WHERE '.$this->_compile_conditions($db, $this->_where);
  311. }
  312. if ( ! empty($this->_group_by))
  313. {
  314. // Add sorting
  315. $query .= ' GROUP BY '.implode(', ', array_map($quote_ident, $this->_group_by));
  316. }
  317. if ( ! empty($this->_having))
  318. {
  319. // Add filtering conditions
  320. $query .= ' HAVING '.$this->_compile_conditions($db, $this->_having);
  321. }
  322. if ( ! empty($this->_order_by))
  323. {
  324. // Add sorting
  325. $query .= ' '.$this->_compile_order_by($db, $this->_order_by);
  326. }
  327. if ($this->_limit !== NULL)
  328. {
  329. // Add limiting
  330. $query .= ' LIMIT '.$this->_limit;
  331. }
  332. if ($this->_offset !== NULL)
  333. {
  334. // Add offsets
  335. $query .= ' OFFSET '.$this->_offset;
  336. }
  337. return $query;
  338. }
  339. public function reset()
  340. {
  341. $this->_select =
  342. $this->_from =
  343. $this->_join =
  344. $this->_where =
  345. $this->_group_by =
  346. $this->_having =
  347. $this->_order_by = array();
  348. $this->_distinct = FALSE;
  349. $this->_limit =
  350. $this->_offset =
  351. $this->_last_join = NULL;
  352. $this->_parameters = array();
  353. return $this;
  354. }
  355. } // End Database_Query_Select