PageRenderTime 40ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/plugins/rainlab/builder/components/RecordList.php

https://gitlab.com/gideonmarked/newlifetrainingcenter-v2
PHP | 335 lines | 243 code | 50 blank | 42 comment | 21 complexity | c265bc8ab93a8cb303c0bd3be8a22e47 MD5 | raw file
  1. <?php namespace RainLab\Builder\Components;
  2. use Lang;
  3. use Cms\Classes\Page;
  4. use Cms\Classes\ComponentBase;
  5. use RainLab\Builder\Classes\ComponentHelper;
  6. use SystemException;
  7. use Exception;
  8. class RecordList extends ComponentBase
  9. {
  10. /**
  11. * A collection of records to display
  12. * @var \October\Rain\Database\Collection
  13. */
  14. public $records;
  15. /**
  16. * Message to display when there are no records.
  17. * @var string
  18. */
  19. public $noRecordsMessage;
  20. /**
  21. * Reference to the page name for linking to details.
  22. * @var string
  23. */
  24. public $detailsPage;
  25. /**
  26. * Specifies the current page number.
  27. * @var integer
  28. */
  29. public $pageNumber;
  30. /**
  31. * Parameter to use for the page number
  32. * @var string
  33. */
  34. public $pageParam;
  35. /**
  36. * Model column name to display in the list.
  37. * @var string
  38. */
  39. public $displayColumn;
  40. /**
  41. * Model column to use as a record identifier in the details page links
  42. * @var string
  43. */
  44. public $detailsKeyColumn;
  45. /**
  46. * Name of the details page URL parameter which takes the record identifier.
  47. * @var string
  48. */
  49. public $detailsUrlParameter;
  50. public function componentDetails()
  51. {
  52. return [
  53. 'name' => 'rainlab.builder::lang.components.list_title',
  54. 'description' => 'rainlab.builder::lang.components.list_description'
  55. ];
  56. }
  57. //
  58. // Properties
  59. //
  60. public function defineProperties()
  61. {
  62. return [
  63. 'modelClass' => [
  64. 'title' => 'rainlab.builder::lang.components.list_model',
  65. 'type' => 'dropdown',
  66. 'showExternalParam' => false
  67. ],
  68. 'scope' => [
  69. 'title' => 'rainlab.builder::lang.components.list_scope',
  70. 'description' => 'rainlab.builder::lang.components.list_scope_description',
  71. 'type' => 'dropdown',
  72. 'depends' => ['modelClass'],
  73. 'showExternalParam' => false
  74. ],
  75. 'displayColumn' => [
  76. 'title' => 'rainlab.builder::lang.components.list_display_column',
  77. 'description' => 'rainlab.builder::lang.components.list_display_column_description',
  78. 'type' => 'autocomplete',
  79. 'depends' => ['modelClass'],
  80. 'validation' => [
  81. 'required' => [
  82. 'message' => Lang::get('rainlab.builder::lang.components.list_display_column_required')
  83. ]
  84. ]
  85. ],
  86. 'noRecordsMessage' => [
  87. 'title' => 'rainlab.builder::lang.components.list_no_records',
  88. 'description' => 'rainlab.builder::lang.components.list_no_records_description',
  89. 'type' => 'string',
  90. 'default' => Lang::get('rainlab.builder::lang.components.list_no_records_default'),
  91. 'showExternalParam' => false,
  92. ],
  93. 'detailsPage' => [
  94. 'title' => 'rainlab.builder::lang.components.list_details_page',
  95. 'description' => 'rainlab.builder::lang.components.list_details_page_description',
  96. 'type' => 'dropdown',
  97. 'showExternalParam' => false,
  98. 'group' => 'rainlab.builder::lang.components.list_detalis_page_link'
  99. ],
  100. 'detailsKeyColumn' => [
  101. 'title' => 'rainlab.builder::lang.components.list_details_key_column',
  102. 'description' => 'rainlab.builder::lang.components.list_details_key_column_description',
  103. 'type' => 'autocomplete',
  104. 'depends' => ['modelClass'],
  105. 'showExternalParam' => false,
  106. 'group' => 'rainlab.builder::lang.components.list_detalis_page_link'
  107. ],
  108. 'detailsUrlParameter' => [
  109. 'title' => 'rainlab.builder::lang.components.list_details_url_parameter',
  110. 'description' => 'rainlab.builder::lang.components.list_details_url_parameter_description',
  111. 'type' => 'string',
  112. 'default' => 'id',
  113. 'showExternalParam' => false,
  114. 'group' => 'rainlab.builder::lang.components.list_detalis_page_link'
  115. ],
  116. 'recordsPerPage' => [
  117. 'title' => 'rainlab.builder::lang.components.list_records_per_page',
  118. 'description' => 'rainlab.builder::lang.components.list_records_per_page_description',
  119. 'type' => 'string',
  120. 'validationPattern' => '^[0-9]*$',
  121. 'validationMessage' => 'rainlab.builder::lang.components.list_records_per_page_validation',
  122. 'group' => 'rainlab.builder::lang.components.list_pagination'
  123. ],
  124. 'pageNumber' => [
  125. 'title' => 'rainlab.builder::lang.components.list_page_number',
  126. 'description' => 'rainlab.builder::lang.components.list_page_number_description',
  127. 'type' => 'string',
  128. 'default' => '{{ :page }}',
  129. 'group' => 'rainlab.builder::lang.components.list_pagination'
  130. ],
  131. 'sortColumn' => [
  132. 'title' => 'rainlab.builder::lang.components.list_sort_column',
  133. 'description' => 'rainlab.builder::lang.components.list_sort_column_description',
  134. 'type' => 'autocomplete',
  135. 'depends' => ['modelClass'],
  136. 'group' => 'rainlab.builder::lang.components.list_sorting',
  137. 'showExternalParam' => false
  138. ],
  139. 'sortDirection' => [
  140. 'title' => 'rainlab.builder::lang.components.list_sort_direction',
  141. 'type' => 'dropdown',
  142. 'showExternalParam' => false,
  143. 'group' => 'rainlab.builder::lang.components.list_sorting',
  144. 'options' => [
  145. 'asc' => 'rainlab.builder::lang.components.list_order_direction_asc',
  146. 'desc' => 'rainlab.builder::lang.components.list_order_direction_desc'
  147. ]
  148. ]
  149. ];
  150. }
  151. public function getDetailsPageOptions()
  152. {
  153. $pages = Page::sortBy('baseFileName')->lists('baseFileName', 'baseFileName');
  154. $pages = [
  155. '-' => Lang::get('rainlab.builder::lang.components.list_details_page_no')
  156. ] + $pages;
  157. return $pages;
  158. }
  159. public function getModelClassOptions()
  160. {
  161. return ComponentHelper::instance()->listGlobalModels();
  162. }
  163. public function getDisplayColumnOptions()
  164. {
  165. return ComponentHelper::instance()->listModelColumnNames();
  166. }
  167. public function getDetailsKeyColumnOptions()
  168. {
  169. return ComponentHelper::instance()->listModelColumnNames();
  170. }
  171. public function getSortColumnOptions()
  172. {
  173. return ComponentHelper::instance()->listModelColumnNames();
  174. }
  175. public function getScopeOptions()
  176. {
  177. $modelClass = ComponentHelper::instance()->getModelClassDesignTime();
  178. $result = [
  179. '-' => Lang::get('rainlab.builder::lang.components.list_scope_default')
  180. ];
  181. try {
  182. $methods = get_class_methods($modelClass);
  183. foreach ($methods as $method) {
  184. if (preg_match('/scope[A-Z].*/', $method)) {
  185. $result[$method] = $method;
  186. }
  187. }
  188. }
  189. catch (Exception $ex) {
  190. // Ignore invalid models
  191. }
  192. return $result;
  193. }
  194. //
  195. // Rendering and processing
  196. //
  197. public function onRun()
  198. {
  199. $this->prepareVars();
  200. $this->records = $this->page['records'] = $this->listRecords();
  201. }
  202. protected function prepareVars()
  203. {
  204. $this->noRecordsMessage = $this->page['noRecordsMessage'] = Lang::get($this->property('noRecordsMessage'));
  205. $this->displayColumn = $this->page['displayColumn'] = $this->property('displayColumn');
  206. $this->pageParam = $this->page['pageParam'] = $this->paramName('pageNumber');
  207. $this->detailsKeyColumn = $this->page['detailsKeyColumn'] = $this->property('detailsKeyColumn');
  208. $this->detailsUrlParameter = $this->page['detailsUrlParameter'] = $this->property('detailsUrlParameter');
  209. $detailsPage = $this->property('detailsPage');
  210. if ($detailsPage == '-') {
  211. $detailsPage = null;
  212. }
  213. $this->detailsPage = $this->page['detailsPage'] = $detailsPage;
  214. if (!strlen($this->displayColumn)) {
  215. throw new SystemException('The display column name is not set.');
  216. }
  217. if (strlen($this->detailsPage)) {
  218. if (!strlen($this->detailsKeyColumn)) {
  219. throw new SystemException('The details key column should be set to generate links to the details page.');
  220. }
  221. if (!strlen($this->detailsUrlParameter)) {
  222. throw new SystemException('The details page URL parameter name should be set to generate links to the details page.');
  223. }
  224. }
  225. }
  226. protected function listRecords()
  227. {
  228. $modelClassName = $this->property('modelClass');
  229. if (!strlen($modelClassName) || !class_exists($modelClassName)) {
  230. throw new SystemException('Invalid model class name');
  231. }
  232. $model = new $modelClassName();
  233. $scope = $this->getScopeName($model);
  234. if ($scope !== null) {
  235. $model = $model->$scope();
  236. }
  237. $model = $this->sort($model);
  238. $records = $this->paginate($model);
  239. return $records;
  240. }
  241. protected function getScopeName($model)
  242. {
  243. $scopeMethod = trim($this->property('scope'));
  244. if (!strlen($scopeMethod) || $scopeMethod == '-') {
  245. return null;
  246. }
  247. if (!preg_match('/scope[A-Z].+/', $scopeMethod)) {
  248. throw new SystemException('Invalid scope method name.');
  249. }
  250. if (!method_exists($model, $scopeMethod)) {
  251. throw new SystemException('Scope method not found.');
  252. }
  253. return lcfirst(substr($scopeMethod, 5));
  254. }
  255. protected function paginate($model)
  256. {
  257. $recordsPerPage = trim($this->property('recordsPerPage'));
  258. if (!strlen($recordsPerPage)) {
  259. // Pagination is disabled - return all records
  260. return $model->get();
  261. }
  262. if (!preg_match('/^[0-9]+$/', $recordsPerPage)) {
  263. throw new SystemException('Invalid records per page value.');
  264. }
  265. $pageNumber = trim($this->property('pageNumber'));
  266. if (!strlen($pageNumber) || !preg_match('/^[0-9]+$/', $pageNumber)) {
  267. $pageNumber = 1;
  268. }
  269. return $model->paginate($recordsPerPage, $pageNumber);
  270. }
  271. protected function sort($model)
  272. {
  273. $sortColumn = trim($this->property('sortColumn'));
  274. if (!strlen($sortColumn)) {
  275. return $model;
  276. }
  277. $sortDirection = trim($this->property('sortDirection'));
  278. if ($sortDirection !== 'desc') {
  279. $sortDirection = 'asc';
  280. }
  281. // Note - no further validation of the sort column
  282. // value is performed here, relying to the ORM sanitizing.
  283. return $model->orderBy($sortColumn, $sortDirection);
  284. }
  285. }