Merge pull request #18997 from eileenmcnaughton/trans
[civicrm-core.git] / CRM / Core / BAO / Email.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 /**
19 * This class contains functions for email handling.
20 */
21 class CRM_Core_BAO_Email extends CRM_Core_DAO_Email {
22
23 /**
24 * Create email address.
25 *
26 * Note that the create function calls 'add' but has more business logic.
27 *
28 * @param array $params
29 * Input parameters.
30 *
31 * @return object
32 */
33 public static function create($params) {
34 CRM_Core_BAO_Block::handlePrimary($params, get_class());
35
36 $hook = empty($params['id']) ? 'create' : 'edit';
37 CRM_Utils_Hook::pre($hook, 'Email', CRM_Utils_Array::value('id', $params), $params);
38
39 $email = new CRM_Core_DAO_Email();
40 $email->copyValues($params);
41 if (!empty($email->email)) {
42 // lower case email field to optimize queries
43 $strtolower = function_exists('mb_strtolower') ? 'mb_strtolower' : 'strtolower';
44 $email->email = $strtolower($email->email);
45 }
46
47 /*
48 * since we're setting bulkmail for 1 of this contact's emails, first reset all their other emails to is_bulkmail false
49 * We shouldn't set the current email to false even though we
50 * are about to reset it to avoid contaminating the changelog if logging is enabled.
51 * (only 1 email address can have is_bulkmail = true)
52 */
53 if ($email->is_bulkmail && !empty($params['contact_id']) && !self::isMultipleBulkMail()) {
54 $sql = "
55 UPDATE civicrm_email
56 SET is_bulkmail = 0
57 WHERE contact_id = {$params['contact_id']}
58 ";
59 if ($hook === 'edit') {
60 $sql .= " AND id <> {$params['id']}";
61 }
62 CRM_Core_DAO::executeQuery($sql);
63 }
64
65 // handle if email is on hold
66 self::holdEmail($email);
67
68 $email->save();
69
70 if ($email->is_primary) {
71 // update the UF user email if that has changed
72 CRM_Core_BAO_UFMatch::updateUFName($email->contact_id);
73 }
74
75 CRM_Utils_Hook::post($hook, 'Email', $email->id, $email);
76 return $email;
77 }
78
79 /**
80 * Takes an associative array and adds email.
81 *
82 * @param array $params
83 * (reference ) an assoc array of name/value pairs.
84 *
85 * @return object
86 * CRM_Core_BAO_Email object on success, null otherwise
87 */
88 public static function add(&$params) {
89 CRM_Core_Error::deprecatedFunctionWarning('apiv4 create');
90 return self::create($params);
91 }
92
93 /**
94 * Given the list of params in the params array, fetch the object
95 * and store the values in the values array
96 *
97 * @param array $entityBlock
98 * Input parameters to find object.
99 *
100 * @return array
101 */
102 public static function getValues($entityBlock) {
103 return CRM_Core_BAO_Block::getValues('email', $entityBlock);
104 }
105
106 /**
107 * Get all the emails for a specified contact_id, with the primary email being first
108 *
109 * @param int $id
110 * The contact id.
111 *
112 * @param bool $updateBlankLocInfo
113 *
114 * @return array
115 * the array of email id's
116 */
117 public static function allEmails($id, $updateBlankLocInfo = FALSE) {
118 if (!$id) {
119 return NULL;
120 }
121
122 $query = "
123 SELECT email,
124 civicrm_location_type.name as locationType,
125 civicrm_email.is_primary as is_primary,
126 civicrm_email.on_hold as on_hold,
127 civicrm_email.id as email_id,
128 civicrm_email.location_type_id as locationTypeId
129 FROM civicrm_contact
130 LEFT JOIN civicrm_email ON ( civicrm_email.contact_id = civicrm_contact.id )
131 LEFT JOIN civicrm_location_type ON ( civicrm_email.location_type_id = civicrm_location_type.id )
132 WHERE civicrm_contact.id = %1
133 ORDER BY civicrm_email.is_primary DESC, email_id ASC ";
134 $params = [
135 1 => [
136 $id,
137 'Integer',
138 ],
139 ];
140
141 $emails = $values = [];
142 $dao = CRM_Core_DAO::executeQuery($query, $params);
143 $count = 1;
144 while ($dao->fetch()) {
145 $values = [
146 'locationType' => $dao->locationType,
147 'is_primary' => $dao->is_primary,
148 'on_hold' => $dao->on_hold,
149 'id' => $dao->email_id,
150 'email' => $dao->email,
151 'locationTypeId' => $dao->locationTypeId,
152 ];
153
154 if ($updateBlankLocInfo) {
155 $emails[$count++] = $values;
156 }
157 else {
158 $emails[$dao->email_id] = $values;
159 }
160 }
161 return $emails;
162 }
163
164 /**
165 * Get all the emails for a specified location_block id, with the primary email being first
166 *
167 * @param array $entityElements
168 * The array containing entity_id and.
169 * entity_table name
170 *
171 * @return array
172 * the array of email id's
173 */
174 public static function allEntityEmails(&$entityElements) {
175 if (empty($entityElements)) {
176 return NULL;
177 }
178
179 $entityId = $entityElements['entity_id'];
180 $entityTable = $entityElements['entity_table'];
181
182 $sql = " SELECT email, ltype.name as locationType, e.is_primary as is_primary, e.on_hold as on_hold,e.id as email_id, e.location_type_id as locationTypeId
183 FROM civicrm_loc_block loc, civicrm_email e, civicrm_location_type ltype, {$entityTable} ev
184 WHERE ev.id = %1
185 AND loc.id = ev.loc_block_id
186 AND e.id IN (loc.email_id, loc.email_2_id)
187 AND ltype.id = e.location_type_id
188 ORDER BY e.is_primary DESC, email_id ASC ";
189
190 $params = [
191 1 => [
192 $entityId,
193 'Integer',
194 ],
195 ];
196
197 $emails = [];
198 $dao = CRM_Core_DAO::executeQuery($sql, $params);
199 while ($dao->fetch()) {
200 $emails[$dao->email_id] = [
201 'locationType' => $dao->locationType,
202 'is_primary' => $dao->is_primary,
203 'on_hold' => $dao->on_hold,
204 'id' => $dao->email_id,
205 'email' => $dao->email,
206 'locationTypeId' => $dao->locationTypeId,
207 ];
208 }
209
210 return $emails;
211 }
212
213 /**
214 * Set / reset hold status for an email
215 *
216 * @param object $email
217 * Email object.
218 */
219 public static function holdEmail(&$email) {
220 if ($email->id && $email->on_hold === NULL) {
221 // email is being updated but no change to on_hold.
222 return;
223 }
224 if ($email->on_hold === 'null' || $email->on_hold === NULL) {
225 // legacy handling, deprecated.
226 $email->on_hold = 0;
227 }
228 $email->on_hold = (int) $email->on_hold;
229
230 //check for update mode
231 if ($email->id) {
232 $params = [1 => [$email->id, 'Integer']];
233 if ($email->on_hold) {
234 $sql = "
235 SELECT id
236 FROM civicrm_email
237 WHERE id = %1
238 AND hold_date IS NULL
239 ";
240 if (CRM_Core_DAO::singleValueQuery($sql, $params)) {
241 $email->hold_date = date('YmdHis');
242 $email->reset_date = 'null';
243 }
244 }
245 elseif ($email->on_hold === 0) {
246 // we do this lookup to see if reset_date should be changed.
247 $sql = "
248 SELECT id
249 FROM civicrm_email
250 WHERE id = %1
251 AND hold_date IS NOT NULL
252 AND reset_date IS NULL
253 ";
254 if (CRM_Core_DAO::singleValueQuery($sql, $params)) {
255 //set reset date only if it is not set and if hold date is set
256 $email->on_hold = FALSE;
257 $email->hold_date = 'null';
258 $email->reset_date = date('YmdHis');
259 }
260 }
261 }
262 else {
263 if ($email->on_hold) {
264 $email->hold_date = date('YmdHis');
265 }
266 }
267 }
268
269 /**
270 * Generate an array of Domain email addresses.
271 * @return array $domainEmails;
272 */
273 public static function domainEmails() {
274 $domainEmails = [];
275 $domainFrom = (array) CRM_Core_OptionGroup::values('from_email_address');
276 foreach (array_keys($domainFrom) as $k) {
277 $domainEmail = $domainFrom[$k];
278 $domainEmails[$domainEmail] = htmlspecialchars($domainEmail);
279 }
280 return $domainEmails;
281 }
282
283 /**
284 * Build From Email as the combination of all the email ids of the logged in user and
285 * the domain email id
286 *
287 * @return array
288 * an array of email ids
289 */
290 public static function getFromEmail() {
291 // add all configured FROM email addresses
292 $fromEmailValues = self::domainEmails();
293
294 if (!Civi::settings()->get('allow_mail_from_logged_in_contact')) {
295 return $fromEmailValues;
296 }
297
298 $contactFromEmails = [];
299 // add logged in user's active email ids
300 $contactID = CRM_Core_Session::getLoggedInContactID();
301 if ($contactID) {
302 $contactEmails = self::allEmails($contactID);
303 $fromDisplayName = CRM_Core_Session::singleton()->getLoggedInContactDisplayName();
304
305 foreach ($contactEmails as $emailId => $emailVal) {
306 $email = trim($emailVal['email']);
307 if (!$email || $emailVal['on_hold']) {
308 continue;
309 }
310 $fromEmail = "$fromDisplayName <$email>";
311 $fromEmailHtml = htmlspecialchars($fromEmail) . ' ' . $emailVal['locationType'];
312
313 if (!empty($emailVal['is_primary'])) {
314 $fromEmailHtml .= ' ' . ts('(preferred)');
315 }
316 $contactFromEmails[$emailId] = $fromEmailHtml;
317 }
318 }
319 return CRM_Utils_Array::crmArrayMerge($contactFromEmails, $fromEmailValues);
320 }
321
322 /**
323 * @return object
324 */
325 public static function isMultipleBulkMail() {
326 return Civi::settings()->get('civimail_multiple_bulk_emails');
327 }
328
329 /**
330 * Call common delete function.
331 *
332 * @param int $id
333 *
334 * @return bool
335 */
336 public static function del($id) {
337 return CRM_Contact_BAO_Contact::deleteObjectWithPrimary('Email', $id);
338 }
339
340 /**
341 * Get filters for entity reference fields.
342 *
343 * @return array
344 */
345 public static function getEntityRefFilters() {
346 $contactFields = CRM_Contact_BAO_Contact::getEntityRefFilters();
347 foreach ($contactFields as $index => &$contactField) {
348 if (!empty($contactField['entity'])) {
349 // For now email_getlist can't parse state, country etc.
350 unset($contactFields[$index]);
351 }
352 elseif ($contactField['key'] !== 'contact_id') {
353 $contactField['entity'] = 'Contact';
354 $contactField['key'] = 'contact_id.' . $contactField['key'];
355 }
356 }
357 return $contactFields;
358 }
359
360 }