4 +--------------------------------------------------------------------+
5 | Copyright CiviCRM LLC. All rights reserved. |
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 +--------------------------------------------------------------------+
13 use Civi\ActionSchedule\Event\MailingQueryEvent
;
14 use Civi\Token\AbstractTokenSubscriber
;
15 use Civi\Token\TokenProcessor
;
16 use Civi\Token\TokenRow
;
19 * Class CRM_Contribute_Tokens
21 * Generate "contribution.*" tokens.
23 * At time of writing, we don't have any particularly special tokens -- we just
24 * do some basic formatting based on the corresponding DB field.
26 class CRM_Contribute_Tokens
extends AbstractTokenSubscriber
{
31 private function getEntityName(): string {
32 return 'contribution';
36 * Get the relevant bao name.
38 public function getBAOName(): string {
39 return CRM_Core_DAO_AllCoreTables
::getFullName(ucfirst($this->getEntityName()));
43 * Metadata about the entity fields.
47 protected $entityFieldMetadata = [];
50 * Get a list of tokens whose name and title match the DB fields.
53 protected function getPassthruTokens(): array {
55 'contribution_page_id',
63 'contribution_cancel_date',
67 'contribution_status_id',
76 protected function getAliasTokens(): array {
78 'id' => 'contribution_id',
79 'payment_instrument' => 'payment_instrument_id',
80 'source' => 'contribution_source',
81 'status' => 'contribution_status_id',
82 'type' => 'financial_type_id',
83 'cancel_date' => 'contribution_cancel_date',
88 * Get tokens supporting the syntax we are migrating to.
90 * In general these are tokens that were not previously supported
91 * so we can add them in the preferred way or that we have
92 * undertaken some, as yet to be written, db update.
94 * See https://lab.civicrm.org/dev/core/-/issues/2650
98 protected function getBasicTokens(): array {
99 return ['contribution_status_id' => ts('Contribution Status ID')];
103 * Get pseudoTokens - it tokens that reflect the name or label of a pseudoconstant.
105 * @internal - this function will likely be made protected soon.
109 public function getPseudoTokens(): array {
111 foreach (array_keys($this->getBasicTokens()) as $fieldName) {
112 if (!empty($this->entityFieldMetadata
[$fieldName]['pseudoconstant'])) {
113 $return[$fieldName . ':label'] = $this->entityFieldMetadata
[$fieldName]['html']['label'];
114 $return[$fieldName . ':name'] = ts('Machine name') . ': ' . $this->entityFieldMetadata
[$fieldName]['html']['label'];
123 public function __construct() {
124 $this->entityFieldMetadata
= CRM_Contribute_DAO_Contribution
::fields();
125 $tokens = CRM_Utils_Array
::subset(
126 CRM_Utils_Array
::collect('title', $this->entityFieldMetadata
),
127 $this->getPassthruTokens()
129 $tokens['id'] = ts('Contribution ID');
130 $tokens['payment_instrument'] = ts('Payment Instrument');
131 $tokens['source'] = ts('Contribution Source');
132 // Per https://lab.civicrm.org/dev/core/-/issues/2650
133 // the intent is to deprecate this field in favour of
134 // {contribution.contribution_status_id:label}
135 $tokens['status'] = ts('Contribution Status');
136 $tokens['type'] = ts('Financial Type');
137 $tokens = array_merge($tokens, $this->getPseudoTokens(), CRM_Utils_Token
::getCustomFieldTokens('Contribution'));
138 parent
::__construct('contribution', $tokens);
142 * Check if the token processor is active.
144 * @param \Civi\Token\TokenProcessor $processor
148 public function checkActive(TokenProcessor
$processor) {
149 return !empty($processor->context
['actionMapping'])
150 && $processor->context
['actionMapping']->getEntity() === 'civicrm_contribution';
154 * Alter action schedule query.
156 * @param \Civi\ActionSchedule\Event\MailingQueryEvent $e
158 public function alterActionScheduleQuery(MailingQueryEvent
$e): void
{
159 if ($e->mapping
->getEntity() !== 'civicrm_contribution') {
163 $fields = CRM_Contribute_DAO_Contribution
::fields();
164 foreach ($this->getPassthruTokens() as $token) {
165 $e->query
->select("e." . $fields[$token]['name'] . " AS contrib_{$token}");
167 foreach (array_keys($this->getPseudoTokens()) as $token) {
168 $split = explode(':', $token);
169 $e->query
->select("e." . $fields[$split[0]]['name'] . " AS contrib_{$split[0]}");
171 foreach ($this->getAliasTokens() as $alias => $orig) {
172 $e->query
->select('e.' . $fields[$orig]['name'] . " AS contrib_{$alias}");
179 public function evaluateToken(TokenRow
$row, $entity, $field, $prefetch = NULL) {
180 $actionSearchResult = $row->context
['actionSearchResult'];
181 $fieldValue = $actionSearchResult->{"contrib_$field"} ??
NULL;
183 $aliasTokens = $this->getAliasTokens();
184 if (in_array($field, ['total_amount', 'fee_amount', 'net_amount'])) {
185 return $row->format('text/plain')->tokens($entity, $field,
186 \CRM_Utils_Money
::format($fieldValue, $actionSearchResult->contrib_currency
));
188 if (isset($aliasTokens[$field])) {
189 $row->dbToken($entity, $field, 'CRM_Contribute_BAO_Contribution', $aliasTokens[$field], $fieldValue);
191 elseif ($cfID = \CRM_Core_BAO_CustomField
::getKeyID($field)) {
192 $row->customToken($entity, $cfID, $actionSearchResult->entity_id
);
194 elseif (array_key_exists($field, $this->getPseudoTokens())) {
195 $split = explode(':', $field);
196 $row->tokens($entity, $field, $this->getPseudoValue($split[0], $split[1], $actionSearchResult->{"contrib_$split[0]"} ??
NULL));
198 elseif (in_array($field, array_keys($this->getBasicTokens()))) {
199 // For now we just ensure that the label fields do not override the
201 // Later we will add support for contribution_status_id:label
202 $row->tokens($entity, $field, $fieldValue);
205 $row->dbToken($entity, $field, 'CRM_Contribute_BAO_Contribution', $field, $fieldValue);
210 * Get the value for the relevant pseudo field.
212 * @param string $realField e.g contribution_status_id
213 * @param string $pseudoKey e.g name
214 * @param int|string $fieldValue e.g 1
217 * Eg. 'Completed' in the example above.
219 * @internal function will likely be protected soon.
221 public function getPseudoValue(string $realField, string $pseudoKey, $fieldValue): string {
222 if ($pseudoKey === 'name') {
223 $fieldValue = (string) CRM_Core_PseudoConstant
::getName($this->getBAOName(), $realField, $fieldValue);
225 if ($pseudoKey === 'label') {
226 $fieldValue = (string) CRM_Core_PseudoConstant
::getLabel($this->getBAOName(), $realField, $fieldValue);
228 return (string) $fieldValue;