'display_name' => 'Display Name',
'nick_name' => 'Nickname',
'image_URL' => 'Image Url',
- 'preferred_communication_method' => 'Preferred Communication Method',
- 'preferred_language' => 'Preferred Language',
- 'preferred_mail_format' => 'Preferred Mail Format',
+ 'preferred_communication_method:label' => 'Preferred Communication Method',
+ 'preferred_language:label' => 'Preferred Language',
+ 'preferred_mail_format:label' => 'Preferred Mail Format',
'hash' => 'Contact Hash',
- 'contact_source' => 'Contact Source',
+ 'source' => 'Contact Source',
'first_name' => 'First Name',
'middle_name' => 'Middle Name',
'last_name' => 'Last Name',
- 'individual_prefix' => 'Individual Prefix',
- 'individual_suffix' => 'Individual Suffix',
+ 'prefix_id:label' => 'Individual Prefix',
+ 'suffix_id:label' => 'Individual Suffix',
'formal_title' => 'Formal Title',
- 'communication_style' => 'Communication Style',
+ 'communication_style_id:label' => 'Communication Style',
'job_title' => 'Job Title',
- 'gender' => 'Gender ID',
+ 'gender_id:label' => 'Gender ID',
'birth_date' => 'Birth Date',
'current_employer_id' => 'Current Employer ID',
- 'contact_is_deleted' => 'Contact is in Trash',
+ 'is_deleted:label' => 'Contact is in Trash',
'created_date' => 'Created Date',
'modified_date' => 'Modified Date',
- 'addressee' => 'Addressee',
- 'email_greeting' => 'Email Greeting',
- 'postal_greeting' => 'Postal Greeting',
+ 'addressee_display' => 'Addressee',
+ 'email_greeting_display' => 'Email Greeting',
+ 'postal_greeting_display' => 'Postal Greeting',
'current_employer' => 'Current Employer',
'location_type' => 'Location Type',
'address_id' => 'Address ID',
'world_region' => 'World Region',
'url' => 'Website',
'checksum' => 'Checksum',
- 'contact_id' => 'Internal Contact ID',
+ 'id' => 'Internal Contact ID',
];
}
}
else {
$row->format('text/html')
- ->tokens('contact', $token, $row->context['contact'][$token] ?? '');
+ ->tokens('contact', $token, $this->getFieldValue($row, $token));
}
}
}
}
+ /**
+ * Get the field value.
+ *
+ * @param \Civi\Token\TokenRow $row
+ * @param string $field
+ * @return string|int
+ */
+ protected function getFieldValue(TokenRow $row, string $field) {
+ $entityName = 'contact';
+ if (isset($this->getDeprecatedTokens()[$field])) {
+ // Check the non-deprecated location first, fall back to deprecated
+ // this is important for the greetings because - they are weird in the query object.
+ $possibilities = [$this->getDeprecatedTokens()[$field], $field];
+ }
+ else {
+ $possibilities = [$field];
+ if (in_array($field, $this->getDeprecatedTokens(), TRUE)) {
+ $possibilities[] = array_search($field, $this->getDeprecatedTokens(), TRUE);
+ }
+ }
+
+ foreach ($possibilities as $possibility) {
+ if (isset($row->context[$entityName][$possibility])) {
+ return $row->context[$entityName][$possibility];
+ }
+ }
+ return '';
+ }
+
/**
* Is the given field a boolean field.
*
*/
protected function getContact(int $contactId, array $requiredFields, bool $getAll = FALSE): array {
$returnProperties = array_fill_keys($requiredFields, 1);
- $mappedFields = [
- 'email_greeting' => 'email_greeting_display',
- 'postal_greeting' => 'postal_greeting_display',
- 'addressee' => 'addressee_display',
- ];
+ $mappedFields = array_flip($this->getDeprecatedTokens());
+
if (!empty($returnProperties['checksum'])) {
$returnProperties['hash'] = 1;
}
- foreach ($mappedFields as $tokenName => $realName) {
+ foreach ($mappedFields as $tokenName => $api3Name) {
if (in_array($tokenName, $requiredFields, TRUE)) {
- $returnProperties[$realName] = 1;
+ $returnProperties[$api3Name] = 1;
}
}
if ($getAll) {
[$contact] = \CRM_Contact_BAO_Query::apiQuery($params, $returnProperties ?? NULL);
//CRM-4524
$contact = reset($contact);
- foreach ($mappedFields as $tokenName => $realName) {
- $contact[$tokenName] = $contact[$realName] ?? '';
+ foreach ($mappedFields as $tokenName => $apiv3Name) {
+ // it would be set already with the right value for a greeting token
+ // the query object returns the db value for email_greeting_display
+ // and a numeric value for email_greeting if you put email_greeting
+ // in the return properties.
+ if (!isset($contact[$tokenName])) {
+ $contact[$tokenName] = $contact[$apiv3Name] ?? '';
+ }
}
//update value of custom field token
];
}
+ /**
+ * These tokens still work but we don't advertise them.
+ *
+ * We can remove from the following places
+ * - scheduled reminders
+ * - add to 'blocked' on pdf letter & email
+ *
+ * & then at some point start issuing warnings for them
+ * but contact tokens are pretty central so it might be
+ * a bit drawn out.
+ *
+ * @return string[]
+ * Keys are deprecated tokens and values are their replacements.
+ */
+ protected function getDeprecatedTokens(): array {
+ return [
+ 'individual_prefix' => 'prefix_id:label',
+ 'individual_suffix' => 'suffix_id:label',
+ 'gender' => 'gender_id:label',
+ 'communication_style' => 'communication_style_id:label',
+ 'preferred_communication_method' => 'preferred_communication_method:label',
+ 'email_greeting' => 'email_greeting_display',
+ 'postal_greeting' => 'postal_greeting_display',
+ 'addressee' => 'addressee_display',
+ 'contact_id' => 'id',
+ 'contact_source' => 'source',
+ 'contact_is_deleted' => 'is_deleted:label',
+ ];
+ }
+
}
use Civi\Api4\Address;
use Civi\Api4\Contact;
+use Civi\Api4\MessageTemplate;
use Civi\Token\TokenProcessor;
/**
CRM_Core_Transaction::create(TRUE)->run(function(CRM_Core_Transaction $tx) {
$tx->rollback();
- \Civi\Api4\MessageTemplate::update()
+ MessageTemplate::update()
->addWhere('workflow_name', '=', 'case_activity')
->addWhere('is_reserved', '=', 0)
->setValues([
CRM_Core_Transaction::create(TRUE)->run(function(CRM_Core_Transaction $tx) {
$tx->rollback();
- \Civi\Api4\MessageTemplate::update()
+ MessageTemplate::update()
->addWhere('workflow_name', '=', 'case_activity')
->addWhere('is_reserved', '=', 0)
->setValues([
$advertisedTokens = CRM_Core_SelectValues::contactTokens();
$this->assertEquals($this->getAdvertisedTokens(), $advertisedTokens);
- // Compare with our token data.
- unset($advertisedTokens['{important_stuff.favourite_emoticon}']);
- foreach (array_keys($advertisedTokens) as $token) {
- $this->assertArrayKeyExists(substr($token, 9, -1), $tokenData);
- }
-
CRM_Core_Smarty::singleton()->assign('pre_assigned_smarty', 'wee');
// This string contains the 4 types of possible replaces just to be sure they
// work in combination.
CRM_Utils_Time::resetTime();
}
+ /**
+ * Test that old contact tokens still work, as we add new-style support.
+ */
+ public function testLegacyTokens(): void {
+ $contactID = $this->individualCreate(['gender_id' => 'Female', 'communication_style' => 1, 'preferred_communication_method' => 'Phone']);
+ $mappings = [
+ ['old' => '{contact.individual_prefix}', 'new' => '{contact.prefix_id:label}', 'output' => 'Mr.'],
+ ['old' => '{contact.individual_suffix}', 'new' => '{contact.suffix_id:label}', 'output' => 'II'],
+ ['old' => '{contact.gender}', 'new' => '{contact.gender_id:label}', 'output' => 'Female'],
+ ['old' => '{contact.communication_style}', 'new' => '{contact.communication_style_id:label}', 'output' => 'Formal'],
+ ['old' => '{contact.preferred_communication_method}', 'new' => '{contact.preferred_communication_method:label}', 'output' => 'Phone'],
+ ['old' => '{contact.contact_id}', 'new' => '{contact.id}', 'output' => $contactID],
+ ['old' => '{contact.email_greeting}', 'new' => '{contact.email_greeting_display}', 'output' => 'Dear Anthony'],
+ ['old' => '{contact.postal_greeting}', 'new' => '{contact.postal_greeting_display}', 'output' => 'Dear Anthony'],
+ ['old' => '{contact.addressee}', 'new' => '{contact.addressee_display}', 'output' => 'Mr. Anthony J. Anderson II'],
+ ];
+
+ foreach ($mappings as $mapping) {
+ foreach (['old', 'new'] as $type) {
+ $messageContent = CRM_Core_BAO_MessageTemplate::renderTemplate([
+ 'contactId' => $contactID,
+ 'messageTemplate' => [
+ 'msg_text' => $mapping[$type],
+ ],
+ ])['text'];
+ $this->assertEquals($mapping['output'], $messageContent, 'could not resolve ' . $mapping[$type]);
+ }
+ }
+ }
+
/**
* Implement token values hook.
*
'{contact.display_name}' => 'Display Name',
'{contact.nick_name}' => 'Nickname',
'{contact.image_URL}' => 'Image Url',
- '{contact.preferred_communication_method}' => 'Preferred Communication Method',
- '{contact.preferred_language}' => 'Preferred Language',
- '{contact.preferred_mail_format}' => 'Preferred Mail Format',
+ '{contact.preferred_communication_method:label}' => 'Preferred Communication Method',
+ '{contact.preferred_language:label}' => 'Preferred Language',
+ '{contact.preferred_mail_format:label}' => 'Preferred Mail Format',
'{contact.hash}' => 'Contact Hash',
- '{contact.contact_source}' => 'Contact Source',
+ '{contact.source}' => 'Contact Source',
'{contact.first_name}' => 'First Name',
'{contact.middle_name}' => 'Middle Name',
'{contact.last_name}' => 'Last Name',
- '{contact.individual_prefix}' => 'Individual Prefix',
- '{contact.individual_suffix}' => 'Individual Suffix',
+ '{contact.prefix_id:label}' => 'Individual Prefix',
+ '{contact.suffix_id:label}' => 'Individual Suffix',
'{contact.formal_title}' => 'Formal Title',
- '{contact.communication_style}' => 'Communication Style',
+ '{contact.communication_style_id:label}' => 'Communication Style',
'{contact.job_title}' => 'Job Title',
- '{contact.gender}' => 'Gender ID',
+ '{contact.gender_id:label}' => 'Gender ID',
'{contact.birth_date}' => 'Birth Date',
'{contact.current_employer_id}' => 'Current Employer ID',
- '{contact.contact_is_deleted}' => 'Contact is in Trash',
+ '{contact.is_deleted:label}' => 'Contact is in Trash',
'{contact.created_date}' => 'Created Date',
'{contact.modified_date}' => 'Modified Date',
- '{contact.addressee}' => 'Addressee',
- '{contact.email_greeting}' => 'Email Greeting',
- '{contact.postal_greeting}' => 'Postal Greeting',
+ '{contact.addressee_display}' => 'Addressee',
+ '{contact.email_greeting_display}' => 'Email Greeting',
+ '{contact.postal_greeting_display}' => 'Postal Greeting',
'{contact.current_employer}' => 'Current Employer',
'{contact.location_type}' => 'Location Type',
'{contact.address_id}' => 'Address ID',
'{contact.custom_12}' => 'Yes No :: Custom Group',
'{contact.custom_3}' => 'Test Date :: Custom Group',
'{contact.checksum}' => 'Checksum',
- '{contact.contact_id}' => 'Internal Contact ID',
+ '{contact.id}' => 'Internal Contact ID',
'{important_stuff.favourite_emoticon}' => 'Best coolest emoticon',
];
}