From: Eileen McNaughton Date: Wed, 6 Oct 2021 11:01:03 +0000 (+1300) Subject: Add token support for participant & membership tasks X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=4f036b713fa84b326d14fc4dfe765389de0a0c7c;p=civicrm-core.git Add token support for participant & membership tasks --- diff --git a/CRM/Case/Form/Task/Email.php b/CRM/Case/Form/Task/Email.php index d96114141a..9c72c8e3d1 100644 --- a/CRM/Case/Form/Task/Email.php +++ b/CRM/Case/Form/Task/Email.php @@ -66,4 +66,18 @@ class CRM_Case_Form_Task_Email extends CRM_Case_Form_Task { return $subject; } + /** + * Get the result rows to email. + * + * @return array + */ + protected function getRows(): array { + // format contact details array to handle multiple emails from same contact + $rows = parent::getRows(); + foreach ($rows as $index => $row) { + $rows[$index]['schema']['caseId'] = $this->getCaseID(); + } + return $rows; + } + } diff --git a/CRM/Contact/Form/Task/EmailTrait.php b/CRM/Contact/Form/Task/EmailTrait.php index 278b256018..f79b53c40d 100644 --- a/CRM/Contact/Form/Task/EmailTrait.php +++ b/CRM/Contact/Form/Task/EmailTrait.php @@ -16,7 +16,6 @@ */ use Civi\Api4\Email; -use Civi\Api4\Contribution; /** * This class provides the common functionality for tasks that send emails. @@ -374,15 +373,8 @@ trait CRM_Contact_Form_Task_EmailTrait { $bcc = $this->getEmailString($bccArray); $additionalDetails .= empty($bccArray) ? '' : "\nbcc : " . $this->getEmailUrlString($bccArray); - // format contact details array to handle multiple emails from same contact - $formattedContactDetails = []; - foreach ($this->getEmails() as $details) { - $formattedContactDetails[$details['contact_id'] . '::' . $details['email']] = $details; - } - // send the mail [$sent, $activityIds] = $this->sendEmail( - $formattedContactDetails, $formValues['text_message'], $formValues['html_message'], $from, @@ -390,7 +382,6 @@ trait CRM_Contact_Form_Task_EmailTrait { $cc, $bcc, $additionalDetails, - $this->getContributionIDs(), CRM_Utils_Array::value('campaign_id', $formValues), $this->getCaseID() ); @@ -448,15 +439,6 @@ trait CRM_Contact_Form_Task_EmailTrait { } } - /** - * List available tokens for this form. - * - * @return array - */ - public function listTokens(): array { - return CRM_Core_SelectValues::contactTokens(); - } - /** * Get the emails from the added element. * @@ -714,8 +696,6 @@ trait CRM_Contact_Form_Task_EmailTrait { * * Also insert a contact activity in each contacts record. * - * @param array $contactDetails - * The array of contact details to send the email. * @param $text * @param $html * @param string $from @@ -727,7 +707,6 @@ trait CRM_Contact_Form_Task_EmailTrait { * Bcc recipient. * @param string|null $additionalDetails * The additional information of CC and BCC appended to the activity Details. - * @param array|null $contributionIds * @param int|null $campaignId * @param int|null $caseId * @@ -737,14 +716,16 @@ trait CRM_Contact_Form_Task_EmailTrait { * * @throws \API_Exception * @throws \CRM_Core_Exception - * @throws \Civi\API\Exception\UnauthorizedException + * @throws \PEAR_Exception * @internal * * Also insert a contact activity in each contacts record. * + * @internal + * + * Also insert a contact activity in each contacts record. */ public function sendEmail( - $contactDetails, $text, $html, $from, @@ -752,46 +733,26 @@ trait CRM_Contact_Form_Task_EmailTrait { $cc = NULL, $bcc = NULL, $additionalDetails = NULL, - $contributionIds = NULL, $campaignId = NULL, $caseId = NULL ) { $userID = CRM_Core_Session::getLoggedInContactID(); - $contributionDetails = []; - if (!empty($contributionIds)) { - $contributionDetails = Contribution::get(FALSE) - ->setSelect(['contact_id']) - ->addWhere('id', 'IN', $contributionIds) - ->execute() - // Note that this indexing means that only the last - // contribution per contact is resolved to tokens. - // this is long-standing functionality, albeit possibly - // not thought through. - ->indexBy('contact_id'); - } - $sent = $notSent = []; $attachmentFileIds = []; $activityIds = []; $firstActivityCreated = FALSE; - foreach ($contactDetails as $values) { - $tokenContext = $caseId ? ['caseId' => $caseId] : []; + foreach ($this->getRowsForEmails() as $values) { $contactId = $values['contact_id']; $emailAddress = $values['email']; - - if (!empty($contributionDetails)) { - $tokenContext['contributionId'] = $contributionDetails[$contactId]['id']; - } - $renderedTemplate = CRM_Core_BAO_MessageTemplate::renderTemplate([ 'messageTemplate' => [ 'msg_text' => $text, 'msg_html' => $html, 'msg_subject' => $this->getSubject(), ], - 'tokenContext' => $tokenContext, + 'tokenContext' => array_merge(['schema' => $this->getTokenSchema()], ($values['schema'] ?? [])), 'contactId' => $contactId, 'disableSmarty' => !CRM_Utils_Constant::value('CIVICRM_MAIL_SMARTY'), ]); @@ -990,4 +951,66 @@ trait CRM_Contact_Form_Task_EmailTrait { return $url; } + /** + * Get the result rows to email. + * + * @return array + * + * @throws \API_Exception + * @throws \CRM_Core_Exception + */ + protected function getRowsForEmails(): array { + $rows = []; + foreach ($this->getRows() as $row) { + $rows[$row['contact_id']][] = $row; + } + // format contact details array to handle multiple emails from same contact + $formattedContactDetails = []; + foreach ($this->getEmails() as $details) { + $contactID = $details['contact_id']; + $index = $contactID . '::' . $details['email']; + if (!isset($rows[$contactID])) { + $formattedContactDetails[$index] = $details; + continue; + } + if ($this->isGroupByContact()) { + foreach ($rows[$contactID] as $rowDetail) { + $details['schema'] = $rowDetail['schema'] ?? []; + } + $formattedContactDetails[$index] = $details; + } + else { + foreach ($rows[$contactID] as $key => $rowDetail) { + $index .= '_' . $key; + $formattedContactDetails[$index] = $details; + $formattedContactDetails[$index]['schema'] = $rowDetail['schema'] ?? []; + } + } + + } + return $formattedContactDetails; + } + + /** + * Only send one email per contact. + * + * This has historically been done for contributions & makes sense if + * no entity specific tokens are in use. + * + * @return bool + */ + protected function isGroupByContact(): bool { + return TRUE; + } + + /** + * Get the tokens in the submitted message. + * + * @return array + * @throws \CRM_Core_Exception + */ + protected function getMessageTokens(): array { + return CRM_Utils_Token::getTokens($this->getSubject() . $this->getSubmittedValue('html_message') . $this->getSubmittedValue('text_message')); + } + } diff --git a/CRM/Contact/Form/Task/PDFTrait.php b/CRM/Contact/Form/Task/PDFTrait.php index dae3544153..8a3146c8d8 100644 --- a/CRM/Contact/Form/Task/PDFTrait.php +++ b/CRM/Contact/Form/Task/PDFTrait.php @@ -241,7 +241,7 @@ trait CRM_Contact_Form_Task_PDFTrait { $tokenHtml = CRM_Core_BAO_MessageTemplate::renderTemplate([ 'contactId' => $row['contact_id'], 'messageTemplate' => ['msg_html' => $html_message], - 'tokenContext' => ['schema' => $row['schema']], + 'tokenContext' => array_merge(['schema' => $this->getTokenSchema()], ($row['schema'] ?? [])), 'disableSmarty' => (!defined('CIVICRM_MAIL_SMARTY') || !CIVICRM_MAIL_SMARTY), ])['html']; diff --git a/CRM/Contribute/Form/Task/Email.php b/CRM/Contribute/Form/Task/Email.php index 7fb87e4c97..da4b638b36 100644 --- a/CRM/Contribute/Form/Task/Email.php +++ b/CRM/Contribute/Form/Task/Email.php @@ -15,6 +15,8 @@ * @copyright CiviCRM LLC https://civicrm.org/licensing */ +use Civi\Api4\Contribution; + /** * This class provides the functionality to email a group of contacts. */ @@ -32,4 +34,35 @@ class CRM_Contribute_Form_Task_Email extends CRM_Contribute_Form_Task { return $this->getIDs(); } + /** + * Get the result rows to email. + * + * @return array + * + * @throws \API_Exception + * @throws \CRM_Core_Exception + */ + protected function getRows(): array { + $contributionDetails = Contribution::get(FALSE) + ->setSelect(['contact_id', 'id']) + ->addWhere('id', 'IN', $this->getContributionIDs()) + ->execute() + // Note that this indexing means that only the last + // contribution per contact is resolved to tokens. + // this is long-standing functionality, albeit possibly + // not thought through. + ->indexBy('contact_id'); + + // format contact details array to handle multiple emails from same contact + $formattedContactDetails = []; + foreach ($this->getEmails() as $details) { + $formattedContactDetails[$details['contact_id'] . '::' . $details['email']] = $details; + if (!empty($contributionDetails[$details['contact_id']])) { + $formattedContactDetails[$details['contact_id'] . '::' . $details['email']]['schema'] = ['contributionId' => $contributionDetails[$details['contact_id']]['id']]; + } + + } + return $formattedContactDetails; + } + } diff --git a/CRM/Core/Form/Task.php b/CRM/Core/Form/Task.php index 5e8501a6ce..3c134e608c 100644 --- a/CRM/Core/Form/Task.php +++ b/CRM/Core/Form/Task.php @@ -75,6 +75,18 @@ abstract class CRM_Core_Form_Task extends CRM_Core_Form { */ public static $entityShortname = NULL; + + /** + * Rows to act on. + * + * e.g + * [ + * ['contact_id' => 4, 'participant_id' => 6, 'schema' => ['contactId' => 5, 'participantId' => 6], + * ] + * @var array + */ + protected $rows = []; + /** * Set where the browser should be directed to next. * @@ -367,7 +379,7 @@ SELECT contact_id protected function getRows(): array { $rows = []; foreach ($this->getContactIDs() as $contactID) { - $rows[] = ['schema' => ['contactId' => $contactID]]; + $rows[] = ['contact_id' => $contactID, 'schema' => ['contactId' => $contactID]]; } return $rows; } diff --git a/CRM/Event/Form/Task/Email.php b/CRM/Event/Form/Task/Email.php index cd0270b376..85f1af9f80 100644 --- a/CRM/Event/Form/Task/Email.php +++ b/CRM/Event/Form/Task/Email.php @@ -22,4 +22,17 @@ class CRM_Event_Form_Task_Email extends CRM_Event_Form_Task { use CRM_Contact_Form_Task_EmailTrait; + /** + * Only send one email per contact. + * + * This has historically been done for contributions & makes sense if + * no entity specific tokens are in use. + * + * @return bool + * @throws \CRM_Core_Exception + */ + protected function isGroupByContact(): bool { + return !empty($this->getMessageTokens()['participant']) || !empty($this->getMessageTokens()['event']); + } + } diff --git a/CRM/Member/Form/Task.php b/CRM/Member/Form/Task.php index 9dd37aa1b9..756355c1e9 100644 --- a/CRM/Member/Form/Task.php +++ b/CRM/Member/Form/Task.php @@ -15,6 +15,8 @@ * @copyright CiviCRM LLC https://civicrm.org/licensing */ +use Civi\Api4\Membership; + /** * Class for member form task actions. * FIXME: This needs refactoring to properly inherit from CRM_Core_Form_Task and share more functions. @@ -95,6 +97,38 @@ class CRM_Member_Form_Task extends CRM_Core_Form_Task { ); } + /** + * @return array + */ + protected function getIDS() { + return $this->_memberIds; + } + + /** + * Get the rows form the search, keyed to make the token processor happy. + * + * @throws \API_Exception + */ + protected function getRows(): array { + if (empty($this->rows)) { + // checkPermissions set to false - in case form is bypassing in some way. + $memberships = Membership::get(FALSE) + ->addWhere('id', 'IN', $this->getIDs()) + ->setSelect(['id', 'contact_id'])->execute(); + foreach ($memberships as $membership) { + $this->rows[] = [ + 'contact_id' => $membership['contact_id'], + 'membership_id' => $membership['id'], + 'schema' => [ + 'contactId' => $membership['contact_id'], + 'membershipId' => $membership['id'], + ], + ]; + } + } + return $this->rows; + } + /** * Get the token processor schema required to list any tokens for this task. * diff --git a/CRM/Member/Form/Task/Email.php b/CRM/Member/Form/Task/Email.php index 5e0e6d4baa..9f19d0fe7e 100644 --- a/CRM/Member/Form/Task/Email.php +++ b/CRM/Member/Form/Task/Email.php @@ -22,4 +22,17 @@ class CRM_Member_Form_Task_Email extends CRM_Member_Form_Task { use CRM_Contact_Form_Task_EmailTrait; + /** + * Only send one email per contact. + * + * This has historically been done for contributions & makes sense if + * no entity specific tokens are in use. + * + * @return bool + * @throws \CRM_Core_Exception + */ + protected function isGroupByContact(): bool { + return !empty($this->getMessageTokens()['membership']); + } + }