Skip to content

Commit

Permalink
Restore contact greeting tokens in scheduled reminders.
Browse files Browse the repository at this point in the history
CRM-19757.

In 4.6, it was possible to use `{contact.email_greeting}` in a scheduled reminder. This was no longer possible in 4.7.

* Add tests to ensure greeting tokens are processed in `CRM_Core_BAO_ActionScheduleTest`
* Modify `CRM_Core_BAO_ActionScheduleTest` to test additional tokens (limited room in message subject due to 128char DB limit)
* Modify function signature of `CRM_Contact_BAO_Contact::create()` to return updated contact.
* Better handle case where contact preferred_mail_format is unset in `CRM_Core_BAO_ActionSchedule::sendReminderEmail()`
* Ensure greeting tokens are loaded in `CRM_Utils_Token::replaceGreetingTokens()` and `\Civi\Token\TokenCompatSubscriber::onEvaluate()`
* Re-order processing of tokens in `\Civi\Token\TokenCompatSubscriber::onRender()` - restores order used in 4.6, allowing greeting tokens which contain contact tokens to be fully processed.
  • Loading branch information
xurizaemon committed Dec 16, 2016
1 parent 74f5fbc commit 08f9b27
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 11 deletions.
6 changes: 5 additions & 1 deletion CRM/Contact/BAO/Contact.php
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ public static function &create(&$params, $fixAddress = TRUE, $invokeHooks = TRUE
}

// process greetings CRM-4575, cache greetings
self::processGreetings($contact);
$contact = self::processGreetings($contact);

return $contact;
}
Expand Down Expand Up @@ -2707,6 +2707,7 @@ public static function processGreetings(&$contact, $useDefaults = FALSE) {
);
$emailGreetingString = CRM_Core_DAO::escapeString(CRM_Utils_String::stripSpaces($emailGreetingString));
$updateQueryString[] = " email_greeting_display = '{$emailGreetingString}'";
$contact->email_greeting_display = $emailGreetingString;
}

//postal greetings
Expand Down Expand Up @@ -2743,6 +2744,7 @@ public static function processGreetings(&$contact, $useDefaults = FALSE) {
);
$postalGreetingString = CRM_Core_DAO::escapeString(CRM_Utils_String::stripSpaces($postalGreetingString));
$updateQueryString[] = " postal_greeting_display = '{$postalGreetingString}'";
$contact->postal_greeting_display = $postalGreetingString;
}

// addressee
Expand Down Expand Up @@ -2787,6 +2789,8 @@ public static function processGreetings(&$contact, $useDefaults = FALSE) {
$queryString = "UPDATE civicrm_contact SET {$updateQueryString} WHERE id = {$contact->id}";
CRM_Core_DAO::executeQuery($queryString);
}

return $contact;
}

/**
Expand Down
7 changes: 7 additions & 0 deletions CRM/Core/BAO/ActionSchedule.php
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,13 @@ protected static function sendReminderEmail($tokenRow, $schedule, $toContactID)
'entity_id' => $schedule->id,
);

if (isset($tokenRow->context['contact'])) {
if (!isset($tokenRow->context['contact']['preferred_mail_format']) ||
$tokenRow->context['contact']['preferred_mail_format'] === NULL) {
$tokenRow->context['contact']['preferred_mail_format'] = 'Both';
}
}

if (!$body_html || $tokenRow->context['contact']['preferred_mail_format'] == 'Text' ||
$tokenRow->context['contact']['preferred_mail_format'] == 'Both'
) {
Expand Down
4 changes: 4 additions & 0 deletions CRM/Utils/Token.php
Original file line number Diff line number Diff line change
Expand Up @@ -1443,6 +1443,10 @@ public static function replaceGreetingTokens(&$tokenString, $contactDetails = NU
$greetingTokens = self::getTokens($tokenString);

if (!empty($greetingTokens)) {
// Some greetings are required.
$greetingTokens[] = 'email_greeting';
$greetingTokens[] = 'postal_greeting';

// first use the existing contact object for token replacement
if (!empty($contactDetails)) {
$tokenString = CRM_Utils_Token::replaceContactTokens($tokenString, $contactDetails, TRUE, $greetingTokens, TRUE, $escapeSmarty);
Expand Down
19 changes: 16 additions & 3 deletions Civi/Token/TokenCompatSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,17 @@ public function onEvaluate(TokenValueEvent $e) {
$params = array(
array('contact_id', '=', $contactId, 0, 0),
);
list($contact, $_) = \CRM_Contact_BAO_Query::apiQuery($params);
// Pass required contact tokens in.
if (isset($messageTokens['contact'])) {
$contactTokens = array();
foreach ($messageTokens['contact'] as $name) {
$contactTokens[$name] = 1;
}
}
else {
$contactTokens = NULL;
}
list($contact, $_) = \CRM_Contact_BAO_Query::apiQuery($params, $contactTokens);
$contact = reset($contact); //CRM-4524
if (!$contact || is_a($contact, 'CRM_Core_Error')) {
// FIXME: Need to differentiate errors which kill the batch vs the individual row.
Expand Down Expand Up @@ -103,12 +113,15 @@ public function onRender(TokenRenderEvent $e) {
$e->string = \CRM_Utils_Token::replaceDomainTokens($e->string, \CRM_Core_BAO_Domain::getDomain(), $isHtml, $e->message['tokens'], $useSmarty);

if (!empty($e->context['contact'])) {
// ::replaceGreetingTokens() may return "Dear {contact.first_name}" so
// must precede ::replaceContactTokens.
//
// Note also inconsistent function signatures - see CRM-19768.
\CRM_Utils_Token::replaceGreetingTokens($e->string, NULL, $e->context['contact']['contact_id'], NULL, $useSmarty);
$e->string = \CRM_Utils_Token::replaceContactTokens($e->string, $e->context['contact'], $isHtml, $e->message['tokens'], FALSE, $useSmarty);

// FIXME: This may depend on $contact being merged with hook values.
$e->string = \CRM_Utils_Token::replaceHookTokens($e->string, $e->context['contact'], $e->context['hookTokenCategories'], $isHtml, $useSmarty);

\CRM_Utils_Token::replaceGreetingTokens($e->string, NULL, $e->context['contact']['contact_id'], NULL, $useSmarty);
}

if ($useSmarty) {
Expand Down
21 changes: 14 additions & 7 deletions tests/phpunit/CRM/Core/BAO/ActionScheduleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ public function setUp() {
'contact_type' => 'Individual',
'email' => 'test-member@example.com',
'gender_id' => 'Female',
'first_name' => 'Churmondleia',
'last_name' => 'Ōtākou',
);
$this->fixtures['contact_birthdate'] = array(
'is_deceased' => 0,
Expand Down Expand Up @@ -603,7 +605,6 @@ public function setUp() {
*/
public function tearDown() {
parent::tearDown();

$this->mut->clearMessages();
$this->mut->stop();
unset($this->mut);
Expand All @@ -621,30 +622,37 @@ public function tearDown() {
public function mailerExamples() {
$cases = array();

$manyTokensTmpl = implode(';;', array(
// Some tokens - short as subject has 128char limit in DB.
$someTokensTmpl = implode(';;', array(
'{contact.display_name}', // basic contact token
'{contact.gender}', // funny legacy contact token
'{contact.gender_id}', // funny legacy contact token
'{domain.name}', // domain token
'{activity.activity_type}', // action-scheduler token
));
// Further tokens can be tested in the body text/html.
$manyTokensTmpl = implode(';;', array(
$someTokensTmpl,
'{contact.email_greeting}',
));
// Note: The behavior of domain-tokens on a scheduled reminder is undefined. All we
// can really do is check that it has something.
$manyTokensExpected = 'test-member@example.com;;Female;;Female;;[a-zA-Z0-9 ]+;;Phone Call';
$someTokensExpected = 'Churmondleia Ōtākou;;Female;;Female;;[a-zA-Z0-9 ]+;;Phone Call';
$manyTokensExpected = "$someTokensExpected;;Dear Churmondleia";

// In this example, we use a lot of tokens cutting across multiple components..
// In this example, we use a lot of tokens cutting across multiple components.
$cases[0] = array(
// Schedule definition.
array(
'subject' => "subj $manyTokensTmpl",
'subject' => "subj $someTokensTmpl",
'body_html' => "html $manyTokensTmpl",
'body_text' => "text $manyTokensTmpl",
),
// Assertions (regex).
array(
'from_name' => "/^FIXME\$/",
'from_email' => "/^info@EXAMPLE.ORG\$/",
'subject' => "/^subj $manyTokensExpected\$/",
'subject' => "/^subj $someTokensExpected\$/",
'body_html' => "/^html $manyTokensExpected\$/",
'body_text' => "/^text $manyTokensExpected\$/",
),
Expand Down Expand Up @@ -755,7 +763,6 @@ public function testMailer($schedule, $patterns) {
}
}
$this->mut->clearMessages();

}

public function testActivityDateTimeMatchNonRepeatableSchedule() {
Expand Down

0 comments on commit 08f9b27

Please sign in to comment.