PageRenderTime 41ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/Backend/helpers/dataTable.php

http://atomikframework.googlecode.com/
PHP | 413 lines | 234 code | 53 blank | 126 comment | 34 complexity | 0d58a956051a57d3788a32f696bc60ab MD5 | raw file
Possible License(s): LGPL-2.1, MIT, CC-BY-3.0
  1. <?php
  2. class DataTableHelper
  3. {
  4. /**
  5. * @var array
  6. */
  7. public static $defaultOptions = array(
  8. 'currentPage' => 1,
  9. 'rowsPerPage' => 20,
  10. 'numberOfPages' => 1,
  11. 'paginate' => true,
  12. 'paginateData' => true,
  13. 'sortable' => true,
  14. 'serverSort' => false,
  15. 'sortColumn' => false,
  16. 'sortOrder' => 'asc',
  17. 'sortData' => true
  18. );
  19. /**
  20. * @var string
  21. */
  22. public $id;
  23. /**
  24. * @var array
  25. */
  26. public $options;
  27. /**
  28. * @var array
  29. */
  30. public $columns = array();
  31. /**
  32. * @var int
  33. */
  34. public $startingRow = 0;
  35. /**
  36. * @var int
  37. */
  38. public $maxRow = 20;
  39. /**
  40. * @var array
  41. */
  42. protected $_data = array();
  43. /**
  44. * Constructor
  45. */
  46. public function __construct()
  47. {
  48. $this->options = self::$defaultOptions;
  49. Atomik_Assets::addNamedAsset('dataTable');
  50. }
  51. /**
  52. * Method used for the view helper
  53. *
  54. * @param string $id
  55. * @param array $data
  56. * @param array $options
  57. * @return DataTableHelper
  58. */
  59. public function dataTable($id = null, $data = array(), $options = array())
  60. {
  61. if ($id === null) {
  62. return $this;
  63. }
  64. $this->id = $id;
  65. $this->options = array_merge(self::$defaultOptions, $options);
  66. // options
  67. $this->options['remote'] = Atomik::url(null, array('dataTableRemote' => $id));
  68. $this->options['url'] = Atomik::get('url', Atomik::url('edit'), $options);
  69. $this->_setupSorting();
  70. $this->setData($data);
  71. return $this;
  72. }
  73. /**
  74. * Sets the data
  75. *
  76. * @param array $data
  77. */
  78. public function setData($data)
  79. {
  80. $this->_data = $data;
  81. $this->_setupColumns();
  82. $this->_setupPagination();
  83. if ($this->options['sortData'] && $this->options['sortColumn'] !== false) {
  84. usort($this->_data, array($this, '_sortData'));
  85. }
  86. }
  87. /**
  88. * Returns the data
  89. *
  90. * @return array
  91. */
  92. public function getData()
  93. {
  94. return $this->_data;
  95. }
  96. /**
  97. * Returns the data which needs to be displayed
  98. *
  99. * @return array
  100. */
  101. public function getDataToDisplay()
  102. {
  103. $data = array();
  104. for($currentRow = $this->startingRow; $currentRow < $this->maxRow; $currentRow++) {
  105. $data[] = $this->_data[$currentRow];
  106. }
  107. return $data;
  108. }
  109. /**
  110. * Sorts the data
  111. */
  112. protected function _sortData($a, $b)
  113. {
  114. $column = $this->options['sortColumn'];
  115. $cmp = strnatcmp($a[$column], $b[$column]);
  116. if ($this->options['sortOrder'] == 'desc') {
  117. return -$cmp;
  118. }
  119. return $cmp;
  120. }
  121. /**
  122. * Setups the table columns
  123. */
  124. protected function _setupColumns()
  125. {
  126. $this->columns = array();
  127. if (!isset($this->options['columns'])) {
  128. // find columns through all rows
  129. foreach ($this->_data as $row) {
  130. foreach ($row as $key => $value) {
  131. if (!isset($this->columns[$key])) {
  132. $this->columns[$key] = $key;
  133. }
  134. }
  135. }
  136. } else {
  137. // clean the columns array
  138. foreach ((array) $this->options['columns'] as $key => $value) {
  139. if (is_int($key)) {
  140. $key = $value;
  141. }
  142. $this->columns[$key] = $value;
  143. }
  144. }
  145. }
  146. /**
  147. * Setups the pagination
  148. */
  149. protected function _setupPagination()
  150. {
  151. $dataCount = count($this->_data);
  152. $this->options['currentPage'] = Atomik::get('request/dataTablePage', Atomik::get('currentPage', 1, $this->options));
  153. $this->options['numberOfRows'] = Atomik::get('numberOfRows', $dataCount, $this->options);
  154. $this->options['rowsPerPage'] = Atomik::get('request/dataTableLength',
  155. Atomik::get('rowsPerPage', self::$defaultOptions['rowsPerPage'], $this->options));
  156. if ($this->options['rowsPerPage'] == -1) {
  157. $this->options['rowsPerPage'] = $this->options['numberOfRows'];
  158. }
  159. if ($this->options['numberOfRows'] > 0) {
  160. $this->options['numberOfPages'] = ceil($this->options['numberOfRows'] / $this->options['rowsPerPage']);
  161. } else {
  162. $this->options['numberOfPages'] = 1;
  163. }
  164. if (!$this->options['paginateData']) {
  165. $this->startingRow = 0;
  166. $this->maxRow = $dataCount;
  167. } else {
  168. $this->startingRow = ($this->options['currentPage'] - 1) * $this->options['rowsPerPage'];
  169. $this->maxRow = min($this->startingRow + $this->options['rowsPerPage'], $dataCount);
  170. }
  171. }
  172. /**
  173. * Setups sorting
  174. */
  175. protected function _setupSorting()
  176. {
  177. if (!$this->options['sortable']) {
  178. return;
  179. }
  180. $this->options['sortColumn'] = Atomik::get('request/dataTableSortColumn',
  181. Atomik::get('sortColumn', false, $this->options));
  182. $this->options['sortOrder'] = Atomik::get('request/dataTableSortOrder',
  183. Atomik::get('sortOrder', 'asc', $this->options));
  184. }
  185. /**
  186. * Starts output bufferization to allow generation of a custom tbody.
  187. * Do not echo the tbody tag.
  188. *
  189. * @return DataTableHelper
  190. */
  191. public function start()
  192. {
  193. ob_start();
  194. return $this;
  195. }
  196. /**
  197. * Stops the output bufferization and renders the full table
  198. *
  199. * @return string
  200. */
  201. public function end()
  202. {
  203. return $this->renderWrapper('<tbody>' . ob_get_clean() . '</tbody>');
  204. }
  205. /**
  206. * Renders the table without a custom tbodu
  207. *
  208. * @return string
  209. */
  210. public function render()
  211. {
  212. return $this->renderWrapper($this->renderBody());
  213. }
  214. /**
  215. * Renders the wrapper div
  216. *
  217. * @param string $tbody
  218. * @return string
  219. */
  220. public function renderWrapper($tbody)
  221. {
  222. // remote call to only get the data
  223. if (isset($_GET['dataTableRemote']) && $_GET['dataTableRemote'] == $this->id) {
  224. ob_clean();
  225. echo $tbody;
  226. Atomik::end(true);
  227. }
  228. $table = sprintf("<table id=\"%s\" class=\"dataTable\">\n%s\n%s\n</table>\n%s",
  229. $this->id, $this->renderHead(), $tbody, $this->renderScript());
  230. return sprintf("<div id=\"%sWrapper\" class=\"dataTableWrapper\">\n%s\n<div class=\"clear\"></div>\n</div>",
  231. $this->id, $this->renderSearch() . $table . $this->renderPager());
  232. }
  233. /**
  234. * Renders the thead part of the table
  235. *
  236. * @return string
  237. */
  238. public function renderHead()
  239. {
  240. $sortClass = $this->options['sortOrder'] == 'asc' ? 'sortAsc' : 'sortDesc';
  241. $thead = "<thead>\n\t<tr>\n";
  242. foreach ($this->columns as $key => $label) {
  243. $thead .= sprintf("\t\t<th id=\"%s\" class=\"sortable %s\">%s</th>\n",
  244. $key,
  245. $this->options['sortColumn'] == $key ? $sortClass : '',
  246. ucfirst($label)
  247. );
  248. }
  249. if (count(Atomik::get('actions', array(), $this->options))) {
  250. $thead .= "\t\t<th class=\"actions\"></th>\n";
  251. }
  252. $thead .= "\t</tr>\n</thead>";
  253. return $thead;
  254. }
  255. /**
  256. * Renders the tbody part of the table
  257. *
  258. * @return string
  259. */
  260. public function renderBody()
  261. {
  262. $clickableColumns = Atomik::get('clickableCols', null, $this->options);
  263. $idColumn = Atomik::get('idColumn', 'id', $this->options);
  264. $actions = Atomik::get('actions', array(), $this->options);
  265. $classes = Atomik::get('classes', array(), $this->options);
  266. $actionsHtml = '';
  267. if (count($actions)) {
  268. $actionsHtml = '<td class="actions">';
  269. foreach ($actions as $action) {
  270. $actionsHtml .= sprintf('<a href="%s" class="action">%s</a> ', $action['url'], $action['label']);
  271. }
  272. $actionsHtml .= '</td>';
  273. }
  274. $tbody = '<tbody>';
  275. foreach ($this->getDataToDisplay() as $row) {
  276. $rel = isset($row[$idColumn]) ? $row[$idColumn] : '';
  277. $tr = '';
  278. $rowClasses = '';
  279. foreach ($this->columns as $key => $value) {
  280. $colClasses = '';
  281. $value = '';
  282. if (isset($row[$key])) {
  283. $value = (string) $this->renderValue($row, $key);
  284. }
  285. if ($clickableColumns !== false || (is_array($clickableColumns) && in_array($key, $clickableColumns))) {
  286. $colClasses = 'clickable';
  287. }
  288. if (isset($classes[$key]) && isset($classes[$key][$value])) {
  289. $rowClasses = ' ' . $classes[$key][$value];
  290. }
  291. $tr .= sprintf("\t\t<td class=\"%s\">%s</td>\n", $colClasses, $value);
  292. }
  293. $tbody .= sprintf("\t<tr class=\"%s\" rel=\"%s\">%s\n%s\t</tr>\n", $rowClasses, $rel, $tr, $actionsHtml);
  294. }
  295. $tbody .= '</tbody>';
  296. return $tbody;
  297. }
  298. /**
  299. * Returns a string representing the value
  300. *
  301. * @param array $row
  302. * @param string $column
  303. * @return string
  304. */
  305. public function renderValue($row, $column)
  306. {
  307. return $row[$column];
  308. }
  309. /**
  310. * Renders the needed javascript
  311. *
  312. * @return string
  313. */
  314. public function renderScript()
  315. {
  316. return sprintf('<script type="text/javascript">jQuery(function($) { $("#%sWrapper").dataTable(%s); })</script>',
  317. $this->id, json_encode($this->options));
  318. }
  319. /**
  320. * Renders the search box
  321. *
  322. * @return string
  323. */
  324. public function renderSearch()
  325. {
  326. }
  327. /**
  328. * Renders the pager
  329. *
  330. * @return string
  331. */
  332. public function renderPager()
  333. {
  334. $selectLength = '';
  335. /*$selectLength = '<div class="dataTableLengthWrapper"><label>' . __('Rows per page') . ': </label>'
  336. . '<select class="dataTableLength"><option value="10">10</option><option value="2">2</option>'
  337. . '<option value="20">20</option><option value="30">30</option>'
  338. . '<option value="50">50</option><option value="100">100</option>'
  339. . '<option value="-1">' . __('All') . '</option></select></div>';*/
  340. if (!$this->options['paginate'] || (($numberOfPages = $this->options['numberOfPages']) <= 1)) {
  341. return $selectLength;
  342. }
  343. $button = "<li><a href=\"#\" class=\"%s\">%s</a></li>\n";
  344. $html = "<ul class=\"dataTablePager\">\n" . sprintf($button, 'previous', 'Previous');
  345. for ($i = 1; $i <= min($numberOfPages, 10); $i++) {
  346. $html .= sprintf("<li><a href=\"#%s\" class=\"page%s\">%s</a></li>\n",
  347. $i, $this->options['currentPage'] == $i ? ' current' : '', $i);
  348. }
  349. $html .= sprintf($button, 'next', 'Next') . "</ul>\n" . $selectLength;
  350. return $html;
  351. }
  352. /**
  353. * @see DataTableHelper::render()
  354. * @return string
  355. */
  356. public function __toString()
  357. {
  358. return $this->render();
  359. }
  360. }