X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=CRM%2FCore%2FEntityTokens.php;h=cc9350bb1374a9f9a1021c230b1c2e80d080ac68;hb=c214450e9f356ac1529ec8f3f89702bc1a8d058c;hp=6ded3ebec5ace00d59b497641a2305e6bdb465ef;hpb=ba484caf3447d1d0ac9a43cf15c6dce7a5047881;p=civicrm-core.git diff --git a/CRM/Core/EntityTokens.php b/CRM/Core/EntityTokens.php index 6ded3ebec5..cc9350bb13 100644 --- a/CRM/Core/EntityTokens.php +++ b/CRM/Core/EntityTokens.php @@ -11,6 +11,7 @@ */ use Civi\Token\AbstractTokenSubscriber; +use Civi\Token\Event\TokenValueEvent; use Civi\Token\TokenRow; use Civi\ActionSchedule\Event\MailingQueryEvent; use Civi\Token\TokenProcessor; @@ -39,11 +40,24 @@ class CRM_Core_EntityTokens extends AbstractTokenSubscriber { public function evaluateToken(TokenRow $row, $entity, $field, $prefetch = NULL) { $this->prefetch = (array) $prefetch; $fieldValue = $this->getFieldValue($row, $field); + if (is_array($fieldValue)) { + // eg. role_id for participant would be an array here. + $fieldValue = implode(',', $fieldValue); + } if ($this->isPseudoField($field)) { + if (!empty($fieldValue)) { + // If it's set here it has already been loaded in pre-fetch. + return $row->format('text/plain')->tokens($entity, $field, (string) $fieldValue); + } + // Once prefetch is fully standardised we can remove this - as long + // as tests pass we should be fine as tests cover this. $split = explode(':', $field); return $row->tokens($entity, $field, $this->getPseudoValue($split[0], $split[1], $this->getFieldValue($row, $split[0]))); } + if ($this->isCustomField($field)) { + return $row->customToken($entity, \CRM_Core_BAO_CustomField::getKeyID($field), $this->getFieldValue($row, 'id')); + } if ($this->isMoneyField($field)) { return $row->format('text/plain')->tokens($entity, $field, \CRM_Utils_Money::format($fieldValue, $this->getCurrency($row))); @@ -51,12 +65,7 @@ class CRM_Core_EntityTokens extends AbstractTokenSubscriber { if ($this->isDateField($field)) { return $row->format('text/plain')->tokens($entity, $field, \CRM_Utils_Date::customFormat($fieldValue)); } - if ($this->isCustomField($field)) { - $row->customToken($entity, \CRM_Core_BAO_CustomField::getKeyID($field), $this->getFieldValue($row, 'id')); - } - else { - $row->format('text/plain')->tokens($entity, $field, (string) $fieldValue); - } + $row->format('text/plain')->tokens($entity, $field, (string) $fieldValue); } /** @@ -118,9 +127,33 @@ class CRM_Core_EntityTokens extends AbstractTokenSubscriber { * Get all the tokens supported by this processor. * * @return array|string[] + * @throws \API_Exception + */ + protected function getAllTokens(): array { + $basicTokens = $this->getBasicTokens(); + foreach (array_keys($basicTokens) as $fieldName) { + // The goal is to be able to render more complete tokens + // (eg. actual booleans, field names, raw ids) for a more + // advanced audiences - ie those using conditionals + // and to specify that audience in the api that retrieves. + // But, for now, let's not advertise, given that most of these fields + // aren't really needed even once... + if ($this->isBooleanField($fieldName)) { + unset($basicTokens[$fieldName]); + } + } + return array_merge($basicTokens, $this->getPseudoTokens(), CRM_Utils_Token::getCustomFieldTokens($this->getApiEntityName())); + } + + /** + * Is the given field a boolean field. + * + * @param string $fieldName + * + * @return bool */ - public function getAllTokens(): array { - return array_merge($this->getBasicTokens(), $this->getPseudoTokens(), CRM_Utils_Token::getCustomFieldTokens('Contribution')); + public function isBooleanField(string $fieldName): bool { + return $this->getFieldMetadata()[$fieldName]['data_type'] === 'Boolean'; } /** @@ -131,7 +164,7 @@ class CRM_Core_EntityTokens extends AbstractTokenSubscriber { * @return bool */ public function isDateField(string $fieldName): bool { - return $this->getFieldMetadata()[$fieldName]['data_type'] === 'Timestamp'; + return in_array($this->getFieldMetadata()[$fieldName]['data_type'], ['Timestamp', 'Date'], TRUE); } /** @@ -200,6 +233,9 @@ class CRM_Core_EntityTokens extends AbstractTokenSubscriber { $return[$fieldName . ':label'] = $fieldLabel; $return[$fieldName . ':name'] = ts('Machine name') . ': ' . $fieldLabel; } + if ($this->isBooleanField($fieldName)) { + $return[$fieldName . ':label'] = $this->getFieldMetadata()[$fieldName]['title']; + } } return $return; } @@ -261,6 +297,11 @@ class CRM_Core_EntityTokens extends AbstractTokenSubscriber { * @return string|int */ protected function getFieldValue(TokenRow $row, string $field) { + $entityName = $this->getEntityName(); + if (isset($row->context[$entityName][$field])) { + return $row->context[$entityName][$field]; + } + $actionSearchResult = $row->context['actionSearchResult']; $aliasedField = $this->getEntityAlias() . $field; if (isset($actionSearchResult->{$aliasedField})) { @@ -321,7 +362,12 @@ class CRM_Core_EntityTokens extends AbstractTokenSubscriber { public function getBasicTokens(): array { $return = []; foreach ($this->getExposedFields() as $fieldName) { - $return[$fieldName] = $this->getFieldMetadata()[$fieldName]['title']; + // Custom fields are still added v3 style - we want to keep v4 naming 'unpoluted' + // for now to allow us to consider how to handle names vs labels vs values + // and other raw vs not raw options. + if ($this->getFieldMetadata()[$fieldName]['type'] !== 'Custom') { + $return[$fieldName] = $this->getFieldMetadata()[$fieldName]['title']; + } } return $return; } @@ -348,7 +394,10 @@ class CRM_Core_EntityTokens extends AbstractTokenSubscriber { * @return string[] */ public function getSkippedFields(): array { - $fields = ['contact_id']; + // tags is offered in 'case' & is one of the only fields that is + // 'not a real field' offered up by case - seems like an oddity + // we should skip at the top level for now. + $fields = ['contact_id', 'tags']; if (!CRM_Campaign_BAO_Campaign::isCampaignEnable()) { $fields[] = 'campaign_id'; } @@ -362,11 +411,11 @@ class CRM_Core_EntityTokens extends AbstractTokenSubscriber { return CRM_Core_DAO_AllCoreTables::convertEntityNameToLower($this->getApiEntityName()); } - public function getEntityIDField() { + public function getEntityIDField(): string { return $this->getEntityName() . 'Id'; } - public function prefetch(\Civi\Token\Event\TokenValueEvent $e): ?array { + public function prefetch(TokenValueEvent $e): ?array { $entityIDs = $e->getTokenProcessor()->getContextValues($this->getEntityIDField()); if (empty($entityIDs)) { return []; @@ -399,8 +448,38 @@ class CRM_Core_EntityTokens extends AbstractTokenSubscriber { return CRM_Core_Config::singleton()->defaultCurrency; } - public function getPrefetchFields(\Civi\Token\Event\TokenValueEvent $e): array { - return array_intersect($this->getActiveTokens($e), $this->getCurrencyFieldName(), array_keys($this->getAllTokens())); + /** + * Get the fields required to prefetch the entity. + * + * @param \Civi\Token\Event\TokenValueEvent $e + * + * @return array + * @throws \API_Exception + */ + public function getPrefetchFields(TokenValueEvent $e): array { + $allTokens = array_keys($this->getAllTokens()); + $requiredFields = array_intersect($this->getActiveTokens($e), $allTokens); + if (empty($requiredFields)) { + return []; + } + $requiredFields = array_merge($requiredFields, array_intersect($allTokens, array_merge(['id'], $this->getCurrencyFieldName()))); + foreach ($this->getDependencies() as $field => $required) { + if (in_array($field, $this->getActiveTokens($e), TRUE)) { + foreach ((array) $required as $key) { + $requiredFields[] = $key; + } + } + } + return $requiredFields; + } + + /** + * Get fields which need to be returned to render another token. + * + * @return array + */ + public function getDependencies(): array { + return []; } }