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