Merge pull request #19631 from colemanw/searchKitLinks
[civicrm-core.git] / CRM / Activity / Tokens.php
CommitLineData
46f5566c
TO
1<?php
2
3/*
4 +--------------------------------------------------------------------+
bc77d7c0 5 | Copyright CiviCRM LLC. All rights reserved. |
46f5566c 6 | |
bc77d7c0
TO
7 | This work is published under the GNU AGPLv3 license with some |
8 | permitted exceptions and without any warranty. For full license |
9 | and copyright information, see https://civicrm.org/licensing |
46f5566c
TO
10 +--------------------------------------------------------------------+
11 */
12
7808aae6
SB
13/**
14 * @package CRM
ca5cec67 15 * @copyright CiviCRM LLC https://civicrm.org/licensing
7808aae6
SB
16 */
17
c2a33d9c 18use Civi\Token\AbstractTokenSubscriber;
19use Civi\Token\Event\TokenValueEvent;
20use Civi\Token\TokenRow;
21
46f5566c
TO
22/**
23 * Class CRM_Member_Tokens
24 *
25 * Generate "activity.*" tokens.
26 *
da9977bd 27 * This TokenSubscriber was originally produced by refactoring the code from the
46f5566c
TO
28 * scheduled-reminder system with the goal of making that system
29 * more flexible. The current implementation is still coupled to
30 * scheduled-reminders. It would be good to figure out a more generic
31 * implementation which is not tied to scheduled reminders, although
32 * that is outside the current scope.
da9977bd
AS
33 *
34 * This has been enhanced to work with PDF/letter merge
46f5566c 35 */
c2a33d9c 36class CRM_Activity_Tokens extends AbstractTokenSubscriber {
46f5566c 37
88d88c53 38 use CRM_Core_TokenTrait;
da9977bd
AS
39
40 /**
88d88c53 41 * @return string
da9977bd 42 */
88d88c53
MW
43 private function getEntityName(): string {
44 return 'activity';
45 }
da9977bd 46
8246bca4 47 /**
88d88c53 48 * @return string
8246bca4 49 */
88d88c53
MW
50 private function getEntityTableName(): string {
51 return 'civicrm_activity';
46f5566c
TO
52 }
53
70599df6 54 /**
88d88c53 55 * @return string
70599df6 56 */
51e25a23 57 private function getEntityContextSchema(): string {
58 return 'activityId';
da9977bd
AS
59 }
60
61 /**
88d88c53 62 * Mapping from tokenName to api return field
f10c962e
MW
63 * Using arrays allows more complex tokens to be handled that require more than one API field.
64 * For example, an address token might want ['street_address', 'city', 'postal_code']
88d88c53
MW
65 *
66 * @var array
da9977bd 67 */
88d88c53
MW
68 private static $fieldMapping = [
69 'activity_id' => ['id'],
70 'activity_type' => ['activity_type_id'],
71 'status' => ['status_id'],
72 'campaign' => ['campaign_id'],
73 ];
46f5566c 74
298795cd
TO
75 /**
76 * @inheritDoc
77 */
f9ec2da6 78 public function alterActionScheduleQuery(\Civi\ActionSchedule\Event\MailingQueryEvent $e) {
88d88c53 79 if ($e->mapping->getEntity() !== $this->getEntityTableName()) {
f9ec2da6
TO
80 return;
81 }
82
7808aae6
SB
83 // The joint expression for activities needs some extra nuance to handle.
84 // Multiple revisions of the activity.
85 // Q: Could we simplify & move the extra AND clauses into `where(...)`?
f9ec2da6 86 $e->query->param('casEntityJoinExpr', 'e.id = reminder.entity_id AND e.is_current_revision = 1 AND e.is_deleted = 0');
da9977bd 87 }
f9ec2da6 88
da9977bd
AS
89 /**
90 * @inheritDoc
91 */
c2a33d9c 92 public function prefetch(TokenValueEvent $e) {
88d88c53
MW
93 // Find all the entity IDs
94 $entityIds
da9977bd 95 = $e->getTokenProcessor()->getContextValues('actionSearchResult', 'entityID')
51e25a23 96 + $e->getTokenProcessor()->getContextValues($this->getEntityContextSchema());
da9977bd 97
88d88c53
MW
98 if (!$entityIds) {
99 return NULL;
da9977bd
AS
100 }
101
102 // Get data on all activities for basic and customfield tokens
68f388d3 103 $prefetch['activity'] = civicrm_api3('Activity', 'get', [
88d88c53 104 'id' => ['IN' => $entityIds],
da9977bd
AS
105 'options' => ['limit' => 0],
106 'return' => self::getReturnFields($this->activeTokens),
68f388d3 107 ])['values'];
da9977bd
AS
108
109 // Store the activity types if needed
68f388d3 110 if (in_array('activity_type', $this->activeTokens, TRUE)) {
da9977bd
AS
111 $this->activityTypes = \CRM_Core_OptionGroup::values('activity_type');
112 }
113
114 // Store the activity statuses if needed
68f388d3 115 if (in_array('status', $this->activeTokens, TRUE)) {
da9977bd
AS
116 $this->activityStatuses = \CRM_Core_OptionGroup::values('activity_status');
117 }
118
119 // Store the campaigns if needed
68f388d3 120 if (in_array('campaign', $this->activeTokens, TRUE)) {
da9977bd 121 $this->campaigns = \CRM_Campaign_BAO_Campaign::getCampaigns();
f9ec2da6 122 }
da9977bd
AS
123
124 return $prefetch;
f9ec2da6
TO
125 }
126
46f5566c 127 /**
298795cd 128 * @inheritDoc
46f5566c 129 */
c2a33d9c 130 public function evaluateToken(TokenRow $row, $entity, $field, $prefetch = NULL) {
da9977bd
AS
131 // maps token name to api field
132 $mapping = [
133 'activity_id' => 'id',
134 ];
135
136 // Get ActivityID either from actionSearchResult (for scheduled reminders) if exists
51e25a23 137 $activityId = $row->context['actionSearchResult']->entityID ?? $row->context[$this->getEntityContextSchema()];
46f5566c 138
f10c962e 139 $activity = $prefetch['activity'][$activityId];
da9977bd 140
c3317f50 141 if (in_array($field, ['activity_date_time', 'created_date', 'modified_date'])) {
f10c962e 142 $row->tokens($entity, $field, \CRM_Utils_Date::customFormat($activity[$field]));
da9977bd 143 }
f10c962e
MW
144 elseif (isset($mapping[$field]) and (isset($activity[$mapping[$field]]))) {
145 $row->tokens($entity, $field, $activity[$mapping[$field]]);
46f5566c 146 }
da9977bd 147 elseif (in_array($field, ['activity_type'])) {
f10c962e 148 $row->tokens($entity, $field, $this->activityTypes[$activity['activity_type_id']]);
46f5566c 149 }
da9977bd 150 elseif (in_array($field, ['status'])) {
f10c962e 151 $row->tokens($entity, $field, $this->activityStatuses[$activity['status_id']]);
4e9b6a62 152 }
da9977bd 153 elseif (in_array($field, ['campaign'])) {
f10c962e 154 $row->tokens($entity, $field, $this->campaigns[$activity['campaign_id']]);
da9977bd 155 }
28f7a9b1
MW
156 elseif (in_array($field, ['case_id'])) {
157 // An activity can be linked to multiple cases so case_id is always an array.
158 // We just return the first case ID for the token.
f10c962e 159 $row->tokens($entity, $field, is_array($activity['case_id']) ? reset($activity['case_id']) : $activity['case_id']);
28f7a9b1 160 }
da9977bd
AS
161 elseif (array_key_exists($field, $this->customFieldTokens)) {
162 $row->tokens($entity, $field,
f10c962e
MW
163 isset($activity[$field])
164 ? \CRM_Core_BAO_CustomField::displayValue($activity[$field], $field)
da9977bd
AS
165 : ''
166 );
167 }
f10c962e
MW
168 elseif (isset($activity[$field])) {
169 $row->tokens($entity, $field, $activity[$field]);
46f5566c
TO
170 }
171 }
172
86420016 173 /**
174 * Get the basic tokens provided.
175 *
176 * @return array token name => token label
177 */
c2a33d9c 178 protected function getBasicTokens(): array {
da9977bd
AS
179 if (!isset($this->basicTokens)) {
180 $this->basicTokens = [
181 'activity_id' => ts('Activity ID'),
182 'activity_type' => ts('Activity Type'),
183 'subject' => ts('Activity Subject'),
184 'details' => ts('Activity Details'),
185 'activity_date_time' => ts('Activity Date-Time'),
c3317f50
MW
186 'created_date' => ts('Activity Created Date'),
187 'modified_date' => ts('Activity Modified Date'),
da9977bd
AS
188 'activity_type_id' => ts('Activity Type ID'),
189 'status' => ts('Activity Status'),
190 'status_id' => ts('Activity Status ID'),
191 'location' => ts('Activity Location'),
da9977bd
AS
192 'duration' => ts('Activity Duration'),
193 'campaign' => ts('Activity Campaign'),
194 'campaign_id' => ts('Activity Campaign ID'),
195 ];
196 if (array_key_exists('CiviCase', CRM_Core_Component::getEnabledComponents())) {
197 $this->basicTokens['case_id'] = ts('Activity Case ID');
198 }
199 }
200 return $this->basicTokens;
86420016 201 }
202
46f5566c 203}