Merge pull request #23809 from eileenmcnaughton/invoice_recur
[civicrm-core.git] / CRM / Event / ActionMapping.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
10 */
11
12 use Civi\ActionSchedule\RecipientBuilder;
13
14 /**
15 * Class CRM_Event_ActionMapping
16 *
17 * This defines the scheduled-reminder functionality for CiviEvent
18 * participants. It allows one to target messages on the
19 * event's start-date/end-date, with additional filtering by
20 * event-type, event-template, or event-id.
21 */
22 class CRM_Event_ActionMapping extends \Civi\ActionSchedule\Mapping {
23
24 /**
25 * The value for civicrm_action_schedule.mapping_id which identifies the
26 * "Event Type" mapping.
27 *
28 * Note: This value is chosen to match legacy DB IDs.
29 */
30 const EVENT_TYPE_MAPPING_ID = 2;
31 const EVENT_NAME_MAPPING_ID = 3;
32 const EVENT_TPL_MAPPING_ID = 5;
33
34 /**
35 * Register CiviEvent-related action mappings.
36 *
37 * @param \Civi\ActionSchedule\Event\MappingRegisterEvent $registrations
38 */
39 public static function onRegisterActionMappings(\Civi\ActionSchedule\Event\MappingRegisterEvent $registrations) {
40 $registrations->register(CRM_Event_ActionMapping::create([
41 'id' => CRM_Event_ActionMapping::EVENT_TYPE_MAPPING_ID,
42 'entity' => 'civicrm_participant',
43 'entity_label' => ts('Event Type'),
44 'entity_value' => 'event_type',
45 'entity_value_label' => ts('Event Type'),
46 'entity_status' => 'civicrm_participant_status_type',
47 'entity_status_label' => ts('Participant Status'),
48 ]));
49 $registrations->register(CRM_Event_ActionMapping::create([
50 'id' => CRM_Event_ActionMapping::EVENT_NAME_MAPPING_ID,
51 'entity' => 'civicrm_participant',
52 'entity_label' => ts('Event Name'),
53 'entity_value' => 'civicrm_event',
54 'entity_value_label' => ts('Event Name'),
55 'entity_status' => 'civicrm_participant_status_type',
56 'entity_status_label' => ts('Participant Status'),
57 ]));
58 $registrations->register(CRM_Event_ActionMapping::create([
59 'id' => CRM_Event_ActionMapping::EVENT_TPL_MAPPING_ID,
60 'entity' => 'civicrm_participant',
61 'entity_label' => ts('Event Template'),
62 'entity_value' => 'event_template',
63 'entity_value_label' => ts('Event Template'),
64 'entity_status' => 'civicrm_participant_status_type',
65 'entity_status_label' => ts('Participant Status'),
66 ]));
67 }
68
69 /**
70 * Get a list of available date fields.
71 *
72 * @return array
73 * Array(string $fieldName => string $fieldLabel).
74 */
75 public function getDateFields() {
76 return [
77 'start_date' => ts('Event Start'),
78 'end_date' => ts('Event End'),
79 'registration_start_date' => ts('Registration Start'),
80 'registration_end_date' => ts('Registration End'),
81 ];
82 }
83
84 /**
85 * Get a list of recipient types.
86 *
87 * Note: A single schedule may filter on *zero* or *one* recipient types.
88 * When an admin chooses a value, it's stored in $schedule->recipient.
89 *
90 * @return array
91 * array(string $value => string $label).
92 * Ex: array('assignee' => 'Activity Assignee').
93 */
94 public function getRecipientTypes() {
95 return \CRM_Core_OptionGroup::values('event_contacts', FALSE, FALSE, FALSE, NULL, 'label', TRUE, FALSE, 'name');
96 }
97
98 /**
99 * Get a list of recipients which match the given type.
100 *
101 * Note: A single schedule may filter on *multiple* recipients.
102 * When an admin chooses value(s), it's stored in $schedule->recipient_listing.
103 *
104 * @param string $recipientType
105 * Ex: 'participant_role'.
106 * @return array
107 * Array(mixed $name => string $label).
108 * Ex: array(1 => 'Attendee', 2 => 'Volunteer').
109 * @see getRecipientTypes
110 */
111 public function getRecipientListing($recipientType) {
112 switch ($recipientType) {
113 case 'participant_role':
114 return \CRM_Event_PseudoConstant::participantRole();
115
116 default:
117 return [];
118 }
119 }
120
121 /**
122 * Generate a query to locate recipients who match the given
123 * schedule.
124 *
125 * @param \CRM_Core_DAO_ActionSchedule $schedule
126 * The schedule as configured by the administrator.
127 * @param string $phase
128 * See, e.g., RecipientBuilder::PHASE_RELATION_FIRST.
129 * @param array $defaultParams
130 *
131 * @return \CRM_Utils_SQL_Select
132 * @see RecipientBuilder
133 */
134 public function createQuery($schedule, $phase, $defaultParams) {
135 $selectedValues = (array) \CRM_Utils_Array::explodePadded($schedule->entity_value);
136 $selectedStatuses = (array) \CRM_Utils_Array::explodePadded($schedule->entity_status);
137
138 $query = \CRM_Utils_SQL_Select::from("{$this->entity} e")->param($defaultParams);
139 $query['casAddlCheckFrom'] = 'civicrm_event r';
140 $query['casContactIdField'] = 'e.contact_id';
141 $query['casEntityIdField'] = 'e.id';
142 $query['casContactTableAlias'] = NULL;
143 $query['casDateField'] = str_replace('event_', 'r.', $schedule->start_action_date);
144 if (empty($query['casDateField']) && $schedule->absolute_date) {
145 $query['casDateField'] = "'" . CRM_Utils_Type::escape($schedule->absolute_date, 'String') . "'";
146 }
147
148 $query->join('r', 'INNER JOIN civicrm_event r ON e.event_id = r.id');
149 if ($schedule->recipient_listing && $schedule->limit_to) {
150 switch ($schedule->recipient) {
151 case 'participant_role':
152 $regex = "([[:cntrl:]]|^)" . implode('([[:cntrl:]]|$)|([[:cntrl:]]|^)', \CRM_Utils_Array::explodePadded($schedule->recipient_listing)) . "([[:cntrl:]]|$)";
153 $query->where("e.role_id REGEXP (@regex)")
154 ->param('regex', $regex);
155 break;
156
157 default:
158 break;
159 }
160 }
161
162 // build where clause
163 // FIXME: This handles scheduled reminder of type "Event Name" and "Event Type", gives incorrect result on "Event Template".
164 if (!empty($selectedValues)) {
165 $valueField = ($this->id == \CRM_Event_ActionMapping::EVENT_TYPE_MAPPING_ID) ? 'event_type_id' : 'id';
166 $query->where("r.{$valueField} IN (@selectedValues)")
167 ->param('selectedValues', $selectedValues);
168 }
169 else {
170 $query->where(($this->id == \CRM_Event_ActionMapping::EVENT_TYPE_MAPPING_ID) ? "r.event_type_id IS NULL" : "r.id IS NULL");
171 }
172
173 $query->where('r.is_active = 1');
174 $query->where('r.is_template = 0');
175
176 // participant status criteria not to be implemented for additional recipients
177 // ... why not?
178 if (!empty($selectedStatuses)) {
179 switch ($phase) {
180 case RecipientBuilder::PHASE_RELATION_FIRST:
181 case RecipientBuilder::PHASE_RELATION_REPEAT:
182 $query->where("e.status_id IN (#selectedStatuses)")
183 ->param('selectedStatuses', $selectedStatuses);
184 break;
185
186 }
187 }
188 return $query;
189 }
190
191 /**
192 * Determine whether a schedule based on this mapping should
193 * send to additional contacts.
194 *
195 * @param string $entityId Either an event ID/event type ID, or a set of event IDs/types separated
196 * by the separation character.
197 */
198 public function sendToAdditional($entityId): bool {
199 $selectedValues = (array) \CRM_Utils_Array::explodePadded($entityId);
200 switch ($this->id) {
201 case self::EVENT_TYPE_MAPPING_ID:
202 $valueTable = 'e';
203 $valueField = 'event_type_id';
204 $templateReminder = FALSE;
205 break;
206
207 case self::EVENT_NAME_MAPPING_ID:
208 $valueTable = 'e';
209 $valueField = 'id';
210 $templateReminder = FALSE;
211 break;
212
213 case self::EVENT_TPL_MAPPING_ID:
214 $valueTable = 't';
215 $valueField = 'id';
216 $templateReminder = TRUE;
217 break;
218 }
219 // Don't send to additional recipients if this event is deleted or a template.
220 $query = new \CRM_Utils_SQL_Select('civicrm_event e');
221 $query
222 ->select('e.id')
223 ->where("e.is_template = 0")
224 ->where("e.is_active = 1");
225 if ($templateReminder) {
226 $query->join('r', 'INNER JOIN civicrm_event t ON e.template_title = t.template_title AND t.is_template = 1');
227 }
228 $sql = $query
229 ->where("{$valueTable}.{$valueField} IN (@selectedValues)")
230 ->param('selectedValues', $selectedValues)
231 ->toSQL();
232 $dao = \CRM_Core_DAO::executeQuery($sql);
233 return (bool) $dao->N;
234 }
235
236 }