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