dev/core#2061 PCP: call the hook_civicrm_links hook for PCP page user actions
[civicrm-core.git] / CRM / PCP / BAO / PCP.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
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 +--------------------------------------------------------------------+
10 */
11
12 /**
13 *
14 * @package CRM
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
16 */
17 class CRM_PCP_BAO_PCP extends CRM_PCP_DAO_PCP {
18
19 /**
20 * The action links that we need to display for the browse screen.
21 *
22 * @var array
23 */
24 public static $_pcpLinks = NULL;
25
26 /**
27 * Class constructor.
28 */
29 public function __construct() {
30 parent::__construct();
31 }
32
33 /**
34 * Add or update either a Personal Campaign Page OR a PCP Block.
35 *
36 * @param array $params
37 * Values to create the pcp.
38 *
39 * @return object
40 */
41 public static function create($params) {
42
43 $dao = new CRM_PCP_DAO_PCP();
44 $dao->copyValues($params);
45
46 // ensure we set status_id since it is a not null field
47 // we should change the schema and allow this to be null
48 if (!$dao->id && !isset($dao->status_id)) {
49 $dao->status_id = 0;
50 }
51
52 // set currency for CRM-1496
53 if (!isset($dao->currency)) {
54 $dao->currency = CRM_Core_Config::singleton()->defaultCurrency;
55 }
56
57 $dao->save();
58 return $dao;
59 }
60
61 /**
62 * Get the Display name of a contact for a PCP.
63 *
64 * @param int $id
65 * Id for the PCP.
66 *
67 * @return null|string
68 * Display name of the contact if found
69 */
70 public static function displayName($id) {
71 $id = CRM_Utils_Type::escape($id, 'Integer');
72
73 $query = "
74 SELECT civicrm_contact.display_name
75 FROM civicrm_pcp, civicrm_contact
76 WHERE civicrm_pcp.contact_id = civicrm_contact.id
77 AND civicrm_pcp.id = {$id}
78 ";
79 return CRM_Core_DAO::singleValueQuery($query);
80 }
81
82 /**
83 * Return PCP Block info for dashboard.
84 *
85 * @param int $contactId
86 *
87 * @return array
88 * array of Pcp if found
89 */
90 public static function getPcpDashboardInfo($contactId) {
91 $query = '
92 SELECT pcp.*, block.is_tellfriend_enabled FROM civicrm_pcp pcp
93 LEFT JOIN civicrm_pcp_block block ON block.id = pcp.pcp_block_id
94 WHERE pcp.is_active = 1
95 AND pcp.contact_id = %1
96 ORDER BY page_type, page_id';
97
98 $params = [1 => [$contactId, 'Integer']];
99 $pcpInfoDao = CRM_Core_DAO::executeQuery($query, $params);
100
101 $links = self::pcpLinks();
102 $hide = $mask = array_sum(array_keys($links['all']));
103 $approved = CRM_Core_PseudoConstant::getKey('CRM_PCP_BAO_PCP', 'status_id', 'Approved');
104 $contactPCPPages = [];
105 $pcpInfo = [];
106
107 while ($pcpInfoDao->fetch()) {
108 $mask = $hide;
109 if ($links) {
110 $replace = [
111 'pcpId' => $pcpInfoDao->id,
112 'pcpBlock' => $pcpInfoDao->pcp_block_id,
113 'pageComponent' => $pcpInfoDao->page_type,
114 ];
115 }
116
117 $pcpLink = $links['all'];
118 $class = '';
119
120 if ($pcpInfoDao->status_id != $approved || $pcpInfoDao->is_active != 1) {
121 $class = 'disabled';
122 if (!$pcpInfoDao->is_tellfriend_enabled) {
123 $mask -= CRM_Core_Action::DETACH;
124 }
125 }
126
127 if ($pcpInfoDao->is_active == 1) {
128 $mask -= CRM_Core_Action::ENABLE;
129 }
130 else {
131 $mask -= CRM_Core_Action::DISABLE;
132 }
133 $action = CRM_Core_Action::formLink($pcpLink, $mask, $replace, ts('more'),
134 FALSE, 'pcp.dashboard.active', 'PCP', $pcpInfoDao->id);
135
136 $pageTitle = self::getPcpTitle($pcpInfoDao->page_type, (int) $pcpInfoDao->page_id);
137
138 $pcpInfo[] = [
139 'pageTitle' => $pageTitle,
140 'pcpId' => $pcpInfoDao->id,
141 'pcpTitle' => $pcpInfoDao->title,
142 'pcpStatus' => CRM_Core_PseudoConstant::getLabel('CRM_PCP_BAO_PCP', 'status_id', $pcpInfoDao->status_id),
143 'action' => $action,
144 'class' => $class,
145 ];
146 $contactPCPPages[$pcpInfoDao->page_type][] = $pcpInfoDao->page_id;
147 }
148
149 $excludePageClause = $clause = NULL;
150 if (!empty($contactPCPPages)) {
151 foreach ($contactPCPPages as $component => $entityIds) {
152 $excludePageClause[] = "
153 ( target_entity_type = '{$component}'
154 AND target_entity_id NOT IN ( " . implode(',', $entityIds) . ") )";
155 }
156
157 $clause = ' AND ' . implode(' OR ', $excludePageClause);
158 }
159
160 $query = "
161 SELECT *
162 FROM civicrm_pcp_block block
163 LEFT JOIN civicrm_pcp pcp ON pcp.pcp_block_id = block.id
164 WHERE block.is_active = 1
165 {$clause}
166 GROUP BY block.id, pcp.id
167 ORDER BY target_entity_type, target_entity_id
168 ";
169 $pcpBlockDao = CRM_Core_DAO::executeQuery($query);
170 $pcpBlock = [];
171 $mask = 0;
172
173 while ($pcpBlockDao->fetch()) {
174 if ($links) {
175 $replace = [
176 'pageId' => $pcpBlockDao->target_entity_id,
177 'pageComponent' => $pcpBlockDao->target_entity_type,
178 ];
179 }
180 $pcpLink = $links['add'];
181 $action = CRM_Core_Action::formLink($pcpLink, $mask, $replace, ts('more'),
182 FALSE, 'pcp.dashboard.other', "{$pcpBlockDao->target_entity_type}_PCP", $pcpBlockDao->target_entity_id);
183 $pageTitle = self::getPcpTitle($pcpBlockDao->target_entity_type, (int) $pcpBlockDao->target_entity_id);
184 if ($pageTitle) {
185 $pcpBlock[] = [
186 'pageId' => $pcpBlockDao->target_entity_id,
187 'pageTitle' => $pageTitle,
188 'action' => $action,
189 ];
190 }
191 }
192
193 return [$pcpBlock, $pcpInfo];
194 }
195
196 /**
197 * Show the total amount for Personal Campaign Page on thermometer.
198 *
199 * @param array $pcpId
200 * Contains the pcp ID.
201 *
202 * @return float
203 * Total amount
204 */
205 public static function thermoMeter($pcpId) {
206 $completedStatusId = CRM_Core_PseudoConstant::getKey(
207 'CRM_Contribute_BAO_Contribution',
208 'contribution_status_id',
209 'Completed'
210 );
211 $query = "
212 SELECT SUM(cc.total_amount) as total
213 FROM civicrm_pcp pcp
214 LEFT JOIN civicrm_contribution_soft cs ON ( pcp.id = cs.pcp_id )
215 LEFT JOIN civicrm_contribution cc ON ( cs.contribution_id = cc.id)
216 WHERE pcp.id = %1 AND cc.contribution_status_id = %2 AND cc.is_test = 0";
217
218 $params = [
219 1 => [$pcpId, 'Integer'],
220 2 => [$completedStatusId, 'Integer'],
221 ];
222 return CRM_Core_DAO::singleValueQuery($query, $params);
223 }
224
225 /**
226 * Show the amount, nickname on honor roll.
227 *
228 * @param array $pcpId
229 * Contains the pcp ID.
230 *
231 * @return array
232 */
233 public static function honorRoll($pcpId) {
234 $completedStatusId = CRM_Core_PseudoConstant::getKey(
235 'CRM_Contribute_BAO_Contribution',
236 'contribution_status_id',
237 'Completed'
238 );
239 $query = "
240 SELECT cc.id, cs.pcp_roll_nickname, cs.pcp_personal_note,
241 cc.total_amount, cc.currency
242 FROM civicrm_contribution cc
243 LEFT JOIN civicrm_contribution_soft cs ON cc.id = cs.contribution_id
244 WHERE cs.pcp_id = %1
245 AND cs.pcp_display_in_roll = 1
246 AND contribution_status_id = %2
247 AND is_test = 0";
248 $params = [
249 1 => [$pcpId, 'Integer'],
250 2 => [$completedStatusId, 'Integer'],
251 ];
252 $dao = CRM_Core_DAO::executeQuery($query, $params);
253 $honor = [];
254 while ($dao->fetch()) {
255 $honor[$dao->id]['nickname'] = ucwords($dao->pcp_roll_nickname);
256 $honor[$dao->id]['total_amount'] = CRM_Utils_Money::format($dao->total_amount, $dao->currency);
257 $honor[$dao->id]['personal_note'] = $dao->pcp_personal_note;
258 }
259 return $honor;
260 }
261
262 /**
263 * Get action links.
264 *
265 * @param int $pcpId
266 * Contains the pcp ID. Defaults to NULL for backwards compatibility.
267 *
268 * @return array
269 * (reference) of action links
270 */
271 public static function &pcpLinks($pcpId = NULL) {
272 if (!(self::$_pcpLinks)) {
273 $deleteExtra = ts('Are you sure you want to delete this Personal Campaign Page?') . '\n' . ts('This action cannot be undone.');
274
275 self::$_pcpLinks['add'] = [
276 CRM_Core_Action::ADD => [
277 'name' => ts('Create a Personal Campaign Page'),
278 'class' => 'no-popup',
279 'url' => 'civicrm/contribute/campaign',
280 'qs' => 'action=add&reset=1&pageId=%%pageId%%&component=%%pageComponent%%',
281 'title' => ts('Configure'),
282 ],
283 ];
284
285 self::$_pcpLinks['all'] = [
286 CRM_Core_Action::UPDATE => [
287 'name' => ts('Edit Your Page'),
288 'url' => 'civicrm/pcp/info',
289 'qs' => 'action=update&reset=1&id=%%pcpId%%&component=%%pageComponent%%',
290 'title' => ts('Configure'),
291 ],
292 CRM_Core_Action::DETACH => [
293 'name' => ts('Tell Friends'),
294 'url' => 'civicrm/friend',
295 'qs' => 'eid=%%pcpId%%&blockId=%%pcpBlock%%&reset=1&pcomponent=pcp&component=%%pageComponent%%',
296 'title' => ts('Tell Friends'),
297 ],
298 CRM_Core_Action::VIEW => [
299 'name' => ts('URL for this Page'),
300 'url' => 'civicrm/pcp/info',
301 'qs' => 'reset=1&id=%%pcpId%%&component=%%pageComponent%%',
302 'title' => ts('URL for this Page'),
303 ],
304 CRM_Core_Action::BROWSE => [
305 'name' => ts('Update Contact Information'),
306 'url' => 'civicrm/pcp/info',
307 'qs' => 'action=browse&reset=1&id=%%pcpId%%&component=%%pageComponent%%',
308 'title' => ts('Update Contact Information'),
309 ],
310 CRM_Core_Action::ENABLE => [
311 'name' => ts('Enable'),
312 'url' => 'civicrm/pcp',
313 'qs' => 'action=enable&reset=1&id=%%pcpId%%&component=%%pageComponent%%',
314 'title' => ts('Enable'),
315 ],
316 CRM_Core_Action::DISABLE => [
317 'name' => ts('Disable'),
318 'url' => 'civicrm/pcp',
319 'qs' => 'action=disable&reset=1&id=%%pcpId%%&component=%%pageComponent%%',
320 'title' => ts('Disable'),
321 ],
322 CRM_Core_Action::DELETE => [
323 'name' => ts('Delete'),
324 'url' => 'civicrm/pcp',
325 'qs' => 'action=delete&reset=1&id=%%pcpId%%&component=%%pageComponent%%',
326 'extra' => 'onclick = "return confirm(\'' . $deleteExtra . '\');"',
327 'title' => ts('Delete'),
328 ],
329 ];
330
331 CRM_Utils_Hook::links('pcp.user.actions', 'Pcp', $pcpId, self::$_pcpLinks);
332 }
333 return self::$_pcpLinks;
334 }
335
336 /**
337 * Delete the campaign page.
338 *
339 * @param int $id
340 * Campaign page id.
341 */
342 public static function deleteById($id) {
343 CRM_Utils_Hook::pre('delete', 'Campaign', $id, CRM_Core_DAO::$_nullArray);
344
345 $transaction = new CRM_Core_Transaction();
346
347 // delete from pcp table
348 $pcp = new CRM_PCP_DAO_PCP();
349 $pcp->id = $id;
350 $pcp->delete();
351
352 $transaction->commit();
353
354 CRM_Utils_Hook::post('delete', 'Campaign', $id, $pcp);
355 }
356
357 /**
358 * Build the form object.
359 *
360 * @param CRM_Core_Form $form
361 * Form object.
362 */
363 public static function buildPCPForm($form) {
364 $form->addElement('checkbox', 'pcp_active', ts('Enable Personal Campaign Pages?'), NULL, ['onclick' => "return showHideByValue('pcp_active',true,'pcpFields','block','radio',false);"]);
365
366 $form->addElement('checkbox', 'is_approval_needed', ts('Approval required'));
367
368 $profile = [];
369 $isUserRequired = NULL;
370 $config = CRM_Core_Config::singleton();
371 if ($config->userFramework != 'Standalone') {
372 $isUserRequired = 2;
373 }
374 CRM_Core_DAO::commonRetrieveAll('CRM_Core_DAO_UFGroup', 'is_cms_user', $isUserRequired, $profiles, [
375 'title',
376 'is_active',
377 ]);
378 if (!empty($profiles)) {
379 foreach ($profiles as $key => $value) {
380 if ($value['is_active']) {
381 $profile[$key] = $value['title'];
382 }
383 }
384 $form->assign('profile', $profile);
385 }
386
387 $form->add('select', 'supporter_profile_id', ts('Supporter Profile'), ['' => ts('- select -')] + $profile, TRUE);
388
389 //CRM-15821 - To add new option for PCP "Owner" notification
390 $ownerNotifications = CRM_Core_OptionGroup::values('pcp_owner_notify');
391 $form->addRadio('owner_notify_id', ts('Owner Email Notification'), $ownerNotifications, NULL, '<br/>', TRUE);
392
393 $form->addElement('checkbox', 'is_tellfriend_enabled', ts("Allow 'Tell a friend' functionality"), NULL, ['onclick' => "return showHideByValue('is_tellfriend_enabled',true,'tflimit','table-row','radio',false);"]);
394
395 $form->add('number',
396 'tellfriend_limit',
397 ts("'Tell a friend' maximum recipients limit"),
398 CRM_Core_DAO::getAttribute('CRM_PCP_DAO_PCPBlock', 'tellfriend_limit')
399 );
400 $form->addRule('tellfriend_limit', ts('Please enter a valid limit.'), 'integer');
401
402 $form->add('text',
403 'link_text',
404 ts("'Create Personal Campaign Page' link text"),
405 CRM_Core_DAO::getAttribute('CRM_PCP_DAO_PCPBlock', 'link_text')
406 );
407
408 $form->add('text', 'notify_email', ts('Notify Email'), CRM_Core_DAO::getAttribute('CRM_PCP_DAO_PCPBlock', 'notify_email'));
409 }
410
411 /**
412 * This function builds the supporter text for the pcp
413 *
414 * @param int $pcpID
415 * the personal campaign page ID
416 * @param int $contributionPageID
417 * @param string $component
418 * one of 'contribute' or 'event'
419 *
420 * @return string
421 */
422 public static function getPcpSupporterText($pcpID, $contributionPageID, $component) {
423 $pcp_supporter_text = '';
424 $text = CRM_PCP_BAO_PCP::getPcpBlockStatus($contributionPageID, $component);
425 $pcpSupporter = CRM_PCP_BAO_PCP::displayName($pcpID);
426 switch ($component) {
427 case 'event':
428 $pcp_supporter_text = ts('This event registration is being made thanks to the efforts of <strong>%1</strong>, who supports our campaign. ', [1 => $pcpSupporter]);
429 if (!empty($text)) {
430 $pcp_supporter_text .= ts('You can support it as well - once you complete the registration, you will be able to create your own Personal Campaign Page!');
431 }
432 break;
433
434 case 'contribute':
435 $pcp_supporter_text = ts('This contribution is being made thanks to the efforts of <strong>%1</strong>, who supports our campaign. ', [1 => $pcpSupporter]);
436 if (!empty($text)) {
437 $pcp_supporter_text .= ts('You can support it as well - once you complete the donation, you will be able to create your own Personal Campaign Page!');
438 }
439 break;
440 }
441 return $pcp_supporter_text;
442 }
443
444 /**
445 * Add PCP form elements to a form.
446 *
447 * @param int $pcpId
448 * @param CRM_Core_Form $page
449 * @param array $elements
450 *
451 * @throws \CiviCRM_API3_Exception
452 */
453 public static function buildPcp($pcpId, &$page, &$elements = NULL) {
454 $prms = ['id' => $pcpId];
455 CRM_Core_DAO::commonRetrieve('CRM_PCP_DAO_PCP', $prms, $pcpInfo);
456
457 if (CRM_PCP_BAO_PCP::displayName($pcpId)) {
458 $pcp_supporter_text = self::getPcpSupporterText($pcpId, $pcpInfo['page_id'], $pcpInfo['page_type']);
459 $page->assign('pcpSupporterText', $pcp_supporter_text);
460 }
461 $page->assign('pcp', TRUE);
462
463 // build honor roll fields for registration form if supporter has honor roll enabled for their PCP
464 if ($pcpInfo['is_honor_roll']) {
465 $page->assign('is_honor_roll', TRUE);
466 $page->add('checkbox', 'pcp_display_in_roll', ts('Show my support in the public honor roll'), NULL, NULL,
467 ['onclick' => "showHideByValue('pcp_display_in_roll','','nameID|nickID|personalNoteID','block','radio',false); pcpAnonymous( );"]
468 );
469 $extraOption = ['onclick' => "return pcpAnonymous( );"];
470 $page->addRadio('pcp_is_anonymous', '', [ts('Include my name and message'), ts('List my support anonymously')], [], '&nbsp;&nbsp;&nbsp;', FALSE, [$extraOption, $extraOption]);
471 $page->_defaults['pcp_is_anonymous'] = 0;
472
473 $page->add('text', 'pcp_roll_nickname', ts('Name'), ['maxlength' => 30]);
474 $page->addField('pcp_personal_note', ['entity' => 'ContributionSoft', 'context' => 'create', 'style' => 'height: 3em; width: 40em;']);
475 }
476 else {
477 $page->assign('is_honor_roll', FALSE);
478 }
479 }
480
481 /**
482 * Process a PCP contribution.
483 *
484 * @param int $pcpId
485 * @param string $component
486 * @param string $entity
487 *
488 * @return array
489 */
490 public static function handlePcp($pcpId, $component, $entity) {
491
492 self::getPcpEntityTable($component);
493
494 if (!$pcpId) {
495 return FALSE;
496 }
497
498 $pcpStatus = CRM_Core_PseudoConstant::get('CRM_PCP_BAO_PCP', 'status_id');
499 $approvedId = array_search('Approved', $pcpStatus);
500
501 $params = ['id' => $pcpId];
502 CRM_Core_DAO::commonRetrieve('CRM_PCP_DAO_PCP', $params, $pcpInfo);
503
504 $params = ['id' => $pcpInfo['pcp_block_id']];
505 CRM_Core_DAO::commonRetrieve('CRM_PCP_DAO_PCPBlock', $params, $pcpBlock);
506
507 $params = ['id' => $pcpInfo['page_id']];
508 $now = time();
509
510 if ($component == 'event') {
511 // figure out where to redirect if an exception occurs below based on target entity
512 $urlBase = 'civicrm/event/register';
513
514 // ignore startDate for events - PCP's can be active long before event start date
515 $startDate = 0;
516 $endDate = CRM_Utils_Date::unixTime(CRM_Utils_Array::value('end_date', $entity));
517 }
518 elseif ($component == 'contribute') {
519 $urlBase = 'civicrm/contribute/transact';
520 //start and end date of the contribution page
521 $startDate = CRM_Utils_Date::unixTime(CRM_Utils_Array::value('start_date', $entity));
522 $endDate = CRM_Utils_Date::unixTime(CRM_Utils_Array::value('end_date', $entity));
523 }
524
525 // define redirect url back to contrib page or event if needed
526 $url = CRM_Utils_System::url($urlBase, "reset=1&id={$pcpBlock['entity_id']}", FALSE, NULL, FALSE, TRUE);
527 $currentPCPStatus = CRM_Core_PseudoConstant::getName('CRM_PCP_BAO_PCP', 'status_id', $pcpInfo['status_id']);
528
529 if ($pcpBlock['target_entity_id'] != $entity['id']) {
530 $statusMessage = ts('This page is not related to the Personal Campaign Page you have just visited. However you can still make a contribution here.');
531 CRM_Core_Error::statusBounce($statusMessage, $url);
532 }
533 elseif ($currentPCPStatus !== 'Approved') {
534 $statusMessage = ts('The Personal Campaign Page you have just visited is currently %1. However you can still support the campaign here.', [1 => $pcpStatus[$pcpInfo['status_id']]]);
535 CRM_Core_Error::statusBounce($statusMessage, $url);
536 }
537 elseif (empty($pcpBlock['is_active'])) {
538 $statusMessage = ts('Personal Campaign Pages are currently not enabled for this contribution page. However you can still support the campaign here.');
539 CRM_Core_Error::statusBounce($statusMessage, $url);
540 }
541 elseif (empty($pcpInfo['is_active'])) {
542 $statusMessage = ts('The Personal Campaign Page you have just visited is currently inactive. However you can still support the campaign here.');
543 CRM_Core_Error::statusBounce($statusMessage, $url);
544 }
545 // Check if we're in range for contribution page start and end dates. for events, check if after event end date
546 elseif (($startDate && $startDate > $now) || ($endDate && $endDate < $now)) {
547 $customStartDate = CRM_Utils_Date::customFormat(CRM_Utils_Array::value('start_date', $entity));
548 $customEndDate = CRM_Utils_Date::customFormat(CRM_Utils_Array::value('end_date', $entity));
549 if ($startDate && $endDate) {
550 $statusMessage = ts('The Personal Campaign Page you have just visited is only active from %1 to %2. However you can still support the campaign here.',
551 [1 => $customStartDate, 2 => $customEndDate]
552 );
553 CRM_Core_Error::statusBounce($statusMessage, $url);
554 }
555 elseif ($startDate) {
556 $statusMessage = ts('The Personal Campaign Page you have just visited will be active beginning on %1. However you can still support the campaign here.', [1 => $customStartDate]);
557 CRM_Core_Error::statusBounce($statusMessage, $url);
558 }
559 elseif ($endDate) {
560 if ($component == 'event') {
561 // Target_entity is an event and the event is over, redirect to event info instead of event registration page.
562 $url = CRM_Utils_System::url('civicrm/event/info',
563 "reset=1&id={$pcpBlock['entity_id']}",
564 FALSE, NULL, FALSE, TRUE
565 );
566 $statusMessage = ts('The event linked to the Personal Campaign Page you have just visited is over (as of %1).', [1 => $customEndDate]);
567 CRM_Core_Error::statusBounce($statusMessage, $url);
568 }
569 else {
570 $statusMessage = ts('The Personal Campaign Page you have just visited is no longer active (as of %1). However you can still support the campaign here.', [1 => $customEndDate]);
571 CRM_Core_Error::statusBounce($statusMessage, $url);
572 }
573 }
574 }
575
576 return [
577 'pcpId' => $pcpId,
578 'pcpBlock' => $pcpBlock,
579 'pcpInfo' => $pcpInfo,
580 ];
581 }
582
583 /**
584 * Approve / Reject the campaign page.
585 *
586 * @param int $id
587 * Campaign page id.
588 *
589 * @param bool $is_active
590 */
591 public static function setIsActive($id, $is_active) {
592 switch ($is_active) {
593 case 0:
594 $is_active = 3;
595 break;
596
597 case 1:
598 $is_active = 2;
599 break;
600 }
601
602 CRM_Core_DAO::setFieldValue('CRM_PCP_DAO_PCP', $id, 'status_id', $is_active);
603
604 $pcpTitle = CRM_Core_DAO::getFieldValue('CRM_PCP_DAO_PCP', $id, 'title');
605 $pcpPageType = CRM_Core_DAO::getFieldValue('CRM_PCP_DAO_PCP', $id, 'page_type');
606
607 $pcpStatus = CRM_Core_OptionGroup::values("pcp_status");
608 $pcpStatus = $pcpStatus[$is_active];
609
610 CRM_Core_Session::setStatus(ts("%1 status has been updated to %2.", [
611 1 => $pcpTitle,
612 2 => $pcpStatus,
613 ]), 'Status Updated', 'success');
614
615 // send status change mail
616 $result = self::sendStatusUpdate($id, $is_active, FALSE, $pcpPageType);
617
618 if ($result) {
619 CRM_Core_Session::setStatus(ts("A notification email has been sent to the supporter."), ts('Email Sent'), 'success');
620 }
621 }
622
623 /**
624 * Send notification email to supporter.
625 *
626 * 1. when their PCP status is changed by site admin.
627 * 2. when supporter initially creates a Personal Campaign Page ($isInitial set to true).
628 *
629 * @param int $pcpId
630 * Campaign page id.
631 * @param int $newStatus
632 * Pcp status id.
633 * @param bool|int $isInitial is it the first time, campaign page has been created by the user
634 *
635 * @param string $component
636 *
637 * @throws Exception
638 * @return null
639 */
640 public static function sendStatusUpdate($pcpId, $newStatus, $isInitial = FALSE, $component = 'contribute') {
641 $pcpStatusName = CRM_Core_OptionGroup::values("pcp_status", FALSE, FALSE, FALSE, NULL, 'name');
642 $pcpStatus = CRM_Core_OptionGroup::values("pcp_status");
643 $config = CRM_Core_Config::singleton();
644
645 if (!isset($pcpStatus[$newStatus])) {
646 return FALSE;
647 }
648
649 require_once 'Mail/mime.php';
650
651 //set loginUrl
652 $loginURL = $config->userSystem->getLoginURL();
653
654 // used in subject templates
655 $contribPageTitle = self::getPcpPageTitle($pcpId, $component);
656
657 $tplParams = [
658 'loginUrl' => $loginURL,
659 'contribPageTitle' => $contribPageTitle,
660 'pcpId' => $pcpId,
661 ];
662
663 //get the default domain email address.
664 list($domainEmailName, $domainEmailAddress) = CRM_Core_BAO_Domain::getNameAndEmail();
665
666 if (!$domainEmailAddress || $domainEmailAddress == 'info@EXAMPLE.ORG') {
667 $fixUrl = CRM_Utils_System::url('civicrm/admin/options/from_email_address', 'reset=1');
668 throw new CRM_Core_Exception(ts('The site administrator needs to enter a valid \'FROM Email Address\' in <a href="%1">Administer CiviCRM &raquo; Communications &raquo; FROM Email Addresses</a>. The email address used may need to be a valid mail account with your email service provider.', [1 => $fixUrl]));
669 }
670
671 $receiptFrom = '"' . $domainEmailName . '" <' . $domainEmailAddress . '>';
672
673 // get recipient (supporter) name and email
674 $params = ['id' => $pcpId];
675 CRM_Core_DAO::commonRetrieve('CRM_PCP_DAO_PCP', $params, $pcpInfo);
676 list($name, $address) = CRM_Contact_BAO_Contact_Location::getEmailDetails($pcpInfo['contact_id']);
677
678 // get pcp block info
679 list($blockId, $eid) = self::getPcpBlockEntityId($pcpId, $component);
680 $params = ['id' => $blockId];
681 CRM_Core_DAO::commonRetrieve('CRM_PCP_DAO_PCPBlock', $params, $pcpBlockInfo);
682
683 // assign urls required in email template
684 if ($pcpStatusName[$newStatus] == 'Approved') {
685 $tplParams['isTellFriendEnabled'] = $pcpBlockInfo['is_tellfriend_enabled'];
686 if ($pcpBlockInfo['is_tellfriend_enabled']) {
687 $pcpTellFriendURL = CRM_Utils_System::url('civicrm/friend',
688 "reset=1&eid=$pcpId&blockId=$blockId&pcomponent=pcp",
689 TRUE, NULL, FALSE, TRUE
690 );
691 $tplParams['pcpTellFriendURL'] = $pcpTellFriendURL;
692 }
693 }
694 $pcpInfoURL = CRM_Utils_System::url('civicrm/pcp/info',
695 "reset=1&id=$pcpId",
696 TRUE, NULL, FALSE, TRUE
697 );
698 $tplParams['pcpInfoURL'] = $pcpInfoURL;
699 $tplParams['contribPageTitle'] = $contribPageTitle;
700 if ($emails = CRM_Utils_Array::value('notify_email', $pcpBlockInfo)) {
701 $emailArray = explode(',', $emails);
702 $tplParams['pcpNotifyEmailAddress'] = $emailArray[0];
703 }
704 // get appropriate message based on status
705 $tplParams['pcpStatus'] = $pcpStatus[$newStatus];
706
707 $tplName = $isInitial ? 'pcp_supporter_notify' : 'pcp_status_change';
708
709 list($sent, $subject, $message, $html) = CRM_Core_BAO_MessageTemplate::sendTemplate(
710 [
711 'groupName' => 'msg_tpl_workflow_contribution',
712 'valueName' => $tplName,
713 'contactId' => $pcpInfo['contact_id'],
714 'tplParams' => $tplParams,
715 'from' => $receiptFrom,
716 'toName' => $name,
717 'toEmail' => $address,
718 ]
719 );
720 return $sent;
721 }
722
723 /**
724 * Enable / Disable the campaign page.
725 *
726 * @param int $id
727 * Campaign page id.
728 *
729 * @param bool $is_active
730 *
731 * @return bool
732 * true if we found and updated the object, else false
733 */
734 public static function setDisable($id, $is_active) {
735 return CRM_Core_DAO::setFieldValue('CRM_PCP_DAO_PCP', $id, 'is_active', $is_active);
736 }
737
738 /**
739 * Get pcp block is active.
740 *
741 * @param int $pcpId
742 * @param $component
743 *
744 * @return int
745 */
746 public static function getStatus($pcpId, $component) {
747 $query = "
748 SELECT pb.is_active
749 FROM civicrm_pcp pcp
750 LEFT JOIN civicrm_pcp_block pb ON ( pcp.page_id = pb.entity_id )
751 WHERE pcp.id = %1
752 AND pb.entity_table = %2";
753
754 $entity_table = self::getPcpEntityTable($component);
755
756 $params = [1 => [$pcpId, 'Integer'], 2 => [$entity_table, 'String']];
757 return CRM_Core_DAO::singleValueQuery($query, $params);
758 }
759
760 /**
761 * Get pcp block is enabled for component page.
762 *
763 * @param int $pageId
764 * @param $component
765 *
766 * @return string
767 */
768 public static function getPcpBlockStatus($pageId, $component) {
769 $query = "
770 SELECT pb.link_text as linkText
771 FROM civicrm_pcp_block pb
772 WHERE pb.is_active = 1 AND
773 pb.entity_id = %1 AND
774 pb.entity_table = %2";
775
776 $entity_table = self::getPcpEntityTable($component);
777
778 $params = [1 => [$pageId, 'Integer'], 2 => [$entity_table, 'String']];
779 return CRM_Core_DAO::singleValueQuery($query, $params);
780 }
781
782 /**
783 * Find out if the PCP block is in use by one or more PCP page.
784 *
785 * @param int $id
786 * Pcp block id.
787 *
788 * @return Bool
789 */
790 public static function getPcpBlockInUse($id) {
791 $query = "
792 SELECT count(*)
793 FROM civicrm_pcp pcp
794 WHERE pcp.pcp_block_id = %1";
795
796 $params = [1 => [$id, 'Integer']];
797 $result = CRM_Core_DAO::singleValueQuery($query, $params);
798 return $result > 0;
799 }
800
801 /**
802 * Get email is enabled for supporter's profile
803 *
804 * @param int $profileId
805 * Supporter's profile id.
806 *
807 * @return bool
808 */
809 public static function checkEmailProfile($profileId) {
810 $query = "
811 SELECT field_name
812 FROM civicrm_uf_field
813 WHERE field_name like 'email%' And is_active = 1 And uf_group_id = %1";
814
815 $params = [1 => [$profileId, 'Integer']];
816 $dao = CRM_Core_DAO::executeQuery($query, $params);
817 if (!$dao->fetch()) {
818 return TRUE;
819 }
820 return FALSE;
821 }
822
823 /**
824 * Obtain the title of page associated with a pcp.
825 *
826 * @param int $pcpId
827 * @param $component
828 *
829 * @return int
830 */
831 public static function getPcpPageTitle($pcpId, $component) {
832 if ($component == 'contribute') {
833 $query = "
834 SELECT cp.title
835 FROM civicrm_pcp pcp
836 LEFT JOIN civicrm_contribution_page as cp ON ( cp.id = pcp.page_id )
837 WHERE pcp.id = %1";
838 }
839 elseif ($component == 'event') {
840 $query = "
841 SELECT ce.title
842 FROM civicrm_pcp pcp
843 LEFT JOIN civicrm_event as ce ON ( ce.id = pcp.page_id )
844 WHERE pcp.id = %1";
845 }
846
847 $params = [1 => [$pcpId, 'Integer']];
848 return CRM_Core_DAO::singleValueQuery($query, $params);
849 }
850
851 /**
852 * Get pcp block & entity id given pcp id
853 *
854 * @param int $pcpId
855 * @param $component
856 *
857 * @return string
858 */
859 public static function getPcpBlockEntityId($pcpId, $component) {
860 $entity_table = self::getPcpEntityTable($component);
861
862 $query = "
863 SELECT pb.id as pcpBlockId, pb.entity_id
864 FROM civicrm_pcp pcp
865 LEFT JOIN civicrm_pcp_block pb ON ( pb.entity_id = pcp.page_id AND pb.entity_table = %2 )
866 WHERE pcp.id = %1";
867
868 $params = [1 => [$pcpId, 'Integer'], 2 => [$entity_table, 'String']];
869 $dao = CRM_Core_DAO::executeQuery($query, $params);
870 if ($dao->fetch()) {
871 return [$dao->pcpBlockId, $dao->entity_id];
872 }
873
874 return [];
875 }
876
877 /**
878 * Get pcp entity table given a component.
879 *
880 * @param $component
881 *
882 * @return string
883 */
884 public static function getPcpEntityTable($component) {
885 $entity_table_map = [
886 'event' => 'civicrm_event',
887 'civicrm_event' => 'civicrm_event',
888 'contribute' => 'civicrm_contribution_page',
889 'civicrm_contribution_page' => 'civicrm_contribution_page',
890 ];
891 return $entity_table_map[$component] ?? FALSE;
892 }
893
894 /**
895 * Get supporter profile id.
896 *
897 * @param int $component_id
898 * @param string $component
899 *
900 * @return int
901 */
902 public static function getSupporterProfileId($component_id, $component = 'contribute') {
903 $entity_table = self::getPcpEntityTable($component);
904
905 $query = "
906 SELECT pcp.supporter_profile_id
907 FROM civicrm_pcp_block pcp
908 INNER JOIN civicrm_uf_group ufgroup
909 ON pcp.supporter_profile_id = ufgroup.id
910 WHERE pcp.entity_id = %1
911 AND pcp.entity_table = %2
912 AND ufgroup.is_active = 1";
913
914 $params = [1 => [$component_id, 'Integer'], 2 => [$entity_table, 'String']];
915 if (!$supporterProfileId = CRM_Core_DAO::singleValueQuery($query, $params)) {
916 throw new CRM_Core_Exception(ts('Supporter profile is not set for this Personal Campaign Page or the profile is disabled. Please contact the site administrator if you need assistance.'));
917 }
918 else {
919 return $supporterProfileId;
920 }
921 }
922
923 /**
924 * Get owner notification id.
925 *
926 * @param int $component_id
927 * @param $component
928 *
929 * @return int
930 */
931 public static function getOwnerNotificationId($component_id, $component = 'contribute') {
932 $entity_table = self::getPcpEntityTable($component);
933 $query = "
934 SELECT pb.owner_notify_id
935 FROM civicrm_pcp_block pb
936 WHERE pb.entity_id = %1 AND pb.entity_table = %2";
937 $params = [1 => [$component_id, 'Integer'], 2 => [$entity_table, 'String']];
938 if (!$ownerNotificationId = CRM_Core_DAO::singleValueQuery($query, $params)) {
939 throw new CRM_Core_Exception(ts('Owner Notification is not set for this Personal Campaign Page. Please contact the site administrator if you need assistance.'));
940 }
941 else {
942 return $ownerNotificationId;
943 }
944 }
945
946 /**
947 * Get the title of the pcp.
948 *
949 * @param string $component
950 * @param int $id
951 *
952 * @return bool|string|null
953 */
954 protected static function getPcpTitle(string $component, int $id) {
955 if ($component === 'contribute') {
956 return CRM_Core_PseudoConstant::getLabel('CRM_Contribute_BAO_Contribution', 'contribution_page_id', $id);
957 }
958 return CRM_Core_PseudoConstant::getLabel('CRM_Event_BAO_Participant', 'event_id', $id);
959 }
960
961 }