Merge pull request #21644 from sunilpawar/processed_token
[civicrm-core.git] / CRM / Core / BAO / ActionSchedule.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 /**
13 *
14 * @package CRM
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
16 */
17
18 use Civi\ActionSchedule\Event\MappingRegisterEvent;
19
20 /**
21 * This class contains functions for managing Scheduled Reminders
22 */
23 class CRM_Core_BAO_ActionSchedule extends CRM_Core_DAO_ActionSchedule {
24
25 /**
26 * @param array $filters
27 * Filter by property (e.g. 'id').
28 *
29 * @return array
30 * Array(scalar $id => Mapping $mapping).
31 *
32 * @throws \CRM_Core_Exception
33 */
34 public static function getMappings($filters = NULL) {
35 static $_action_mapping;
36
37 if ($_action_mapping === NULL) {
38 $event = \Civi::dispatcher()
39 ->dispatch('civi.actionSchedule.getMappings',
40 new MappingRegisterEvent());
41 $_action_mapping = $event->getMappings();
42 }
43
44 if (empty($filters)) {
45 return $_action_mapping;
46 }
47 if (isset($filters['id'])) {
48 return [$filters['id'] => $_action_mapping[$filters['id']]];
49 }
50 throw new CRM_Core_Exception("getMappings() called with unsupported filter: " . implode(', ', array_keys($filters)));
51 }
52
53 /**
54 * @param string|int $id
55 *
56 * @return \Civi\ActionSchedule\Mapping|NULL
57 * @throws \CRM_Core_Exception
58 */
59 public static function getMapping($id) {
60 $mappings = self::getMappings();
61 return $mappings[$id] ?? NULL;
62 }
63
64 /**
65 * For each entity, get a list of entity-value labels.
66 *
67 * @return array
68 * Ex: $entityValueLabels[$mappingId][$valueId] = $valueLabel.
69 * @throws CRM_Core_Exception
70 */
71 public static function getAllEntityValueLabels() {
72 $entityValueLabels = [];
73 foreach (CRM_Core_BAO_ActionSchedule::getMappings() as $mapping) {
74 /** @var \Civi\ActionSchedule\Mapping $mapping */
75 $entityValueLabels[$mapping->getId()] = $mapping->getValueLabels();
76 $valueLabel = ['- ' . strtolower($mapping->getValueHeader()) . ' -'];
77 $entityValueLabels[$mapping->getId()] = $valueLabel + $entityValueLabels[$mapping->getId()];
78 }
79 return $entityValueLabels;
80 }
81
82 /**
83 * For each entity, get a list of entity-status labels.
84 *
85 * @return array
86 * Ex: $entityValueLabels[$mappingId][$valueId][$statusId] = $statusLabel.
87 */
88 public static function getAllEntityStatusLabels() {
89 $entityValueLabels = self::getAllEntityValueLabels();
90 $entityStatusLabels = [];
91 foreach (CRM_Core_BAO_ActionSchedule::getMappings() as $mapping) {
92 /** @var \Civi\ActionSchedule\Mapping $mapping */
93 $statusLabel = ['- ' . strtolower($mapping->getStatusHeader()) . ' -'];
94 $entityStatusLabels[$mapping->getId()] = $entityValueLabels[$mapping->getId()];
95 foreach ($entityStatusLabels[$mapping->getId()] as $kkey => & $vval) {
96 $vval = $statusLabel + $mapping->getStatusLabels($kkey);
97 }
98 }
99 return $entityStatusLabels;
100 }
101
102 /**
103 * Retrieve list of Scheduled Reminders.
104 *
105 * @param \Civi\ActionSchedule\Mapping|null $filterMapping
106 * Filter by the schedule's mapping type.
107 * @param int $filterValue
108 * Filter by the schedule's entity_value.
109 *
110 * @return array
111 * (reference) reminder list
112 * @throws \CRM_Core_Exception
113 */
114 public static function getList($filterMapping = NULL, $filterValue = NULL): array {
115 $list = [];
116 $query = "
117 SELECT
118 title,
119 cas.id as id,
120 cas.mapping_id,
121 cas.entity_value as entityValueIds,
122 cas.entity_status as entityStatusIds,
123 cas.start_action_date as entityDate,
124 cas.start_action_offset,
125 cas.start_action_unit,
126 cas.start_action_condition,
127 cas.absolute_date,
128 is_repeat,
129 is_active
130
131 FROM civicrm_action_schedule cas
132 ";
133 $queryParams = [];
134 $where = " WHERE 1 ";
135 if ($filterMapping and $filterValue) {
136 $where .= " AND cas.entity_value = %1 AND cas.mapping_id = %2";
137 $queryParams[1] = [$filterValue, 'Integer'];
138 $queryParams[2] = [$filterMapping->getId(), 'String'];
139 }
140 $where .= " AND cas.used_for IS NULL";
141 $query .= $where;
142 $dao = CRM_Core_DAO::executeQuery($query, $queryParams);
143 while ($dao->fetch()) {
144 /** @var Civi\ActionSchedule\Mapping $filterMapping */
145 $filterMapping = CRM_Utils_Array::first(self::getMappings([
146 'id' => $dao->mapping_id,
147 ]));
148 $list[$dao->id]['id'] = $dao->id;
149 $list[$dao->id]['title'] = $dao->title;
150 $list[$dao->id]['start_action_offset'] = $dao->start_action_offset;
151 $list[$dao->id]['start_action_unit'] = $dao->start_action_unit;
152 $list[$dao->id]['start_action_condition'] = $dao->start_action_condition;
153 $list[$dao->id]['entityDate'] = ucwords(str_replace('_', ' ', $dao->entityDate));
154 $list[$dao->id]['absolute_date'] = $dao->absolute_date;
155 $list[$dao->id]['entity'] = $filterMapping->getLabel();
156 $list[$dao->id]['value'] = implode(', ', CRM_Utils_Array::subset(
157 $filterMapping->getValueLabels(),
158 explode(CRM_Core_DAO::VALUE_SEPARATOR, $dao->entityValueIds)
159 ));
160 $list[$dao->id]['status'] = implode(', ', CRM_Utils_Array::subset(
161 $filterMapping->getStatusLabels($dao->entityValueIds),
162 explode(CRM_Core_DAO::VALUE_SEPARATOR, $dao->entityStatusIds)
163 ));
164 $list[$dao->id]['is_repeat'] = $dao->is_repeat;
165 $list[$dao->id]['is_active'] = $dao->is_active;
166 }
167
168 return $list;
169 }
170
171 /**
172 * Add the scheduled reminders in the db.
173 *
174 * @param array $params
175 * An assoc array of name/value pairs.
176 *
177 * @return CRM_Core_DAO_ActionSchedule
178 * @throws \CRM_Core_Exception
179 */
180 public static function add(array $params): CRM_Core_DAO_ActionSchedule {
181 return self::writeRecord($params);
182 }
183
184 /**
185 * Retrieve DB object based on input parameters.
186 *
187 * It also stores all the retrieved values in the default array.
188 *
189 * @param array $params
190 * (reference ) an assoc array of name/value pairs.
191 * @param array $values
192 * (reference ) an assoc array to hold the flattened values.
193 *
194 * @return CRM_Core_DAO_ActionSchedule|null
195 * object on success, null otherwise
196 */
197 public static function retrieve(&$params, &$values) {
198 if (empty($params)) {
199 return NULL;
200 }
201 $actionSchedule = new CRM_Core_DAO_ActionSchedule();
202
203 $actionSchedule->copyValues($params);
204
205 if ($actionSchedule->find(TRUE)) {
206 CRM_Core_DAO::storeValues($actionSchedule, $values);
207 return $actionSchedule;
208 }
209 return NULL;
210 }
211
212 /**
213 * Delete a Reminder.
214 *
215 * @param int $id
216 * @deprecated
217 * @throws CRM_Core_Exception
218 */
219 public static function del($id) {
220 self::deleteRecord(['id' => $id]);
221 }
222
223 /**
224 * Update the is_active flag in the db.
225 *
226 * @param int $id
227 * Id of the database record.
228 * @param bool $is_active
229 * Value we want to set the is_active field.
230 *
231 * @return bool
232 * true if we found and updated the object, else false
233 */
234 public static function setIsActive($id, $is_active) {
235 return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_ActionSchedule', $id, 'is_active', $is_active);
236 }
237
238 /**
239 * @param int $mappingID
240 * @param $now
241 *
242 * @throws CRM_Core_Exception
243 */
244 public static function sendMailings($mappingID, $now) {
245 $mapping = CRM_Utils_Array::first(self::getMappings([
246 'id' => $mappingID,
247 ]));
248
249 $actionSchedule = new CRM_Core_DAO_ActionSchedule();
250 $actionSchedule->mapping_id = $mappingID;
251 $actionSchedule->is_active = 1;
252 $actionSchedule->find(FALSE);
253
254 while ($actionSchedule->fetch()) {
255 $query = CRM_Core_BAO_ActionSchedule::prepareMailingQuery($mapping, $actionSchedule);
256 $dao = CRM_Core_DAO::executeQuery($query,
257 [1 => [$actionSchedule->id, 'Integer']]
258 );
259
260 $multilingual = CRM_Core_I18n::isMultilingual();
261 $tokenProcessor = self::createTokenProcessor($actionSchedule, $mapping);
262 while ($dao->fetch()) {
263 $row = $tokenProcessor->addRow()
264 ->context('contactId', $dao->contactID)
265 ->context('actionSearchResult', (object) $dao->toArray());
266
267 // switch language if necessary
268 if ($multilingual) {
269 $preferred_language = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $dao->contactID, 'preferred_language');
270 $row->context('locale', CRM_Core_BAO_ActionSchedule::pickLocale($actionSchedule->communication_language, $preferred_language));
271 }
272
273 foreach ($dao->toArray() as $key => $value) {
274 if (preg_match('/^tokenContext_(.*)/', $key, $m)) {
275 if (!in_array($m[1], $tokenProcessor->context['schema'])) {
276 $tokenProcessor->context['schema'][] = $m[1];
277 }
278 $row->context($m[1], $value);
279 }
280 }
281 }
282
283 $tokenProcessor->evaluate();
284 foreach ($tokenProcessor->getRows() as $tokenRow) {
285 $dao = $tokenRow->context['actionSearchResult'];
286 $errors = [];
287
288 // It's possible, eg, that sendReminderEmail fires Hook::alterMailParams() and that some listener use ts().
289 $swapLocale = empty($row->context['locale']) ? NULL : \CRM_Utils_AutoClean::swapLocale($row->context['locale']);
290
291 if ($actionSchedule->mode === 'SMS' || $actionSchedule->mode === 'User_Preference') {
292 CRM_Utils_Array::extend($errors, self::sendReminderSms($tokenRow, $actionSchedule, $dao->contactID));
293 }
294
295 if ($actionSchedule->mode === 'Email' || $actionSchedule->mode === 'User_Preference') {
296 CRM_Utils_Array::extend($errors, self::sendReminderEmail($tokenRow, $actionSchedule, $dao->contactID));
297 }
298 // insert activity log record if needed
299 if ($actionSchedule->record_activity && empty($errors)) {
300 $caseID = empty($dao->case_id) ? NULL : $dao->case_id;
301 CRM_Core_BAO_ActionSchedule::createMailingActivity($tokenRow, $mapping, $dao->contactID, $dao->entityID, $caseID);
302 }
303
304 unset($swapLocale);
305
306 // update action log record
307 $logParams = [
308 'id' => $dao->reminderID,
309 'is_error' => !empty($errors),
310 'message' => empty($errors) ? "null" : implode(' ', $errors),
311 'action_date_time' => $now,
312 ];
313 CRM_Core_BAO_ActionLog::create($logParams);
314 }
315
316 }
317 }
318
319 /**
320 * Build a list of the contacts to send to.
321 *
322 * @param string $mappingID
323 * Value from the mapping_id field in the civicrm_action_schedule able. It might be a string like
324 * 'contribpage' for an older class like CRM_Contribute_ActionMapping_ByPage of for ones following
325 * more recent patterns, an integer.
326 * @param string $now
327 * @param array $params
328 *
329 * @throws API_Exception
330 * @throws \CRM_Core_Exception
331 */
332 public static function buildRecipientContacts(string $mappingID, $now, $params = []) {
333 $actionSchedule = new CRM_Core_DAO_ActionSchedule();
334
335 $actionSchedule->mapping_id = $mappingID;
336 $actionSchedule->is_active = 1;
337 if (!empty($params)) {
338 _civicrm_api3_dao_set_filter($actionSchedule, $params, FALSE);
339 }
340 $actionSchedule->find();
341
342 while ($actionSchedule->fetch()) {
343 /** @var \Civi\ActionSchedule\Mapping $mapping */
344 $mapping = CRM_Utils_Array::first(self::getMappings([
345 'id' => $mappingID,
346 ]));
347 $builder = new \Civi\ActionSchedule\RecipientBuilder($now, $actionSchedule, $mapping);
348 $builder->build();
349 }
350 }
351
352 /**
353 * Main processing callback for sending out scheduled reminders.
354 *
355 * @param string $now
356 * @param array $params
357 *
358 * @throws \API_Exception
359 * @throws \CRM_Core_Exception
360 */
361 public static function processQueue($now = NULL, $params = []): void {
362 $now = $now ? CRM_Utils_Time::setTime($now) : CRM_Utils_Time::getTime();
363
364 $mappings = CRM_Core_BAO_ActionSchedule::getMappings();
365 foreach ($mappings as $mappingID => $mapping) {
366 CRM_Core_BAO_ActionSchedule::buildRecipientContacts((string) $mappingID, $now, $params);
367 CRM_Core_BAO_ActionSchedule::sendMailings($mappingID, $now);
368 }
369 }
370
371 /**
372 * @param int $id
373 * @param int $mappingID
374 *
375 * @return null|string
376 */
377 public static function isConfigured($id, $mappingID) {
378 $queryString = "SELECT count(id) FROM civicrm_action_schedule
379 WHERE mapping_id = %1 AND
380 entity_value = %2";
381
382 $params = [
383 1 => [$mappingID, 'String'],
384 2 => [$id, 'Integer'],
385 ];
386 return CRM_Core_DAO::singleValueQuery($queryString, $params);
387 }
388
389 /**
390 * @param int $mappingID
391 * @param $recipientType
392 *
393 * @return array
394 */
395 public static function getRecipientListing($mappingID, $recipientType) {
396 if (!$mappingID) {
397 return [];
398 }
399
400 /** @var \Civi\ActionSchedule\Mapping $mapping */
401 $mapping = CRM_Utils_Array::first(CRM_Core_BAO_ActionSchedule::getMappings([
402 'id' => $mappingID,
403 ]));
404 return $mapping->getRecipientListing($recipientType);
405 }
406
407 /**
408 * @param string|null $communication_language
409 * @param string|null $preferred_language
410 * @return string
411 */
412 public static function pickLocale($communication_language, $preferred_language) {
413 $currentLocale = CRM_Core_I18n::getLocale();
414 $language = $currentLocale;
415
416 // prepare the language for the email
417 if ($communication_language == CRM_Core_I18n::AUTO) {
418 if (!empty($preferred_language)) {
419 $language = $preferred_language;
420 }
421 }
422 else {
423 $language = $communication_language;
424 }
425
426 // language not in the existing language, use default
427 $languages = CRM_Core_I18n::languages(TRUE);
428 if (!array_key_exists($language, $languages)) {
429 $language = $currentLocale;
430 }
431
432 // change the language
433 return $language;
434 }
435
436 /**
437 * Save a record about the delivery of a reminder email.
438 *
439 * WISHLIST: Instead of saving $actionSchedule->body_html, call this immediately after
440 * sending the message and pass in the fully rendered text of the message.
441 *
442 * @param object $tokenRow
443 * @param Civi\ActionSchedule\Mapping $mapping
444 * @param int $contactID
445 * @param int $entityID
446 * @param int|null $caseID
447 * @throws CRM_Core_Exception
448 */
449 protected static function createMailingActivity($tokenRow, $mapping, $contactID, $entityID, $caseID) {
450 $session = CRM_Core_Session::singleton();
451
452 if ($mapping->getEntity() == 'civicrm_membership') {
453 // @todo - not required with api
454 $activityTypeID
455 = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Membership Renewal Reminder');
456 }
457 else {
458 // @todo - not required with api
459 $activityTypeID
460 = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Reminder Sent');
461 }
462
463 $activityParams = [
464 'subject' => $tokenRow->render('subject'),
465 'details' => $tokenRow->render('body_html'),
466 'source_contact_id' => $session->get('userID') ? $session->get('userID') : $contactID,
467 'target_contact_id' => $contactID,
468 // @todo - not required with api
469 'activity_date_time' => CRM_Utils_Time::getTime('YmdHis'),
470 // @todo - not required with api
471 'status_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'status_id', 'Completed'),
472 'activity_type_id' => $activityTypeID,
473 'source_record_id' => $entityID,
474 ];
475 // @todo use api, remove all the above wrangling
476 $activity = CRM_Activity_BAO_Activity::create($activityParams);
477
478 //file reminder on case if source activity is a case activity
479 if (!empty($caseID)) {
480 $caseActivityParams = [];
481 $caseActivityParams['case_id'] = $caseID;
482 $caseActivityParams['activity_id'] = $activity->id;
483 CRM_Case_BAO_Case::processCaseActivity($caseActivityParams);
484 }
485 }
486
487 /**
488 * @param \Civi\ActionSchedule\MappingInterface $mapping
489 * @param \CRM_Core_DAO_ActionSchedule $actionSchedule
490 *
491 * @return string
492 */
493 protected static function prepareMailingQuery($mapping, $actionSchedule) {
494 $select = CRM_Utils_SQL_Select::from('civicrm_action_log reminder')
495 ->select("reminder.id as reminderID, reminder.contact_id as contactID, reminder.entity_table as entityTable, reminder.*, e.id AS entityID")
496 ->join('e', "!casMailingJoinType !casMappingEntity e ON !casEntityJoinExpr")
497 ->select("e.id as entityID, e.*")
498 ->where("reminder.action_schedule_id = #casActionScheduleId")
499 ->where("reminder.action_date_time IS NULL")
500 ->param([
501 'casActionScheduleId' => $actionSchedule->id,
502 'casMailingJoinType' => ($actionSchedule->limit_to == 0) ? 'LEFT JOIN' : 'INNER JOIN',
503 'casMappingId' => $mapping->getId(),
504 'casMappingEntity' => $mapping->getEntity(),
505 'casEntityJoinExpr' => 'e.id = IF(reminder.entity_table = "civicrm_contact", reminder.contact_id, reminder.entity_id)',
506 ]);
507
508 if ($actionSchedule->limit_to == 0) {
509 $select->where("e.id = reminder.entity_id OR reminder.entity_table = 'civicrm_contact'");
510 }
511
512 \Civi::dispatcher()
513 ->dispatch(
514 'civi.actionSchedule.prepareMailingQuery',
515 new \Civi\ActionSchedule\Event\MailingQueryEvent($actionSchedule, $mapping, $select)
516 );
517
518 return $select->toSQL();
519 }
520
521 /**
522 * @param \Civi\Token\TokenRow $tokenRow
523 * @param CRM_Core_DAO_ActionSchedule $schedule
524 * @param int $toContactID
525 * @throws CRM_Core_Exception
526 * @return array
527 * List of error messages.
528 */
529 protected static function sendReminderSms($tokenRow, $schedule, $toContactID) {
530 $toPhoneNumber = self::pickSmsPhoneNumber($toContactID);
531 if (!$toPhoneNumber) {
532 return ["sms_phone_missing" => "Couldn't find recipient's phone number."];
533 }
534
535 // dev/core#369 If an SMS provider is deleted then the relevant row in the action_schedule_table is set to NULL
536 // So we need to exclude them.
537 if (CRM_Utils_System::isNull($schedule->sms_provider_id)) {
538 return ["sms_provider_missing" => "SMS reminder cannot be sent because the SMS provider has been deleted."];
539 }
540
541 $messageSubject = $tokenRow->render('subject');
542 $sms_body_text = $tokenRow->render('sms_body_text');
543
544 $session = CRM_Core_Session::singleton();
545 $userID = $session->get('userID') ? $session->get('userID') : $tokenRow->context['contactId'];
546 $smsParams = [
547 'To' => $toPhoneNumber,
548 'provider_id' => $schedule->sms_provider_id,
549 'activity_subject' => $messageSubject,
550 ];
551 $activityTypeID = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'SMS');
552 $activityParams = [
553 'source_contact_id' => $userID,
554 'activity_type_id' => $activityTypeID,
555 'activity_date_time' => date('YmdHis'),
556 'subject' => $messageSubject,
557 'details' => $sms_body_text,
558 'status_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'status_id', 'Completed'),
559 ];
560
561 $activity = CRM_Activity_BAO_Activity::create($activityParams);
562
563 try {
564 CRM_Activity_BAO_Activity::sendSMSMessage($tokenRow->context['contactId'],
565 $sms_body_text,
566 $smsParams,
567 $activity->id,
568 $userID
569 );
570 }
571 catch (CRM_Core_Exception $e) {
572 return ["sms_send_error" => $e->getMessage()];
573 }
574
575 return [];
576 }
577
578 /**
579 * @param CRM_Core_DAO_ActionSchedule $actionSchedule
580 *
581 * @return string
582 * Ex: "Alice <alice@example.org>".
583 * @throws \CRM_Core_Exception
584 */
585 protected static function pickFromEmail($actionSchedule) {
586 $domainValues = CRM_Core_BAO_Domain::getNameAndEmail();
587 $fromEmailAddress = "$domainValues[0] <$domainValues[1]>";
588 if ($actionSchedule->from_email) {
589 $fromEmailAddress = "\"$actionSchedule->from_name\" <$actionSchedule->from_email>";
590 return $fromEmailAddress;
591 }
592 return $fromEmailAddress;
593 }
594
595 /**
596 * @param \Civi\Token\TokenRow $tokenRow
597 * @param CRM_Core_DAO_ActionSchedule $schedule
598 * @param int $toContactID
599 * @return array
600 * List of error messages.
601 */
602 protected static function sendReminderEmail($tokenRow, $schedule, $toContactID): array {
603 $toEmail = CRM_Contact_BAO_Contact::getPrimaryEmail($toContactID, TRUE);
604 if (!$toEmail) {
605 return ["email_missing" => "Couldn't find recipient's email address."];
606 }
607
608 $body_text = $tokenRow->render('body_text');
609 $body_html = $tokenRow->render('body_html');
610 if (!$schedule->body_text) {
611 $body_text = CRM_Utils_String::htmlToText($body_html);
612 }
613
614 // set up the parameters for CRM_Utils_Mail::send
615 $mailParams = [
616 'groupName' => 'Scheduled Reminder Sender',
617 'from' => self::pickFromEmail($schedule),
618 'toName' => $tokenRow->render('toName'),
619 'toEmail' => $toEmail,
620 'subject' => $tokenRow->render('subject'),
621 'entity' => 'action_schedule',
622 'entity_id' => $schedule->id,
623 ];
624
625 $preferredMailFormat = $tokenRow->render('preferred_mail_format');
626 if (!$body_html || $preferredMailFormat === 'Text' || $preferredMailFormat === 'Both'
627 ) {
628 // render the &amp; entities in text mode, so that the links work
629 $mailParams['text'] = str_replace('&amp;', '&', $body_text);
630 }
631 if ($body_html && ($tokenRow->context['contact']['preferred_mail_format'] === 'HTML' ||
632 $tokenRow->context['contact']['preferred_mail_format'] === 'Both'
633 )
634 ) {
635 $mailParams['html'] = $body_html;
636 }
637 $result = CRM_Utils_Mail::send($mailParams);
638 if (!$result) {
639 return ['email_fail' => 'Failed to send message'];
640 }
641
642 return [];
643 }
644
645 /**
646 * @param CRM_Core_DAO_ActionSchedule $schedule
647 * @param \Civi\ActionSchedule\Mapping $mapping
648 * @return \Civi\Token\TokenProcessor
649 */
650 protected static function createTokenProcessor($schedule, $mapping) {
651 $tp = new \Civi\Token\TokenProcessor(\Civi::dispatcher(), [
652 'controller' => __CLASS__,
653 'actionSchedule' => $schedule,
654 'actionMapping' => $mapping,
655 'smarty' => TRUE,
656 ]);
657 $tp->addMessage('body_text', $schedule->body_text, 'text/plain');
658 $tp->addMessage('body_html', $schedule->body_html, 'text/html');
659 $tp->addMessage('sms_body_text', $schedule->sms_body_text, 'text/plain');
660 $tp->addMessage('subject', $schedule->subject, 'text/plain');
661 // These 2 are not 'real' tokens - but it tells the processor to load them.
662 $tp->addMessage('toName', '{contact.display_name}', 'text/plain');
663 $tp->addMessage('preferred_mail_format', '{contact.preferred_mail_format}', 'text/plain');
664
665 return $tp;
666 }
667
668 /**
669 * Pick SMS phone number.
670 *
671 * @param int $smsToContactId
672 *
673 * @return NULL|string
674 */
675 protected static function pickSmsPhoneNumber($smsToContactId) {
676 $toPhoneNumbers = CRM_Core_BAO_Phone::allPhones($smsToContactId, FALSE, 'Mobile', [
677 'is_deceased' => 0,
678 'is_deleted' => 0,
679 'do_not_sms' => 0,
680 ]);
681 //to get primary mobile ph,if not get a first mobile phONE
682 if (!empty($toPhoneNumbers)) {
683 $toPhoneNumberDetails = reset($toPhoneNumbers);
684 $toPhoneNumber = $toPhoneNumberDetails['phone'] ?? NULL;
685 return $toPhoneNumber;
686 }
687 return NULL;
688 }
689
690 /**
691 * Get the list of generic recipient types supported by all entities/mappings.
692 *
693 * @return array
694 * array(mixed $value => string $label).
695 */
696 public static function getAdditionalRecipients(): array {
697 return [
698 'manual' => ts('Choose Recipient(s)'),
699 'group' => ts('Select Group'),
700 ];
701 }
702
703 }