3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
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 +--------------------------------------------------------------------+
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
17 class CRM_Mailing_Event_BAO_Forward
extends CRM_Mailing_Event_DAO_Forward
{
20 * Create a new forward event, create a new contact if necessary
25 * @param $forward_email
26 * @param string|null $fromEmail
27 * @param array|null $comment
31 public static function &forward($job_id, $queue_id, $hash, $forward_email, $fromEmail = NULL, $comment = NULL) {
32 $q = CRM_Mailing_Event_BAO_Queue
::verify($job_id, $queue_id, $hash);
34 $successfulForward = FALSE;
37 return $successfulForward;
40 // Find the email address/contact, if it exists.
42 $contact = CRM_Contact_BAO_Contact
::getTableName();
43 $email = CRM_Core_BAO_Email
::getTableName();
44 $queueTable = CRM_Mailing_Event_BAO_Queue
::getTableName();
45 $job = CRM_Mailing_BAO_MailingJob
::getTableName();
47 $dao = new CRM_Core_DAO();
49 SELECT $contact.id as contact_id,
50 $email.id as email_id,
51 $contact.do_not_email as do_not_email,
52 $queueTable.id as queue_id
53 FROM ($email, $job as temp_job)
55 ON $email.contact_id = $contact.id
57 ON $email.id = $queueTable.email_id
59 ON $queueTable.job_id = $job.id
60 AND temp_job.mailing_id = $job.mailing_id
61 WHERE $queueTable.job_id = $job_id
62 AND $email.email = '" .
63 CRM_Utils_Type
::escape($forward_email, 'String') . "'"
68 $transaction = new CRM_Core_Transaction();
70 if (isset($dao->queue_id
) ||
71 (isset($dao->do_not_email
) && $dao->do_not_email
== 1)
73 // We already sent this mailing to $forward_email, or we should
74 // never email this contact. Give up.
76 return $successfulForward;
79 require_once 'api/api.php';
81 'email' => $forward_email,
84 $contactValues = civicrm_api('contact', 'get', $contactParams);
85 $count = $contactValues['count'];
88 // If the contact does not exist, create one.
91 'contact_type' => 'Individual',
94 $locationType = CRM_Core_BAO_LocationType
::getDefault();
96 'email' => $forward_email,
97 'location_type_id' => $locationType->id
,
99 self
::_civicrm_api3_deprecated_add_formatted_param($value, $formatted);
100 $formatted['onDuplicate'] = CRM_Import_Parser
::DUPLICATE_SKIP
;
101 $formatted['fixAddress'] = TRUE;
102 $contact = civicrm_api('contact', 'create', $formatted);
103 if (civicrm_error($contact)) {
104 return $successfulForward;
106 $contact_id = $contact['id'];
108 $email = new CRM_Core_DAO_Email();
109 $email->email
= $forward_email;
111 $email_id = $email->id
;
113 $contact_id = $email->contact_id
;
116 // Create a new queue event.
119 'email_id' => $email_id,
120 'contact_id' => $contact_id,
124 $queue = CRM_Mailing_Event_BAO_Queue
::create($queue_params);
126 $forward = new CRM_Mailing_Event_BAO_Forward();
127 $forward->time_stamp
= date('YmdHis');
128 $forward->event_queue_id
= $queue_id;
129 $forward->dest_queue_id
= $queue->id
;
133 $dao->query(" SELECT $job.mailing_id as mailing_id
136 CRM_Utils_Type
::escape($job_id, 'Integer')
139 $mailing_obj = new CRM_Mailing_BAO_Mailing();
140 $mailing_obj->id
= $dao->mailing_id
;
141 $mailing_obj->find(TRUE);
143 $config = CRM_Core_Config
::singleton();
144 $mailer = \Civi
::service('pear_mail');
148 $message = $mailing_obj->compose($job_id, $queue->id
, $queue->hash
,
149 $queue->contact_id
, $forward_email, $recipient, FALSE, NULL, $attachments, TRUE, $fromEmail
151 //append comment if added while forwarding.
152 if (count($comment)) {
153 $message->_txtbody
= CRM_Utils_Array
::value('body_text', $comment) . $message->_txtbody
;
154 if (!empty($comment['body_html'])) {
155 $message->_htmlbody
= $comment['body_html'] . '<br />---------------Original message---------------------<br />' . $message->_htmlbody
;
159 $body = $message->get();
160 $headers = $message->headers();
163 if (is_object($mailer)) {
164 $errorScope = CRM_Core_TemporaryErrorScope
::ignoreException();
165 $result = $mailer->send($recipient, $headers, $body);
170 'event_queue_id' => $queue->id
,
172 'hash' => $queue->hash
,
174 if (is_a($result, 'PEAR_Error')) {
175 // Register the bounce event.
177 $params = array_merge($params,
178 CRM_Mailing_BAO_BouncePattern
::match($result->getMessage())
180 CRM_Mailing_Event_BAO_Bounce
::create($params);
183 $successfulForward = TRUE;
184 // Register the delivery event.
186 CRM_Mailing_Event_BAO_Delivered
::create($params);
189 $transaction->commit();
191 return $successfulForward;
195 * This function adds the contact variable in $values to the
196 * parameter list $params. For most cases, $values should have length 1. If
197 * the variable being added is a child of Location, a location_type_id must
198 * also be included. If it is a child of phone, a phone_type must be included.
200 * @param array $values
201 * The variable(s) to be added.
202 * @param array $params
203 * The structured parameter list.
205 * @return bool|CRM_Utils_Error
207 protected static function _civicrm_api3_deprecated_add_formatted_param(&$values, &$params) {
208 // @todo - most of this code is UNREACHABLE.
209 // Crawl through the possible classes:
222 // Cache the various object fields
223 static $fields = NULL;
225 if ($fields == NULL) {
229 // first add core contact values since for other Civi modules they are not added
230 require_once 'CRM/Contact/BAO/Contact.php';
231 $contactFields = CRM_Contact_DAO_Contact
::fields();
232 _civicrm_api3_store_values($contactFields, $values, $params);
234 if (isset($values['contact_type'])) {
235 // we're an individual/household/org property
237 $fields[$values['contact_type']] = CRM_Contact_DAO_Contact
::fields();
239 _civicrm_api3_store_values($fields[$values['contact_type']], $values, $params);
243 if (isset($values['individual_prefix'])) {
244 if (!empty($params['prefix_id'])) {
245 $prefixes = CRM_Core_PseudoConstant
::get('CRM_Contact_DAO_Contact', 'prefix_id');
246 $params['prefix'] = $prefixes[$params['prefix_id']];
249 $params['prefix'] = $values['individual_prefix'];
254 if (isset($values['individual_suffix'])) {
255 if (!empty($params['suffix_id'])) {
256 $suffixes = CRM_Core_PseudoConstant
::get('CRM_Contact_DAO_Contact', 'suffix_id');
257 $params['suffix'] = $suffixes[$params['suffix_id']];
260 $params['suffix'] = $values['individual_suffix'];
266 if (isset($values['email_greeting'])) {
267 if (!empty($params['email_greeting_id'])) {
268 $emailGreetingFilter = [
269 'contact_type' => $params['contact_type'] ??
NULL,
270 'greeting_type' => 'email_greeting',
272 $emailGreetings = CRM_Core_PseudoConstant
::greeting($emailGreetingFilter);
273 $params['email_greeting'] = $emailGreetings[$params['email_greeting_id']];
276 $params['email_greeting'] = $values['email_greeting'];
282 if (isset($values['postal_greeting'])) {
283 if (!empty($params['postal_greeting_id'])) {
284 $postalGreetingFilter = [
285 'contact_type' => $params['contact_type'] ??
NULL,
286 'greeting_type' => 'postal_greeting',
288 $postalGreetings = CRM_Core_PseudoConstant
::greeting($postalGreetingFilter);
289 $params['postal_greeting'] = $postalGreetings[$params['postal_greeting_id']];
292 $params['postal_greeting'] = $values['postal_greeting'];
297 if (isset($values['addressee'])) {
298 $params['addressee'] = $values['addressee'];
302 if (isset($values['gender'])) {
303 if (!empty($params['gender_id'])) {
304 $genders = CRM_Core_PseudoConstant
::get('CRM_Contact_DAO_Contact', 'gender_id');
305 $params['gender'] = $genders[$params['gender_id']];
308 $params['gender'] = $values['gender'];
313 if (!empty($values['preferred_communication_method'])) {
315 $pcm = array_change_key_case(array_flip(CRM_Core_PseudoConstant
::get('CRM_Contact_DAO_Contact', 'preferred_communication_method')), CASE_LOWER
);
317 $preffComm = explode(',', $values['preferred_communication_method']);
318 foreach ($preffComm as $v) {
319 $v = strtolower(trim($v));
320 if (array_key_exists($v, $pcm)) {
325 $params['preferred_communication_method'] = $comm;
329 // format the website params.
330 if (!empty($values['url'])) {
331 static $websiteFields;
332 if (!is_array($websiteFields)) {
333 require_once 'CRM/Core/DAO/Website.php';
334 $websiteFields = CRM_Core_DAO_Website
::fields();
336 if (!array_key_exists('website', $params) ||
337 !is_array($params['website'])
339 $params['website'] = [];
342 $websiteCount = count($params['website']);
343 _civicrm_api3_store_values($websiteFields, $values,
344 $params['website'][++
$websiteCount]
350 // get the formatted location blocks into params - w/ 3.0 format, CRM-4605
351 if (!empty($values['location_type_id'])) {
352 static $fields = NULL;
353 if ($fields == NULL) {
357 foreach (['Phone', 'Email', 'IM', 'OpenID', 'Phone_Ext'] as $block) {
358 $name = strtolower($block);
359 if (!array_key_exists($name, $values)) {
363 if ($name === 'phone_ext') {
367 // block present in value array.
368 if (!array_key_exists($name, $params) ||
!is_array($params[$name])) {
372 if (!array_key_exists($block, $fields)) {
373 $className = "CRM_Core_DAO_$block";
374 $fields[$block] =& $className::fields();
377 $blockCnt = count($params[$name]);
379 // copy value to dao field name.
381 $values['name'] = $values[$name];
384 _civicrm_api3_store_values($fields[$block], $values,
385 $params[$name][++
$blockCnt]
388 if (empty($params['id']) && ($blockCnt == 1)) {
389 $params[$name][$blockCnt]['is_primary'] = TRUE;
392 // we only process single block at a time.
396 // handle address fields.
397 if (!array_key_exists('address', $params) ||
!is_array($params['address'])) {
398 $params['address'] = [];
402 foreach ($params['address'] as $cnt => $addressBlock) {
403 if (CRM_Utils_Array
::value('location_type_id', $values) ==
404 CRM_Utils_Array
::value('location_type_id', $addressBlock)
412 if (!array_key_exists('Address', $fields)) {
413 $fields['Address'] = CRM_Core_DAO_Address
::fields();
416 // Note: we doing multiple value formatting here for address custom fields, plus putting into right format.
417 // The actual formatting (like date, country ..etc) for address custom fields is taken care of while saving
418 // the address in CRM_Core_BAO_Address::create method
419 if (!empty($values['location_type_id'])) {
420 static $customFields = [];
421 if (empty($customFields)) {
422 $customFields = CRM_Core_BAO_CustomField
::getFields('Address');
424 // make a copy of values, as we going to make changes
425 $newValues = $values;
426 foreach ($values as $key => $val) {
427 $customFieldID = CRM_Core_BAO_CustomField
::getKeyID($key);
428 if ($customFieldID && array_key_exists($customFieldID, $customFields)) {
429 // mark an entry in fields array since we want the value of custom field to be copied
430 $fields['Address'][$key] = NULL;
432 $htmlType = $customFields[$customFieldID]['html_type'] ??
NULL;
433 if (CRM_Core_BAO_CustomField
::isSerialized($customFields[$customFieldID]) && $val) {
434 $mulValues = explode(',', $val);
435 $customOption = CRM_Core_BAO_CustomOption
::getCustomOption($customFieldID, TRUE);
436 $newValues[$key] = [];
437 foreach ($mulValues as $v1) {
438 foreach ($customOption as $v2) {
439 if ((strtolower($v2['label']) == strtolower(trim($v1))) ||
440 (strtolower($v2['value']) == strtolower(trim($v1)))
442 if ($htmlType == 'CheckBox') {
443 $newValues[$key][$v2['value']] = 1;
446 $newValues[$key][] = $v2['value'];
454 // consider new values
455 $values = $newValues;
458 _civicrm_api3_store_values($fields['Address'], $values, $params['address'][$addressCnt]);
464 'supplemental_address_1',
465 'supplemental_address_2',
466 'supplemental_address_3',
467 'StateProvince.name',
470 foreach ($addressFields as $field) {
471 if (array_key_exists($field, $values)) {
472 if (!array_key_exists('address', $params)) {
473 $params['address'] = [];
475 $params['address'][$addressCnt][$field] = $values[$field];
479 if ($addressCnt == 1) {
481 $params['address'][$addressCnt]['is_primary'] = TRUE;
486 if (isset($values['note'])) {
488 if (!isset($params['note'])) {
489 $params['note'] = [];
491 $noteBlock = count($params['note']) +
1;
493 $params['note'][$noteBlock] = [];
494 if (!isset($fields['Note'])) {
495 $fields['Note'] = CRM_Core_DAO_Note
::fields();
498 // get the current logged in civicrm user
499 $session = CRM_Core_Session
::singleton();
500 $userID = $session->get('userID');
503 $values['contact_id'] = $userID;
506 _civicrm_api3_store_values($fields['Note'], $values, $params['note'][$noteBlock]);
511 // Check for custom field values
513 if (empty($fields['custom'])) {
514 $fields['custom'] = &CRM_Core_BAO_CustomField
::getFields(CRM_Utils_Array
::value('contact_type', $values),
515 FALSE, FALSE, NULL, NULL, FALSE, FALSE, FALSE
519 foreach ($values as $key => $value) {
520 if ($customFieldID = CRM_Core_BAO_CustomField
::getKeyID($key)) {
521 // check if it's a valid custom field id
523 if (!array_key_exists($customFieldID, $fields['custom'])) {
524 return civicrm_api3_create_error('Invalid custom field ID');
527 $params[$key] = $value;
534 * Get row count for the event selector.
536 * @param int $mailing_id
539 * Optional ID of a job to filter on.
540 * @param bool $is_distinct
541 * Group by queue ID?.
544 * Number of rows in result set
546 public static function getTotalCount(
547 $mailing_id, $job_id = NULL,
550 $dao = new CRM_Core_DAO();
552 $forward = self
::getTableName();
553 $queue = CRM_Mailing_Event_BAO_Queue
::getTableName();
554 $mailing = CRM_Mailing_BAO_Mailing
::getTableName();
555 $job = CRM_Mailing_BAO_MailingJob
::getTableName();
558 SELECT COUNT($forward.id) as forward
561 ON $forward.event_queue_id = $queue.id
563 ON $queue.job_id = $job.id
565 ON $job.mailing_id = $mailing.id
567 WHERE $mailing.id = " . CRM_Utils_Type
::escape($mailing_id, 'Integer');
569 if (!empty($job_id)) {
570 $query .= " AND $job.id = " . CRM_Utils_Type
::escape($job_id, 'Integer');
574 $query .= " GROUP BY $queue.id ";
581 return $dao->forward
;
588 * Get rows for the event browser.
590 * @param int $mailing_id
593 * Optional ID of the job.
594 * @param bool $is_distinct
595 * Group by queue id?.
598 * @param int $rowCount
606 public static function &getRows(
607 $mailing_id, $job_id = NULL,
608 $is_distinct = FALSE, $offset = NULL, $rowCount = NULL, $sort = NULL
611 $dao = new CRM_Core_DAO();
613 $forward = self
::getTableName();
614 $queue = CRM_Mailing_Event_BAO_Queue
::getTableName();
615 $mailing = CRM_Mailing_BAO_Mailing
::getTableName();
616 $job = CRM_Mailing_BAO_MailingJob
::getTableName();
617 $contact = CRM_Contact_BAO_Contact
::getTableName();
618 $email = CRM_Core_BAO_Email
::getTableName();
621 SELECT $contact.display_name as from_name,
622 $contact.id as from_id,
623 $email.email as from_email,
624 dest_contact.id as dest_id,
625 dest_email.email as dest_email,
626 $forward.time_stamp as date
629 ON $queue.contact_id = $contact.id
631 ON $queue.email_id = $email.id
633 ON $forward.event_queue_id = $queue.id
634 INNER JOIN $queue as dest_queue
635 ON $forward.dest_queue_id = dest_queue.id
636 INNER JOIN $contact as dest_contact
637 ON dest_queue.contact_id = dest_contact.id
638 INNER JOIN $email as dest_email
639 ON dest_queue.email_id = dest_email.id
641 ON $queue.job_id = $job.id
643 ON $job.mailing_id = $mailing.id
645 WHERE $mailing.id = " . CRM_Utils_Type
::escape($mailing_id, 'Integer');
647 if (!empty($job_id)) {
648 $query .= " AND $job.id = " . CRM_Utils_Type
::escape($job_id, 'Integer');
652 $query .= " GROUP BY $queue.id, dest_contact.id, dest_email.email, $forward.time_stamp ";
655 $orderBy = "$contact.sort_name ASC, {$forward}.time_stamp DESC";
657 if (is_string($sort)) {
658 $sort = CRM_Utils_Type
::escape($sort, 'String');
662 $orderBy = trim($sort->orderBy());
666 $query .= " ORDER BY {$orderBy} ";
668 if ($offset ||
$rowCount) {
669 //Added "||$rowCount" to avoid displaying all records on first page
670 $query .= ' LIMIT ' . CRM_Utils_Type
::escape($offset, 'Integer') . ', ' . CRM_Utils_Type
::escape($rowCount, 'Integer');
677 while ($dao->fetch()) {
678 $from_url = CRM_Utils_System
::url('civicrm/contact/view',
679 "reset=1&cid={$dao->from_id}"
681 $dest_url = CRM_Utils_System
::url('civicrm/contact/view',
682 "reset=1&cid={$dao->dest_id}"
685 'from_name' => "<a href=\"$from_url\">{$dao->from_name}</a>",
686 'from_email' => $dao->from_email
,
687 'dest_email' => "<a href=\"$dest_url\">{$dao->dest_email}</a>",
688 'date' => CRM_Utils_Date
::customFormat($dao->date
),