Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dev/core#2747 - Reconcile fields. Consolidate/simplify loading of APIv4-style tokens. #21079

Closed
wants to merge 11 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 5 additions & 11 deletions CRM/Campaign/BAO/Campaign.php
Original file line number Diff line number Diff line change
Expand Up @@ -301,20 +301,14 @@ public static function getPermissionedCampaigns(

/**
* Is CiviCampaign enabled.
*
* @return bool
*/
public static function isCampaignEnable() {
static $isEnable = NULL;

if (!isset($isEnable)) {
$isEnable = FALSE;
$config = CRM_Core_Config::singleton();
if (in_array('CiviCampaign', $config->enableComponents)) {
$isEnable = TRUE;
}
public static function isCampaignEnable(): bool {
if (!isset(Civi::$statics[__CLASS__]['is_enabled'])) {
Civi::$statics[__CLASS__]['is_enabled'] = in_array('CiviCampaign', CRM_Core_Config::singleton()->enableComponents, TRUE);
}

return $isEnable;
return Civi::$statics[__CLASS__]['is_enabled'];
}

/**
Expand Down
6 changes: 1 addition & 5 deletions CRM/Contribute/BAO/Contribution.php
Original file line number Diff line number Diff line change
Expand Up @@ -5167,11 +5167,7 @@ public static function getContributionTokenValues($id, $messageToken) {
}
if (!empty($messageToken['contribution'])) {
$processor = new CRM_Contribute_Tokens();
$pseudoFields = array_keys($processor->getPseudoTokens());
foreach ($pseudoFields as $pseudoField) {
$split = explode(':', $pseudoField);
$result['values'][$id][$pseudoField] = $processor->getPseudoValue($split[0], $split[1], $result['values'][$id][$split[0]] ?? '');
}
$result['values'][$id] = array_merge($result['values'][$id], $processor->getPseudoValues($id));
}
return $result;
}
Expand Down
76 changes: 50 additions & 26 deletions CRM/Contribute/Tokens.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,6 @@ protected function getEntityName(): string {
return 'contribution';
}

/**
* @return string
*/
protected function getEntityAlias(): string {
return 'contrib_';
Copy link
Contributor

@eileenmcnaughton eileenmcnaughton Aug 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK - if changing this is definitely ok for scheduled reminders

}

/**
* Get the entity name for api v4 calls.
*
Expand All @@ -47,16 +40,17 @@ protected function getApiEntityName(): string {
}

/**
* Get a list of tokens for the entity for which access is permitted to.
* Get a list of tokens which are loaded via APIv4.
*
* This list is historical and we need to question whether we
* should filter out any fields (other than those fields, like api_key
* on the contact entity) with permissions defined.
*
* @return array
* Ex: ['foo', 'bar_id', 'bar_id:name', 'bar_id:label']
*/
protected function getExposedFields(): array {
return [
protected function getApiTokens(): array {
Copy link
Contributor

@eileenmcnaughton eileenmcnaughton Aug 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So once we resolve https://lab.civicrm.org/dev/core/-/issues/2745 my expectation is we would entirely remove this function in favour of a metadata-driven function on the parent class - because there is nothing (yet) in this token class that should not be purely metadata driven

At some point in the future we probably will need to add some calculated fields (paid_amount, balance_amount) but that is out of scope

$fields = [
'contribution_page_id',
'source',
'id',
Expand All @@ -73,28 +67,58 @@ protected function getExposedFields(): array {
'thankyou_date',
'tax_amount',
'contribution_status_id',
'contribution_status_id:name',
'contribution_status_id:label',
'financial_type_id',
'financial_type_id:name',
'financial_type_id:label',
'payment_instrument_id',
'payment_instrument_id:name',
'payment_instrument_id:label',
'cancel_reason',
'amount_level',
'check_number',
];
if (CRM_Campaign_BAO_Campaign::isCampaignEnable()) {
$fields[] = 'campaign_id';
$fields[] = 'campaign_id.name';
$fields[] = 'campaign_id.title';
}

return $fields;
}

/**
* Get tokens supporting the syntax we are migrating to.
*
* In general these are tokens that were not previously supported
* so we can add them in the preferred way or that we have
* undertaken some, as yet to be written, db update.
*
* See https://lab.civicrm.org/dev/core/-/issues/2650
*
* @return string[]
*/
public function getBasicTokens(): array {
$return = [];
foreach ($this->getExposedFields() as $fieldName) {
$return[$fieldName] = $this->getFieldMetadata()[$fieldName]['title'];
public function getAliasTokens(): array {
Copy link
Contributor

@eileenmcnaughton eileenmcnaughton Aug 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think at some point we will need a getDeprecatedTokens function - but we don't want to add already-deprecated tokens - we should agree what the syntax is we are adding and standardise on it

ie I think we have 'advertised tokens' and 'deprecatedTokens' but we shouldn't need 'aliasTokens' - that's apiv3 all over again.

$aliases = [];
if (CRM_Campaign_BAO_Campaign::isCampaignEnable()) {
// Unit-tests are written to use these funny tokens - but they're not valid in APIv4.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the unit tests from one of the 2 PRs used them..... the other one used campaign_id.name - we just need to agree which syntax it is

$aliases['campaign'] = 'campaign_id.name';
$aliases['campaign_id:name'] = 'campaign_id.name';
$aliases['campaign_id:label'] = 'campaign_id.title';
}
return $aliases;
}

public function getPrefetchFields(\Civi\Token\Event\TokenValueEvent $e): array {
$result = parent::getPrefetchFields($e);

// Always prefetch 'civicrm_contribution.currency' in case we need to format other fields (fee_amount, total_amount, etc).
$result[] = 'currency';

return array_unique($result);
}

public function evaluateToken(\Civi\Token\TokenRow $row, $entity, $field, $prefetch = NULL) {
$values = $prefetch[$row->context[$this->getEntityIDField()]];

// Any monetary fields in a `Contribution` (`fee_amount`, `total_amount`, etc) should be formatted in matching `currency`.
// This formatting rule would be nonsensical in any other entity.
if ($this->isApiFieldType($field, 'Money')) {
return $row->format('text/plain')->tokens($entity, $field,
\CRM_Utils_Money::format($values[$field], $values['currency']));
}
return $return;

return parent::evaluateToken($row, $entity, $field, $prefetch);
}

}
59 changes: 32 additions & 27 deletions CRM/Core/BAO/ActionSchedule.php
Original file line number Diff line number Diff line change
Expand Up @@ -267,38 +267,44 @@ public static function sendMailings($mappingID, $now) {
);

$multilingual = CRM_Core_I18n::isMultilingual();
$tokenProcessor = self::createTokenProcessor($actionSchedule, $mapping);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If these changes all work - I'm all for them :-)

while ($dao->fetch()) {
$row = $tokenProcessor->addRow()
->context('contactId', $dao->contactID)
->context('actionSearchResult', (object) $dao->toArray());

// switch language if necessary
if ($multilingual) {
$preferred_language = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $dao->contactID, 'preferred_language');
CRM_Core_BAO_ActionSchedule::setCommunicationLanguage($actionSchedule->communication_language, $preferred_language);
$row->context('locale', CRM_Core_BAO_ActionSchedule::pickLocale($actionSchedule->communication_language, $preferred_language));
}

$errors = [];
try {
$tokenProcessor = self::createTokenProcessor($actionSchedule, $mapping);
$tokenProcessor->addRow()
->context('contactId', $dao->contactID)
->context('actionSearchResult', (object) $dao->toArray());
foreach ($tokenProcessor->evaluate()->getRows() as $tokenRow) {
if ($actionSchedule->mode === 'SMS' || $actionSchedule->mode === 'User_Preference') {
CRM_Utils_Array::extend($errors, self::sendReminderSms($tokenRow, $actionSchedule, $dao->contactID));
}

if ($actionSchedule->mode === 'Email' || $actionSchedule->mode === 'User_Preference') {
CRM_Utils_Array::extend($errors, self::sendReminderEmail($tokenRow, $actionSchedule, $dao->contactID));
}
// insert activity log record if needed
if ($actionSchedule->record_activity && empty($errors)) {
$caseID = empty($dao->case_id) ? NULL : $dao->case_id;
CRM_Core_BAO_ActionSchedule::createMailingActivity($tokenRow, $mapping, $dao->contactID, $dao->entityID, $caseID);
foreach ($dao->toArray() as $key => $value) {
if (preg_match('/^tokenContext_(.*)/', $key, $m)) {
if (!in_array($m[1], $tokenProcessor->context['schema'])) {
$tokenProcessor->context['schema'][] = $m[1];
}
$row->context($m[1], $value);
}
}
catch (\Civi\Token\TokenException $e) {
$errors['token_exception'] = $e->getMessage();
}

$tokenProcessor->evaluate();
foreach ($tokenProcessor->getRows() as $tokenRow) {
$dao = $tokenRow->context['actionSearchResult'];
$errors = [];
if ($actionSchedule->mode === 'SMS' || $actionSchedule->mode === 'User_Preference') {
CRM_Utils_Array::extend($errors, self::sendReminderSms($tokenRow, $actionSchedule, $dao->contactID));
}

if ($actionSchedule->mode === 'Email' || $actionSchedule->mode === 'User_Preference') {
CRM_Utils_Array::extend($errors, self::sendReminderEmail($tokenRow, $actionSchedule, $dao->contactID));
}
// insert activity log record if needed
if ($actionSchedule->record_activity && empty($errors)) {
$caseID = empty($dao->case_id) ? NULL : $dao->case_id;
CRM_Core_BAO_ActionSchedule::createMailingActivity($tokenRow, $mapping, $dao->contactID, $dao->entityID, $caseID);
}
// update action log record
$logParams = [
'id' => $dao->reminderID,
Expand All @@ -308,7 +314,6 @@ public static function sendMailings($mappingID, $now) {
];
CRM_Core_BAO_ActionLog::create($logParams);
}

}
}

Expand Down Expand Up @@ -401,10 +406,11 @@ public static function getRecipientListing($mappingID, $recipientType) {
}

/**
* @param $communication_language
* @param $preferred_language
* @param string|null $communication_language
* @param string|null $preferred_language
* @return string
*/
public static function setCommunicationLanguage($communication_language, $preferred_language) {
public static function pickLocale($communication_language, $preferred_language) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool

$currentLocale = CRM_Core_I18n::getLocale();
$language = $currentLocale;

Expand All @@ -425,8 +431,7 @@ public static function setCommunicationLanguage($communication_language, $prefer
}

// change the language
$i18n = CRM_Core_I18n::singleton();
$i18n->setLocale($language);
return $language;
}

/**
Expand Down
Loading