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

https://bitbucket.org/sriedel/iccrm-wip · PHP · 440 lines · 212 code · 72 blank · 156 comment · 17 complexity · 3a37b8f89ad8d0cf7207c639e9610570 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. * @param bool if true, don't merge but overwrite
  75. * @return $this
  76. */
  77. public function select_array(array $columns, $reset = false)
  78. {
  79. $this->_select = $reset ? $columns : array_merge($this->_select, $columns);
  80. return $this;
  81. }
  82. /**
  83. * Choose the tables to select "FROM ..."
  84. *
  85. * @param mixed table name or array($table, $alias) or object
  86. * @param ...
  87. * @return $this
  88. */
  89. public function from($tables)
  90. {
  91. $tables = func_get_args();
  92. $this->_from = array_merge($this->_from, $tables);
  93. return $this;
  94. }
  95. /**
  96. * Adds addition tables to "JOIN ...".
  97. *
  98. * @param mixed column name or array($column, $alias) or object
  99. * @param string join type (LEFT, RIGHT, INNER, etc)
  100. * @return $this
  101. */
  102. public function join($table, $type = NULL)
  103. {
  104. $this->_join[] = $this->_last_join = new \Database_Query_Builder_Join($table, $type);
  105. return $this;
  106. }
  107. /**
  108. * Adds "ON ..." conditions for the last created JOIN statement.
  109. *
  110. * @param mixed column name or array($column, $alias) or object
  111. * @param string logic operator
  112. * @param mixed column name or array($column, $alias) or object
  113. * @return $this
  114. */
  115. public function on($c1, $op, $c2)
  116. {
  117. $this->_last_join->on($c1, $op, $c2);
  118. return $this;
  119. }
  120. /**
  121. * Creates a "GROUP BY ..." filter.
  122. *
  123. * @param mixed column name or array($column, $column) or object
  124. * @param ...
  125. * @return $this
  126. */
  127. public function group_by($columns)
  128. {
  129. $columns = func_get_args();
  130. foreach($columns as $idx => $column)
  131. {
  132. // if an array of columns is passed, flatten it
  133. if (is_array($column))
  134. {
  135. foreach($column as $c)
  136. {
  137. $columns[] = $c;
  138. }
  139. unset($columns[$idx]);
  140. }
  141. }
  142. $this->_group_by = array_merge($this->_group_by, $columns);
  143. return $this;
  144. }
  145. /**
  146. * Alias of and_having()
  147. *
  148. * @param mixed column name or array($column, $alias) or object
  149. * @param string logic operator
  150. * @param mixed column value
  151. * @return $this
  152. */
  153. public function having($column, $op = null, $value = NULL)
  154. {
  155. return call_user_func_array(array($this, 'and_having'), func_get_args());
  156. }
  157. /**
  158. * Creates a new "AND HAVING" condition for the query.
  159. *
  160. * @param mixed column name or array($column, $alias) or object
  161. * @param string logic operator
  162. * @param mixed column value
  163. * @return $this
  164. */
  165. public function and_having($column, $op = null, $value = null)
  166. {
  167. if($column instanceof \Closure)
  168. {
  169. $this->and_having_open();
  170. $column($this);
  171. $this->and_having_close();
  172. return $this;
  173. }
  174. if(func_num_args() === 2)
  175. {
  176. $value = $op;
  177. $op = '=';
  178. }
  179. $this->_having[] = array('AND' => array($column, $op, $value));
  180. return $this;
  181. }
  182. /**
  183. * Creates a new "OR HAVING" condition for the query.
  184. *
  185. * @param mixed column name or array($column, $alias) or object
  186. * @param string logic operator
  187. * @param mixed column value
  188. * @return $this
  189. */
  190. public function or_having($column, $op = null, $value = null)
  191. {
  192. if($column instanceof \Closure)
  193. {
  194. $this->or_having_open();
  195. $column($this);
  196. $this->or_having_close();
  197. return $this;
  198. }
  199. if(func_num_args() === 2)
  200. {
  201. $value = $op;
  202. $op = '=';
  203. }
  204. $this->_having[] = array('OR' => array($column, $op, $value));
  205. return $this;
  206. }
  207. /**
  208. * Alias of and_having_open()
  209. *
  210. * @return $this
  211. */
  212. public function having_open()
  213. {
  214. return $this->and_having_open();
  215. }
  216. /**
  217. * Opens a new "AND HAVING (...)" grouping.
  218. *
  219. * @return $this
  220. */
  221. public function and_having_open()
  222. {
  223. $this->_having[] = array('AND' => '(');
  224. return $this;
  225. }
  226. /**
  227. * Opens a new "OR HAVING (...)" grouping.
  228. *
  229. * @return $this
  230. */
  231. public function or_having_open()
  232. {
  233. $this->_having[] = array('OR' => '(');
  234. return $this;
  235. }
  236. /**
  237. * Closes an open "AND HAVING (...)" grouping.
  238. *
  239. * @return $this
  240. */
  241. public function having_close()
  242. {
  243. return $this->and_having_close();
  244. }
  245. /**
  246. * Closes an open "AND HAVING (...)" grouping.
  247. *
  248. * @return $this
  249. */
  250. public function and_having_close()
  251. {
  252. $this->_having[] = array('AND' => ')');
  253. return $this;
  254. }
  255. /**
  256. * Closes an open "OR HAVING (...)" grouping.
  257. *
  258. * @return $this
  259. */
  260. public function or_having_close()
  261. {
  262. $this->_having[] = array('OR' => ')');
  263. return $this;
  264. }
  265. /**
  266. * Start returning results after "OFFSET ..."
  267. *
  268. * @param integer starting result number
  269. * @return $this
  270. */
  271. public function offset($number)
  272. {
  273. $this->_offset = (int) $number;
  274. return $this;
  275. }
  276. /**
  277. * Compile the SQL query and return it.
  278. *
  279. * @param mixed Database instance or instance name
  280. * @return string
  281. */
  282. public function compile($db = null)
  283. {
  284. if ( ! $db instanceof \Database_Connection)
  285. {
  286. // Get the database instance
  287. $db = \Database_Connection::instance($db);
  288. }
  289. // Callback to quote identifiers
  290. $quote_ident = array($db, 'quote_identifier');
  291. // Callback to quote tables
  292. $quote_table = array($db, 'quote_table');
  293. // Start a selection query
  294. $query = 'SELECT ';
  295. if ($this->_distinct === TRUE)
  296. {
  297. // Select only unique results
  298. $query .= 'DISTINCT ';
  299. }
  300. if (empty($this->_select))
  301. {
  302. // Select all columns
  303. $query .= '*';
  304. }
  305. else
  306. {
  307. // Select all columns
  308. $query .= implode(', ', array_unique(array_map($quote_ident, $this->_select)));
  309. }
  310. if ( ! empty($this->_from))
  311. {
  312. // Set tables to select from
  313. $query .= ' FROM '.implode(', ', array_unique(array_map($quote_table, $this->_from)));
  314. }
  315. if ( ! empty($this->_join))
  316. {
  317. // Add tables to join
  318. $query .= ' '.$this->_compile_join($db, $this->_join);
  319. }
  320. if ( ! empty($this->_where))
  321. {
  322. // Add selection conditions
  323. $query .= ' WHERE '.$this->_compile_conditions($db, $this->_where);
  324. }
  325. if ( ! empty($this->_group_by))
  326. {
  327. // Add sorting
  328. $query .= ' GROUP BY '.implode(', ', array_map($quote_ident, $this->_group_by));
  329. }
  330. if ( ! empty($this->_having))
  331. {
  332. // Add filtering conditions
  333. $query .= ' HAVING '.$this->_compile_conditions($db, $this->_having);
  334. }
  335. if ( ! empty($this->_order_by))
  336. {
  337. // Add sorting
  338. $query .= ' '.$this->_compile_order_by($db, $this->_order_by);
  339. }
  340. if ($this->_limit !== NULL)
  341. {
  342. // Add limiting
  343. $query .= ' LIMIT '.$this->_limit;
  344. }
  345. if ($this->_offset !== NULL)
  346. {
  347. // Add offsets
  348. $query .= ' OFFSET '.$this->_offset;
  349. }
  350. return $query;
  351. }
  352. public function reset()
  353. {
  354. $this->_select =
  355. $this->_from =
  356. $this->_join =
  357. $this->_where =
  358. $this->_group_by =
  359. $this->_having =
  360. $this->_order_by = array();
  361. $this->_distinct = FALSE;
  362. $this->_limit =
  363. $this->_offset =
  364. $this->_last_join = NULL;
  365. $this->_parameters = array();
  366. return $this;
  367. }
  368. } // End Database_Query_Select