From b7472bd6e34f6c0aa1e264b88d994e4c43b1e4b7 Mon Sep 17 00:00:00 2001 From: Eileen McNaughton Date: Sun, 19 Sep 2021 10:49:29 +1200 Subject: [PATCH] Convert event badges to use token processor This adds the token processor class for participants and switches the one place where we currently resolve participant tokens to use it. In the process I upgrade the badge tokens with a syntax change and drop a few more that are actually a) weird / seemingly accidentally exposed and b) not really part of the participant entity ie event template title & default role id With participant tokens we have been fortunate not to let a non-standard implementation go out so it's only the event badges which are a bit obscure / less used / less likely to be blindly used. I have added token replacement but I think it will be all very edge case --- CRM/Badge/BAO/Badge.php | 54 ++++++++++--------- CRM/Core/EntityTokens.php | 4 ++ CRM/Core/SelectValues.php | 18 +++---- CRM/Event/ParticipantTokens.php | 36 +++++++++++++ .../Incremental/php/FiveFortyThree.php | 25 +++++++++ Civi/Core/Container.php | 4 ++ .../phpunit/CRM/Event/Form/Task/BadgeTest.php | 21 ++++---- .../CRM/Utils/TokenConsistencyTest.php | 18 +++---- 8 files changed, 122 insertions(+), 58 deletions(-) create mode 100644 CRM/Event/ParticipantTokens.php diff --git a/CRM/Badge/BAO/Badge.php b/CRM/Badge/BAO/Badge.php index e501e95ff7..adb8dd791c 100644 --- a/CRM/Badge/BAO/Badge.php +++ b/CRM/Badge/BAO/Badge.php @@ -15,6 +15,8 @@ * @copyright CiviCRM LLC https://civicrm.org/licensing */ +use Civi\Token\TokenProcessor; + /** * Class CRM_Badge_Format_Badge. * @@ -87,7 +89,7 @@ class CRM_Badge_BAO_Badge { if ($element) { $value = $row[$element]; // hack to fix date field display format - if (strpos($element, '_date')) { + if (in_array($element, ['event_start_date', 'event_end_date'], TRUE)) { $value = CRM_Utils_Date::customFormat($value, "%B %E%f"); } } @@ -369,7 +371,7 @@ class CRM_Badge_BAO_Badge { $this->imgRes = 300; if ($img) { - list($w, $h) = self::getImageProperties($img, $this->imgRes, $w, $h); + [$w, $h] = self::getImageProperties($img, $this->imgRes, $w, $h); $this->pdf->Image($img, $x, $y, $w, $h, '', '', '', FALSE, 72, '', FALSE, FALSE, $this->debug, FALSE, FALSE, FALSE); } @@ -402,39 +404,36 @@ class CRM_Badge_BAO_Badge { public static function buildBadges(&$params, &$form) { // get name badge layout info $layoutInfo = CRM_Badge_BAO_Layout::buildLayout($params); - + $tokenProcessor = new TokenProcessor(\Civi::dispatcher(), ['schema' => ['participantId'], 'smarty' => FALSE]); // split/get actual field names from token and individual contact image URLs - $returnProperties = []; + $returnProperties = $processorTokens = []; if (!empty($layoutInfo['data']['token'])) { foreach ($layoutInfo['data']['token'] as $index => $value) { - $element = ''; if ($value) { $token = CRM_Utils_Token::getTokens($value); - if (key($token) == 'contact') { - $element = $token['contact'][0]; - } - elseif (key($token) == 'event') { + if (strpos($value, '{event.') === 0) { $element = $token['event'][0]; //FIX ME - we need to standardize event token names if (substr($element, 0, 6) != 'event_') { + // legacy style. $element = 'event_' . $element; + $returnProperties[$element] = 1; + // add actual field name to row element + $layoutInfo['data']['rowElements'][$index] = $element; } } - elseif (key($token) == 'participant') { - $element = $token['participant'][0]; + else { + $tokenName = str_replace(['}', '{contact.', '{participant.'], '', $value); + $tokenProcessor->addMessage($tokenName, $value, 'text/plain'); + $processorTokens[] = $tokenName; + $layoutInfo['data']['rowElements'][$index] = $tokenName; } - - // build returnproperties for query - $returnProperties[$element] = 1; } - - // add actual field name to row element - $layoutInfo['data']['rowElements'][$index] = $element; } } // add additional required fields for query execution - $additionalFields = ['participant_register_date', 'participant_id', 'event_id', 'contact_id', 'image_URL']; + $additionalFields = ['participant_id', 'event_id', 'contact_id']; foreach ($additionalFields as $field) { $returnProperties[$field] = 1; } @@ -450,7 +449,7 @@ class CRM_Badge_BAO_Badge { CRM_Contact_BAO_Query::MODE_EVENT ); - list($select, $from, $where, $having) = $query->query(); + [$select, $from, $where, $having] = $query->query(); if (empty($where)) { $where = "WHERE {$form->_componentClause}"; } @@ -469,16 +468,19 @@ class CRM_Badge_BAO_Badge { $dao = CRM_Core_DAO::executeQuery($queryString); $rows = []; + while ($dao->fetch()) { - $query->convertToPseudoNames($dao); + $tokenProcessor->addRow(['contactId' => $dao->contact_id, 'participantId' => $dao->participant_id]); $rows[$dao->participant_id] = []; foreach ($returnProperties as $key => $dontCare) { - $value = $dao->$key ?? NULL; - // Format custom fields - if (strstr($key, 'custom_') && isset($value)) { - $value = CRM_Core_BAO_CustomField::displayValue($value, substr($key, 7), $dao->contact_id); - } - $rows[$dao->participant_id][$key] = $value; + // we are now only resolving the 4 event tokens here. + $rows[$dao->participant_id][$key] = $dao->$key ?? NULL; + } + } + $tokenProcessor->evaluate(); + foreach ($tokenProcessor->getRows() as $row) { + foreach ($processorTokens as $processorToken) { + $rows[$row->context['participantId']][$processorToken] = $row->render($processorToken); } } diff --git a/CRM/Core/EntityTokens.php b/CRM/Core/EntityTokens.php index d879efdc73..cc9350bb13 100644 --- a/CRM/Core/EntityTokens.php +++ b/CRM/Core/EntityTokens.php @@ -40,6 +40,10 @@ class CRM_Core_EntityTokens extends AbstractTokenSubscriber { public function evaluateToken(TokenRow $row, $entity, $field, $prefetch = NULL) { $this->prefetch = (array) $prefetch; $fieldValue = $this->getFieldValue($row, $field); + if (is_array($fieldValue)) { + // eg. role_id for participant would be an array here. + $fieldValue = implode(',', $fieldValue); + } if ($this->isPseudoField($field)) { if (!empty($fieldValue)) { diff --git a/CRM/Core/SelectValues.php b/CRM/Core/SelectValues.php index 2acad7d0b5..b0e5f24d51 100644 --- a/CRM/Core/SelectValues.php +++ b/CRM/Core/SelectValues.php @@ -594,18 +594,16 @@ class CRM_Core_SelectValues { */ public static function participantTokens(): array { $tokens = [ - '{participant.participant_status_id}' => 'Status ID', - '{participant.participant_role_id}' => 'Participant Role (ID)', - '{participant.participant_register_date}' => 'Register date', - '{participant.participant_source}' => 'Participant Source', - '{participant.participant_fee_level}' => 'Fee level', - '{participant.participant_fee_amount}' => 'Fee Amount', - '{participant.participant_registered_by_id}' => 'Registered By Participant ID', + '{participant.status_id}' => 'Status ID', + '{participant.role_id}' => 'Participant Role (ID)', + '{participant.register_date}' => 'Register date', + '{participant.source}' => 'Participant Source', + '{participant.fee_level}' => 'Fee level', + '{participant.fee_amount}' => 'Fee Amount', + '{participant.registered_by_id}' => 'Registered By Participant ID', '{participant.transferred_to_contact_id}' => 'Transferred to Contact ID', - '{participant.participant_role}' => 'Participant Role (label)', + '{participant.role_id:label}' => 'Participant Role (label)', '{participant.fee_label}' => 'Fee Label', - '{participant.default_role_id}' => 'Default Role', - '{participant.template_title}' => 'Event Template Title', ]; $customFields = CRM_Core_BAO_CustomField::getFields('Participant'); diff --git a/CRM/Event/ParticipantTokens.php b/CRM/Event/ParticipantTokens.php new file mode 100644 index 0000000000..717b11756f --- /dev/null +++ b/CRM/Event/ParticipantTokens.php @@ -0,0 +1,36 @@ +addTask('Replace duplicate event end date token in event badges', 'updatePrintLabelToken', 'participant.event_end_date', 'event.end_date', $rev ); + $this->addTask('Update participant status id token in event badges', + 'updatePrintLabelToken', 'participant.participant_status_id', 'participant.status_id', $rev + ); + $this->addTask('Update participant role id token in event badges', + 'updatePrintLabelToken', 'participant.participant_role_id', 'participant.role_id', $rev + ); + $this->addTask('Update participant role label token in event badges', + 'updatePrintLabelToken', 'participant.participant_role', 'participant.role_id:label', $rev + ); + $this->addTask('Update participant register date token in event badges', + 'updatePrintLabelToken', 'participant.participant_register_date', 'participant.register_date', $rev + ); + $this->addTask('Update participant source token in event badges', + 'updatePrintLabelToken', 'participant.participant_source', 'participant.source', $rev + ); + $this->addTask('Update participant fee level token in event badges', + 'updatePrintLabelToken', 'participant.participant_fee_level', 'participant.fee_level', $rev + ); + $this->addTask('Update participant fee amount token in event badges', + 'updatePrintLabelToken', 'participant.participant_fee_amount', 'participant.fee_amount', $rev + ); + $this->addTask('Update participant registered by id token in event badges', + 'updatePrintLabelToken', 'participant.participant_registered_by_id', 'participant.registered_by_id', $rev + ); + } /** diff --git a/Civi/Core/Container.php b/Civi/Core/Container.php index 5c74d402bc..69f05d1bec 100644 --- a/Civi/Core/Container.php +++ b/Civi/Core/Container.php @@ -333,6 +333,10 @@ class Container { [] ))->addTag('kernel.event_subscriber')->setPublic(TRUE); } + $container->setDefinition('crm_participant_tokens', new Definition( + 'CRM_Event_ParticipantTokens', + [] + ))->addTag('kernel.event_subscriber')->setPublic(TRUE); $container->setDefinition('crm_contribution_recur_tokens', new Definition( 'CRM_Contribute_RecurTokens', [] diff --git a/tests/phpunit/CRM/Event/Form/Task/BadgeTest.php b/tests/phpunit/CRM/Event/Form/Task/BadgeTest.php index aa0c19763f..8e0d4db5b2 100644 --- a/tests/phpunit/CRM/Event/Form/Task/BadgeTest.php +++ b/tests/phpunit/CRM/Event/Form/Task/BadgeTest.php @@ -84,27 +84,24 @@ class CRM_Event_Form_Task_BadgeTest extends CiviUnitTestCase { * @return string[] */ protected function getAvailableTokens(): array { - $tokens = [ + return [ '{event.title}' => 'Annual CiviCRM meet', '{contact.display_name}' => 'Mr. Anthony Anderson II', '{contact.current_employer}' => 'Default Organization', '{event.start_date}' => 'October 21st', - '{participant.participant_status_id}' => 2, - '{participant.participant_role_id}' => 1, - '{participant.participant_register_date}' => 'February 19th', - '{participant.participant_source}' => 'Wimbeldon', - '{participant.participant_fee_level}' => 'low', - '{participant.participant_fee_amount}' => NULL, - '{participant.participant_registered_by_id}' => NULL, + '{participant.status_id}' => 2, + '{participant.role_id}' => 1, + '{participant.register_date}' => 'February 19th, 2007 12:00 AM', + '{participant.source}' => 'Wimbeldon', + '{participant.fee_level}' => 'low', + '{participant.fee_amount}' => NULL, + '{participant.registered_by_id}' => NULL, '{participant.transferred_to_contact_id}' => NULL, - '{participant.participant_role}' => 'Attendee', + '{participant.role_id:label}' => 'Attendee', '{participant.fee_label}' => NULL, - '{participant.default_role_id}' => 1, - '{participant.template_title}' => NULL, '{event.end_date}' => 'October 23rd', '{event.id}' => 1, ]; - return $tokens; } } diff --git a/tests/phpunit/CRM/Utils/TokenConsistencyTest.php b/tests/phpunit/CRM/Utils/TokenConsistencyTest.php index d13406b264..0a0ab45571 100644 --- a/tests/phpunit/CRM/Utils/TokenConsistencyTest.php +++ b/tests/phpunit/CRM/Utils/TokenConsistencyTest.php @@ -483,18 +483,16 @@ December 21st, 2007 */ public function getParticipantTokens(): array { return [ - '{participant.participant_status_id}' => 'Status ID', - '{participant.participant_role_id}' => 'Participant Role (ID)', - '{participant.participant_register_date}' => 'Register date', - '{participant.participant_source}' => 'Participant Source', - '{participant.participant_fee_level}' => 'Fee level', - '{participant.participant_fee_amount}' => 'Fee Amount', - '{participant.participant_registered_by_id}' => 'Registered By Participant ID', + '{participant.status_id}' => 'Status ID', + '{participant.role_id}' => 'Participant Role (ID)', + '{participant.register_date}' => 'Register date', + '{participant.source}' => 'Participant Source', + '{participant.fee_level}' => 'Fee level', + '{participant.fee_amount}' => 'Fee Amount', + '{participant.registered_by_id}' => 'Registered By Participant ID', '{participant.transferred_to_contact_id}' => 'Transferred to Contact ID', - '{participant.participant_role}' => 'Participant Role (label)', + '{participant.role_id:label}' => 'Participant Role (label)', '{participant.fee_label}' => 'Fee Label', - '{participant.default_role_id}' => 'Default Role', - '{participant.template_title}' => 'Event Template Title', '{participant.' . $this->getCustomFieldName('text') . '}' => 'Enter text here :: Group with field text', ]; } -- 2.25.1