Merge pull request #21094 from mattwire/hideextensionkeyupgrade
[civicrm-core.git] / CRM / Activity / Tokens.php
1 <?php
2
3 /*
4 +--------------------------------------------------------------------+
5 | Copyright CiviCRM LLC. All rights reserved. |
6 | |
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 |
10 +--------------------------------------------------------------------+
11 */
12
13 /**
14 * @package CRM
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
16 */
17
18 use Civi\Token\AbstractTokenSubscriber;
19 use Civi\Token\Event\TokenValueEvent;
20 use Civi\Token\TokenRow;
21
22 /**
23 * Class CRM_Member_Tokens
24 *
25 * Generate "activity.*" tokens.
26 *
27 * This TokenSubscriber was originally produced by refactoring the code from the
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.
33 *
34 * This has been enhanced to work with PDF/letter merge
35 */
36 class CRM_Activity_Tokens extends AbstractTokenSubscriber {
37
38 use CRM_Core_TokenTrait;
39
40 /**
41 * @return string
42 */
43 private function getEntityName(): string {
44 return 'activity';
45 }
46
47 /**
48 * @return string
49 */
50 private function getEntityTableName(): string {
51 return 'civicrm_activity';
52 }
53
54 /**
55 * @return string
56 */
57 private function getEntityContextSchema(): string {
58 return 'activityId';
59 }
60
61 /**
62 * Mapping from tokenName to api return field
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']
65 *
66 * @var array
67 */
68 private static $fieldMapping = [
69 'activity_id' => ['id'],
70 'activity_type' => ['activity_type_id'],
71 'status' => ['status_id'],
72 'campaign' => ['campaign_id'],
73 ];
74
75 /**
76 * @inheritDoc
77 */
78 public function alterActionScheduleQuery(\Civi\ActionSchedule\Event\MailingQueryEvent $e) {
79 if ($e->mapping->getEntity() !== $this->getEntityTableName()) {
80 return;
81 }
82
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(...)`?
86 $e->query->param('casEntityJoinExpr', 'e.id = reminder.entity_id AND e.is_current_revision = 1 AND e.is_deleted = 0');
87 $e->query->select('e.id AS tokenContext_' . $this->getEntityContextSchema());
88 }
89
90 /**
91 * @inheritDoc
92 */
93 public function prefetch(TokenValueEvent $e) {
94 // Find all the entity IDs
95 $entityIds = $e->getTokenProcessor()->getContextValues($this->getEntityContextSchema());
96
97 if (!$entityIds) {
98 return NULL;
99 }
100
101 // Get data on all activities for basic and customfield tokens
102 $prefetch['activity'] = civicrm_api3('Activity', 'get', [
103 'id' => ['IN' => $entityIds],
104 'options' => ['limit' => 0],
105 'return' => self::getReturnFields($this->activeTokens),
106 ])['values'];
107
108 // Store the activity types if needed
109 if (in_array('activity_type', $this->activeTokens, TRUE)) {
110 $this->activityTypes = \CRM_Core_OptionGroup::values('activity_type');
111 }
112
113 // Store the activity statuses if needed
114 if (in_array('status', $this->activeTokens, TRUE)) {
115 $this->activityStatuses = \CRM_Core_OptionGroup::values('activity_status');
116 }
117
118 // Store the campaigns if needed
119 if (in_array('campaign', $this->activeTokens, TRUE)) {
120 $this->campaigns = \CRM_Campaign_BAO_Campaign::getCampaigns();
121 }
122
123 return $prefetch;
124 }
125
126 /**
127 * Evaluate the content of a single token.
128 *
129 * @param \Civi\Token\TokenRow $row
130 * The record for which we want token values.
131 * @param string $entity
132 * The name of the token entity.
133 * @param string $field
134 * The name of the token field.
135 * @param mixed $prefetch
136 * Any data that was returned by the prefetch().
137 *
138 * @throws \CRM_Core_Exception
139 */
140 public function evaluateToken(TokenRow $row, $entity, $field, $prefetch = NULL) {
141 // maps token name to api field
142 $mapping = [
143 'activity_id' => 'id',
144 ];
145
146 $activityId = $row->context[$this->getEntityContextSchema()];
147
148 $activity = $prefetch['activity'][$activityId];
149
150 if (in_array($field, ['activity_date_time', 'created_date', 'modified_date'])) {
151 $row->tokens($entity, $field, \CRM_Utils_Date::customFormat($activity[$field]));
152 }
153 elseif (isset($mapping[$field]) and (isset($activity[$mapping[$field]]))) {
154 $row->tokens($entity, $field, $activity[$mapping[$field]]);
155 }
156 elseif (in_array($field, ['activity_type'])) {
157 $row->tokens($entity, $field, $this->activityTypes[$activity['activity_type_id']]);
158 }
159 elseif (in_array($field, ['status'])) {
160 $row->tokens($entity, $field, $this->activityStatuses[$activity['status_id']]);
161 }
162 elseif (in_array($field, ['campaign'])) {
163 $row->tokens($entity, $field, $this->campaigns[$activity['campaign_id']]);
164 }
165 elseif (in_array($field, ['case_id'])) {
166 // An activity can be linked to multiple cases so case_id is always an array.
167 // We just return the first case ID for the token.
168 $row->tokens($entity, $field, is_array($activity['case_id']) ? reset($activity['case_id']) : $activity['case_id']);
169 }
170 elseif (array_key_exists($field, $this->customFieldTokens)) {
171 $row->tokens($entity, $field,
172 isset($activity[$field])
173 ? \CRM_Core_BAO_CustomField::displayValue($activity[$field], $field)
174 : ''
175 );
176 }
177 elseif (isset($activity[$field])) {
178 $row->tokens($entity, $field, $activity[$field]);
179 }
180 }
181
182 /**
183 * Get the basic tokens provided.
184 *
185 * @return array token name => token label
186 */
187 protected function getBasicTokens(): array {
188 if (!isset($this->basicTokens)) {
189 $this->basicTokens = [
190 'activity_id' => ts('Activity ID'),
191 'activity_type' => ts('Activity Type'),
192 'subject' => ts('Activity Subject'),
193 'details' => ts('Activity Details'),
194 'activity_date_time' => ts('Activity Date-Time'),
195 'created_date' => ts('Activity Created Date'),
196 'modified_date' => ts('Activity Modified Date'),
197 'activity_type_id' => ts('Activity Type ID'),
198 'status' => ts('Activity Status'),
199 'status_id' => ts('Activity Status ID'),
200 'location' => ts('Activity Location'),
201 'duration' => ts('Activity Duration'),
202 'campaign' => ts('Activity Campaign'),
203 'campaign_id' => ts('Activity Campaign ID'),
204 ];
205 if (array_key_exists('CiviCase', CRM_Core_Component::getEnabledComponents())) {
206 $this->basicTokens['case_id'] = ts('Activity Case ID');
207 }
208 }
209 return $this->basicTokens;
210 }
211
212 }