/fo/classes/record/RecordQuery.class.php

https://github.com/openstate/HNS.dev · PHP · 238 lines · 168 code · 16 blank · 54 comment · 10 complexity · c4d6e36f45e77903f45728bf7866dca5 MD5 · raw file

  1. <?php
  2. require_once 'record/RecordCollection.class.php';
  3. class RecordQuery {
  4. protected $className = null;
  5. protected $db = null;
  6. const FETCH_OBJ = 'fetch_object';
  7. const FETCH_ARRAY = 'fetch_array';
  8. const FETCH_STATEMENT = 'fetch_statement';
  9. protected $queryData = array(
  10. 'fetchMode' => self::FETCH_OBJ,
  11. 'recordColumns' => true,
  12. 'extraColumns' => array(),
  13. 'alias' => 't1',
  14. 'withHasOne' => Record::LOAD_DEFAULT,
  15. 'join' => array(),
  16. 'where' => array(),
  17. 'order' => array(),
  18. 'limitCount' => false,
  19. 'limitOffset' => false,
  20. 'group' => array(),
  21. 'having' => array()
  22. );
  23. public function __construct(Database $db, $className) {
  24. $this->className = $className;
  25. $this->db = $db;
  26. }
  27. public function __sleep() {
  28. throw new Exception('Serialization of the RecordQuery isn\'t allowed');
  29. }
  30. //chain functions
  31. /*
  32. Method to exclude the default record columns, will only use the extra columns added with addExtraColumn.
  33. */
  34. public function addRecordColumns($bool) {
  35. $this->queryData['recordColumns'] = (bool)$bool;
  36. if (!$bool && $this->queryData['fetchMode'] === self::FETCH_OBJ)
  37. $this->queryData['fetchMode'] = self::FETCH_STATEMENT;
  38. return $this;
  39. }
  40. /*
  41. Sets the fetchmode for the get() function, only possible to get an object if you are also getting the record's columns
  42. */
  43. public function setFetchMode($mode) {
  44. $fetchModes = array(self::FETCH_ARRAY, self::FETCH_STATEMENT);
  45. if ($this->queryData['recordColumns'] === true) //only allow object fetching if we still get the columns for it.
  46. $fetchModes[] = self::FETCH_OBJ;
  47. if (in_array($mode, $fetchModes))
  48. $this->queryData['fetchMode'] = $mode;
  49. return $this;
  50. }
  51. /*
  52. Add a join
  53. */
  54. public function join($query) {
  55. $args = func_get_args();
  56. $this->queryData['join'][] = call_user_func_array(array($this->db, 'formatQuery'), $args);
  57. return $this;
  58. }
  59. /*
  60. Add a where
  61. all where calls will be joined with AND and will have ( ) around them.
  62. For OR you'll need to do it manually within one call
  63. */
  64. public function where($query) {
  65. $args = func_get_args();
  66. $this->queryData['where'][] = call_user_func_array(array($this->db, 'formatQuery'), $args);
  67. return $this;
  68. }
  69. /*
  70. Adds a order by
  71. All order by calls will be joined with ', '
  72. */
  73. public function order($query) {
  74. $args = func_get_args();
  75. $this->queryData['order'][] = call_user_func_array(array($this->db, 'formatQuery'), $args);
  76. return $this;
  77. }
  78. /*
  79. Adds a limit (and offset)
  80. only accepts 2 parameters the first is the count, the second is the offset
  81. */
  82. public function limit($count) {
  83. $args = func_get_args();
  84. switch (count($args)) {
  85. case 1:
  86. $this->queryData['limitCount'] = $args[0];
  87. $this->queryData['limitOffset'] = false;
  88. break;
  89. case 2:
  90. $this->queryData['limitCount'] = $args[0];
  91. $this->queryData['limitOffset'] = $args[1];
  92. break;
  93. default:
  94. $this->queryData['limitCount'] = false;
  95. $this->queryData['limitOffset'] = false;
  96. }
  97. return $this;
  98. }
  99. /*
  100. Adds a group by
  101. all group by calls are joined with ', '
  102. */
  103. public function group($query) {
  104. $args = func_get_args();
  105. $this->queryData['group'][] = call_user_func_array(array($this->db, 'formatQuery'), $args);
  106. return $this;
  107. }
  108. /*
  109. Adds a having
  110. all where calls will be joined with AND and will have ( ) around them.
  111. For OR you'll need to do it manually within one call
  112. */
  113. public function having($query) {
  114. $args = func_get_args();
  115. $this->queryData['having'][] = call_user_func_array(array($this->db, 'formatQuery'), $args);
  116. return $this;
  117. }
  118. /*
  119. Set's the alias to be used for the main table
  120. Be careful with this.
  121. */
  122. public function setAlias($alias) {
  123. $this->queryData['alias'] = $alias;
  124. return $this;
  125. }
  126. /*
  127. Sets if the records should be loaded with the has_one relations
  128. LOAD_DEFAULT will only load them in configured that way
  129. */
  130. public function withHasOne($withHasOne) {
  131. if (in_array($withHasOne, array(Record::LOAD_ALL, Record::LOAD_NONE, Record::LOAD_DEFAULT)))
  132. $this->queryData['withHasOne'] = $withHasOne;
  133. return $this;
  134. }
  135. /*
  136. Adds an extra column to the select statement
  137. */
  138. public function addExtraColumn($column) {
  139. $args = func_get_args();
  140. $this->queryData['extraColumns'][] = call_user_func_array(array($this->db, 'formatQuery'), $args);
  141. return $this;
  142. }
  143. //get functions
  144. public function get() {
  145. switch ($this->queryData['fetchMode']) {
  146. case self::FETCH_STATEMENT:
  147. $rec = new $this->className();
  148. $query = $rec->buildFetchQuery($this->queryData);
  149. return $this->db->query($query);
  150. break;
  151. case self::FETCH_ARRAY:
  152. $rec = new $this->className();
  153. $query = $rec->buildFetchQuery($this->queryData);
  154. $rows = $this->db->query($query)->fetchAllRows();
  155. $result = array();
  156. foreach($rows as $row) {
  157. $key = array_shift($row);
  158. $result[$key] = current($row);
  159. }
  160. return $result;
  161. break;
  162. case self::FETCH_OBJ:
  163. default:
  164. $rc = new RecordCollection($this->className);
  165. $rc->fetch($this->db, $this->queryData);
  166. return $rc;
  167. break;
  168. }
  169. }
  170. public function getCountGrouped($groupby = false) {
  171. $rec = new $this->className();
  172. $queryData = $this->queryData;
  173. $queryData['extraColumns'] = array(); //delete any set column
  174. $queryData['extraColumns'][] = 'COUNT(*) as count';
  175. $queryData['recordColumns'] = false; //remove record columns
  176. //people are allowed to add multiple groups in on ->group call, so split them here
  177. $groups = implode(',', $queryData['group']);
  178. $groups = explode(',', $groups);
  179. //add the group by columns
  180. foreach ($groups as $group) {
  181. if (empty($group)) continue;
  182. $queryData['extraColumns'][] = trim($group);
  183. }
  184. if ($groupby) {
  185. if (!is_array($groupby))
  186. $groupby = array($groupby);
  187. foreach ($groupby as $group) {
  188. $queryData['extraColumns'][] = $group;
  189. $queryData['group'][] = $group;
  190. }
  191. }
  192. $query = $rec->buildFetchQuery($queryData);
  193. return $this->db->query($query)->fetchAllRows();
  194. }
  195. //Returns an number of results in the query
  196. public function getCount() {
  197. $rec = new $this->className();
  198. $queryData = $this->queryData;
  199. $queryData['extraColumns'] = array(); //delete any set column
  200. $queryData['extraColumns'][] = 'COUNT(*) as Count';
  201. $queryData['recordColumns'] = false; //remove record columns
  202. //notice to make sure it is understood what is happening here.
  203. if (!empty($queryData['group']))
  204. trigger_error('Grouping columns are added and will be removed, use getCountGrouped instead if you want them added', E_USER_NOTICE);
  205. $queryData['group'] = array();
  206. $query = $rec->buildFetchQuery($queryData);
  207. return (int)$this->db->query($query)->fetchCell();
  208. }
  209. public function getStatement() {
  210. return $this->setFetchMode(self::FETCH_STATEMENT)->get();
  211. }
  212. /**
  213. * Return the query that will be executed to get the data.
  214. *
  215. * @return string The query
  216. * @author Harro
  217. **/
  218. public function getQuery() {
  219. $rec = new $this->className();
  220. return $rec->buildFetchQuery($this->queryData);
  221. }
  222. }