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