Commit | Line | Data |
---|---|---|
6a488035 TO |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
bc77d7c0 | 4 | | Copyright CiviCRM LLC. All rights reserved. | |
6a488035 | 5 | | | |
bc77d7c0 TO |
6 | | This work is published under the GNU AGPLv3 license with some | |
7 | | permitted exceptions and without any warranty. For full license | | |
8 | | and copyright information, see https://civicrm.org/licensing | | |
6a488035 | 9 | +--------------------------------------------------------------------+ |
d25dd0ee | 10 | */ |
6a488035 TO |
11 | |
12 | /** | |
13 | * | |
14 | * This class is a generic class to be used when we want to display | |
15 | * a list of rows along with a set of associated actions | |
16 | * | |
17 | * Centralizing this code enables us to write a generic lister and enables | |
18 | * us to automate the export process. To use this class, the object has to | |
19 | * implement the Selector/Api.interface.php class | |
20 | * | |
21 | * @package CRM | |
ca5cec67 | 22 | * @copyright CiviCRM LLC https://civicrm.org/licensing |
6a488035 TO |
23 | * $Id$ |
24 | * | |
25 | */ | |
26 | class CRM_Core_Selector_Controller { | |
27 | ||
28 | /** | |
100fef9d | 29 | * Constants to determine if we should store |
6a488035 TO |
30 | * the output in the session or template |
31 | * @var int | |
32 | */ | |
33 | // move the values from the session to the template | |
7da04cde | 34 | const SESSION = 1, TEMPLATE = 2, |
353ffa53 | 35 | TRANSFER = 4, EXPORT = 8, SCREEN = 16, PDF = 32; |
6a488035 TO |
36 | |
37 | /** | |
fe482240 | 38 | * A CRM Object that implements CRM_Core_Selector_API. |
6a488035 TO |
39 | * @var object |
40 | */ | |
41 | protected $_object; | |
42 | ||
c490a46a CW |
43 | /** |
44 | * @var CRM_Utils_Sort | |
45 | */ | |
6a488035 TO |
46 | protected $_sort; |
47 | ||
c490a46a | 48 | /** |
100fef9d | 49 | * The current column to sort on |
c490a46a CW |
50 | * @var int |
51 | */ | |
6a488035 TO |
52 | protected $_sortID; |
53 | ||
c490a46a | 54 | /** |
100fef9d | 55 | * The sortOrder array |
c490a46a CW |
56 | * @var array |
57 | */ | |
6a488035 TO |
58 | protected $_sortOrder; |
59 | ||
c490a46a CW |
60 | /** |
61 | * @var CRM_Utils_Pager | |
62 | */ | |
6a488035 TO |
63 | protected $_pager; |
64 | ||
c490a46a | 65 | /** |
100fef9d | 66 | * The pageID |
c490a46a CW |
67 | * @var int |
68 | */ | |
6a488035 TO |
69 | protected $_pageID; |
70 | ||
c490a46a | 71 | /** |
100fef9d | 72 | * Offset |
c490a46a CW |
73 | * @var int |
74 | */ | |
6a488035 TO |
75 | protected $_pagerOffset; |
76 | ||
77 | /** | |
100fef9d | 78 | * Number of rows to return |
6a488035 TO |
79 | * @var int |
80 | */ | |
81 | protected $_pagerRowCount; | |
82 | ||
83 | /** | |
100fef9d | 84 | * Total number of rows |
6a488035 TO |
85 | * @var int |
86 | */ | |
87 | protected $_total; | |
88 | ||
c490a46a | 89 | /** |
100fef9d | 90 | * The objectAction for the WebObject |
518fa0ee | 91 | * @var int |
c490a46a | 92 | */ |
6a488035 TO |
93 | protected $_action; |
94 | ||
95 | /** | |
96 | * This caches the content for the display system | |
97 | * | |
98 | * @var string | |
99 | */ | |
100 | protected $_content; | |
101 | ||
102 | /** | |
103 | * Is this object being embedded in another object. If | |
104 | * so the display routine needs to not do any work. (The | |
105 | * parent object takes care of the display) | |
106 | * | |
317fceb4 | 107 | * @var bool |
6a488035 TO |
108 | */ |
109 | protected $_embedded = FALSE; | |
110 | ||
111 | /** | |
112 | * Are we in print mode? if so we need to modify the display | |
113 | * functionality to do a minimal display :) | |
114 | * | |
317fceb4 | 115 | * @var bool |
6a488035 TO |
116 | */ |
117 | protected $_print = FALSE; | |
118 | ||
119 | /** | |
120 | * The storage object (typically a form or a page) | |
121 | * | |
122 | * @var Object | |
123 | */ | |
124 | protected $_store; | |
125 | ||
126 | /** | |
127 | * Output target, session, template or both? | |
128 | * | |
129 | * @var int | |
130 | */ | |
131 | protected $_output; | |
132 | ||
133 | /** | |
134 | * Prefif for the selector variables | |
135 | * | |
136 | * @var int | |
137 | */ | |
138 | protected $_prefix; | |
139 | ||
140 | /** | |
100fef9d | 141 | * Cache the smarty template for efficiency reasons |
6a488035 TO |
142 | * |
143 | * @var CRM_Core_Smarty | |
144 | */ | |
145 | public static $_template; | |
146 | ||
147 | /** | |
148 | * Array of properties that the controller dumps into the output object | |
149 | * | |
150 | * @var array | |
6a488035 | 151 | */ |
be2fb01f | 152 | public static $_properties = ['columnHeaders', 'rows', 'rowsEmpty']; |
6a488035 TO |
153 | |
154 | /** | |
155 | * Should we compute actions dynamically (since they are quite verbose) | |
156 | * | |
317fceb4 | 157 | * @var bool |
6a488035 TO |
158 | */ |
159 | protected $_dynamicAction = FALSE; | |
160 | ||
161 | /** | |
fe482240 | 162 | * Class constructor. |
6a488035 | 163 | * |
6a0b768e TO |
164 | * @param CRM_Core_Selector_API $object |
165 | * An object that implements the selector API. | |
166 | * @param int $pageID | |
167 | * Default pageID. | |
168 | * @param int $sortID | |
169 | * Default sortID. | |
170 | * @param int $action | |
171 | * The actions to potentially support. | |
da6b46f4 | 172 | * @param CRM_Core_Page|CRM_Core_Form $store place in session to store some values |
6a0b768e TO |
173 | * @param int $output |
174 | * What do we so with the output, session/template//both. | |
6a488035 | 175 | * |
da6b46f4 EM |
176 | * @param null $prefix |
177 | * @param null $case | |
178 | * | |
179 | * @return \CRM_Core_Selector_Controller | |
da6b46f4 | 180 | */ |
00be9182 | 181 | public function __construct($object, $pageID, $sortID, $action, $store = NULL, $output = self::TEMPLATE, $prefix = NULL, $case = NULL) { |
6a488035 TO |
182 | |
183 | $this->_object = $object; | |
184 | $this->_pageID = $pageID ? $pageID : 1; | |
185 | $this->_sortID = $sortID ? $sortID : NULL; | |
186 | $this->_action = $action; | |
353ffa53 | 187 | $this->_store = $store; |
6a488035 TO |
188 | $this->_output = $output; |
189 | $this->_prefix = $prefix; | |
353ffa53 | 190 | $this->_case = $case; |
6a488035 TO |
191 | |
192 | // fix sortID | |
193 | if ($this->_sortID && strpos($this->_sortID, '_') === FALSE) { | |
194 | $this->_sortID .= '_u'; | |
195 | } | |
196 | ||
be2fb01f | 197 | $params = [ |
6a488035 | 198 | 'pageID' => $this->_pageID, |
be2fb01f | 199 | ]; |
6a488035 TO |
200 | |
201 | // let the constructor initialize this, should happen only once | |
202 | if (!isset(self::$_template)) { | |
203 | self::$_template = CRM_Core_Smarty::singleton(); | |
204 | } | |
205 | ||
206 | $this->_sortOrder = &$this->_object->getSortOrder($action); | |
207 | $this->_sort = new CRM_Utils_Sort($this->_sortOrder, $this->_sortID); | |
208 | ||
209 | /* | |
f4bff68a CW |
210 | * if we are in transfer mode, do not goto database, use the |
211 | * session values instead | |
212 | */ | |
6a488035 TO |
213 | |
214 | if ($output == self::TRANSFER) { | |
215 | $params['total'] = $this->_store->get($this->_prefix . 'rowCount'); | |
216 | } | |
217 | else { | |
218 | $params['total'] = $this->_object->getTotalCount($action, $this->_case); | |
219 | } | |
220 | ||
221 | $this->_total = $params['total']; | |
222 | $this->_object->getPagerParams($action, $params); | |
223 | ||
224 | /* | |
f4bff68a CW |
225 | * Set the default values of RowsPerPage |
226 | */ | |
6a488035 TO |
227 | |
228 | $storeRowCount = $store->get($this->_prefix . CRM_Utils_Pager::PAGE_ROWCOUNT); | |
229 | if ($storeRowCount) { | |
230 | $params['rowCount'] = $storeRowCount; | |
231 | } | |
232 | elseif (!isset($params['rowCount'])) { | |
233 | $params['rowCount'] = CRM_Utils_Pager::ROWCOUNT; | |
234 | } | |
235 | ||
236 | $this->_pager = new CRM_Utils_Pager($params); | |
237 | list($this->_pagerOffset, $this->_pagerRowCount) = $this->_pager->getOffsetAndRowCount(); | |
238 | } | |
239 | ||
240 | /** | |
100fef9d | 241 | * Have the GET vars changed, i.e. pageId or sortId that forces us to recompute the search values |
6a488035 | 242 | * |
6a0b768e TO |
243 | * @param int $reset |
244 | * Are we being reset. | |
6a488035 | 245 | * |
317fceb4 | 246 | * @return bool |
a6c01b45 | 247 | * if the GET params are different from the session params |
6a488035 | 248 | */ |
00be9182 | 249 | public function hasChanged($reset) { |
6a488035 TO |
250 | |
251 | /** | |
252 | * if we are in reset state, i.e the store is cleaned out, we return false | |
253 | * we also return if we dont have a record of the sort id or page id | |
254 | */ | |
255 | if ($reset || | |
256 | $this->_store->get($this->_prefix . CRM_Utils_Pager::PAGE_ID) == NULL || | |
257 | $this->_store->get($this->_prefix . CRM_Utils_Sort::SORT_ID) == NULL | |
258 | ) { | |
259 | return FALSE; | |
260 | } | |
261 | ||
262 | if ($this->_store->get($this->_prefix . CRM_Utils_Pager::PAGE_ID) != $this->_pager->getCurrentPageID() || | |
263 | $this->_store->get($this->_prefix . CRM_Utils_Sort::SORT_ID) != $this->_sort->getCurrentSortID() || | |
264 | $this->_store->get($this->_prefix . CRM_Utils_Sort::SORT_DIRECTION) != $this->_sort->getCurrentSortDirection() | |
265 | ) { | |
266 | return TRUE; | |
267 | } | |
268 | return FALSE; | |
269 | } | |
270 | ||
271 | /** | |
272 | * Heart of the Controller. This is where all the action takes place | |
273 | * | |
274 | * - The rows are fetched and stored depending on the type of output needed | |
275 | * | |
276 | * - For export/printing all rows are selected. | |
277 | * | |
278 | * - for displaying on screen paging parameters are used to display the | |
279 | * required rows. | |
280 | * | |
281 | * - also depending on output type of session or template rows are appropriately stored in session | |
282 | * or template variables are updated. | |
283 | * | |
284 | * | |
285 | * @return void | |
6a488035 | 286 | */ |
00be9182 | 287 | public function run() { |
6a488035 TO |
288 | |
289 | // get the column headers | |
290 | $columnHeaders = &$this->_object->getColumnHeaders($this->_action, $this->_output); | |
291 | ||
292 | $contextArray = explode('_', get_class($this->_object)); | |
293 | ||
294 | $contextName = strtolower($contextArray[1]); | |
295 | ||
296 | // fix contribute and member | |
297 | if ($contextName == 'contribute') { | |
298 | $contextName = 'contribution'; | |
299 | } | |
300 | elseif ($contextName == 'member') { | |
301 | $contextName = 'membership'; | |
302 | } | |
303 | ||
304 | // we need to get the rows if we are exporting or printing them | |
305 | if ($this->_output == self::EXPORT || $this->_output == self::SCREEN) { | |
306 | // get rows (without paging criteria) | |
307 | $rows = self::getRows($this); | |
308 | CRM_Utils_Hook::searchColumns($contextName, $columnHeaders, $rows, $this); | |
309 | if ($this->_output == self::EXPORT) { | |
310 | // export the rows. | |
77b68348 | 311 | CRM_Core_Error::deprecatedFunctionWarning('This code is believed to be unreachable & to be later removed. Please log how you reached it in gitlab'); |
6a488035 TO |
312 | CRM_Core_Report_Excel::writeCSVFile($this->_object->getExportFileName(), |
313 | $columnHeaders, | |
314 | $rows | |
315 | ); | |
316 | CRM_Utils_System::civiExit(); | |
317 | } | |
318 | else { | |
319 | // assign to template and display them. | |
320 | self::$_template->assign_by_ref('rows', $rows); | |
321 | self::$_template->assign_by_ref('columnHeaders', $columnHeaders); | |
322 | } | |
323 | } | |
324 | else { | |
325 | // output requires paging/sorting capability | |
326 | $rows = self::getRows($this); | |
327 | CRM_Utils_Hook::searchColumns($contextName, $columnHeaders, $rows, $this); | |
be2fb01f CW |
328 | $reorderedHeaders = []; |
329 | $noWeightHeaders = []; | |
4fb5fcf3 | 330 | foreach ($columnHeaders as $key => $columnHeader) { |
331 | // So far only contribution selector sets weight, so just use key if not. | |
332 | // Extension writers will need to fix other getColumnHeaders (or add a wrapper) | |
333 | // to extend. | |
334 | if (isset($columnHeader['weight'])) { | |
335 | $reorderedHeaders[$columnHeader['weight']] = $columnHeader; | |
336 | } | |
337 | else { | |
db167477 | 338 | $noWeightHeaders[$key] = $columnHeader; |
4fb5fcf3 | 339 | } |
340 | } | |
0824019e | 341 | ksort($reorderedHeaders); |
db167477 | 342 | // Merge headers not containing weight to ordered headers |
343 | $finalColumnHeaders = array_merge($reorderedHeaders, $noWeightHeaders); | |
344 | ||
6a488035 | 345 | $rowsEmpty = count($rows) ? FALSE : TRUE; |
353ffa53 TO |
346 | $qill = $this->getQill(); |
347 | $summary = $this->getSummary(); | |
6a488035 TO |
348 | // if we need to store in session, lets update session |
349 | if ($this->_output & self::SESSION) { | |
db167477 | 350 | $this->_store->set("{$this->_prefix}columnHeaders", $finalColumnHeaders); |
6a488035 TO |
351 | if ($this->_dynamicAction) { |
352 | $this->_object->removeActions($rows); | |
353 | } | |
354 | $this->_store->set("{$this->_prefix}rows", $rows); | |
355 | $this->_store->set("{$this->_prefix}rowCount", $this->_total); | |
356 | $this->_store->set("{$this->_prefix}rowsEmpty", $rowsEmpty); | |
357 | $this->_store->set("{$this->_prefix}qill", $qill); | |
358 | $this->_store->set("{$this->_prefix}summary", $summary); | |
359 | } | |
360 | else { | |
361 | self::$_template->assign_by_ref("{$this->_prefix}pager", $this->_pager); | |
362 | self::$_template->assign_by_ref("{$this->_prefix}sort", $this->_sort); | |
363 | ||
db167477 | 364 | self::$_template->assign_by_ref("{$this->_prefix}columnHeaders", $finalColumnHeaders); |
6a488035 TO |
365 | self::$_template->assign_by_ref("{$this->_prefix}rows", $rows); |
366 | self::$_template->assign("{$this->_prefix}rowsEmpty", $rowsEmpty); | |
367 | self::$_template->assign("{$this->_prefix}qill", $qill); | |
368 | self::$_template->assign("{$this->_prefix}summary", $summary); | |
369 | } | |
370 | ||
6a488035 TO |
371 | // always store the current pageID and sortID |
372 | $this->_store->set($this->_prefix . CRM_Utils_Pager::PAGE_ID, | |
373 | $this->_pager->getCurrentPageID() | |
374 | ); | |
375 | $this->_store->set($this->_prefix . CRM_Utils_Sort::SORT_ID, | |
376 | $this->_sort->getCurrentSortID() | |
377 | ); | |
378 | $this->_store->set($this->_prefix . CRM_Utils_Sort::SORT_DIRECTION, | |
379 | $this->_sort->getCurrentSortDirection() | |
380 | ); | |
381 | $this->_store->set($this->_prefix . CRM_Utils_Sort::SORT_ORDER, | |
382 | $this->_sort->orderBy() | |
383 | ); | |
384 | $this->_store->set($this->_prefix . CRM_Utils_Pager::PAGE_ROWCOUNT, | |
385 | $this->_pager->_perPage | |
386 | ); | |
387 | } | |
388 | } | |
389 | ||
390 | /** | |
100fef9d | 391 | * Retrieve rows. |
6a488035 | 392 | * |
c490a46a | 393 | * @param CRM_Core_Form $form |
2a6da8d7 | 394 | * |
a6c01b45 | 395 | * @return array |
16b10e64 | 396 | * Array of rows |
6a488035 TO |
397 | */ |
398 | public function getRows($form) { | |
399 | if ($form->_output == self::EXPORT || $form->_output == self::SCREEN) { | |
400 | //get rows (without paging criteria) | |
401 | return $form->_object->getRows($form->_action, 0, 0, $form->_sort, $form->_output); | |
402 | } | |
403 | else { | |
404 | return $form->_object->getRows($form->_action, $form->_pagerOffset, $form->_pagerRowCount, | |
405 | $form->_sort, $form->_output, $form->_case | |
406 | ); | |
407 | } | |
408 | } | |
409 | ||
410 | /** | |
100fef9d | 411 | * Default function for qill, if needed to be implemented, we |
6a488035 TO |
412 | * expect the subclass to do it |
413 | * | |
a6c01b45 CW |
414 | * @return string |
415 | * the status message | |
6a488035 TO |
416 | */ |
417 | public function getQill() { | |
418 | return $this->_object->getQill(); | |
419 | } | |
420 | ||
a0ee3941 EM |
421 | /** |
422 | * @return mixed | |
423 | */ | |
6a488035 TO |
424 | public function getSummary() { |
425 | return $this->_object->getSummary(); | |
426 | } | |
427 | ||
428 | /** | |
fe482240 | 429 | * Getter for pager. |
6a488035 | 430 | * |
c490a46a | 431 | * @return CRM_Utils_Pager |
6a488035 | 432 | */ |
00be9182 | 433 | public function getPager() { |
6a488035 TO |
434 | return $this->_pager; |
435 | } | |
436 | ||
437 | /** | |
fe482240 | 438 | * Getter for sort. |
6a488035 | 439 | * |
c490a46a | 440 | * @return CRM_Utils_Sort |
6a488035 | 441 | */ |
00be9182 | 442 | public function getSort() { |
6a488035 TO |
443 | return $this->_sort; |
444 | } | |
445 | ||
446 | /** | |
fe482240 | 447 | * Move the variables from the session to the template. |
6a488035 TO |
448 | * |
449 | * @return void | |
6a488035 | 450 | */ |
00be9182 | 451 | public function moveFromSessionToTemplate() { |
6a488035 TO |
452 | self::$_template->assign_by_ref("{$this->_prefix}pager", $this->_pager); |
453 | ||
454 | $rows = $this->_store->get("{$this->_prefix}rows"); | |
455 | ||
456 | if ($rows) { | |
457 | if ($this->_dynamicAction) { | |
458 | $this->_object->addActions($rows); | |
459 | } | |
460 | ||
461 | self::$_template->assign("{$this->_prefix}aToZ", | |
462 | $this->_store->get("{$this->_prefix}AToZBar") | |
463 | ); | |
464 | } | |
465 | ||
466 | self::$_template->assign_by_ref("{$this->_prefix}sort", $this->_sort); | |
467 | self::$_template->assign("{$this->_prefix}columnHeaders", $this->_store->get("{$this->_prefix}columnHeaders")); | |
468 | self::$_template->assign("{$this->_prefix}rows", $rows); | |
469 | self::$_template->assign("{$this->_prefix}rowsEmpty", $this->_store->get("{$this->_prefix}rowsEmpty")); | |
470 | self::$_template->assign("{$this->_prefix}qill", $this->_store->get("{$this->_prefix}qill")); | |
471 | self::$_template->assign("{$this->_prefix}summary", $this->_store->get("{$this->_prefix}summary")); | |
472 | ||
473 | if ($this->_embedded) { | |
474 | return; | |
475 | } | |
476 | ||
8aac22c8 | 477 | self::$_template->assign('tplFile', $this->_object->getHookedTemplateFileName()); |
6a488035 TO |
478 | if ($this->_print) { |
479 | $content = self::$_template->fetch('CRM/common/print.tpl'); | |
480 | } | |
481 | else { | |
482 | $config = CRM_Core_Config::singleton(); | |
483 | $content = self::$_template->fetch('CRM/common/' . strtolower($config->userFramework) . '.tpl'); | |
484 | } | |
485 | echo CRM_Utils_System::theme($content, $this->_print); | |
486 | } | |
487 | ||
488 | /** | |
fe482240 | 489 | * Setter for embedded. |
6a488035 | 490 | * |
6a0b768e | 491 | * @param bool $embedded |
6a488035 TO |
492 | * |
493 | * @return void | |
6a488035 | 494 | */ |
00be9182 | 495 | public function setEmbedded($embedded) { |
6a488035 TO |
496 | $this->_embedded = $embedded; |
497 | } | |
498 | ||
499 | /** | |
fe482240 | 500 | * Getter for embedded. |
6a488035 | 501 | * |
317fceb4 | 502 | * @return bool |
a6c01b45 | 503 | * return the embedded value |
6a488035 | 504 | */ |
00be9182 | 505 | public function getEmbedded() { |
6a488035 TO |
506 | return $this->_embedded; |
507 | } | |
508 | ||
509 | /** | |
fe482240 | 510 | * Setter for print. |
6a488035 | 511 | * |
6a0b768e | 512 | * @param bool $print |
6a488035 TO |
513 | * |
514 | * @return void | |
6a488035 | 515 | */ |
00be9182 | 516 | public function setPrint($print) { |
6a488035 TO |
517 | $this->_print = $print; |
518 | } | |
519 | ||
520 | /** | |
fe482240 | 521 | * Getter for print. |
6a488035 | 522 | * |
317fceb4 | 523 | * @return bool |
a6c01b45 | 524 | * return the print value |
6a488035 | 525 | */ |
00be9182 | 526 | public function getPrint() { |
6a488035 TO |
527 | return $this->_print; |
528 | } | |
529 | ||
a0ee3941 EM |
530 | /** |
531 | * @param $value | |
532 | */ | |
00be9182 | 533 | public function setDynamicAction($value) { |
6a488035 TO |
534 | $this->_dynamicAction = $value; |
535 | } | |
536 | ||
a0ee3941 EM |
537 | /** |
538 | * @return bool | |
539 | */ | |
00be9182 | 540 | public function getDynamicAction() { |
6a488035 TO |
541 | return $this->_dynamicAction; |
542 | } | |
96025800 | 543 | |
6a488035 | 544 | } |