3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
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 |
9 +--------------------------------------------------------------------+
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
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
22 * @copyright CiviCRM LLC https://civicrm.org/licensing
26 class CRM_Core_Selector_Controller
{
29 * Constants to determine if we should store
30 * the output in the session or template
33 // move the values from the session to the template
34 const SESSION
= 1, TEMPLATE
= 2,
35 TRANSFER
= 4, EXPORT
= 8, SCREEN
= 16, PDF
= 32;
38 * A CRM Object that implements CRM_Core_Selector_API.
49 * The current column to sort on
58 protected $_sortOrder;
61 * @var CRM_Utils_Pager
75 protected $_pagerOffset;
78 * Number of rows to return
81 protected $_pagerRowCount;
84 * Total number of rows
90 * The objectAction for the WebObject
96 * This caches the content for the display system
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)
109 protected $_embedded = FALSE;
112 * Are we in print mode? if so we need to modify the display
113 * functionality to do a minimal display :)
117 protected $_print = FALSE;
120 * The storage object (typically a form or a page)
127 * Output target, session, template or both?
134 * Prefif for the selector variables
141 * Cache the smarty template for efficiency reasons
143 * @var CRM_Core_Smarty
145 public static $_template;
148 * Array of properties that the controller dumps into the output object
152 public static $_properties = ['columnHeaders', 'rows', 'rowsEmpty'];
155 * Should we compute actions dynamically (since they are quite verbose)
159 protected $_dynamicAction = FALSE;
164 * @param CRM_Core_Selector_API $object
165 * An object that implements the selector API.
171 * The actions to potentially support.
172 * @param CRM_Core_Page|CRM_Core_Form $store place in session to store some values
174 * What do we so with the output, session/template//both.
176 * @param null $prefix
179 * @return \CRM_Core_Selector_Controller
181 public function __construct($object, $pageID, $sortID, $action, $store = NULL, $output = self
::TEMPLATE
, $prefix = NULL, $case = NULL) {
183 $this->_object
= $object;
184 $this->_pageID
= $pageID ?
$pageID : 1;
185 $this->_sortID
= $sortID ?
$sortID : NULL;
186 $this->_action
= $action;
187 $this->_store
= $store;
188 $this->_output
= $output;
189 $this->_prefix
= $prefix;
190 $this->_case
= $case;
193 if ($this->_sortID
&& strpos($this->_sortID
, '_') === FALSE) {
194 $this->_sortID
.= '_u';
198 'pageID' => $this->_pageID
,
201 // let the constructor initialize this, should happen only once
202 if (!isset(self
::$_template)) {
203 self
::$_template = CRM_Core_Smarty
::singleton();
206 $this->_sortOrder
= &$this->_object
->getSortOrder($action);
207 $this->_sort
= new CRM_Utils_Sort($this->_sortOrder
, $this->_sortID
);
210 * if we are in transfer mode, do not goto database, use the
211 * session values instead
214 if ($output == self
::TRANSFER
) {
215 $params['total'] = $this->_store
->get($this->_prefix
. 'rowCount');
218 $params['total'] = $this->_object
->getTotalCount($action, $this->_case
);
221 $this->_total
= $params['total'];
222 $this->_object
->getPagerParams($action, $params);
225 * Set the default values of RowsPerPage
228 $storeRowCount = $store->get($this->_prefix
. CRM_Utils_Pager
::PAGE_ROWCOUNT
);
229 if ($storeRowCount) {
230 $params['rowCount'] = $storeRowCount;
232 elseif (!isset($params['rowCount'])) {
233 $params['rowCount'] = CRM_Utils_Pager
::ROWCOUNT
;
236 $this->_pager
= new CRM_Utils_Pager($params);
237 list($this->_pagerOffset
, $this->_pagerRowCount
) = $this->_pager
->getOffsetAndRowCount();
241 * Have the GET vars changed, i.e. pageId or sortId that forces us to recompute the search values
244 * Are we being reset.
247 * if the GET params are different from the session params
249 public function hasChanged($reset) {
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
256 $this->_store
->get($this->_prefix
. CRM_Utils_Pager
::PAGE_ID
) == NULL ||
257 $this->_store
->get($this->_prefix
. CRM_Utils_Sort
::SORT_ID
) == NULL
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()
272 * Heart of the Controller. This is where all the action takes place
274 * - The rows are fetched and stored depending on the type of output needed
276 * - For export/printing all rows are selected.
278 * - for displaying on screen paging parameters are used to display the
281 * - also depending on output type of session or template rows are appropriately stored in session
282 * or template variables are updated.
287 public function run() {
289 // get the column headers
290 $columnHeaders = &$this->_object
->getColumnHeaders($this->_action
, $this->_output
);
292 $contextArray = explode('_', get_class($this->_object
));
294 $contextName = strtolower($contextArray[1]);
296 // fix contribute and member
297 if ($contextName == 'contribute') {
298 $contextName = 'contribution';
300 elseif ($contextName == 'member') {
301 $contextName = 'membership';
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
) {
311 CRM_Core_Error
::deprecatedFunctionWarning('This code is believed to be unreachable & to be later removed. Please log how you reached it in gitlab');
312 CRM_Core_Report_Excel
::writeCSVFile($this->_object
->getExportFileName(),
316 CRM_Utils_System
::civiExit();
319 // assign to template and display them.
320 self
::$_template->assign_by_ref('rows', $rows);
321 self
::$_template->assign_by_ref('columnHeaders', $columnHeaders);
325 // output requires paging/sorting capability
326 $rows = self
::getRows($this);
327 CRM_Utils_Hook
::searchColumns($contextName, $columnHeaders, $rows, $this);
328 $reorderedHeaders = [];
329 $noWeightHeaders = [];
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)
334 if (isset($columnHeader['weight'])) {
335 $reorderedHeaders[$columnHeader['weight']] = $columnHeader;
338 $noWeightHeaders[$key] = $columnHeader;
341 ksort($reorderedHeaders);
342 // Merge headers not containing weight to ordered headers
343 $finalColumnHeaders = array_merge($reorderedHeaders, $noWeightHeaders);
345 $rowsEmpty = count($rows) ?
FALSE : TRUE;
346 $qill = $this->getQill();
347 $summary = $this->getSummary();
348 // if we need to store in session, lets update session
349 if ($this->_output
& self
::SESSION
) {
350 $this->_store
->set("{$this->_prefix}columnHeaders", $finalColumnHeaders);
351 if ($this->_dynamicAction
) {
352 $this->_object
->removeActions($rows);
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);
361 self
::$_template->assign_by_ref("{$this->_prefix}pager", $this->_pager
);
362 self
::$_template->assign_by_ref("{$this->_prefix}sort", $this->_sort
);
364 self
::$_template->assign_by_ref("{$this->_prefix}columnHeaders", $finalColumnHeaders);
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);
371 // always store the current pageID and sortID
372 $this->_store
->set($this->_prefix
. CRM_Utils_Pager
::PAGE_ID
,
373 $this->_pager
->getCurrentPageID()
375 $this->_store
->set($this->_prefix
. CRM_Utils_Sort
::SORT_ID
,
376 $this->_sort
->getCurrentSortID()
378 $this->_store
->set($this->_prefix
. CRM_Utils_Sort
::SORT_DIRECTION
,
379 $this->_sort
->getCurrentSortDirection()
381 $this->_store
->set($this->_prefix
. CRM_Utils_Sort
::SORT_ORDER
,
382 $this->_sort
->orderBy()
384 $this->_store
->set($this->_prefix
. CRM_Utils_Pager
::PAGE_ROWCOUNT
,
385 $this->_pager
->_perPage
393 * @param CRM_Core_Form $form
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
);
404 return $form->_object
->getRows($form->_action
, $form->_pagerOffset
, $form->_pagerRowCount
,
405 $form->_sort
, $form->_output
, $form->_case
411 * Default function for qill, if needed to be implemented, we
412 * expect the subclass to do it
417 public function getQill() {
418 return $this->_object
->getQill();
424 public function getSummary() {
425 return $this->_object
->getSummary();
431 * @return CRM_Utils_Pager
433 public function getPager() {
434 return $this->_pager
;
440 * @return CRM_Utils_Sort
442 public function getSort() {
447 * Move the variables from the session to the template.
451 public function moveFromSessionToTemplate() {
452 self
::$_template->assign_by_ref("{$this->_prefix}pager", $this->_pager
);
454 $rows = $this->_store
->get("{$this->_prefix}rows");
457 if ($this->_dynamicAction
) {
458 $this->_object
->addActions($rows);
461 self
::$_template->assign("{$this->_prefix}aToZ",
462 $this->_store
->get("{$this->_prefix}AToZBar")
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"));
473 if ($this->_embedded
) {
477 self
::$_template->assign('tplFile', $this->_object
->getHookedTemplateFileName());
479 $content = self
::$_template->fetch('CRM/common/print.tpl');
482 $config = CRM_Core_Config
::singleton();
483 $content = self
::$_template->fetch('CRM/common/' . strtolower($config->userFramework
) . '.tpl');
485 echo CRM_Utils_System
::theme($content, $this->_print
);
489 * Setter for embedded.
491 * @param bool $embedded
495 public function setEmbedded($embedded) {
496 $this->_embedded
= $embedded;
500 * Getter for embedded.
503 * return the embedded value
505 public function getEmbedded() {
506 return $this->_embedded
;
516 public function setPrint($print) {
517 $this->_print
= $print;
524 * return the print value
526 public function getPrint() {
527 return $this->_print
;
533 public function setDynamicAction($value) {
534 $this->_dynamicAction
= $value;
540 public function getDynamicAction() {
541 return $this->_dynamicAction
;