From 4b21d3176873009151736a62ef5c04886bde4381 Mon Sep 17 00:00:00 2001 From: colemanw Date: Mon, 17 Jul 2023 20:27:51 -0400 Subject: [PATCH] ActionMapping - Improve class structure Completes the refactoring that began with https://github.com/civicrm/civicrm-core/pull/6687 Fully migrates from the old model based on the civicrm_action_mapping table (dropped in https://github.com/civicrm/civicrm-core/pull/26646) by removing all references to that structure and fully embracing the object-model. New common base-class added to make it eaiser to implement MappingInterface. --- CRM/Activity/ActionMapping.php | 71 ++-- CRM/Contact/ActionMapping.php | 79 ++-- CRM/Contribute/ActionMapping.php | 51 +++ CRM/Contribute/ActionMapping/ByPage.php | 143 +------ CRM/Contribute/ActionMapping/ByType.php | 119 +----- CRM/Event/ActionMapping.php | 74 ++-- CRM/Event/ActionMapping/ByEvent.php | 30 ++ CRM/Event/ActionMapping/ByTemplate.php | 35 ++ CRM/Event/ActionMapping/ByType.php | 30 ++ CRM/Member/ActionMapping.php | 68 ++-- Civi/ActionSchedule/Mapping.php | 356 ------------------ Civi/ActionSchedule/MappingBase.php | 79 ++++ Civi/ActionSchedule/MappingInterface.php | 31 +- Civi/Core/Container.php | 4 +- .../Contribute/ActionMapping/ByTypeTest.php | 8 +- 15 files changed, 402 insertions(+), 776 deletions(-) create mode 100644 CRM/Contribute/ActionMapping.php create mode 100644 CRM/Event/ActionMapping/ByEvent.php create mode 100644 CRM/Event/ActionMapping/ByTemplate.php create mode 100644 CRM/Event/ActionMapping/ByType.php delete mode 100644 Civi/ActionSchedule/Mapping.php create mode 100644 Civi/ActionSchedule/MappingBase.php diff --git a/CRM/Activity/ActionMapping.php b/CRM/Activity/ActionMapping.php index 5618a2eb15..91f46b5bb5 100644 --- a/CRM/Activity/ActionMapping.php +++ b/CRM/Activity/ActionMapping.php @@ -16,38 +16,49 @@ /** - * Class CRM_Activity_ActionMapping - * * This defines the scheduled-reminder functionality for Activities. * It is useful for, e.g., sending a reminder based on scheduled * date or other custom dates on the activity record. */ -class CRM_Activity_ActionMapping extends \Civi\ActionSchedule\Mapping { +class CRM_Activity_ActionMapping extends \Civi\ActionSchedule\MappingBase { /** - * The value for civicrm_action_schedule.mapping_id which identifies the - * "Activity" mapping. - * - * Note: This value is chosen to match legacy DB IDs. + * Note: This value is an integer for legacy reasons; but going forward any new + * action mapping classes should return a string from `getId` instead of using a constant. */ const ACTIVITY_MAPPING_ID = 1; - /** - * Register Activity-related action mappings. - * - * @param \Civi\ActionSchedule\Event\MappingRegisterEvent $registrations - */ - public static function onRegisterActionMappings(\Civi\ActionSchedule\Event\MappingRegisterEvent $registrations) { - $registrations->register(CRM_Activity_ActionMapping::create([ - 'id' => CRM_Activity_ActionMapping::ACTIVITY_MAPPING_ID, - 'entity' => 'civicrm_activity', - 'entity_label' => ts('Activity'), - 'entity_value' => 'activity_type', - 'entity_value_label' => ts('Activity Type'), - 'entity_status' => 'activity_status', - 'entity_status_label' => ts('Activity Status'), - 'entity_date_start' => 'activity_date_time', - ])); + public function getId() { + return self::ACTIVITY_MAPPING_ID; + } + + public function getEntityName(): string { + return 'Activity'; + } + + public function getValueHeader(): string { + return ts('Activity Type'); + } + + public function getValueLabels(): array { + // CRM-20510: Include CiviCampaign activity types along with CiviCase IF component is enabled + $activityTypes = \CRM_Core_PseudoConstant::activityType(TRUE, TRUE, FALSE, 'label', TRUE); + asort($activityTypes); + return $activityTypes; + } + + public function getStatusHeader(): string { + return ts('Activity Status'); + } + + public function getStatusLabels($value): array { + return CRM_Core_PseudoConstant::activityStatus(); + } + + public function getDateFields(): array { + return [ + 'activity_date_time' => ts('Activity Date'), + ]; } /** @@ -60,7 +71,7 @@ class CRM_Activity_ActionMapping extends \Civi\ActionSchedule\Mapping { * array(string $value => string $label). * Ex: array('assignee' => 'Activity Assignee'). */ - public function getRecipientTypes() { + public function getRecipientTypes(): array { return \CRM_Core_OptionGroup::values('activity_contacts'); } @@ -78,11 +89,11 @@ class CRM_Activity_ActionMapping extends \Civi\ActionSchedule\Mapping { * @return \CRM_Utils_SQL_Select * @see RecipientBuilder */ - public function createQuery($schedule, $phase, $defaultParams) { + public function createQuery($schedule, $phase, $defaultParams): CRM_Utils_SQL_Select { $selectedValues = (array) \CRM_Utils_Array::explodePadded($schedule->entity_value); $selectedStatuses = (array) \CRM_Utils_Array::explodePadded($schedule->entity_status); - $query = \CRM_Utils_SQL_Select::from("{$this->entity} e")->param($defaultParams); + $query = \CRM_Utils_SQL_Select::from("{$this->getEntityTable()} e")->param($defaultParams); $query['casAddlCheckFrom'] = 'civicrm_activity e'; $query['casContactIdField'] = 'r.contact_id'; $query['casEntityIdField'] = 'e.id'; @@ -117,12 +128,4 @@ class CRM_Activity_ActionMapping extends \Civi\ActionSchedule\Mapping { return $query; } - /** - * Determine whether a schedule based on this mapping should - * send to additional contacts. - */ - public function sendToAdditional($entityId): bool { - return TRUE; - } - } diff --git a/CRM/Contact/ActionMapping.php b/CRM/Contact/ActionMapping.php index ea96b5da78..281da12a2f 100644 --- a/CRM/Contact/ActionMapping.php +++ b/CRM/Contact/ActionMapping.php @@ -11,39 +11,58 @@ /** - * Class CRM_Contact_ActionMapping - * * This defines the scheduled-reminder functionality for contact * entities. It is useful for, e.g., sending a reminder based on * birth date, modification date, or other custom dates on * the contact record. */ -class CRM_Contact_ActionMapping extends \Civi\ActionSchedule\Mapping { +class CRM_Contact_ActionMapping extends \Civi\ActionSchedule\MappingBase { /** - * The value for civicrm_action_schedule.mapping_id which identifies the - * "Contact" mapping. - * - * Note: This value is chosen to match legacy DB IDs. + * Note: This value is an integer for legacy reasons; but going forward any new + * action mapping classes should return a string from `getId` instead of using a constant. */ const CONTACT_MAPPING_ID = 6; - /** - * Register Contact-related action mappings. - * - * @param \Civi\ActionSchedule\Event\MappingRegisterEvent $registrations - */ - public static function onRegisterActionMappings(\Civi\ActionSchedule\Event\MappingRegisterEvent $registrations) { - $registrations->register(CRM_Contact_ActionMapping::create([ - 'id' => CRM_Contact_ActionMapping::CONTACT_MAPPING_ID, - 'entity' => 'civicrm_contact', - 'entity_label' => ts('Contact'), - 'entity_value' => 'civicrm_contact', - 'entity_value_label' => ts('Date Field'), - 'entity_status' => 'contact_date_reminder_options', - 'entity_status_label' => ts('Annual Options'), - 'entity_date_start' => 'date_field', - ])); + public function getId() { + return self::CONTACT_MAPPING_ID; + } + + public function getEntityName(): string { + return 'Contact'; + } + + public function getValueHeader(): string { + return ts('Date Field'); + } + + public function getValueLabels(): array { + $allCustomFields = \CRM_Core_BAO_CustomField::getFields(''); + $dateFields = [ + 'birth_date' => ts('Birth Date'), + 'created_date' => ts('Created Date'), + 'modified_date' => ts('Modified Date'), + ]; + foreach ($allCustomFields as $fieldID => $field) { + if ($field['data_type'] == 'Date') { + $dateFields["custom_$fieldID"] = $field['label']; + } + } + return $dateFields; + } + + public function getStatusHeader(): string { + return ts('Annual Options'); + } + + public function getStatusLabels($value): array { + return CRM_Core_OptionGroup::values('contact_date_reminder_options'); + } + + public function getDateFields(): array { + return [ + 'date_field' => ts('Date Field'), + ]; } private $contactDateFields = [ @@ -61,7 +80,7 @@ class CRM_Contact_ActionMapping extends \Civi\ActionSchedule\Mapping { * Array (string $code => string $message). * List of error messages. */ - public function validateSchedule($schedule) { + public function validateSchedule($schedule): array { $errors = []; if (CRM_Utils_System::isNull($schedule->entity_value) || $schedule->entity_value === '0') { $errors['entity'] = ts('Please select a specific date field.'); @@ -90,7 +109,7 @@ class CRM_Contact_ActionMapping extends \Civi\ActionSchedule\Mapping { * @throws \CRM_Core_Exception * @see RecipientBuilder */ - public function createQuery($schedule, $phase, $defaultParams) { + public function createQuery($schedule, $phase, $defaultParams): CRM_Utils_SQL_Select { $selectedValues = (array) \CRM_Utils_Array::explodePadded($schedule->entity_value); $selectedStatuses = (array) \CRM_Utils_Array::explodePadded($schedule->entity_status); @@ -101,7 +120,7 @@ class CRM_Contact_ActionMapping extends \Civi\ActionSchedule\Mapping { } elseif (in_array($selectedValues[0], $this->contactDateFields)) { $dateDBField = $selectedValues[0]; - $query = \CRM_Utils_SQL_Select::from("{$this->entity} e")->param($defaultParams); + $query = \CRM_Utils_SQL_Select::from("{$this->getEntityTable()} e")->param($defaultParams); $query->param([ 'casAddlCheckFrom' => 'civicrm_contact e', 'casContactIdField' => 'e.id', @@ -139,12 +158,4 @@ class CRM_Contact_ActionMapping extends \Civi\ActionSchedule\Mapping { return $query; } - /** - * Determine whether a schedule based on this mapping should - * send to additional contacts. - */ - public function sendToAdditional($entityId): bool { - return TRUE; - } - } diff --git a/CRM/Contribute/ActionMapping.php b/CRM/Contribute/ActionMapping.php new file mode 100644 index 0000000000..ed5aaaa631 --- /dev/null +++ b/CRM/Contribute/ActionMapping.php @@ -0,0 +1,51 @@ + ts('Receive Date'), + 'cancel_date' => ts('Cancel Date'), + 'receipt_date' => ts('Receipt Date'), + 'thankyou_date' => ts('Thank You Date'), + ]; + } + +} diff --git a/CRM/Contribute/ActionMapping/ByPage.php b/CRM/Contribute/ActionMapping/ByPage.php index b975b8098d..f332d6f1e9 100644 --- a/CRM/Contribute/ActionMapping/ByPage.php +++ b/CRM/Contribute/ActionMapping/ByPage.php @@ -18,39 +18,13 @@ * - The receipt-date, cancel-date, or thankyou-date. * - The page on which the contribution was made. */ -class CRM_Contribute_ActionMapping_ByPage implements \Civi\ActionSchedule\MappingInterface { - - /** - * The value for civicrm_action_schedule.mapping_id which identifies the - * "Contribution Page" mapping. - */ - const MAPPING_ID = 'contribpage'; - - /** - * Register Activity-related action mappings. - * - * @param \Civi\ActionSchedule\Event\MappingRegisterEvent $registrations - */ - public static function onRegisterActionMappings(\Civi\ActionSchedule\Event\MappingRegisterEvent $registrations) { - $registrations->register(new static()); - } - - /** - * @return mixed - */ - public function getId() { - return self::MAPPING_ID; - } +class CRM_Contribute_ActionMapping_ByPage extends CRM_Contribute_ActionMapping { /** * @return string */ - public function getEntityTable(): string { - return 'civicrm_contribution'; - } - - public function getEntityName(): string { - return 'Contribution'; + public function getId() { + return 'contribpage'; } /** @@ -58,7 +32,7 @@ class CRM_Contribute_ActionMapping_ByPage implements \Civi\ActionSchedule\Mappin * * @return string */ - public function getLabel() { + public function getLabel(): string { return ts('Contribution Page'); } @@ -67,19 +41,10 @@ class CRM_Contribute_ActionMapping_ByPage implements \Civi\ActionSchedule\Mappin * * @return string */ - public function getValueHeader() { + public function getValueHeader(): string { return ts('Contribution Page'); } - /** - * Get a printable label to use as the header on the 'status' filter. - * - * @return string - */ - public function getStatusHeader() { - return ts('Contribution Status'); - } - /** * Get a list of value options. * @@ -88,84 +53,10 @@ class CRM_Contribute_ActionMapping_ByPage implements \Civi\ActionSchedule\Mappin * Ex: array(123 => 'Phone Call', 456 => 'Meeting'). * @throws CRM_Core_Exception */ - public function getValueLabels() { + public function getValueLabels(): array { return CRM_Contribute_BAO_Contribution::buildOptions('contribution_page_id', 'get', []); } - /** - * Get a list of status options. - * - * @param string|int $value - * The list of status options may be contingent upon the selected filter value. - * This is the selected filter value. - * @return array - * Array(string $value => string $label). - * Ex: Array(123 => 'Completed', 456 => 'Scheduled'). - * @throws CRM_Core_Exception - */ - public function getStatusLabels($value) { - return CRM_Contribute_BAO_Contribution::buildOptions('contribution_status_id', 'get', []); - } - - /** - * Get a list of available date fields. - * - * @return array - * Array(string $fieldName => string $fieldLabel). - */ - public function getDateFields() { - return [ - 'receive_date' => ts('Receive Date'), - 'cancel_date' => ts('Cancel Date'), - 'receipt_date' => ts('Receipt Date'), - 'thankyou_date' => ts('Thank You Date'), - ]; - } - - /** - * Get a list of recipient types. - * - * Note: A single schedule may filter on *zero* or *one* recipient types. - * When an admin chooses a value, it's stored in $schedule->recipient. - * - * @return array - * array(string $value => string $label). - * Ex: array('assignee' => 'Activity Assignee'). - */ - public function getRecipientTypes() { - return []; - } - - /** - * Get a list of recipients which match the given type. - * - * Note: A single schedule may filter on *multiple* recipients. - * When an admin chooses value(s), it's stored in $schedule->recipient_listing. - * - * @param string $recipientType - * Ex: 'participant_role'. - * @return array - * Array(mixed $name => string $label). - * Ex: array(1 => 'Attendee', 2 => 'Volunteer'). - * @see getRecipientTypes - */ - public function getRecipientListing($recipientType) { - return []; - } - - /** - * Determine whether a schedule based on this mapping is sufficiently - * complete. - * - * @param \CRM_Core_DAO_ActionSchedule $schedule - * @return array - * Array (string $code => string $message). - * List of error messages. - */ - public function validateSchedule($schedule) { - return []; - } - /** * Generate a query to locate contacts who match the given * schedule. @@ -179,7 +70,7 @@ class CRM_Contribute_ActionMapping_ByPage implements \Civi\ActionSchedule\Mappin * @see RecipientBuilder * @throws CRM_Core_Exception */ - public function createQuery($schedule, $phase, $defaultParams) { + public function createQuery($schedule, $phase, $defaultParams): CRM_Utils_SQL_Select { $selectedValues = (array) \CRM_Utils_Array::explodePadded($schedule->entity_value); $selectedStatuses = (array) \CRM_Utils_Array::explodePadded($schedule->entity_status); @@ -208,24 +99,4 @@ class CRM_Contribute_ActionMapping_ByPage implements \Civi\ActionSchedule\Mappin return $query; } - /** - * Determine whether a schedule based on this mapping should - * reset the reminder state if the trigger date changes. - * - * @return bool - * - * @param \CRM_Core_DAO_ActionSchedule $schedule - */ - public function resetOnTriggerDateChange($schedule) { - return FALSE; - } - - /** - * Determine whether a schedule based on this mapping should - * send to additional contacts. - */ - public function sendToAdditional($entityId): bool { - return TRUE; - } - } diff --git a/CRM/Contribute/ActionMapping/ByType.php b/CRM/Contribute/ActionMapping/ByType.php index 688f8c753a..27f0c48184 100644 --- a/CRM/Contribute/ActionMapping/ByType.php +++ b/CRM/Contribute/ActionMapping/ByType.php @@ -18,42 +18,13 @@ * - The receipt-date, cancel-date, or thankyou-date. * - The type of contribution. */ -class CRM_Contribute_ActionMapping_ByType implements \Civi\ActionSchedule\MappingInterface { - - /** - * The value for civicrm_action_schedule.mapping_id which identifies the - * "Contribution Page" mapping. - */ - const MAPPING_ID = 'contribtype'; - - /** - * Register Activity-related action mappings. - * - * @param \Civi\ActionSchedule\Event\MappingRegisterEvent $registrations - */ - public static function onRegisterActionMappings(\Civi\ActionSchedule\Event\MappingRegisterEvent $registrations) { - $registrations->register(new static()); - } - - /** - * @return mixed - */ - public function getId() { - return self::MAPPING_ID; - } - - /** - * @return string - */ - public function getEntityTable(): string { - return 'civicrm_contribution'; - } +class CRM_Contribute_ActionMapping_ByType extends CRM_Contribute_ActionMapping { /** * @return string */ - public function getEntityName(): string { - return 'Contribution'; + public function getId() { + return 'contribtype'; } /** @@ -61,7 +32,7 @@ class CRM_Contribute_ActionMapping_ByType implements \Civi\ActionSchedule\Mappin * * @return string */ - public function getLabel() { + public function getLabel(): string { return ts('Contribution Type'); } @@ -70,19 +41,10 @@ class CRM_Contribute_ActionMapping_ByType implements \Civi\ActionSchedule\Mappin * * @return string */ - public function getValueHeader() { + public function getValueHeader(): string { return ts('Financial Type'); } - /** - * Get a printable label to use as the header on the 'status' filter. - * - * @return string - */ - public function getStatusHeader() { - return ts('Contribution Status'); - } - /** * Get a list of value options. * @@ -91,40 +53,10 @@ class CRM_Contribute_ActionMapping_ByType implements \Civi\ActionSchedule\Mappin * Ex: array(123 => 'Phone Call', 456 => 'Meeting'). * @throws CRM_Core_Exception */ - public function getValueLabels() { + public function getValueLabels(): array { return CRM_Contribute_BAO_Contribution::buildOptions('financial_type_id', 'get', []); } - /** - * Get a list of status options. - * - * @param string|int $value - * The list of status options may be contingent upon the selected filter value. - * This is the selected filter value. - * @return array - * Array(string $value => string $label). - * Ex: Array(123 => 'Completed', 456 => 'Scheduled'). - * @throws CRM_Core_Exception - */ - public function getStatusLabels($value) { - return CRM_Contribute_BAO_Contribution::buildOptions('contribution_status_id', 'get', []); - } - - /** - * Get a list of available date fields. - * - * @return array - * Array(string $fieldName => string $fieldLabel). - */ - public function getDateFields() { - return [ - 'receive_date' => ts('Receive Date'), - 'cancel_date' => ts('Cancel Date'), - 'receipt_date' => ts('Receipt Date'), - 'thankyou_date' => ts('Thank You Date'), - ]; - } - /** * Get a list of recipient types. * @@ -135,7 +67,7 @@ class CRM_Contribute_ActionMapping_ByType implements \Civi\ActionSchedule\Mappin * array(string $value => string $label). * Ex: array('assignee' => 'Activity Assignee'). */ - public function getRecipientTypes() { + public function getRecipientTypes(): array { return [ 'soft_credit_type' => ts('Soft Credit Role'), ]; @@ -154,7 +86,7 @@ class CRM_Contribute_ActionMapping_ByType implements \Civi\ActionSchedule\Mappin * Ex: array(1 => 'Attendee', 2 => 'Volunteer'). * @see getRecipientTypes */ - public function getRecipientListing($recipientType) { + public function getRecipientListing($recipientType): array { switch ($recipientType) { case 'soft_credit_type': return \CRM_Core_OptionGroup::values('soft_credit_type', FALSE, FALSE, FALSE, NULL, 'label', TRUE, FALSE, 'name'); @@ -164,19 +96,6 @@ class CRM_Contribute_ActionMapping_ByType implements \Civi\ActionSchedule\Mappin } } - /** - * Determine whether a schedule based on this mapping is sufficiently - * complete. - * - * @param \CRM_Core_DAO_ActionSchedule $schedule - * @return array - * Array (string $code => string $message). - * List of error messages. - */ - public function validateSchedule($schedule) { - return []; - } - /** * Generate a query to locate contacts who match the given * schedule. @@ -190,7 +109,7 @@ class CRM_Contribute_ActionMapping_ByType implements \Civi\ActionSchedule\Mappin * @see RecipientBuilder * @throws CRM_Core_Exception */ - public function createQuery($schedule, $phase, $defaultParams) { + public function createQuery($schedule, $phase, $defaultParams): CRM_Utils_SQL_Select { $selectedValues = (array) \CRM_Utils_Array::explodePadded($schedule->entity_value); $selectedStatuses = (array) \CRM_Utils_Array::explodePadded($schedule->entity_status); @@ -230,24 +149,4 @@ class CRM_Contribute_ActionMapping_ByType implements \Civi\ActionSchedule\Mappin return $query; } - /** - * Determine whether a schedule based on this mapping should - * reset the reminder state if the trigger date changes. - * - * @return bool - * - * @param \CRM_Core_DAO_ActionSchedule $schedule - */ - public function resetOnTriggerDateChange($schedule) { - return FALSE; - } - - /** - * Determine whether a schedule based on this mapping should - * send to additional contacts. - */ - public function sendToAdditional($entityId): bool { - return TRUE; - } - } diff --git a/CRM/Event/ActionMapping.php b/CRM/Event/ActionMapping.php index c474a8dba6..1aa9057f69 100644 --- a/CRM/Event/ActionMapping.php +++ b/CRM/Event/ActionMapping.php @@ -12,58 +12,28 @@ use Civi\ActionSchedule\RecipientBuilder; /** - * Class CRM_Event_ActionMapping - * - * This defines the scheduled-reminder functionality for CiviEvent - * participants. It allows one to target messages on the - * event's start-date/end-date, with additional filtering by - * event-type, event-template, or event-id. + * Shared scheduled-reminder functionality for CiviEvent participants. */ -class CRM_Event_ActionMapping extends \Civi\ActionSchedule\Mapping { +abstract class CRM_Event_ActionMapping extends \Civi\ActionSchedule\MappingBase { /** - * The value for civicrm_action_schedule.mapping_id which identifies the - * "Event Type" mapping. - * - * Note: This value is chosen to match legacy DB IDs. + * Note: These values are integers for legacy reasons; but going forward any new + * action mapping classes should return a string from `getId` instead of using a constant. */ const EVENT_TYPE_MAPPING_ID = 2; const EVENT_NAME_MAPPING_ID = 3; const EVENT_TPL_MAPPING_ID = 5; - /** - * Register CiviEvent-related action mappings. - * - * @param \Civi\ActionSchedule\Event\MappingRegisterEvent $registrations - */ - public static function onRegisterActionMappings(\Civi\ActionSchedule\Event\MappingRegisterEvent $registrations) { - $registrations->register(CRM_Event_ActionMapping::create([ - 'id' => CRM_Event_ActionMapping::EVENT_TYPE_MAPPING_ID, - 'entity' => 'civicrm_participant', - 'entity_label' => ts('Event Type'), - 'entity_value' => 'event_type', - 'entity_value_label' => ts('Event Type'), - 'entity_status' => 'civicrm_participant_status_type', - 'entity_status_label' => ts('Participant Status'), - ])); - $registrations->register(CRM_Event_ActionMapping::create([ - 'id' => CRM_Event_ActionMapping::EVENT_NAME_MAPPING_ID, - 'entity' => 'civicrm_participant', - 'entity_label' => ts('Event Name'), - 'entity_value' => 'civicrm_event', - 'entity_value_label' => ts('Event Name'), - 'entity_status' => 'civicrm_participant_status_type', - 'entity_status_label' => ts('Participant Status'), - ])); - $registrations->register(CRM_Event_ActionMapping::create([ - 'id' => CRM_Event_ActionMapping::EVENT_TPL_MAPPING_ID, - 'entity' => 'civicrm_participant', - 'entity_label' => ts('Event Template'), - 'entity_value' => 'event_template', - 'entity_value_label' => ts('Event Template'), - 'entity_status' => 'civicrm_participant_status_type', - 'entity_status_label' => ts('Participant Status'), - ])); + public function getEntityName(): string { + return 'Participant'; + } + + public function getStatusHeader(): string { + return ts('Participant Status'); + } + + public function getStatusLabels($value): array { + return CRM_Event_PseudoConstant::participantStatus(NULL, NULL, 'label'); } /** @@ -72,7 +42,7 @@ class CRM_Event_ActionMapping extends \Civi\ActionSchedule\Mapping { * @return array * Array(string $fieldName => string $fieldLabel). */ - public function getDateFields() { + public function getDateFields(): array { return [ 'start_date' => ts('Event Start'), 'end_date' => ts('Event End'), @@ -91,7 +61,7 @@ class CRM_Event_ActionMapping extends \Civi\ActionSchedule\Mapping { * array(string $value => string $label). * Ex: array('assignee' => 'Activity Assignee'). */ - public function getRecipientTypes() { + public function getRecipientTypes(): array { return \CRM_Core_OptionGroup::values('event_contacts', FALSE, FALSE, FALSE, NULL, 'label', TRUE, FALSE, 'name'); } @@ -108,7 +78,7 @@ class CRM_Event_ActionMapping extends \Civi\ActionSchedule\Mapping { * Ex: array(1 => 'Attendee', 2 => 'Volunteer'). * @see getRecipientTypes */ - public function getRecipientListing($recipientType) { + public function getRecipientListing($recipientType): array { switch ($recipientType) { case 'participant_role': return \CRM_Event_PseudoConstant::participantRole(); @@ -131,11 +101,11 @@ class CRM_Event_ActionMapping extends \Civi\ActionSchedule\Mapping { * @return \CRM_Utils_SQL_Select * @see RecipientBuilder */ - public function createQuery($schedule, $phase, $defaultParams) { + public function createQuery($schedule, $phase, $defaultParams): CRM_Utils_SQL_Select { $selectedValues = (array) \CRM_Utils_Array::explodePadded($schedule->entity_value); $selectedStatuses = (array) \CRM_Utils_Array::explodePadded($schedule->entity_status); - $query = \CRM_Utils_SQL_Select::from("{$this->entity} e")->param($defaultParams); + $query = \CRM_Utils_SQL_Select::from("{$this->getEntityTable()} e")->param($defaultParams); $query['casAddlCheckFrom'] = 'civicrm_event r'; $query['casContactIdField'] = 'e.contact_id'; $query['casEntityIdField'] = 'e.id'; @@ -162,12 +132,12 @@ class CRM_Event_ActionMapping extends \Civi\ActionSchedule\Mapping { // build where clause // FIXME: This handles scheduled reminder of type "Event Name" and "Event Type", gives incorrect result on "Event Template". if (!empty($selectedValues)) { - $valueField = ($this->id == \CRM_Event_ActionMapping::EVENT_TYPE_MAPPING_ID) ? 'event_type_id' : 'id'; + $valueField = ($this->getId() == self::EVENT_TYPE_MAPPING_ID) ? 'event_type_id' : 'id'; $query->where("r.{$valueField} IN (@selectedValues)") ->param('selectedValues', $selectedValues); } else { - $query->where(($this->id == \CRM_Event_ActionMapping::EVENT_TYPE_MAPPING_ID) ? "r.event_type_id IS NULL" : "r.id IS NULL"); + $query->where(($this->getId() == self::EVENT_TYPE_MAPPING_ID) ? "r.event_type_id IS NULL" : "r.id IS NULL"); } $query->where('r.is_active = 1'); @@ -197,7 +167,7 @@ class CRM_Event_ActionMapping extends \Civi\ActionSchedule\Mapping { */ public function sendToAdditional($entityId): bool { $selectedValues = (array) \CRM_Utils_Array::explodePadded($entityId); - switch ($this->id) { + switch ($this->getId()) { case self::EVENT_TYPE_MAPPING_ID: $valueTable = 'e'; $valueField = 'event_type_id'; diff --git a/CRM/Event/ActionMapping/ByEvent.php b/CRM/Event/ActionMapping/ByEvent.php new file mode 100644 index 0000000000..ddb8107245 --- /dev/null +++ b/CRM/Event/ActionMapping/ByEvent.php @@ -0,0 +1,30 @@ +addWhere('is_template', '=', TRUE) + ->addWhere('is_active', '=', TRUE) + ->execute() + ->indexBy('id') + ->column('template_title'); + } + +} diff --git a/CRM/Event/ActionMapping/ByType.php b/CRM/Event/ActionMapping/ByType.php new file mode 100644 index 0000000000..fdba67d9e6 --- /dev/null +++ b/CRM/Event/ActionMapping/ByType.php @@ -0,0 +1,30 @@ +register(CRM_Member_ActionMapping::create([ - 'id' => CRM_Member_ActionMapping::MEMBERSHIP_TYPE_MAPPING_ID, - 'entity' => 'civicrm_membership', - 'entity_label' => ts('Membership'), - 'entity_value' => 'civicrm_membership_type', - 'entity_value_label' => ts('Membership Type'), - 'entity_status' => 'auto_renew_options', - 'entity_status_label' => ts('Auto Renew Options'), - ])); + public function getId() { + return self::MEMBERSHIP_TYPE_MAPPING_ID; + } + + public function getEntityName(): string { + return 'Membership'; + } + + public function getValueHeader(): string { + return ts('Membership Type'); + } + + public function getValueLabels(): array { + return CRM_Member_PseudoConstant::membershipType(); + } + + public function getStatusHeader(): string { + return ts('Auto Renew Options'); + } + + public function getStatusLabels($value): array { + if ($value && \CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $value, 'auto_renew')) { + return \CRM_Core_OptionGroup::values('auto_renew_options'); + } + else { + return []; + } } /** @@ -50,7 +58,7 @@ class CRM_Member_ActionMapping extends \Civi\ActionSchedule\Mapping { * @return array * Array(string $fieldName => string $fieldLabel). */ - public function getDateFields() { + public function getDateFields(): array { return [ 'join_date' => ts('Member Since'), 'start_date' => ts('Membership Start Date'), @@ -71,11 +79,11 @@ class CRM_Member_ActionMapping extends \Civi\ActionSchedule\Mapping { * @return \CRM_Utils_SQL_Select * @see RecipientBuilder */ - public function createQuery($schedule, $phase, $defaultParams) { + public function createQuery($schedule, $phase, $defaultParams): CRM_Utils_SQL_Select { $selectedValues = (array) \CRM_Utils_Array::explodePadded($schedule->entity_value); $selectedStatuses = (array) \CRM_Utils_Array::explodePadded($schedule->entity_status); - $query = \CRM_Utils_SQL_Select::from("{$this->entity} e")->param($defaultParams); + $query = \CRM_Utils_SQL_Select::from("{$this->getEntityTable()} e")->param($defaultParams); $query['casAddlCheckFrom'] = 'civicrm_membership e'; $query['casContactIdField'] = 'e.contact_id'; $query['casEntityIdField'] = 'e.id'; @@ -159,7 +167,7 @@ class CRM_Member_ActionMapping extends \Civi\ActionSchedule\Mapping { * * @param \CRM_Core_DAO_ActionSchedule $schedule */ - public function resetOnTriggerDateChange($schedule) { + public function resetOnTriggerDateChange($schedule): bool { if ($schedule->absolute_date !== NULL) { return FALSE; } @@ -168,12 +176,4 @@ class CRM_Member_ActionMapping extends \Civi\ActionSchedule\Mapping { } } - /** - * Determine whether a schedule based on this mapping should - * send to additional contacts. - */ - public function sendToAdditional($entityId): bool { - return TRUE; - } - } diff --git a/Civi/ActionSchedule/Mapping.php b/Civi/ActionSchedule/Mapping.php deleted file mode 100644 index aeea2663eb..0000000000 --- a/Civi/ActionSchedule/Mapping.php +++ /dev/null @@ -1,356 +0,0 @@ -{$field} = $params[$field]; - } - } - } - - protected $id; - - /** - * The basic entity to query (table name). - * - * @var string - * Ex: 'civicrm_activity', 'civicrm_event'. - */ - protected $entity; - - /** - * The basic entity to query (label). - * - * @var string - * Ex: 'Activity', 'Event' - */ - private $entity_label; - - /** - * Level 1 filter -- the field/option-list to filter on. - * - * @var string - * Ex: 'activity_type', 'civicrm_event', 'event_template'. - */ - private $entity_value; - - /** - * Level 1 filter -- The field label. - * - * @var string - * Ex: 'Activity Type', 'Event Name', 'Event Template'. - */ - private $entity_value_label; - - /** - * Level 2 filter -- the field/option-list to filter on. - * @var string - * Ex: 'activity_status, 'civicrm_participant_status_type', 'auto_renew_options'. - */ - private $entity_status; - - /** - * Level 2 filter -- the field label. - * @var string - * Ex: 'Activity Status', 'Participant Status', 'Auto Rewnewal Options'. - */ - private $entity_status_label; - - /** - * Date filter -- the field name. - * @var string|null - * Ex: 'event_start_date' - */ - private $entity_date_start; - - /** - * Date filter -- the field name. - * @var string|null - * Ex: 'event_end_date'. - */ - private $entity_date_end; - - /** - * @return mixed - */ - public function getId() { - return $this->id; - } - - /** - * @return string - */ - public function getEntityTable(): string { - return $this->entity; - } - - public function getEntityName(): string { - return \CRM_Core_DAO_AllCoreTables::getEntityNameForTable($this->getEntityTable()); - } - - /** - * Get a printable label for this mapping type. - * - * @return string - */ - public function getLabel() { - return $this->entity_label; - } - - /** - * Get a printable label to use a header on the 'value' filter. - * - * @return string - */ - public function getValueHeader() { - return $this->entity_value_label; - } - - /** - * Get a printable label to use a header on the 'status' filter. - * - * @return string - */ - public function getStatusHeader() { - return $this->entity_status_label; - } - - /** - * Get a list of value options. - * - * @return array - * Array(string $value => string $label). - * Ex: array(123 => 'Phone Call', 456 => 'Meeting'). - */ - public function getValueLabels() { - return self::getValueLabelMap($this->entity_value); - } - - /** - * Get a list of status options. - * - * @param string|int $value - * The list of status options may be contingent upon the selected filter value. - * This is the selected filter value. - * @return array - * Array(string $value => string $label). - * Ex: Array(123 => 'Completed', 456 => 'Scheduled'). - */ - public function getStatusLabels($value) { - if ($this->entity_status === 'auto_renew_options') { - if ($value && \CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $value, 'auto_renew')) { - return \CRM_Core_OptionGroup::values('auto_renew_options'); - } - else { - return []; - } - } - return self::getValueLabelMap($this->entity_status); - } - - /** - * Get a list of available date fields. - * - * @return array - * Array(string $fieldName => string $fieldLabel). - */ - public function getDateFields() { - $dateFieldLabels = []; - if (!empty($this->entity_date_start)) { - $dateFieldLabels[$this->entity_date_start] = ucwords(str_replace('_', ' ', $this->entity_date_start)); - } - if (!empty($this->entity_date_end)) { - $dateFieldLabels[$this->entity_date_end] = ucwords(str_replace('_', ' ', $this->entity_date_end)); - } - return $dateFieldLabels; - } - - /** - * Get a list of recipient types. - * - * Note: A single schedule may filter on *zero* or *one* recipient types. - * When an admin chooses a value, it's stored in $schedule->recipient. - * - * @return array - * array(string $value => string $label). - * Ex: array('assignee' => 'Activity Assignee'). - */ - public function getRecipientTypes() { - return []; - } - - /** - * Get a list of recipients which match the given type. - * - * Note: A single schedule may filter on *multiple* recipients. - * When an admin chooses value(s), it's stored in $schedule->recipient_listing. - * - * @param string $recipientType - * Ex: 'participant_role'. - * @return array - * Array(mixed $name => string $label). - * Ex: array(1 => 'Attendee', 2 => 'Volunteer'). - * @see getRecipientTypes - */ - public function getRecipientListing($recipientType) { - return []; - } - - protected static function getValueLabelMap($name) { - static $valueLabelMap = NULL; - if ($valueLabelMap === NULL) { - // CRM-20510: Include CiviCampaign activity types along with CiviCase IF component is enabled - $valueLabelMap['activity_type'] = \CRM_Core_PseudoConstant::activityType(TRUE, TRUE, FALSE, 'label', TRUE); - asort($valueLabelMap['activity_type']); - - $valueLabelMap['activity_status'] = \CRM_Core_PseudoConstant::activityStatus(); - $valueLabelMap['event_type'] = \CRM_Event_PseudoConstant::eventType(); - $valueLabelMap['civicrm_event'] = \CRM_Event_PseudoConstant::event(NULL, FALSE, "( is_template IS NULL OR is_template != 1 )"); - $valueLabelMap['civicrm_participant_status_type'] = \CRM_Event_PseudoConstant::participantStatus(NULL, NULL, 'label'); - $valueLabelMap['event_template'] = \Civi\Api4\Event::get(FALSE) - ->addWhere('is_template', '=', TRUE) - ->addWhere('is_active', '=', TRUE) - ->execute() - ->indexBy('id') - ->column('template_title'); - $valueLabelMap['auto_renew_options'] = \CRM_Core_OptionGroup::values('auto_renew_options'); - $valueLabelMap['contact_date_reminder_options'] = \CRM_Core_OptionGroup::values('contact_date_reminder_options'); - $valueLabelMap['civicrm_membership_type'] = \CRM_Member_PseudoConstant::membershipType(); - - $allCustomFields = \CRM_Core_BAO_CustomField::getFields(''); - $dateFields = [ - 'birth_date' => ts('Birth Date'), - 'created_date' => ts('Created Date'), - 'modified_date' => ts('Modified Date'), - ]; - foreach ($allCustomFields as $fieldID => $field) { - if ($field['data_type'] == 'Date') { - $dateFields["custom_$fieldID"] = $field['label']; - } - } - $valueLabelMap['civicrm_contact'] = $dateFields; - } - - return $valueLabelMap[$name]; - } - - /** - * Determine whether a schedule based on this mapping is sufficiently - * complete. - * - * @param \CRM_Core_DAO_ActionSchedule $schedule - * @return array - * Array (string $code => string $message). - * List of error messages. - */ - public function validateSchedule($schedule) { - return []; - } - - /** - * Generate a query to locate contacts who match the given - * schedule. - * - * @param \CRM_Core_DAO_ActionSchedule $schedule - * @param string $phase - * See, e.g., RecipientBuilder::PHASE_RELATION_FIRST. - * @param array $defaultParams - * @return \CRM_Utils_SQL_Select - */ - abstract public function createQuery($schedule, $phase, $defaultParams); - - /** - * Determine whether a schedule based on this mapping should - * reset the reminder state if the trigger date changes. - * - * @return bool - * - * @param \CRM_Core_DAO_ActionSchedule $schedule - */ - public function resetOnTriggerDateChange($schedule) { - return FALSE; - } - - /** - * Determine whether a schedule based on this mapping should - * send to additional contacts. - */ - abstract public function sendToAdditional($entityId): bool; - -} diff --git a/Civi/ActionSchedule/MappingBase.php b/Civi/ActionSchedule/MappingBase.php new file mode 100644 index 0000000000..cf4f997fc1 --- /dev/null +++ b/Civi/ActionSchedule/MappingBase.php @@ -0,0 +1,79 @@ +register(new static()); + } + + public function getEntityTable(): string { + return \CRM_Core_DAO_AllCoreTables::getTableForEntityName($this->getEntityName()); + } + + /** + * Deprecated ambiguously-named function. + * @deprecated + * @return string + */ + public function getEntity(): string { + \CRM_Core_Error::deprecatedFunctionWarning('getEntityTable'); + return $this->getEntityTable(); + } + + public function getLabel(): string { + return CoreUtil::getInfoItem($this->getEntityName(), 'title'); + } + + public function getValueHeader(): string { + return $this->getLabel(); + } + + public function getRecipientListing($recipientType): array { + return []; + } + + public function getRecipientTypes(): array { + return []; + } + + public function validateSchedule($schedule): array { + return []; + } + + public function getDateFields(): array { + return []; + } + + public function resetOnTriggerDateChange($schedule): bool { + return FALSE; + } + + public function sendToAdditional($entityId): bool { + return TRUE; + } + +} diff --git a/Civi/ActionSchedule/MappingInterface.php b/Civi/ActionSchedule/MappingInterface.php index 62e530bf87..42fe2e8a1f 100644 --- a/Civi/ActionSchedule/MappingInterface.php +++ b/Civi/ActionSchedule/MappingInterface.php @@ -18,7 +18,10 @@ namespace Civi\ActionSchedule; interface MappingInterface { /** - * @return mixed + * Unique identifier of this mapping type. + * + * Should return a "machine name" style string (older implementations return an int -- don't follow their example). + * @return string|int */ public function getId(); @@ -35,25 +38,23 @@ interface MappingInterface { public function getEntityName(): string; /** - * Get a printable label for this mapping type. - * + * Label of this mapping type as shown in the "Entity" dropdown-select on the form. * @return string */ public function getLabel(); /** - * Get a printable label to use as the header on the 'value' filter. - * + * Label of the primary filter field on the form, e.g. "Activity Type" * @return string */ - public function getValueHeader(); + public function getValueHeader(): string; /** * Get a printable label to use as the header on the 'status' filter. * * @return string */ - public function getStatusHeader(); + public function getStatusHeader(): string; /** * Get a list of value options. @@ -62,7 +63,7 @@ interface MappingInterface { * Array(string $value => string $label). * Ex: array(123 => 'Phone Call', 456 => 'Meeting'). */ - public function getValueLabels(); + public function getValueLabels(): array; /** * Get a list of status options. @@ -74,7 +75,7 @@ interface MappingInterface { * Array(string $value => string $label). * Ex: Array(123 => 'Completed', 456 => 'Scheduled'). */ - public function getStatusLabels($value); + public function getStatusLabels($value): array; /** * Get a list of available date fields. @@ -82,7 +83,7 @@ interface MappingInterface { * @return array * Array(string $fieldName => string $fieldLabel). */ - public function getDateFields(); + public function getDateFields(): array; /** * Get a list of recipient types. @@ -94,7 +95,7 @@ interface MappingInterface { * array(string $value => string $label). * Ex: array('assignee' => 'Activity Assignee'). */ - public function getRecipientTypes(); + public function getRecipientTypes(): array; /** * Get a list of recipients which match the given type. @@ -109,7 +110,7 @@ interface MappingInterface { * Ex: array(1 => 'Attendee', 2 => 'Volunteer'). * @see getRecipientTypes */ - public function getRecipientListing($recipientType); + public function getRecipientListing($recipientType): array; /** * Determine whether a schedule based on this mapping is sufficiently @@ -120,7 +121,7 @@ interface MappingInterface { * Array (string $code => string $message). * List of error messages. */ - public function validateSchedule($schedule); + public function validateSchedule($schedule): array; /** * Generate a query to locate contacts who match the given @@ -134,7 +135,7 @@ interface MappingInterface { * @return \CRM_Utils_SQL_Select * @see RecipientBuilder */ - public function createQuery($schedule, $phase, $defaultParams); + public function createQuery($schedule, $phase, $defaultParams): \CRM_Utils_SQL_Select; /** * Determine whether a schedule based on this mapping should @@ -144,7 +145,7 @@ interface MappingInterface { * * @param \CRM_Core_DAO_ActionSchedule $schedule */ - public function resetOnTriggerDateChange($schedule); + public function resetOnTriggerDateChange($schedule): bool; /** * Determine whether a schedule based on this mapping should diff --git a/Civi/Core/Container.php b/Civi/Core/Container.php index e4ec975ee0..245c3b835e 100644 --- a/Civi/Core/Container.php +++ b/Civi/Core/Container.php @@ -481,7 +481,9 @@ class Container { $dispatcher->addListener('civi.actionSchedule.getMappings', ['CRM_Contact_ActionMapping', 'onRegisterActionMappings']); $dispatcher->addListener('civi.actionSchedule.getMappings', ['CRM_Contribute_ActionMapping_ByPage', 'onRegisterActionMappings']); $dispatcher->addListener('civi.actionSchedule.getMappings', ['CRM_Contribute_ActionMapping_ByType', 'onRegisterActionMappings']); - $dispatcher->addListener('civi.actionSchedule.getMappings', ['CRM_Event_ActionMapping', 'onRegisterActionMappings']); + $dispatcher->addListener('civi.actionSchedule.getMappings', ['CRM_Event_ActionMapping_ByType', 'onRegisterActionMappings']); + $dispatcher->addListener('civi.actionSchedule.getMappings', ['CRM_Event_ActionMapping_ByEvent', 'onRegisterActionMappings']); + $dispatcher->addListener('civi.actionSchedule.getMappings', ['CRM_Event_ActionMapping_ByTemplate', 'onRegisterActionMappings']); $dispatcher->addListener('civi.actionSchedule.getMappings', ['CRM_Member_ActionMapping', 'onRegisterActionMappings']); return $dispatcher; diff --git a/tests/phpunit/CRM/Contribute/ActionMapping/ByTypeTest.php b/tests/phpunit/CRM/Contribute/ActionMapping/ByTypeTest.php index efd9027dd4..f33292c618 100644 --- a/tests/phpunit/CRM/Contribute/ActionMapping/ByTypeTest.php +++ b/tests/phpunit/CRM/Contribute/ActionMapping/ByTypeTest.php @@ -229,7 +229,7 @@ class CRM_Contribute_ActionMapping_ByTypeTest extends \Civi\ActionSchedule\Abstr * Schedule message delivery for contributions of type "Member Dues". */ public function scheduleForDues() { - $this->schedule->mapping_id = CRM_Contribute_ActionMapping_ByType::MAPPING_ID; + $this->schedule->mapping_id = 'contribtype'; $this->schedule->start_action_date = 'receive_date'; $this->schedule->entity_value = CRM_Utils_Array::implodePadded([1]); $this->schedule->entity_status = CRM_Utils_Array::implodePadded([1]); @@ -239,7 +239,7 @@ class CRM_Contribute_ActionMapping_ByTypeTest extends \Civi\ActionSchedule\Abstr * Schedule message delivery for contributions of type "Donation". */ public function scheduleForDonation() { - $this->schedule->mapping_id = CRM_Contribute_ActionMapping_ByType::MAPPING_ID; + $this->schedule->mapping_id = 'contribtype'; $this->schedule->start_action_date = 'receive_date'; $this->schedule->entity_value = CRM_Utils_Array::implodePadded([2]); $this->schedule->entity_status = CRM_Utils_Array::implodePadded(NULL); @@ -249,7 +249,7 @@ class CRM_Contribute_ActionMapping_ByTypeTest extends \Civi\ActionSchedule\Abstr * Schedule message delivery for any contribution, regardless of type. */ public function scheduleForAny() { - $this->schedule->mapping_id = CRM_Contribute_ActionMapping_ByType::MAPPING_ID; + $this->schedule->mapping_id = 'contribtype'; $this->schedule->start_action_date = 'receive_date'; $this->schedule->entity_value = CRM_Utils_Array::implodePadded(NULL); $this->schedule->entity_status = CRM_Utils_Array::implodePadded(NULL); @@ -259,7 +259,7 @@ class CRM_Contribute_ActionMapping_ByTypeTest extends \Civi\ActionSchedule\Abstr * Schedule message delivery to the 'soft credit' assignee. */ public function scheduleForSoftCreditor() { - $this->schedule->mapping_id = CRM_Contribute_ActionMapping_ByType::MAPPING_ID; + $this->schedule->mapping_id = 'contribtype'; $this->schedule->start_action_date = 'receive_date'; $this->schedule->entity_value = CRM_Utils_Array::implodePadded(NULL); $this->schedule->entity_status = CRM_Utils_Array::implodePadded(NULL); -- 2.25.1