Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consolidate building of contact token list #21429

Merged
merged 2 commits into from
Sep 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 5 additions & 71 deletions CRM/Core/SelectValues.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
+--------------------------------------------------------------------+
*/

use Civi\Token\TokenProcessor;

/**
* One place to store frequently used values in Select Elements. Note that
* some of the below elements will be dynamic, so we'll probably have a
Expand Down Expand Up @@ -576,77 +578,9 @@ public static function contributionTokens(): array {
*
* @return array
*/
public static function contactTokens() {
static $tokens = NULL;
if (!$tokens) {
$additionalFields = [
'checksum' => ['title' => ts('Checksum')],
'contact_id' => ['title' => ts('Internal Contact ID')],
];
$exportFields = array_merge(CRM_Contact_BAO_Contact::exportableFields(), $additionalFields);

$values = array_merge(array_keys($exportFields));
unset($values[0]);

//FIXME:skipping some tokens for time being.
$skipTokens = [
'is_bulkmail',
'group',
'tag',
'contact_sub_type',
'note',
'is_deceased',
'deceased_date',
'legal_identifier',
'contact_sub_type',
'user_unique_id',
'addressee_id',
'email_greeting_id',
'postal_greeting_id',
];

$customFields = CRM_Core_BAO_CustomField::getFields(['Individual', 'Address']);
$legacyTokenNames = array_flip(CRM_Utils_Token::legacyContactTokens());

foreach ($values as $val) {
if (in_array($val, $skipTokens)) {
continue;
}
//keys for $tokens should be constant. $token Values are changed for Custom Fields. CRM-3734
$customFieldId = CRM_Core_BAO_CustomField::getKeyID($val);
if ($customFieldId) {
// CRM-15191 - if key is not in $customFields then the field is disabled and should be ignored
if (!empty($customFields[$customFieldId])) {
$tokens["{contact.$val}"] = $customFields[$customFieldId]['label'] . " :: " . $customFields[$customFieldId]['groupTitle'];
}
}
else {
// Support legacy token names
$tokenName = CRM_Utils_Array::value($val, $legacyTokenNames, $val);
$tokens["{contact.$tokenName}"] = $exportFields[$val]['title'];
}
}

// Get all the hook tokens too
$hookTokens = [];
CRM_Utils_Hook::tokens($hookTokens);
foreach ($hookTokens as $tokenValues) {
foreach ($tokenValues as $key => $value) {
if (is_numeric($key)) {
$key = $value;
}
if (!preg_match('/^\{[^\}]+\}$/', $key)) {
$key = '{' . $key . '}';
}
if (preg_match('/^\{([^\}]+)\}$/', $value, $matches)) {
$value = $matches[1];
}
$tokens[$key] = $value;
}
}
}

return $tokens;
public static function contactTokens(): array {
$tokenProcessor = new TokenProcessor(Civi::dispatcher(), ['schema' => ['contactId']]);
return $tokenProcessor->listTokens();
}

/**
Expand Down
186 changes: 185 additions & 1 deletion Civi/Token/TokenCompatSubscriber.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php
namespace Civi\Token;

use Civi\Token\Event\TokenRegisterEvent;
use Civi\Token\Event\TokenRenderEvent;
use Civi\Token\Event\TokenValueEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
Expand All @@ -20,16 +21,199 @@
*/
class TokenCompatSubscriber implements EventSubscriberInterface {

protected $entity = 'contact';

/**
* @inheritDoc
*/
public static function getSubscribedEvents() {
public static function getSubscribedEvents(): array {
return [
'civi.token.eval' => [
['setupSmartyAliases', 1000],
['onEvaluate'],
],
'civi.token.render' => 'onRender',
'civi.token.list' => 'registerTokens',
];
}

/**
* Register the declared tokens.
*
* @param \Civi\Token\Event\TokenRegisterEvent $e
* The registration event. Add new tokens using register().
*/
public function registerTokens(TokenRegisterEvent $e): void {
if (!$this->checkActive($e->getTokenProcessor())) {
return;
}
foreach (array_merge($this->getContactTokens(), $this->getCustomFieldTokens()) as $name => $label) {
$e->register([
'entity' => $this->entity,
'field' => $name,
'label' => $label,
]);
}
foreach ($this->getLegacyHookTokens() as $legacyHookToken) {
$e->register([
'entity' => $legacyHookToken['category'],
'field' => $legacyHookToken['name'],
'label' => $legacyHookToken['label'],
]);
}
}

/**
* Determine whether this token-handler should be used with
* the given processor.
*
* To short-circuit token-processing in irrelevant contexts,
* override this.
*
* @param \Civi\Token\TokenProcessor $processor
* @return bool
*/
public function checkActive(\Civi\Token\TokenProcessor $processor) {
return in_array($this->getEntityIDField(), $processor->context['schema'], TRUE);
}

/**
* @return string
*/
public function getEntityIDField(): string {
return 'contactId';
}

/**
* Get functions declared using the legacy hook.
*
* Note that these only extend the contact entity (
* ie they are based on having a contact ID which they.
* may or may not use, but they don't have other
* entity IDs.)
*
* @return array
*/
public function getLegacyHookTokens(): array {
$tokens = [];
$hookTokens = [];
\CRM_Utils_Hook::tokens($hookTokens);
foreach ($hookTokens as $tokenValues) {
foreach ($tokenValues as $key => $value) {
if (is_numeric($key)) {
// This appears to be an attempt to compensate for
// inconsistencies described in https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_tokenValues/#example
// in effect there is a suggestion that
// Send an Email" and "CiviMail" send different parameters to the tokenValues hook
// As of now 'send an email' renders hooks through this class.
// CiviMail it depends on the use or otherwise of flexmailer.
$key = $value;
}
if (preg_match('/^\{([^\}]+)\}$/', $value, $matches)) {
$value = $matches[1];
}
$keyParts = explode('.', $key);
$tokens[$key] = [
'category' => $keyParts[0],
'name' => $keyParts[1],
'label' => $value,
];
}
}
return $tokens;
}

/**
* @return array
* @throws \CRM_Core_Exception
*/
public function getCustomFieldTokens(): array {
$tokens = [];
$customFields = \CRM_Core_BAO_CustomField::getFields(['Individual', 'Address', 'Contact']);
foreach ($customFields as $customField) {
$tokens['custom_' . $customField['id']] = $customField['label'] . " :: " . $customField['groupTitle'];
}
return $tokens;
}

/**
* Get all tokens advertised as contact tokens.
*
* @return string[]
*/
public function getContactTokens(): array {
return [
'contact_type' => 'Contact Type',
'do_not_email' => 'Do Not Email',
'do_not_phone' => 'Do Not Phone',
'do_not_mail' => 'Do Not Mail',
'do_not_sms' => 'Do Not Sms',
'do_not_trade' => 'Do Not Trade',
'is_opt_out' => 'No Bulk Emails (User Opt Out)',
'external_identifier' => 'External Identifier',
'sort_name' => 'Sort Name',
'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',
'hash' => 'Contact Hash',
'contact_source' => 'Contact Source',
'first_name' => 'First Name',
'middle_name' => 'Middle Name',
'last_name' => 'Last Name',
'individual_prefix' => 'Individual Prefix',
'individual_suffix' => 'Individual Suffix',
'formal_title' => 'Formal Title',
'communication_style' => 'Communication Style',
'job_title' => 'Job Title',
'gender' => 'Gender ID',
'birth_date' => 'Birth Date',
'current_employer_id' => 'Current Employer ID',
'contact_is_deleted' => 'Contact is in Trash',
'created_date' => 'Created Date',
'modified_date' => 'Modified Date',
'addressee' => 'Addressee',
'email_greeting' => 'Email Greeting',
'postal_greeting' => 'Postal Greeting',
'current_employer' => 'Current Employer',
'location_type' => 'Location Type',
'address_id' => 'Address ID',
'street_address' => 'Street Address',
'street_number' => 'Street Number',
'street_number_suffix' => 'Street Number Suffix',
'street_name' => 'Street Name',
'street_unit' => 'Street Unit',
'supplemental_address_1' => 'Supplemental Address 1',
'supplemental_address_2' => 'Supplemental Address 2',
'supplemental_address_3' => 'Supplemental Address 3',
'city' => 'City',
'postal_code_suffix' => 'Postal Code Suffix',
'postal_code' => 'Postal Code',
'geo_code_1' => 'Latitude',
'geo_code_2' => 'Longitude',
'manual_geo_code' => 'Is Manually Geocoded',
'address_name' => 'Address Name',
'master_id' => 'Master Address ID',
'county' => 'County',
'state_province' => 'State',
'country' => 'Country',
'phone' => 'Phone',
'phone_ext' => 'Phone Extension',
'phone_type_id' => 'Phone Type ID',
'phone_type' => 'Phone Type',
'email' => 'Email',
'on_hold' => 'On Hold',
'signature_text' => 'Signature Text',
'signature_html' => 'Signature Html',
'im_provider' => 'IM Provider',
'im' => 'IM Screen Name',
'openid' => 'OpenID',
'world_region' => 'World Region',
'url' => 'Website',
'checksum' => 'Checksum',
'contact_id' => 'Internal Contact ID',
];
}

Expand Down
Loading