From aca31c5c0b067c5bf69b5d94d0901dee7f39273c Mon Sep 17 00:00:00 2001
From: Justin Freeman <justin@agileware.com.au>
Date: Tue, 18 May 2021 13:02:34 +1000
Subject: [PATCH] CIVICRM-1731 Adds support for Participant fields and
 Participant Custom Fields as Tokens in Scheduled Reminders.

---
 CRM/Admin/Form/ScheduleReminders.php |  1 +
 CRM/Core/SelectValues.php            | 42 ++++--------
 CRM/Event/Participant/Tokens.php     | 96 ++++++++++++++++++++++++++++
 Civi/Core/Container.php              |  2 +-
 4 files changed, 109 insertions(+), 32 deletions(-)
 create mode 100644 CRM/Event/Participant/Tokens.php

diff --git a/CRM/Admin/Form/ScheduleReminders.php b/CRM/Admin/Form/ScheduleReminders.php
index 15a7a24a5afd..9e24eaabc0c2 100644
--- a/CRM/Admin/Form/ScheduleReminders.php
+++ b/CRM/Admin/Form/ScheduleReminders.php
@@ -693,6 +693,7 @@ public function listTokens() {
     $tokens = CRM_Core_SelectValues::contactTokens();
     $tokens = array_merge(CRM_Core_SelectValues::activityTokens(), $tokens);
     $tokens = array_merge(CRM_Core_SelectValues::eventTokens(), $tokens);
+    $tokens = array_merge(CRM_Core_SelectValues::participantTokens(), $tokens);
     $tokens = array_merge(CRM_Core_SelectValues::membershipTokens(), $tokens);
     $tokens = array_merge(CRM_Core_SelectValues::contributionTokens(), $tokens);
     return $tokens;
diff --git a/CRM/Core/SelectValues.php b/CRM/Core/SelectValues.php
index 2eadd2b6a724..432197ccf39e 100644
--- a/CRM/Core/SelectValues.php
+++ b/CRM/Core/SelectValues.php
@@ -682,39 +682,19 @@ public static function contactTokens() {
   public static function participantTokens() {
     static $tokens = NULL;
     if (!$tokens) {
-      $exportFields = CRM_Event_BAO_Participant::exportableFields();
-
-      $values = array_merge(array_keys($exportFields));
-      unset($values[0]);
-
-      // skipping some tokens for time being.
-      $skipTokens = [
-        'event_id',
-        'participant_is_pay_later',
-        'participant_is_test',
-        'participant_contact_id',
-        'participant_fee_currency',
-        'participant_campaign_id',
-        'participant_status',
-        'participant_discount_name',
-      ];
-
-      $customFields = CRM_Core_BAO_CustomField::getFields('Participant');
+      $tokens = array_merge([
+        '{participant.status}' => ts('Participant Status'),
+        '{participant.role}' => ts('Participant Role'),
+        '{participant.register_date}' => ts('Registration Date'),
+        '{participant.source}' => ts('Source'),
+        '{participant.fee_level}' => ts('Fee Level'),
+        '{participant.fee_amount}' => ts('Fee Amount'),
+        '{participant.is_pay_later}' => ts('Is Pay Later'),
+        '{participant.must_wait}' => ts('On Waiting List'),
+      ], CRM_Utils_Token::getCustomFieldTokens('Participant', TRUE));
 
-      foreach ($values as $key => $val) {
-        if (in_array($val, $skipTokens)) {
-          continue;
-        }
-        //keys for $tokens should be constant. $token Values are changed for Custom Fields. CRM-3734
-        if ($customFieldId = CRM_Core_BAO_CustomField::getKeyID($val)) {
-          $tokens["{participant.$val}"] = !empty($customFields[$customFieldId]) ? $customFields[$customFieldId]['label'] . " :: " . $customFields[$customFieldId]['groupTitle'] : '';
-        }
-        else {
-          $tokens["{participant.$val}"] = $exportFields[$val]['title'];
-        }
-      }
+      return $tokens;
     }
-    return $tokens;
   }
 
   /**
diff --git a/CRM/Event/Participant/Tokens.php b/CRM/Event/Participant/Tokens.php
new file mode 100644
index 000000000000..921024fef247
--- /dev/null
+++ b/CRM/Event/Participant/Tokens.php
@@ -0,0 +1,96 @@
+<?php
+
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved.                        |
+ |                                                                    |
+ | This work is published under the GNU AGPLv3 license with some      |
+ | permitted exceptions and without any warranty. For full license    |
+ | and copyright information, see https://civicrm.org/licensing       |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ * Class CRM_Event_Participant_Tokens
+ *
+ * Generate "participant.*" tokens.
+ *
+ */
+class CRM_Event_Participant_Tokens extends \Civi\Token\AbstractTokenSubscriber {
+
+  /**
+   * Class constructor.
+   */
+  public function __construct() {
+    parent::__construct('participant', array_merge(
+      [
+        'status' => ts('Participant Status'),
+        'role' => ts('Participant Role'),
+        'register_date' => ts('Registration Date'),
+        'source' => ts('Source'),
+        'fee_level' => ts('Fee Level'),
+        'fee_amount' => ts('Fee Amount'),
+        'is_pay_later' => ts('Is Pay Later'),
+        'must_wait' => ts('On Waiting List'),
+      ],
+      CRM_Utils_Token::getCustomFieldTokens('Participant')
+    ));
+  }
+
+  /**
+   * @inheritDoc
+   */
+  public function checkActive(\Civi\Token\TokenProcessor $processor) {
+    // Extracted from scheduled-reminders code. See the class description.
+    return !empty($processor->context['actionMapping'])
+      && $processor->context['actionMapping']->getEntity() === 'civicrm_participant';
+  }
+
+  /**
+   * @inheritDoc
+   */
+  public function evaluateToken(\Civi\Token\TokenRow $row, $entity, $field, $prefetch = NULL) {
+    $actionSearchResult = $row->context['actionSearchResult'];
+
+    if ($field == 'status') {
+      $row->tokens($entity, $field, \CRM_Event_PseudoConstant::participantStatus($actionSearchResult->status_id, NULL, 'label'));
+    }
+    elseif ($field == 'role') {
+      $role_ids = CRM_Utils_Array::explodePadded($actionSearchResult->role_id);
+      foreach ($role_ids as $role_id) {
+        $roles[] = \CRM_Event_PseudoConstant::participantRole($role_id);
+      }
+      $row->tokens($entity, $field, (!empty($roles)) ? implode(', ', $roles) : '');
+    }
+    elseif ($field == 'register_date') {
+      $row->tokens($entity, $field, \CRM_Utils_Date::customFormat($actionSearchResult->register_date, Civi::settings()
+        ->get('dateformatshortdate')));
+    }
+    elseif ($field == 'source') {
+      $row->tokens($entity, $field, $actionSearchResult->source);
+    }
+    elseif ($field == 'fee_level') {
+      $fee_level_multiple = \CRM_Utils_Array::explodePadded($actionSearchResult->fee_level);
+      foreach ($fee_level_multiple as $fee_level_single) {
+        $fee_levels[] = $fee_level_single;
+      }
+      $row->tokens($entity, $field, (!empty($fee_levels)) ? implode(', ', $fee_levels) : '');
+    }
+    elseif ($field == 'fee_amount') {
+      $row->tokens($entity, $field, \CRM_Utils_Money::format($actionSearchResult->fee_amount));
+    }
+    elseif ($field == 'is_pay_later') {
+      $row->tokens($entity, $field, ($actionSearchResult->is_pay_later == 0) ? '' : ts('You have opted to pay later for this event.'));
+    }
+    elseif ($field == 'must_wait') {
+      $row->tokens($entity, $field, (empty($actionSearchResult->must_wait)) ? '' : ts('You have been added to the WAIT LIST for this event.'));
+    }
+    elseif ($cfID = \CRM_Core_BAO_CustomField::getKeyID($field)) {
+      $row->customToken($entity, $cfID, $actionSearchResult->entity_id);
+    }
+    else {
+      $row->tokens($entity, $field, '');
+    }
+  }
+
+}
diff --git a/Civi/Core/Container.php b/Civi/Core/Container.php
index 947a2657d8d3..de302a68979f 100644
--- a/Civi/Core/Container.php
+++ b/Civi/Core/Container.php
@@ -331,7 +331,7 @@ public function createContainer() {
       []
     ))->addTag('kernel.event_subscriber')->setPublic(TRUE);
 
-    foreach (['Activity', 'Contribute', 'Event', 'Mailing', 'Member'] as $comp) {
+    foreach (['Activity', 'Contribute', 'Event', 'Event_Participant', 'Mailing', 'Member'] as $comp) {
       $container->setDefinition("crm_" . strtolower($comp) . "_tokens", new Definition(
         "CRM_{$comp}_Tokens",
         []