Merge pull request #15927 from eileenmcnaughton/event_form
[civicrm-core.git] / CRM / Core / Selector / Controller.php
CommitLineData
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 */
26class 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}