Merge pull request #4314 from cividesk/CRM-13227
[civicrm-core.git] / CRM / Member / Selector / Search.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.5 |
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 * @package CRM
31 * @copyright CiviCRM LLC (c) 2004-2014
32 * $Id$
33 *
34 */
35
36 /**
37 * This class is used to retrieve and display a range of
38 * contacts that match the given criteria (specifically for
39 * results of advanced search options.
40 *
41 */
42 class CRM_Member_Selector_Search extends CRM_Core_Selector_Base implements CRM_Core_Selector_API {
43
44 /**
45 * This defines two actions- View and Edit.
46 *
47 * @var array
48 * @static
49 */
50 static $_links = NULL;
51
52 /**
53 * we use desc to remind us what that column is, name is used in the tpl
54 *
55 * @var array
56 * @static
57 */
58 static $_columnHeaders;
59
60 /**
61 * Properties of contact we're interested in displaying
62 * @var array
63 * @static
64 */
65 static $_properties = array(
66 'contact_id',
67 'membership_id',
68 'contact_type',
69 'sort_name',
70 'membership_type',
71 'join_date',
72 'membership_start_date',
73 'membership_end_date',
74 'membership_source',
75 'status_id',
76 'member_is_test',
77 'owner_membership_id',
78 'membership_status',
79 'member_campaign_id',
80 );
81
82 /**
83 * are we restricting ourselves to a single contact
84 *
85 * @access protected
86 * @var boolean
87 */
88 protected $_single = FALSE;
89
90 /**
91 * are we restricting ourselves to a single contact
92 *
93 * @access protected
94 * @var boolean
95 */
96 protected $_limit = NULL;
97
98 /**
99 * what context are we being invoked from
100 *
101 * @access protected
102 * @var string
103 */
104 protected $_context = NULL;
105
106 /**
107 * queryParams is the array returned by exportValues called on
108 * the HTML_QuickForm_Controller for that page.
109 *
110 * @var array
111 * @access protected
112 */
113 public $_queryParams;
114
115 /**
116 * represent the type of selector
117 *
118 * @var int
119 * @access protected
120 */
121 protected $_action;
122
123 /**
124 * The additional clause that we restrict the search with
125 *
126 * @var string
127 */
128 protected $_memberClause = NULL;
129
130 /**
131 * The query object
132 *
133 * @var string
134 */
135 protected $_query;
136
137 /**
138 * Class constructor
139 *
140 * @param array $queryParams array of parameters for query
141 * @param \const|int $action - action of search basic or advanced.
142 * @param string $memberClause if the caller wants to further restrict the search (used in memberships)
143 * @param boolean $single are we dealing only with one contact?
144 * @param int $limit how many memberships do we want returned
145 *
146 * @param string $context
147 *
148 * @return \CRM_Member_Selector_Search
149 @access public
150 */
151 function __construct(&$queryParams,
152 $action = CRM_Core_Action::NONE,
153 $memberClause = NULL,
154 $single = FALSE,
155 $limit = NULL,
156 $context = 'search'
157 ) {
158 // submitted form values
159 $this->_queryParams = &$queryParams;
160
161 $this->_single = $single;
162 $this->_limit = $limit;
163 $this->_context = $context;
164
165 $this->_memberClause = $memberClause;
166
167 // type of selector
168 $this->_action = $action;
169
170 $this->_query = new CRM_Contact_BAO_Query($this->_queryParams,
171 CRM_Member_BAO_Query::defaultReturnProperties(CRM_Contact_BAO_Query::MODE_MEMBER,
172 FALSE
173 ),
174 NULL, FALSE, FALSE,
175 CRM_Contact_BAO_Query::MODE_MEMBER
176 );
177 $this->_query->_distinctComponentClause = " civicrm_membership.id";
178 $this->_query->_groupByComponentClause = " GROUP BY civicrm_membership.id ";
179 }
180 //end of constructor
181
182 /**
183 * This method returns the links that are given for each search row.
184 * currently the links added for each row are
185 *
186 * - View
187 * - Edit
188 *
189 * @param string $status
190 * @param null $isPaymentProcessor
191 * @param null $accessContribution
192 * @param null $qfKey
193 * @param null $context
194 * @param bool $isCancelSupported
195 *
196 * @return array
197 * @access public
198 */
199 static
200 function &links($status = 'all',
201 $isPaymentProcessor = NULL,
202 $accessContribution = NULL,
203 $qfKey = NULL,
204 $context = NULL,
205 $isCancelSupported = FALSE
206 ) {
207 $extraParams = NULL;
208 if ($context == 'search') {
209 $extraParams .= '&compContext=membership';
210 }
211 if ($qfKey) {
212 $extraParams .= "&key={$qfKey}";
213 }
214
215 if (!self::$_links['view']) {
216 self::$_links['view'] = array(
217 CRM_Core_Action::VIEW => array(
218 'name' => ts('View'),
219 'url' => 'civicrm/contact/view/membership',
220 'qs' => 'reset=1&id=%%id%%&cid=%%cid%%&action=view&context=%%cxt%%&selectedChild=member' . $extraParams,
221 'title' => ts('View Membership'),
222 ),
223 );
224 }
225 if (!isset(self::$_links['all']) || !self::$_links['all']) {
226 $extraLinks = array(
227 CRM_Core_Action::UPDATE => array(
228 'name' => ts('Edit'),
229 'url' => 'civicrm/contact/view/membership',
230 'qs' => 'reset=1&action=update&id=%%id%%&cid=%%cid%%&context=%%cxt%%' . $extraParams,
231 'title' => ts('Edit Membership'),
232 ),
233 CRM_Core_Action::DELETE => array(
234 'name' => ts('Delete'),
235 'url' => 'civicrm/contact/view/membership',
236 'qs' => 'reset=1&action=delete&id=%%id%%&cid=%%cid%%&context=%%cxt%%' . $extraParams,
237 'title' => ts('Delete Membership'),
238 ),
239 CRM_Core_Action::RENEW => array(
240 'name' => ts('Renew'),
241 'url' => 'civicrm/contact/view/membership',
242 'qs' => 'reset=1&action=renew&id=%%id%%&cid=%%cid%%&context=%%cxt%%' . $extraParams,
243 'title' => ts('Renew Membership'),
244 ),
245 CRM_Core_Action::FOLLOWUP => array(
246 'name' => ts('Renew-Credit Card'),
247 'url' => 'civicrm/contact/view/membership',
248 'qs' => 'action=renew&reset=1&cid=%%cid%%&id=%%id%%&context=%%cxt%%&mode=live' . $extraParams,
249 'title' => ts('Renew Membership Using Credit Card'),
250 ),
251 );
252 if (!$isPaymentProcessor || !$accessContribution) {
253 //unset the renew with credit card when payment
254 //processor is not available or user not permitted to make contributions
255 unset($extraLinks[CRM_Core_Action::FOLLOWUP]);
256 }
257
258 self::$_links['all'] = self::$_links['view'] + $extraLinks;
259 }
260
261 if ($isCancelSupported) {
262 self::$_links['all'][CRM_Core_Action::DISABLE] = array(
263 'name' => ts('Cancel Auto-renewal'),
264 'url' => 'civicrm/contribute/unsubscribe',
265 'qs' => 'reset=1&mid=%%id%%&context=%%cxt%%' . $extraParams,
266 'title' => 'Cancel Auto Renew Subscription',
267 );
268 }
269 elseif (isset(self::$_links['all'][CRM_Core_Action::DISABLE])) {
270 unset(self::$_links['all'][CRM_Core_Action::DISABLE]);
271 }
272
273 return self::$_links[$status];
274 }
275 //end of function
276
277 /**
278 * getter for array of the parameters required for creating pager.
279 *
280 * @param $action
281 * @param $params
282 * @internal param $
283 * @access public
284 */
285 function getPagerParams($action, &$params) {
286 $params['status'] = ts('Member') . ' %%StatusMessage%%';
287 $params['csvString'] = NULL;
288 if ($this->_limit) {
289 $params['rowCount'] = $this->_limit;
290 }
291 else {
292 $params['rowCount'] = CRM_Utils_Pager::ROWCOUNT;
293 }
294
295 $params['buttonTop'] = 'PagerTopButton';
296 $params['buttonBottom'] = 'PagerBottomButton';
297 }
298 //end of function
299
300 /**
301 * Returns total number of rows for the query.
302 *
303 * @param
304 *
305 * @return int Total number of rows
306 * @access public
307 */
308 function getTotalCount($action) {
309 return $this->_query->searchQuery(0, 0, NULL,
310 TRUE, FALSE,
311 FALSE, FALSE,
312 FALSE,
313 $this->_memberClause
314 );
315 }
316
317 /**
318 * returns all the rows in the given offset and rowCount
319 *
320 * @param enum $action the action being performed
321 * @param int $offset the row number to start from
322 * @param int $rowCount the number of rows to return
323 * @param string $sort the sql string that describes the sort order
324 * @param enum $output what should the result set include (web/email/csv)
325 *
326 * @return int the total number of rows for this action
327 */
328 function &getRows($action, $offset, $rowCount, $sort, $output = NULL) {
329 // check if we can process credit card registration
330 $processors = CRM_Core_PseudoConstant::paymentProcessor(FALSE, FALSE,
331 "billing_mode IN ( 1, 3 )"
332 );
333 if (count($processors) > 0) {
334 $this->_isPaymentProcessor = TRUE;
335 }
336 else {
337 $this->_isPaymentProcessor = FALSE;
338 }
339
340 // Only show credit card membership signup and renewal if user has CiviContribute permission
341 if (CRM_Core_Permission::access('CiviContribute')) {
342 $this->_accessContribution = TRUE;
343 }
344 else {
345 $this->_accessContribution = FALSE;
346 }
347
348 //get all campaigns.
349 $allCampaigns = CRM_Campaign_BAO_Campaign::getCampaigns(NULL, NULL, FALSE, FALSE, FALSE, TRUE);
350
351 $result = $this->_query->searchQuery($offset, $rowCount, $sort,
352 FALSE, FALSE,
353 FALSE, FALSE,
354 FALSE,
355 $this->_memberClause
356 );
357
358 // process the result of the query
359 $rows = array();
360
361 //CRM-4418 check for view, edit, delete
362 $permissions = array(CRM_Core_Permission::VIEW);
363 if (CRM_Core_Permission::check('edit memberships')) {
364 $permissions[] = CRM_Core_Permission::EDIT;
365 }
366 if (CRM_Core_Permission::check('delete in CiviMember')) {
367 $permissions[] = CRM_Core_Permission::DELETE;
368 }
369 $mask = CRM_Core_Action::mask($permissions);
370
371 while ($result->fetch()) {
372 $row = array();
373
374 // the columns we are interested in
375 foreach (self::$_properties as $property) {
376 if (property_exists($result, $property)) {
377 $row[$property] = $result->$property;
378 }
379 }
380
381 //carry campaign on selectors.
382 $row['campaign'] = CRM_Utils_Array::value($result->member_campaign_id, $allCampaigns);
383 $row['campaign_id'] = $result->member_campaign_id;
384
385 if (!empty($row['member_is_test'])) {
386 $row['membership_type'] = $row['membership_type'] . " (test)";
387 }
388
389 $row['checkbox'] = CRM_Core_Form::CB_PREFIX . $result->membership_id;
390
391 if (!isset($result->owner_membership_id)) {
392 // unset renew and followup link for deceased membership
393 $currentMask = $mask;
394 if ($result->membership_status == 'Deceased') {
395 $currentMask = $currentMask & ~CRM_Core_Action::RENEW & ~CRM_Core_Action::FOLLOWUP;
396 }
397
398 $isCancelSupported = CRM_Member_BAO_Membership::isCancelSubscriptionSupported($row['membership_id']);
399 $row['action'] = CRM_Core_Action::formLink(self::links('all',
400 $this->_isPaymentProcessor,
401 $this->_accessContribution,
402 $this->_key,
403 $this->_context,
404 $isCancelSupported
405 ),
406 $currentMask,
407 array(
408 'id' => $result->membership_id,
409 'cid' => $result->contact_id,
410 'cxt' => $this->_context,
411 ),
412 ts('more'),
413 FALSE,
414 'membership.selector.row',
415 'Membership',
416 $result->membership_id
417 );
418 }
419 else {
420 $row['action'] = CRM_Core_Action::formLink(self::links('view'), $mask,
421 array(
422 'id' => $result->membership_id,
423 'cid' => $result->contact_id,
424 'cxt' => $this->_context,
425 ),
426 ts('more'),
427 FALSE,
428 'membership.selector.row',
429 'Membership',
430 $result->membership_id
431 );
432 }
433
434 //does membership have auto renew CRM-7137.
435 $autoRenew = FALSE;
436 if (isset($result->membership_recur_id) && $result->membership_recur_id &&
437 !CRM_Member_BAO_Membership::isSubscriptionCancelled($row['membership_id'])
438 ) {
439 $autoRenew = TRUE;
440 }
441 $row['auto_renew'] = $autoRenew;
442
443 $row['contact_type'] = CRM_Contact_BAO_Contact_Utils::getImage($result->contact_sub_type ?
444 $result->contact_sub_type : $result->contact_type, FALSE, $result->contact_id
445 );
446
447 $rows[] = $row;
448 }
449
450 return $rows;
451 }
452
453 /**
454 *
455 * @return array $qill which contains an array of strings
456 * @access public
457 */
458
459 // the current internationalisation is bad, but should more or less work
460 // for most of "European" languages
461 public function getQILL() {
462 return $this->_query->qill();
463 }
464
465 /**
466 * returns the column headers as an array of tuples:
467 * (name, sortName (key to the sort array))
468 *
469 * @param string $action the action being performed
470 * @param enum $output what should the result set include (web/email/csv)
471 *
472 * @return array the column headers that need to be displayed
473 * @access public
474 */
475 public function &getColumnHeaders($action = NULL, $output = NULL) {
476 if (!isset(self::$_columnHeaders)) {
477 self::$_columnHeaders = array(
478 array(
479 'name' => ts('Type'),
480 'sort' => 'membership_type',
481 'direction' => CRM_Utils_Sort::DONTCARE,
482 ),
483 array('name' => ts('Member Since'),
484 'sort' => 'join_date',
485 'direction' => CRM_Utils_Sort::DESCENDING,
486 ),
487 array(
488 'name' => ts('Start Date'),
489 'sort' => 'membership_start_date',
490 'direction' => CRM_Utils_Sort::DONTCARE,
491 ),
492 array(
493 'name' => ts('End Date'),
494 'sort' => 'membership_end_date',
495 'direction' => CRM_Utils_Sort::DONTCARE,
496 ),
497 array(
498 'name' => ts('Source'),
499 'sort' => 'membership_source',
500 'direction' => CRM_Utils_Sort::DONTCARE,
501 ),
502 array(
503 'name' => ts('Status'),
504 'sort' => 'membership_status',
505 'direction' => CRM_Utils_Sort::DONTCARE,
506 ),
507 array(
508 'name' => ts('Auto-renew?'),
509 ),
510 array('desc' => ts('Actions')),
511 );
512
513 if (!$this->_single) {
514 $pre = array(
515 array('desc' => ts('Contact Type')),
516 array(
517 'name' => ts('Name'),
518 'sort' => 'sort_name',
519 'direction' => CRM_Utils_Sort::DONTCARE,
520 ),
521 );
522 self::$_columnHeaders = array_merge($pre, self::$_columnHeaders);
523 }
524 }
525 return self::$_columnHeaders;
526 }
527
528 /**
529 * @return mixed
530 */
531 function alphabetQuery() {
532 return $this->_query->searchQuery(NULL, NULL, NULL, FALSE, FALSE, TRUE);
533 }
534
535 /**
536 * @return string
537 */
538 function &getQuery() {
539 return $this->_query;
540 }
541
542 /**
543 * name of export file.
544 *
545 * @param string $output type of output
546 *
547 * @return string name of the file
548 */
549 function getExportFileName($output = 'csv') {
550 return ts('CiviCRM Member Search');
551 }
552 }
553 //end of class
554