PageRenderTime 50ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/libraries/joomla/application/component/modellist.php

https://bitbucket.org/organicdevelopment/joomla-2.5
PHP | 373 lines | 163 code | 48 blank | 162 comment | 20 complexity | a9b91139fbe8c2c26bbd4db448610d37 MD5 | raw file
Possible License(s): LGPL-3.0, GPL-2.0, MIT, BSD-3-Clause, LGPL-2.1
  1. <?php
  2. /**
  3. * @package Joomla.Platform
  4. * @subpackage Application
  5. *
  6. * @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE
  8. */
  9. defined('JPATH_PLATFORM') or die;
  10. jimport('joomla.application.component.model');
  11. /**
  12. * Model class for handling lists of items.
  13. *
  14. * @package Joomla.Platform
  15. * @subpackage Application
  16. * @since 11.1
  17. */
  18. class JModelList extends JModel
  19. {
  20. /**
  21. * Internal memory based cache array of data.
  22. *
  23. * @var array
  24. * @since 11.1
  25. */
  26. protected $cache = array();
  27. /**
  28. * Context string for the model type. This is used to handle uniqueness
  29. * when dealing with the getStoreId() method and caching data structures.
  30. *
  31. * @var string
  32. * @since 11.1
  33. */
  34. protected $context = null;
  35. /**
  36. * Valid filter fields or ordering.
  37. *
  38. * @var array
  39. * @since 11.1
  40. */
  41. protected $filter_fields = array();
  42. /**
  43. * An internal cache for the last query used.
  44. *
  45. * @var JDatabaseQuery
  46. * @since 11.1
  47. */
  48. protected $query = array();
  49. /**
  50. * Constructor.
  51. *
  52. * @param array $config An optional associative array of configuration settings.
  53. *
  54. * @see JController
  55. * @since 11.1
  56. */
  57. public function __construct($config = array())
  58. {
  59. parent::__construct($config);
  60. // Add the ordering filtering fields white list.
  61. if (isset($config['filter_fields']))
  62. {
  63. $this->filter_fields = $config['filter_fields'];
  64. }
  65. // Guess the context as Option.ModelName.
  66. if (empty($this->context))
  67. {
  68. $this->context = strtolower($this->option . '.' . $this->getName());
  69. }
  70. }
  71. /**
  72. * Method to cache the last query constructed.
  73. *
  74. * This method ensures that the query is constructed only once for a given state of the model.
  75. *
  76. * @return JDatabaseQuery A JDatabaseQuery object
  77. *
  78. * @since 11.1
  79. */
  80. protected function _getListQuery()
  81. {
  82. // Capture the last store id used.
  83. static $lastStoreId;
  84. // Compute the current store id.
  85. $currentStoreId = $this->getStoreId();
  86. // If the last store id is different from the current, refresh the query.
  87. if ($lastStoreId != $currentStoreId || empty($this->query))
  88. {
  89. $lastStoreId = $currentStoreId;
  90. $this->query = $this->getListQuery();
  91. }
  92. return $this->query;
  93. }
  94. /**
  95. * Method to get an array of data items.
  96. *
  97. * @return mixed An array of data items on success, false on failure.
  98. *
  99. * @since 11.1
  100. */
  101. public function getItems()
  102. {
  103. // Get a storage key.
  104. $store = $this->getStoreId();
  105. // Try to load the data from internal storage.
  106. if (isset($this->cache[$store]))
  107. {
  108. return $this->cache[$store];
  109. }
  110. // Load the list items.
  111. $query = $this->_getListQuery();
  112. $items = $this->_getList($query, $this->getStart(), $this->getState('list.limit'));
  113. // Check for a database error.
  114. if ($this->_db->getErrorNum())
  115. {
  116. $this->setError($this->_db->getErrorMsg());
  117. return false;
  118. }
  119. // Add the items to the internal cache.
  120. $this->cache[$store] = $items;
  121. return $this->cache[$store];
  122. }
  123. /**
  124. * Method to get a JDatabaseQuery object for retrieving the data set from a database.
  125. *
  126. * @return JDatabaseQuery A JDatabaseQuery object to retrieve the data set.
  127. *
  128. * @since 11.1
  129. */
  130. protected function getListQuery()
  131. {
  132. $db = $this->getDbo();
  133. $query = $db->getQuery(true);
  134. return $query;
  135. }
  136. /**
  137. * Method to get a JPagination object for the data set.
  138. *
  139. * @return JPagination A JPagination object for the data set.
  140. *
  141. * @since 11.1
  142. */
  143. public function getPagination()
  144. {
  145. // Get a storage key.
  146. $store = $this->getStoreId('getPagination');
  147. // Try to load the data from internal storage.
  148. if (isset($this->cache[$store]))
  149. {
  150. return $this->cache[$store];
  151. }
  152. // Create the pagination object.
  153. jimport('joomla.html.pagination');
  154. $limit = (int) $this->getState('list.limit') - (int) $this->getState('list.links');
  155. $page = new JPagination($this->getTotal(), $this->getStart(), $limit);
  156. // Add the object to the internal cache.
  157. $this->cache[$store] = $page;
  158. return $this->cache[$store];
  159. }
  160. /**
  161. * Method to get a store id based on the model configuration state.
  162. *
  163. * This is necessary because the model is used by the component and
  164. * different modules that might need different sets of data or different
  165. * ordering requirements.
  166. *
  167. * @param string $id An identifier string to generate the store id.
  168. *
  169. * @return string A store id.
  170. *
  171. * @since 11.1
  172. */
  173. protected function getStoreId($id = '')
  174. {
  175. // Add the list state to the store id.
  176. $id .= ':' . $this->getState('list.start');
  177. $id .= ':' . $this->getState('list.limit');
  178. $id .= ':' . $this->getState('list.ordering');
  179. $id .= ':' . $this->getState('list.direction');
  180. return md5($this->context . ':' . $id);
  181. }
  182. /**
  183. * Method to get the total number of items for the data set.
  184. *
  185. * @return integer The total number of items available in the data set.
  186. *
  187. * @since 11.1
  188. */
  189. public function getTotal()
  190. {
  191. // Get a storage key.
  192. $store = $this->getStoreId('getTotal');
  193. // Try to load the data from internal storage.
  194. if (isset($this->cache[$store]))
  195. {
  196. return $this->cache[$store];
  197. }
  198. // Load the total.
  199. $query = $this->_getListQuery();
  200. $total = (int) $this->_getListCount($query);
  201. // Check for a database error.
  202. if ($this->_db->getErrorNum())
  203. {
  204. $this->setError($this->_db->getErrorMsg());
  205. return false;
  206. }
  207. // Add the total to the internal cache.
  208. $this->cache[$store] = $total;
  209. return $this->cache[$store];
  210. }
  211. /**
  212. * Method to get the starting number of items for the data set.
  213. *
  214. * @return integer The starting number of items available in the data set.
  215. *
  216. * @since 11.1
  217. */
  218. public function getStart()
  219. {
  220. $store = $this->getStoreId('getstart');
  221. // Try to load the data from internal storage.
  222. if (isset($this->cache[$store]))
  223. {
  224. return $this->cache[$store];
  225. }
  226. $start = $this->getState('list.start');
  227. $limit = $this->getState('list.limit');
  228. $total = $this->getTotal();
  229. if ($start > $total - $limit)
  230. {
  231. $start = max(0, (int) (ceil($total / $limit) - 1) * $limit);
  232. }
  233. // Add the total to the internal cache.
  234. $this->cache[$store] = $start;
  235. return $this->cache[$store];
  236. }
  237. /**
  238. * Method to auto-populate the model state.
  239. *
  240. * This method should only be called once per instantiation and is designed
  241. * to be called on the first call to the getState() method unless the model
  242. * configuration flag to ignore the request is set.
  243. *
  244. * Note. Calling getState in this method will result in recursion.
  245. *
  246. * @param string $ordering An optional ordering field.
  247. * @param string $direction An optional direction (asc|desc).
  248. *
  249. * @return void
  250. *
  251. * @since 11.1
  252. */
  253. protected function populateState($ordering = null, $direction = null)
  254. {
  255. // If the context is set, assume that stateful lists are used.
  256. if ($this->context)
  257. {
  258. $app = JFactory::getApplication();
  259. $value = $app->getUserStateFromRequest('global.list.limit', 'limit', $app->getCfg('list_limit'), 'uint');
  260. $limit = $value;
  261. $this->setState('list.limit', $limit);
  262. $value = $app->getUserStateFromRequest($this->context . '.limitstart', 'limitstart', 0);
  263. $limitstart = ($limit != 0 ? (floor($value / $limit) * $limit) : 0);
  264. $this->setState('list.start', $limitstart);
  265. // Check if the ordering field is in the white list, otherwise use the incoming value.
  266. $value = $app->getUserStateFromRequest($this->context . '.ordercol', 'filter_order', $ordering);
  267. if (!in_array($value, $this->filter_fields))
  268. {
  269. $value = $ordering;
  270. $app->setUserState($this->context . '.ordercol', $value);
  271. }
  272. $this->setState('list.ordering', $value);
  273. // Check if the ordering direction is valid, otherwise use the incoming value.
  274. $value = $app->getUserStateFromRequest($this->context . '.orderdirn', 'filter_order_Dir', $direction);
  275. if (!in_array(strtoupper($value), array('ASC', 'DESC', '')))
  276. {
  277. $value = $direction;
  278. $app->setUserState($this->context . '.orderdirn', $value);
  279. }
  280. $this->setState('list.direction', $value);
  281. }
  282. else
  283. {
  284. $this->setState('list.start', 0);
  285. $this->state->set('list.limit', 0);
  286. }
  287. }
  288. /**
  289. * Gets the value of a user state variable and sets it in the session
  290. *
  291. * This is the same as the method in JApplication except that this also can optionally
  292. * force you back to the first page when a filter has changed
  293. *
  294. * @param string $key The key of the user state variable.
  295. * @param string $request The name of the variable passed in a request.
  296. * @param string $default The default value for the variable if not found. Optional.
  297. * @param string $type Filter for the variable, for valid values see {@link JFilterInput::clean()}. Optional.
  298. * @param boolean $resetPage If true, the limitstart in request is set to zero
  299. *
  300. * @return The request user state.
  301. *
  302. * @since 11.1
  303. */
  304. public function getUserStateFromRequest($key, $request, $default = null, $type = 'none', $resetPage = true)
  305. {
  306. $app = JFactory::getApplication();
  307. $old_state = $app->getUserState($key);
  308. $cur_state = (!is_null($old_state)) ? $old_state : $default;
  309. $new_state = JRequest::getVar($request, null, 'default', $type);
  310. if (($cur_state != $new_state) && ($resetPage))
  311. {
  312. JRequest::setVar('limitstart', 0);
  313. }
  314. // Save the new value only if it is set in this request.
  315. if ($new_state !== null)
  316. {
  317. $app->setUserState($key, $new_state);
  318. }
  319. else
  320. {
  321. $new_state = $cur_state;
  322. }
  323. return $new_state;
  324. }
  325. }