PageRenderTime 26ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/QubitQuery.class.php

https://github.com/mikesname/ehri-ica-atom
PHP | 410 lines | 300 code | 77 blank | 33 comment | 33 complexity | 56d9489678404a618dd10449a5fdbcd5 MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of Qubit Toolkit.
  4. *
  5. * Qubit Toolkit is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * Qubit Toolkit is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with Qubit Toolkit. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. class QubitQuery implements ArrayAccess, Countable, Iterator
  19. {
  20. protected
  21. $parent = null,
  22. $criteria = null,
  23. $className = null,
  24. $options = null,
  25. $statement = null,
  26. $objects = null,
  27. $count = null,
  28. $offset = 0,
  29. $orderByName = null,
  30. $andSelf = null,
  31. $indexByName = null,
  32. $orderByNames = null;
  33. public static function create(array $options = array())
  34. {
  35. $query = new QubitQuery;
  36. $query->options = $options;
  37. return $query;
  38. }
  39. public static function createFromCriteria(Criteria $criteria, $className, array $options = array())
  40. {
  41. $query = new QubitQuery;
  42. $query->criteria = $criteria;
  43. $query->className = $className;
  44. $query->options = $options;
  45. return $query;
  46. }
  47. // Not recursive: Only ever called from the root.
  48. protected function getStatement(QubitQuery $leaf)
  49. {
  50. // HACK Tell the caller whether we sorted according to the leaf
  51. $sorted = false;
  52. if (!isset($this->statement))
  53. {
  54. foreach ($leaf->getOrderByNames() as $name)
  55. {
  56. $this->criteria->addAscendingOrderByColumn(constant($this->className.'::'.strtoupper($name)));
  57. }
  58. $sorted = true;
  59. $this->statement = BasePeer::doSelect($this->criteria);
  60. }
  61. // TODO Determine whether the sort order matches the previous sort order
  62. return array($this->statement, $sorted);
  63. }
  64. protected function getObjects(QubitQuery $leaf)
  65. {
  66. // HACK Tell the caller whether we sorted according to the leaf
  67. $sorted = false;
  68. if (!isset($this->objects))
  69. {
  70. if (isset($this->parent))
  71. {
  72. list ($this->objects, $sorted) = $this->parent->getObjects($leaf);
  73. // Possibly re-index
  74. if (isset($this->indexByName))
  75. {
  76. $objects = array();
  77. foreach ($this->objects as $object)
  78. {
  79. $objects[$object[$this->indexByName]] = $object;
  80. }
  81. $this->objects = $objects;
  82. }
  83. }
  84. else
  85. {
  86. $this->objects = array();
  87. $sorted = true;
  88. if (isset($this->criteria))
  89. {
  90. list ($this->statement, $sorted) = $this->getStatement($leaf);
  91. while ($row = $this->statement->fetch())
  92. {
  93. // $this->parent is unset, so we should have a className?
  94. $object = call_user_func(array($this->className, 'getFromRow'), $row);
  95. // TODO $this->parent is unset, so we probably do not have
  96. // $this->indexByName, but it would be nice to use the indexByName
  97. // of the leaf
  98. if (isset($this->indexByName))
  99. {
  100. $this->objects[call_user_func(array($object, 'get'.$this->indexByName))] = $object;
  101. }
  102. else
  103. {
  104. $this->objects[] = $object;
  105. }
  106. }
  107. }
  108. }
  109. // Possibly add self
  110. if (isset($this->andSelf))
  111. {
  112. if (count($this->objects) > 0)
  113. {
  114. $sorted = false;
  115. }
  116. if (isset($this->indexByName))
  117. {
  118. $this->objects[call_user_func(array($this->andSelf, 'get'.$this->indexByName))] = $this->andSelf;
  119. }
  120. else
  121. {
  122. $this->objects[] = $this->andSelf;
  123. }
  124. }
  125. // If we added to the array of objects, or we should sort and have not
  126. // yet sorted, then sort according to the leaf. Since the leaf is a
  127. // refinement, we will be sorted at least according to our orderByName.
  128. // Indicate that we sorted according to the leaf, to save further
  129. // sorting by descendants.
  130. if (isset($this->orderByName) && !$sorted)
  131. {
  132. if (isset($this->indexByName))
  133. {
  134. $sorted = uasort($this->objects, array($leaf, 'sortCallback'));
  135. }
  136. else
  137. {
  138. $sorted = usort($this->objects, array($leaf, 'sortCallback'));
  139. }
  140. }
  141. }
  142. return array($this->objects, $sorted);
  143. }
  144. public function __isset($name)
  145. {
  146. list ($objects, $sorted) = $this->getObjects($this);
  147. return array_key_exists($name, $this->objects);
  148. }
  149. public function offsetExists($offset)
  150. {
  151. $args = func_get_args();
  152. return call_user_func_array(array($this, '__isset'), $args);
  153. }
  154. public function __get($name)
  155. {
  156. if ('transient' === $name)
  157. {
  158. if (!isset($this->objects))
  159. {
  160. return array();
  161. }
  162. return $this->objects;
  163. }
  164. list ($objects, $sorted) = $this->getObjects($this);
  165. if (isset($this->objects[$name]))
  166. {
  167. return $this->objects[$name];
  168. }
  169. }
  170. public function offsetGet($offset)
  171. {
  172. $args = func_get_args();
  173. return call_user_func_array(array($this, '__get'), $args);
  174. }
  175. public function __set($name, $value)
  176. {
  177. if (null === $name)
  178. {
  179. $this->objects[] = $value;
  180. }
  181. if (isset($this->indexByName))
  182. {
  183. $value[$this->indexByName] = $name;
  184. $this->objects[$name] = $value;
  185. // HACK
  186. if (isset($this->parent))
  187. {
  188. $this->parent[] = $value;
  189. }
  190. }
  191. return $this;
  192. }
  193. public function offsetSet($offset, $value)
  194. {
  195. $args = func_get_args();
  196. return call_user_func_array(array($this, '__set'), $args);
  197. }
  198. public function offsetUnset($offset)
  199. {
  200. }
  201. protected function getCount(QubitQuery $leaf)
  202. {
  203. if (!isset($this->objects))
  204. {
  205. $count = 0;
  206. if (isset($this->parent))
  207. {
  208. $count = $this->parent->getCount($leaf);
  209. }
  210. else if (isset($this->count))
  211. {
  212. $count = $this->count;
  213. }
  214. else if (isset($this->criteria))
  215. {
  216. $countCriteria = clone $this->criteria;
  217. $this->count = intval(BasePeer::doCount($countCriteria)->fetchColumn(0));
  218. $count = $this->count;
  219. }
  220. if (isset($this->andSelf))
  221. {
  222. $count++;
  223. }
  224. return $count;
  225. }
  226. return count($this->objects);
  227. }
  228. public function count()
  229. {
  230. return $this->getCount($this);
  231. }
  232. public function current()
  233. {
  234. list ($objects, $sorted) = $this->getObjects($this);
  235. return current($this->objects);
  236. }
  237. public function key()
  238. {
  239. list ($objects, $sorted) = $this->getObjects($this);
  240. return key($this->objects);
  241. }
  242. public function next()
  243. {
  244. $this->offset++;
  245. list ($objects, $sorted) = $this->getObjects($this);
  246. return next($this->objects);
  247. }
  248. public function rewind()
  249. {
  250. $this->offset = 0;
  251. list ($objects, $sorted) = $this->getObjects($this);
  252. return reset($this->objects);
  253. }
  254. public function valid()
  255. {
  256. list ($objects, $sorted) = $this->getObjects($this);
  257. return $this->offset < count($this->objects);
  258. }
  259. protected function getOrderByNames()
  260. {
  261. if (!isset($this->orderByNames))
  262. {
  263. if (isset($this->parent))
  264. {
  265. $this->orderByNames = $this->parent->getOrderByNames();
  266. }
  267. else
  268. {
  269. $this->orderByNames = array();
  270. }
  271. if (isset($this->orderByName))
  272. {
  273. $this->orderByNames[] = $this->orderByName;
  274. }
  275. }
  276. return $this->orderByNames;
  277. }
  278. protected function sortCallback($a, $b)
  279. {
  280. foreach ($this->getOrderByNames() as $name)
  281. {
  282. $aGet = call_user_func(array($a, 'get'.$name));
  283. $bGet = call_user_func(array($b, 'get'.$name));
  284. if ($aGet < $bGet)
  285. {
  286. return -1;
  287. }
  288. if ($aGet > $bGet)
  289. {
  290. return 1;
  291. }
  292. }
  293. }
  294. public function orderBy($name)
  295. {
  296. $query = new QubitQuery;
  297. $query->parent = $this;
  298. $query->orderByName = $name;
  299. return $query;
  300. }
  301. protected function getOptions()
  302. {
  303. if (!isset($this->options))
  304. {
  305. if (isset($this->parent))
  306. {
  307. $this->options = $this->parent->getOptions();
  308. }
  309. else
  310. {
  311. $this->options = array();
  312. }
  313. }
  314. return $this->options;
  315. }
  316. public function andSelf()
  317. {
  318. $query = new QubitQuery;
  319. $query->parent = $this;
  320. // Set andSelf and remove 'self' option
  321. $query->options = $this->getOptions();
  322. $query->andSelf = $query->options['self'];
  323. unset($query->options['self']);
  324. return $query;
  325. }
  326. public function indexBy($name)
  327. {
  328. $query = new QubitQuery;
  329. $query->parent = $this;
  330. $query->indexByName = $name;
  331. return $query;
  332. }
  333. }