Add in APIv4 Logging Entity
[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\ActionSchedule\Event\MailingQueryEvent;
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 CRM_Core_EntityTokens {
37
38 /**
39 * Get the entity name for api v4 calls.
40 *
41 * @return string
42 */
43 protected function getApiEntityName(): string {
44 return 'Activity';
45 }
46
47 /**
48 * @inheritDoc
49 */
50 public function alterActionScheduleQuery(MailingQueryEvent $e): void {
51 if ($e->mapping->getEntity() !== $this->getExtendableTableName()) {
52 return;
53 }
54
55 // The joint expression for activities needs some extra nuance to handle.
56 // Multiple revisions of the activity.
57 // Q: Could we simplify & move the extra AND clauses into `where(...)`?
58 $e->query->param('casEntityJoinExpr', 'e.id = reminder.entity_id AND e.is_current_revision = 1 AND e.is_deleted = 0');
59 parent::alterActionScheduleQuery($e);
60 }
61
62 /**
63 * Evaluate the content of a single token.
64 *
65 * @param \Civi\Token\TokenRow $row
66 * The record for which we want token values.
67 * @param string $entity
68 * The name of the token entity.
69 * @param string $field
70 * The name of the token field.
71 * @param mixed $prefetch
72 * Any data that was returned by the prefetch().
73 *
74 * @throws \CRM_Core_Exception
75 */
76 public function evaluateToken(TokenRow $row, $entity, $field, $prefetch = NULL) {
77 $activityId = $this->getFieldValue($row, 'id');
78
79 if (!empty($this->getDeprecatedTokens()[$field])) {
80 $realField = $this->getDeprecatedTokens()[$field];
81 parent::evaluateToken($row, $entity, $realField, $prefetch);
82 $row->format('text/plain')->tokens($entity, $field, $row->tokens['activity'][$realField]);
83 }
84 elseif ($field === 'case_id') {
85 // An activity can be linked to multiple cases so case_id is always an array.
86 // We just return the first case ID for the token.
87 // this weird hack might exist because apiv3 is weird &
88 $caseID = CRM_Core_DAO::singleValueQuery('SELECT case_id FROM civicrm_case_activity WHERE activity_id = %1 LIMIT 1', [1 => [$activityId, 'Integer']]);
89 $row->tokens($entity, $field, $caseID ?? '');
90 }
91 else {
92 parent::evaluateToken($row, $entity, $field, $prefetch);
93 }
94 }
95
96 /**
97 * Get tokens that are special or calculated for this enitty.
98 *
99 * @return array|array[]
100 */
101 protected function getBespokeTokens(): array {
102 $tokens = [];
103 if (CRM_Core_Component::isEnabled('CiviCase')) {
104 $tokens['case_id'] = [
105 'title' => ts('Activity Case ID'),
106 'name' => 'case_id',
107 'type' => 'calculated',
108 'options' => NULL,
109 'data_type' => 'Integer',
110 'audience' => 'user',
111 ];
112 }
113 return $tokens;
114 }
115
116 /**
117 * Get fields Fieldshistorically not advertised for tokens.
118 *
119 * @return string[]
120 */
121 protected function getSkippedFields(): array {
122 return array_merge(parent::getSkippedFields(), [
123 'source_record_id',
124 'phone_id',
125 'phone_number',
126 'priority_id',
127 'parent_id',
128 'is_test',
129 'medium_id',
130 'is_auto',
131 'relationship_id',
132 'is_current_revision',
133 'original_id',
134 'result',
135 'is_deleted',
136 'engagement_level',
137 'weight',
138 'is_star',
139 ]);
140 }
141
142 /**
143 * @inheritDoc
144 */
145 public function getActiveTokens(TokenValueEvent $e) {
146 $messageTokens = $e->getTokenProcessor()->getMessageTokens();
147 if (!isset($messageTokens[$this->entity])) {
148 return NULL;
149 }
150
151 $activeTokens = [];
152 foreach ($messageTokens[$this->entity] as $msgToken) {
153 if (array_key_exists($msgToken, $this->getTokenMetadata())) {
154 $activeTokens[] = $msgToken;
155 }
156 // case_id is probably set in metadata anyway.
157 elseif ($msgToken === 'case_id' || isset($this->getDeprecatedTokens()[$msgToken])) {
158 $activeTokens[] = $msgToken;
159 }
160 }
161 return array_unique($activeTokens);
162 }
163
164 public function getPrefetchFields(TokenValueEvent $e): array {
165 $tokens = parent::getPrefetchFields($e);
166 $active = $this->getActiveTokens($e);
167 foreach ($this->getDeprecatedTokens() as $old => $new) {
168 if (in_array($old, $active, TRUE) && !in_array($new, $active, TRUE)) {
169 $tokens[] = $new;
170 }
171 }
172 return $tokens;
173 }
174
175 /**
176 * These tokens still work but we don't advertise them.
177 *
178 * We will actively remove from the following places
179 * - scheduled reminders
180 * - add to 'blocked' on pdf letter & email
181 *
182 * & then at some point start issuing warnings for them.
183 *
184 * @return string[]
185 */
186 protected function getDeprecatedTokens(): array {
187 return [
188 'activity_id' => 'id',
189 'activity_type' => 'activity_type_id:label',
190 'status' => 'status_id:label',
191 'campaign' => 'campaign_id:label',
192 ];
193 }
194
195 }