PageRenderTime 47ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/libraries/koowa/database/query/query.php

https://bitbucket.org/organicdevelopment/joomla-2.5
PHP | 483 lines | 226 code | 75 blank | 182 comment | 23 complexity | d1c746f04e0d659ce7c07f4cd5974062 MD5 | raw file
Possible License(s): LGPL-3.0, GPL-2.0, MIT, BSD-3-Clause, LGPL-2.1
  1. <?php
  2. /**
  3. * @version $Id: query.php 4477 2012-02-10 01:06:38Z johanjanssens $
  4. * @category Koowa
  5. * @package Koowa_Database
  6. * @subpackage Query
  7. * @copyright Copyright (C) 2007 - 2012 Johan Janssens. All rights reserved.
  8. * @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html>
  9. * @link http://www.nooku.org
  10. */
  11. /**
  12. * Database Select Class for database select statement generation
  13. *
  14. * @author Johan Janssens <johan@nooku.org>
  15. * @category Koowa
  16. * @package Koowa_Database
  17. * @subpackage Query
  18. */
  19. class KDatabaseQuery
  20. {
  21. /**
  22. * Count operation
  23. *
  24. * @var boolean
  25. */
  26. public $count = false;
  27. /**
  28. * Distinct operation
  29. *
  30. * @var boolean
  31. */
  32. public $distinct = false;
  33. /**
  34. * The columns
  35. *
  36. * @var array
  37. */
  38. public $columns = array();
  39. /**
  40. * The from element
  41. *
  42. * @var array
  43. */
  44. public $from = array();
  45. /**
  46. * The join element
  47. *
  48. * @var array
  49. */
  50. public $join = array();
  51. /**
  52. * The where element
  53. *
  54. * @var array
  55. */
  56. public $where = array();
  57. /**
  58. * The group element
  59. *
  60. * @var array
  61. */
  62. public $group = array();
  63. /**
  64. * The having element
  65. *
  66. * @var array
  67. */
  68. public $having = array();
  69. /**
  70. * The order element
  71. *
  72. * @var string
  73. */
  74. public $order = array();
  75. /**
  76. * The limit element
  77. *
  78. * @var integer
  79. */
  80. public $limit = null;
  81. /**
  82. * The limit offset element
  83. *
  84. * @var integer
  85. */
  86. public $offset = null;
  87. /**
  88. * Database connector
  89. *
  90. * @var object
  91. */
  92. protected $_adapter;
  93. /**
  94. * Table prefix
  95. *
  96. * @var object
  97. */
  98. protected $_prefix;
  99. /**
  100. * Object constructor
  101. *
  102. * Can be overloaded/supplemented by the child class
  103. *
  104. * @param object An optional KConfig object with configuration options.
  105. */
  106. public function __construct( KConfig $config )
  107. {
  108. //If no config is passed create it
  109. if(!isset($config)) $config = new KConfig();
  110. //Initialise the object
  111. $this->_initialize($config);
  112. //set the model adapter
  113. $this->_adapter = $config->adapter;
  114. }
  115. /**
  116. * Initializes the options for the object
  117. *
  118. * @param object An optional KConfig object with configuration options.
  119. */
  120. protected function _initialize(KConfig $config)
  121. {
  122. $config->append(array(
  123. 'adapter' => '',
  124. ));
  125. }
  126. /**
  127. * Gets the database adapter for this particular KDatabaseQuery object.
  128. *
  129. * @return KDatabaseAdapterInterface
  130. */
  131. public function getAdapter()
  132. {
  133. return $this->_adapter;
  134. }
  135. /**
  136. * Set the database adapter for this particular KDatabaseQuery object.
  137. *
  138. * @param object A KDatabaseAdapterInterface object
  139. * @return KDatabaseQuery
  140. */
  141. public function setAdapter(KDatabaseAdapterInterface $adapter)
  142. {
  143. $this->_adapter = $adapter;
  144. return $this;
  145. }
  146. /**
  147. * Built a select query
  148. *
  149. * @param array|string A string or an array of column names
  150. * @return KDatabaseQuery
  151. */
  152. public function select( $columns = '*')
  153. {
  154. settype($columns, 'array');
  155. $this->columns = array_unique( array_merge( $this->columns, $columns ) );
  156. return $this;
  157. }
  158. /**
  159. * Built a count query
  160. *
  161. * @return KDatabaseQuery
  162. */
  163. public function count()
  164. {
  165. $this->count = true;
  166. $this->columns = array();
  167. return $this;
  168. }
  169. /**
  170. * Make the query distinct
  171. *
  172. * @return KDatabaseQuery
  173. */
  174. public function distinct()
  175. {
  176. $this->distinct = true;
  177. return $this;
  178. }
  179. /**
  180. * Built the from clause of the query
  181. *
  182. * @param array|string A string or array of table names
  183. * @return KDatabaseQuery
  184. */
  185. public function from( $tables )
  186. {
  187. settype($tables, 'array');
  188. //The table needle
  189. $needle = $this->_adapter->getTableNeedle();
  190. //Prepent the table prefix
  191. foreach($tables as &$table)
  192. {
  193. if(strpos($table, $needle) !== 0) {
  194. $table = $needle.$table;
  195. }
  196. }
  197. $this->from = array_unique(array_merge($this->from, $tables));
  198. return $this;
  199. }
  200. /**
  201. * Built the join clause of the query
  202. *
  203. * @param string The type of join; empty for a plain JOIN, or "LEFT", "INNER", etc.
  204. * @param string The table name to join to.
  205. * @param string|array Join on this condition.
  206. * @return KDatabaseQuery
  207. */
  208. public function join($type, $table, $condition)
  209. {
  210. settype($condition, 'array');
  211. //The table needle
  212. $needle = $this->_adapter->getTableNeedle();
  213. if(strpos($table, $needle) !== 0) {
  214. $table = $needle.$table;
  215. }
  216. $this->join[] = array(
  217. 'type' => strtoupper($type),
  218. 'table' => $table,
  219. 'condition' => $condition,
  220. );
  221. return $this;
  222. }
  223. /**
  224. * Built the where clause of the query
  225. *
  226. * @param string The name of the property the constraint applies too, or a SQL function or statement
  227. * @param string The comparison used for the constraint
  228. * @param string|array The value compared to the property value using the constraint
  229. * @param string The where condition, defaults to 'AND'
  230. * @return KDatabaseQuery
  231. */
  232. public function where( $property, $constraint = null, $value = null, $condition = 'AND' )
  233. {
  234. if(!empty($property))
  235. {
  236. $where = array();
  237. $where['property'] = $property;
  238. if(isset($constraint))
  239. {
  240. $constraint = strtoupper($constraint);
  241. $condition = strtoupper($condition);
  242. $where['constraint'] = $constraint;
  243. $where['value'] = $value;
  244. }
  245. $where['condition'] = count($this->where) ? $condition : '';
  246. //Make sure we don't store the same where clauses twice
  247. $signature = md5($property.$constraint.$value);
  248. if(!isset($this->where[$signature])) {
  249. $this->where[$signature] = $where;
  250. }
  251. }
  252. return $this;
  253. }
  254. /**
  255. * Built the group clause of the query
  256. *
  257. * @param array|string A string or array of ordering columns
  258. * @return KDatabaseQuery
  259. */
  260. public function group( $columns )
  261. {
  262. settype($columns, 'array'); //force to an array
  263. $this->group = array_unique( array_merge( $this->group, $columns));
  264. return $this;
  265. }
  266. /**
  267. * Built the having clause of the query
  268. *
  269. * @param array|string A string or array of ordering columns
  270. * @return KDatabaseQuery
  271. */
  272. public function having( $columns )
  273. {
  274. settype($columns, 'array'); //force to an array
  275. $this->having = array_unique( array_merge( $this->having, $columns ));
  276. return $this;
  277. }
  278. /**
  279. * Build the order clause of the query
  280. *
  281. * @param array|string A string or array of ordering columns
  282. * @param string Either DESC or ASC
  283. * @return KDatabaseQuery
  284. */
  285. public function order( $columns, $direction = 'ASC' )
  286. {
  287. settype($columns, 'array'); //force to an array
  288. foreach($columns as $column)
  289. {
  290. $this->order[] = array(
  291. 'column' => $column,
  292. 'direction' => $direction
  293. );
  294. }
  295. return $this;
  296. }
  297. /**
  298. * Built the limit element of the query
  299. *
  300. * @param integer Number of items to fetch.
  301. * @param integer Offset to start fetching at.
  302. * @return KDatabaseQuery
  303. */
  304. public function limit( $limit, $offset = 0 )
  305. {
  306. $this->limit = (int) $limit;
  307. $this->offset = (int) $offset;
  308. return $this;
  309. }
  310. /**
  311. * Render the query to a string
  312. *
  313. * @return string The completed query
  314. */
  315. public function __toString()
  316. {
  317. $query = '';
  318. if(!empty($this->columns) || $this->count)
  319. {
  320. $query = 'SELECT';
  321. if($this->distinct) {
  322. $query .= ' DISTINCT';
  323. }
  324. if($this->count) {
  325. $query .= ' COUNT(*)';
  326. }
  327. }
  328. if (!empty($this->columns) && ! $this->count)
  329. {
  330. $columns = array();
  331. foreach($this->columns as $column) {
  332. $columns[] = $this->_adapter->quoteName($column);
  333. }
  334. $query .= ' '.implode(' , ', $columns);
  335. }
  336. if (!empty($this->from))
  337. {
  338. $tables = array();
  339. foreach($this->from as $table) {
  340. $tables[] = $this->_adapter->quoteName($table);
  341. }
  342. $query .= ' FROM '.implode(' , ', $tables);
  343. }
  344. if (!empty($this->join))
  345. {
  346. $joins = array();
  347. foreach ($this->join as $join)
  348. {
  349. $tmp = ' ';
  350. if (! empty($join['type'])) {
  351. $tmp .= $join['type'] . ' ';
  352. }
  353. $tmp .= ' JOIN ' . $this->_adapter->quoteName($join['table']);
  354. $tmp .= ' ON (' . implode(' AND ', $this->_adapter->quoteName($join['condition'])) . ')';
  355. $joins[] = $tmp;
  356. }
  357. $query .= implode(' ', $joins);
  358. }
  359. if (!empty($this->where))
  360. {
  361. $query .= ' WHERE';
  362. foreach($this->where as $where)
  363. {
  364. if(isset($where['condition'])) {
  365. $query .= ' '.$where['condition'];
  366. }
  367. $query .= ' '. $this->_adapter->quoteName($where['property']);
  368. if(isset($where['constraint']))
  369. {
  370. $value = $this->_adapter->quoteValue($where['value']);
  371. if(in_array($where['constraint'], array('IN', 'NOT IN'))) {
  372. $value = ' ( '.$value. ' ) ';
  373. }
  374. $query .= ' '.$where['constraint'].' '.$value;
  375. }
  376. }
  377. }
  378. if (!empty($this->group))
  379. {
  380. $columns = array();
  381. foreach($this->group as $column) {
  382. $columns[] = $this->_adapter->quoteName($column);
  383. }
  384. $query .= ' GROUP BY '.implode(' , ', $columns);
  385. }
  386. if (!empty($this->having))
  387. {
  388. $columns = array();
  389. foreach($this->having as $column) {
  390. $columns[] = $this->_adapter->quoteName($column);
  391. }
  392. $query .= ' HAVING '.implode(' , ', $columns);
  393. }
  394. if (!empty($this->order) )
  395. {
  396. $query .= ' ORDER BY ';
  397. $list = array();
  398. foreach ($this->order as $order) {
  399. $list[] = $this->_adapter->quoteName($order['column']).' '.$order['direction'];
  400. }
  401. $query .= implode(' , ', $list);
  402. }
  403. if (!empty($this->limit)) {
  404. $query .= ' LIMIT '.$this->offset.' , '.$this->limit;
  405. }
  406. return $query;
  407. }
  408. }