Merge pull request #16142 from eileenmcnaughton/deadlock_err
[civicrm-core.git] / CRM / Contact / BAO / Individual.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
bc77d7c0 4 | Copyright CiviCRM LLC. All rights reserved. |
6a488035 5 | |
bc77d7c0
TO
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 |
6a488035 9 +--------------------------------------------------------------------+
d25dd0ee 10 */
6a488035
TO
11
12/**
13 *
14 * @package CRM
ca5cec67 15 * @copyright CiviCRM LLC https://civicrm.org/licensing
6a488035
TO
16 */
17
18/**
67d19299 19 * Class contains functions for individual contact type.
6a488035
TO
20 */
21class CRM_Contact_BAO_Individual extends CRM_Contact_DAO_Contact {
22
23 /**
67d19299 24 * Class constructor.
6a488035 25 */
6ea503d4
TO
26 public function __construct() {
27 }
6a488035
TO
28
29 /**
fe482240 30 * Function is used to format the individual contact values.
6a488035 31 *
77c5b619
TO
32 * @param array $params
33 * (reference ) an assoc array of name/value pairs.
f6b81482 34 * @param CRM_Contact_BAO_Contact $contact
77c5b619 35 * Contact object.
6a488035 36 *
16b10e64 37 * @return CRM_Contact_BAO_Contact
6a488035 38 */
00be9182 39 public static function format(&$params, &$contact) {
6a488035 40 if (!self::dataExists($params)) {
5396af74 41 return NULL;
6a488035
TO
42 }
43
44 // "null" value for example is passed by dedupe merge in order to empty.
45 // Display name computation shouldn't consider such values.
be2fb01f 46 foreach (['first_name', 'middle_name', 'last_name', 'nick_name', 'formal_title', 'birth_date', 'deceased_date'] as $displayField) {
6a488035
TO
47 if (CRM_Utils_Array::value($displayField, $params) == "null") {
48 $params[$displayField] = '';
49 }
50 }
51
353ffa53
TO
52 $sortName = $displayName = '';
53 $firstName = CRM_Utils_Array::value('first_name', $params, '');
6a488035 54 $middleName = CRM_Utils_Array::value('middle_name', $params, '');
353ffa53
TO
55 $lastName = CRM_Utils_Array::value('last_name', $params, '');
56 $nickName = CRM_Utils_Array::value('nick_name', $params, '');
57 $prefix_id = CRM_Utils_Array::value('prefix_id', $params, '');
58 $suffix_id = CRM_Utils_Array::value('suffix_id', $params, '');
e171748b 59 $formalTitle = CRM_Utils_Array::value('formal_title', $params, '');
6a488035
TO
60
61 // get prefix and suffix names
6a488035
TO
62 $prefix = $suffix = NULL;
63 if ($prefix_id) {
874347bd 64 $params['individual_prefix'] = $prefix = CRM_Core_PseudoConstant::getLabel('CRM_Contact_DAO_Contact', 'prefix_id', $prefix_id);
6a488035
TO
65 }
66 if ($suffix_id) {
874347bd 67 $params['individual_suffix'] = $suffix = CRM_Core_PseudoConstant::getLabel('CRM_Contact_DAO_Contact', 'suffix_id', $suffix_id);
6a488035
TO
68 }
69
70 $params['is_deceased'] = CRM_Utils_Array::value('is_deceased', $params, FALSE);
71
72 $individual = NULL;
73 if ($contact->id) {
74 $individual = new CRM_Contact_BAO_Contact();
75 $individual->id = $contact->id;
76 if ($individual->find(TRUE)) {
77
78 //lets allow to update single name field though preserveDBName
79 //but if db having null value and params contain value, CRM-4330.
be2fb01f 80 $useDBNames = [];
6a488035 81
be2fb01f 82 foreach (['last', 'middle', 'first', 'nick'] as $name) {
6a488035
TO
83 $dbName = "{$name}_name";
84 $value = $individual->$dbName;
85
86 // the db has name values
8cc574cf 87 if ($value && !empty($params['preserveDBName'])) {
6a488035
TO
88 $useDBNames[] = $name;
89 }
90 }
91
be2fb01f 92 foreach (['prefix', 'suffix'] as $name) {
6a488035
TO
93 $dbName = "{$name}_id";
94 $value = $individual->$dbName;
8cc574cf 95 if ($value && !empty($params['preserveDBName'])) {
6a488035
TO
96 $useDBNames[] = $name;
97 }
98 }
99
8cc574cf 100 if ($individual->formal_title && !empty($params['preserveDBName'])) {
e171748b
OB
101 $useDBNames[] = 'formal_title';
102 }
103
6a488035
TO
104 // CRM-4430
105 //1. preserve db name if want
106 //2. lets get value from param if exists.
107 //3. if not in params, lets get from db.
108
be2fb01f 109 foreach (['last', 'middle', 'first', 'nick'] as $name) {
6a488035 110 $phpName = "{$name}Name";
353ffa53
TO
111 $dbName = "{$name}_name";
112 $value = $individual->$dbName;
6a488035 113 if (in_array($name, $useDBNames)) {
353ffa53 114 $params[$dbName] = $value;
6a488035 115 $contact->$dbName = $value;
353ffa53 116 $$phpName = $value;
6a488035
TO
117 }
118 elseif (array_key_exists($dbName, $params)) {
119 $$phpName = $params[$dbName];
120 }
121 elseif ($value) {
122 $$phpName = $value;
123 }
124 }
125
be2fb01f 126 foreach (['prefix', 'suffix'] as $name) {
353ffa53 127 $dbName = "{$name}_id";
6a488035
TO
128
129 $value = $individual->$dbName;
130 if (in_array($name, $useDBNames)) {
131 $params[$dbName] = $value;
132 $contact->$dbName = $value;
133 if ($value) {
ec5cc0a3 134 $$name = CRM_Core_PseudoConstant::getLabel('CRM_Contact_DAO_Contact', $dbName, $value);
6a488035
TO
135 }
136 else {
309a09df 137 $$name = NULL;
6a488035
TO
138 }
139 }
140 elseif (array_key_exists($dbName, $params)) {
6a488035
TO
141 // CRM-5278
142 if (!empty($params[$dbName])) {
309a09df 143 $$name = CRM_Core_PseudoConstant::getLabel('CRM_Contact_DAO_Contact', $dbName, $params[$dbName]);
6a488035
TO
144 }
145 }
146 elseif ($value) {
ec5cc0a3 147 $$name = CRM_Core_PseudoConstant::getLabel('CRM_Contact_DAO_Contact', $dbName, $value);
6a488035
TO
148 }
149 }
e171748b
OB
150
151 if (in_array('formal_title', $useDBNames)) {
152 $params['formal_title'] = $individual->formal_title;
353ffa53
TO
153 $contact->formal_title = $individual->formal_title;
154 $formalTitle = $individual->formal_title;
e171748b
OB
155 }
156 elseif (array_key_exists('formal_title', $params)) {
157 $formalTitle = $params['formal_title'];
158 }
159 elseif ($individual->formal_title) {
160 $formalTitle = $individual->formal_title;
161 }
6a488035
TO
162 }
163 }
164
165 //first trim before further processing.
be2fb01f 166 foreach (['lastName', 'firstName', 'middleName'] as $fld) {
6a488035
TO
167 $$fld = trim($$fld);
168 }
169
170 if ($lastName || $firstName || $middleName) {
171 // make sure we have values for all the name fields.
172 $formatted = $params;
be2fb01f 173 $nameParams = [
6a488035
TO
174 'first_name' => $firstName,
175 'middle_name' => $middleName,
176 'last_name' => $lastName,
177 'nick_name' => $nickName,
178 'individual_suffix' => $suffix,
179 'individual_prefix' => $prefix,
180 'prefix_id' => $prefix_id,
181 'suffix_id' => $suffix_id,
e171748b 182 'formal_title' => $formalTitle,
be2fb01f 183 ];
6a488035
TO
184 // make sure we have all the name fields.
185 foreach ($nameParams as $name => $value) {
a7488080 186 if (empty($formatted[$name]) && $value) {
6a488035
TO
187 $formatted[$name] = $value;
188 }
189 }
190
be2fb01f 191 $tokens = [];
6a488035 192 CRM_Utils_Hook::tokens($tokens);
be2fb01f 193 $tokenFields = [];
874347bd 194 foreach ($tokens as $catTokens) {
6a488035
TO
195 foreach ($catTokens as $token => $label) {
196 $tokenFields[] = $token;
197 }
198 }
199
200 //build the sort name.
aaffa79f 201 $format = Civi::settings()->get('sort_name_format');
6a488035 202 $sortName = CRM_Utils_Address::format($formatted, $format,
4c49535e 203 FALSE, FALSE, $tokenFields
6a488035
TO
204 );
205 $sortName = trim($sortName);
206
207 //build the display name.
aaffa79f 208 $format = Civi::settings()->get('display_name_format');
6a488035 209 $displayName = CRM_Utils_Address::format($formatted, $format,
4c49535e 210 FALSE, FALSE, $tokenFields
6a488035
TO
211 );
212 $displayName = trim($displayName);
213 }
214
215 //start further check for email.
216 if (empty($sortName) || empty($displayName)) {
217 $email = NULL;
a7488080 218 if (!empty($params['email']) &&
6a488035
TO
219 is_array($params['email'])
220 ) {
221 foreach ($params['email'] as $emailBlock) {
222 if (isset($emailBlock['is_primary'])) {
223 $email = $emailBlock['email'];
224 break;
225 }
226 }
227 }
228 $uniqId = CRM_Utils_Array::value('user_unique_id', $params);
229 if (!$email && $contact->id) {
230 $email = CRM_Contact_BAO_Contact::getPrimaryEmail($contact->id);
231 }
232 }
233
234 //now set the names.
be2fb01f 235 $names = ['displayName' => 'display_name', 'sortName' => 'sort_name'];
6a488035
TO
236 foreach ($names as $value => $name) {
237 if (empty($$value)) {
238 if ($email) {
239 $$value = $email;
240 }
241 elseif ($uniqId) {
242 $$value = $uniqId;
243 }
c10e7177 244 elseif (!empty($params[$name])) {
245 $$value = $params[$name];
246 }
247 // If we have nothing else going on set sort_name to display_name.
248 elseif ($displayName) {
249 $$value = $displayName;
250 }
6a488035
TO
251 }
252 //finally if we could not pass anything lets keep db.
253 if (!empty($$value)) {
254 $contact->$name = $$value;
255 }
256 }
257
258 $format = CRM_Utils_Date::getDateFormat('birth');
259 if ($date = CRM_Utils_Array::value('birth_date', $params)) {
be2fb01f 260 if (in_array($format, [
353ffa53 261 'dd-mm',
5396af74 262 'mm/dd',
be2fb01f 263 ])) {
6a488035
TO
264 $separator = '/';
265 if ($format == 'dd-mm') {
266 $separator = '-';
267 }
268 $date = $date . $separator . '1902';
269 }
be2fb01f 270 elseif (in_array($format, [
5396af74 271 'yy-mm',
be2fb01f 272 ])) {
6a488035
TO
273 $date = $date . '-01';
274 }
be2fb01f 275 elseif (in_array($format, [
5396af74 276 'M yy',
be2fb01f 277 ])) {
6a488035
TO
278 $date = $date . '-01';
279 }
be2fb01f 280 elseif (in_array($format, [
5396af74 281 'yy',
be2fb01f 282 ])) {
6a488035
TO
283 $date = $date . '-01-01';
284 }
285 $contact->birth_date = CRM_Utils_Date::processDate($date);
286 }
287 elseif ($contact->birth_date) {
288 $contact->birth_date = CRM_Utils_Date::isoToMysql($contact->birth_date);
289 }
290
291 if ($date = CRM_Utils_Array::value('deceased_date', $params)) {
be2fb01f 292 if (in_array($format, [
353ffa53 293 'dd-mm',
5396af74 294 'mm/dd',
be2fb01f 295 ])) {
6a488035
TO
296 $separator = '/';
297 if ($format == 'dd-mm') {
298 $separator = '-';
299 }
300 $date = $date . $separator . '1902';
301 }
be2fb01f 302 elseif (in_array($format, [
5396af74 303 'yy-mm',
be2fb01f 304 ])) {
6a488035
TO
305 $date = $date . '-01';
306 }
be2fb01f 307 elseif (in_array($format, [
5396af74 308 'M yy',
be2fb01f 309 ])) {
6a488035
TO
310 $date = $date . '-01';
311 }
be2fb01f 312 elseif (in_array($format, [
5396af74 313 'yy',
be2fb01f 314 ])) {
6a488035
TO
315 $date = $date . '-01-01';
316 }
317
318 $contact->deceased_date = CRM_Utils_Date::processDate($date);
319 }
320 elseif ($contact->deceased_date) {
321 $contact->deceased_date = CRM_Utils_Date::isoToMysql($contact->deceased_date);
322 }
323
324 if ($middle_name = CRM_Utils_Array::value('middle_name', $params)) {
325 $contact->middle_name = $middle_name;
326 }
327
328 return $contact;
329 }
330
331 /**
67d19299 332 * Regenerates display_name for contacts with given prefixes/suffixes.
6a488035 333 *
77c5b619
TO
334 * @param array $ids
335 * The array with the prefix/suffix id governing which contacts to regenerate.
336 * @param int $action
337 * The action describing whether prefix/suffix was UPDATED or DELETED.
6a488035 338 */
00be9182 339 public static function updateDisplayNames(&$ids, $action) {
6a488035
TO
340 // get the proper field name (prefix_id or suffix_id) and its value
341 $fieldName = '';
342 foreach ($ids as $key => $value) {
343 switch ($key) {
344 case 'individualPrefix':
345 $fieldName = 'prefix_id';
346 $fieldValue = $value;
347 break 2;
348
349 case 'individualSuffix':
350 $fieldName = 'suffix_id';
351 $fieldValue = $value;
352 break 2;
353 }
354 }
355 if ($fieldName == '') {
356 return;
357 }
358
359 // query for the affected individuals
353ffa53
TO
360 $fieldValue = CRM_Utils_Type::escape($fieldValue, 'Integer');
361 $contact = new CRM_Contact_BAO_Contact();
6a488035
TO
362 $contact->$fieldName = $fieldValue;
363 $contact->find();
364
365 // iterate through the affected individuals and rebuild their display_names
366 while ($contact->fetch()) {
367 $contact = new CRM_Contact_BAO_Contact();
368 $contact->id = $contact->contact_id;
369 if ($action == CRM_Core_Action::DELETE) {
370 $contact->$fieldName = 'NULL';
371 $contact->save();
372 }
373 $contact->display_name = $contact->displayName();
374 $contact->save();
375 }
376 }
377
378 /**
fe482240 379 * Creates display name.
6a488035 380 *
a6c01b45
CW
381 * @return string
382 * the constructed display name
6a488035 383 */
00be9182 384 public function displayName() {
e6c4755b
CW
385 $prefix = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'prefix_id');
386 $suffix = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'suffix_id');
6a488035
TO
387 return str_replace(' ', ' ', trim($prefix[$this->prefix_id] . ' ' . $this->first_name . ' ' . $this->middle_name . ' ' . $this->last_name . ' ' . $suffix[$this->suffix_id]));
388 }
389
390 /**
fe482240 391 * Check if there is data to create the object.
6a488035 392 *
77c5b619 393 * @param array $params
6a488035 394 *
5396af74 395 * @return bool
6a488035 396 */
c10e7177 397 public static function dataExists($params) {
6a488035
TO
398 if ($params['contact_type'] == 'Individual') {
399 return TRUE;
400 }
401
402 return FALSE;
403 }
96025800 404
6a488035 405}