CRM-21527 - Add default to extra address::create param
[civicrm-core.git] / CRM / Core / BAO / Address.php
CommitLineData
6a488035 1<?php
6a488035
TO
2/*
3 +--------------------------------------------------------------------+
7e9e8871 4 | CiviCRM version 4.7 |
6a488035 5 +--------------------------------------------------------------------+
0f03f337 6 | Copyright CiviCRM LLC (c) 2004-2017 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
d25dd0ee 26 */
6a488035
TO
27
28/**
29 *
30 * @package CRM
0f03f337 31 * @copyright CiviCRM LLC (c) 2004-2017
6a488035
TO
32 */
33
34/**
192d36c5 35 * This is class to handle address related functions.
6a488035
TO
36 */
37class CRM_Core_BAO_Address extends CRM_Core_DAO_Address {
38
39 /**
fe482240 40 * Takes an associative array and creates a address.
6a488035 41 *
6a0b768e
TO
42 * @param array $params
43 * (reference ) an assoc array of name/value pairs.
44 * @param bool $fixAddress
45 * True if you need to fix (format) address values.
6a488035
TO
46 * before inserting in db
47 *
e63aff1c
EM
48 * @param null $entity
49 *
a1a2a83d 50 * @return array|NULL
a6c01b45 51 * array of created address
6a488035 52 */
00be9182 53 public static function create(&$params, $fixAddress = TRUE, $entity = NULL) {
6a488035 54 if (!isset($params['address']) || !is_array($params['address'])) {
a1a2a83d 55 return NULL;
6a488035
TO
56 }
57 CRM_Core_BAO_Block::sortPrimaryFirst($params['address']);
58 $addresses = array();
59 $contactId = NULL;
60
61 $updateBlankLocInfo = CRM_Utils_Array::value('updateBlankLocInfo', $params, FALSE);
62 if (!$entity) {
63 $contactId = $params['contact_id'];
64 //get all the addresses for this contact
85c882c5 65 $addresses = self::allAddress($contactId);
6a488035
TO
66 }
67 else {
68 // get all address from location block
69 $entityElements = array(
70 'entity_table' => $params['entity_table'],
71 'entity_id' => $params['entity_id'],
72 );
73 $addresses = self::allEntityAddress($entityElements);
74 }
75
76 $isPrimary = $isBilling = TRUE;
77 $blocks = array();
78 foreach ($params['address'] as $key => $value) {
79 if (!is_array($value)) {
80 continue;
81 }
82
83 $addressExists = self::dataExists($value);
dfcbddc8 84 if (empty($value['id'])) {
85c882c5 85 if (!empty($addresses) && array_key_exists(CRM_Utils_Array::value('location_type_id', $value), $addresses)) {
86 $value['id'] = $addresses[CRM_Utils_Array::value('location_type_id', $value)];
6a488035
TO
87 }
88 }
89
90 // Note there could be cases when address info already exist ($value[id] is set) for a contact/entity
91 // BUT info is not present at this time, and therefore we should be really careful when deleting the block.
92 // $updateBlankLocInfo will help take appropriate decision. CRM-5969
dfcbddc8 93 if (isset($value['id']) && !$addressExists && $updateBlankLocInfo) {
6a488035
TO
94 //delete the existing record
95 CRM_Core_BAO_Block::blockDelete('Address', array('id' => $value['id']));
96 continue;
97 }
98 elseif (!$addressExists) {
99 continue;
100 }
101
8cc574cf 102 if ($isPrimary && !empty($value['is_primary'])) {
6a488035
TO
103 $isPrimary = FALSE;
104 }
105 else {
106 $value['is_primary'] = 0;
107 }
108
8cc574cf 109 if ($isBilling && !empty($value['is_billing'])) {
6a488035
TO
110 $isBilling = FALSE;
111 }
112 else {
113 $value['is_billing'] = 0;
114 }
115
a7488080 116 if (empty($value['manual_geo_code'])) {
6a488035
TO
117 $value['manual_geo_code'] = 0;
118 }
119 $value['contact_id'] = $contactId;
120 $blocks[] = self::add($value, $fixAddress);
121 }
122
123 return $blocks;
124 }
125
126 /**
fe482240 127 * Takes an associative array and adds address.
6a488035 128 *
6a0b768e
TO
129 * @param array $params
130 * (reference ) an assoc array of name/value pairs.
131 * @param bool $fixAddress
132 * True if you need to fix (format) address values.
6a488035
TO
133 * before inserting in db
134 *
906e6120 135 * @return CRM_Core_BAO_Address|null
6a488035 136 */
be6b584c 137 public static function add(&$params, $fixAddress = FALSE) {
e9ff5391 138
6a488035 139 $address = new CRM_Core_DAO_Address();
e9ff5391 140 $checkPermissions = isset($params['check_permissions']) ? $params['check_permissions'] : TRUE;
6a488035
TO
141
142 // fixAddress mode to be done
143 if ($fixAddress) {
144 CRM_Core_BAO_Address::fixAddress($params);
145 }
146
147 $hook = empty($params['id']) ? 'create' : 'edit';
148 CRM_Utils_Hook::pre($hook, 'Address', CRM_Utils_Array::value('id', $params), $params);
149
150 // if id is set & is_primary isn't we can assume no change
151 if (is_numeric(CRM_Utils_Array::value('is_primary', $params)) || empty($params['id'])) {
152 CRM_Core_BAO_Block::handlePrimary($params, get_class());
153 }
e9ff5391 154
be41af0b 155 // (prevent chaining 1 and 3) CRM-21214
6b60d8a3 156 if (isset($params['master_id']) && !CRM_Utils_System::isNull($params['master_id'])) {
38e60804 157 self::fixSharedAddress($params);
810c57a2
D
158 }
159
6a488035
TO
160 $address->copyValues($params);
161
162 $address->save();
163
164 if ($address->id) {
e9ff5391 165 $customFields = CRM_Core_BAO_CustomField::getFields('Address', FALSE, TRUE, NULL, NULL, FALSE, FALSE, $checkPermissions);
166
6a488035
TO
167 if (!empty($customFields)) {
168 $addressCustom = CRM_Core_BAO_CustomField::postProcess($params,
6a488035
TO
169 $address->id,
170 'Address',
e9ff5391 171 FALSE,
172 $checkPermissions
6a488035
TO
173 );
174 }
175 if (!empty($addressCustom)) {
176 CRM_Core_BAO_CustomValueTable::store($addressCustom, 'civicrm_address', $address->id);
177 }
178
810c57a2
D
179 // call the function to sync shared address and create relationships
180 // if address is already shared, share master_id with all children and update relationships accordingly
38e60804 181 // (prevent chaining 2) CRM-21214
6a488035
TO
182 self::processSharedAddress($address->id, $params);
183
6a488035
TO
184 // lets call the post hook only after we've done all the follow on processing
185 CRM_Utils_Hook::post($hook, 'Address', $address->id, $address);
186 }
187
188 return $address;
189 }
190
191 /**
fe482240 192 * Format the address params to have reasonable values.
6a488035 193 *
6a0b768e
TO
194 * @param array $params
195 * (reference ) an assoc array of name/value pairs.
6a488035 196 */
00be9182 197 public static function fixAddress(&$params) {
a7488080 198 if (!empty($params['billing_street_address'])) {
b44e3f84 199 //Check address is coming from online contribution / registration page
6a488035
TO
200 //Fixed :CRM-5076
201 $billing = array(
202 'street_address' => 'billing_street_address',
203 'city' => 'billing_city',
204 'postal_code' => 'billing_postal_code',
205 'state_province' => 'billing_state_province',
206 'state_province_id' => 'billing_state_province_id',
207 'country' => 'billing_country',
208 'country_id' => 'billing_country_id',
209 );
210
211 foreach ($billing as $key => $val) {
212 if ($value = CRM_Utils_Array::value($val, $params)) {
a7488080 213 if (!empty($params[$key])) {
6a488035
TO
214 unset($params[$val]);
215 }
216 else {
217 //add new key and removed old
218 $params[$key] = $value;
219 unset($params[$val]);
220 }
221 }
222 }
223 }
224
225 /* Split the zip and +4, if it's in US format */
a7488080 226 if (!empty($params['postal_code']) &&
6a488035
TO
227 preg_match('/^(\d{4,5})[+-](\d{4})$/',
228 $params['postal_code'],
229 $match
230 )
231 ) {
232 $params['postal_code'] = $match[1];
233 $params['postal_code_suffix'] = $match[2];
234 }
235
236 // add country id if not set
237 if ((!isset($params['country_id']) || !is_numeric($params['country_id'])) &&
238 isset($params['country'])
239 ) {
240 $country = new CRM_Core_DAO_Country();
241 $country->name = $params['country'];
242 if (!$country->find(TRUE)) {
243 $country->name = NULL;
244 $country->iso_code = $params['country'];
245 $country->find(TRUE);
246 }
247 $params['country_id'] = $country->id;
248 }
249
250 // add state_id if state is set
251 if ((!isset($params['state_province_id']) || !is_numeric($params['state_province_id']))
252 && isset($params['state_province'])
253 ) {
254 if (!empty($params['state_province'])) {
255 $state_province = new CRM_Core_DAO_StateProvince();
256 $state_province->name = $params['state_province'];
257
258 // add country id if present
259 if (!empty($params['country_id'])) {
260 $state_province->country_id = $params['country_id'];
261 }
262
263 if (!$state_province->find(TRUE)) {
264 unset($state_province->name);
265 $state_province->abbreviation = $params['state_province'];
266 $state_province->find(TRUE);
267 }
268 $params['state_province_id'] = $state_province->id;
269 if (empty($params['country_id'])) {
270 // set this here since we have it
271 $params['country_id'] = $state_province->country_id;
272 }
273 }
274 else {
275 $params['state_province_id'] = 'null';
276 }
277 }
278
279 // add county id if county is set
280 // CRM-7837
281 if ((!isset($params['county_id']) || !is_numeric($params['county_id']))
282 && isset($params['county']) && !empty($params['county'])
283 ) {
284 $county = new CRM_Core_DAO_County();
285 $county->name = $params['county'];
286
287 if (isset($params['state_province_id'])) {
288 $county->state_province_id = $params['state_province_id'];
289 }
290
291 if ($county->find(TRUE)) {
292 $params['county_id'] = $county->id;
293 }
294 }
295
296 // currently copy values populates empty fields with the string "null"
297 // and hence need to check for the string null
298 if (isset($params['state_province_id']) &&
299 is_numeric($params['state_province_id']) &&
300 (!isset($params['country_id']) || empty($params['country_id']))
301 ) {
302 // since state id present and country id not present, hence lets populate it
303 // jira issue http://issues.civicrm.org/jira/browse/CRM-56
304 $params['country_id'] = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_StateProvince',
305 $params['state_province_id'],
306 'country_id'
307 );
308 }
309
310 //special check to ignore non numeric values if they are not
311 //detected by formRule(sometimes happens due to internet latency), also allow user to unselect state/country
312 if (isset($params['state_province_id'])) {
313 if (empty($params['state_province_id'])) {
314 $params['state_province_id'] = 'null';
315 }
316 elseif (!is_numeric($params['state_province_id']) ||
317 ((int ) $params['state_province_id'] < 1000)
318 ) {
319 // CRM-3393 ( the hacky 1000 check)
320 $params['state_province_id'] = 'null';
321 }
322 }
323
324 if (isset($params['country_id'])) {
325 if (empty($params['country_id'])) {
326 $params['country_id'] = 'null';
327 }
328 elseif (!is_numeric($params['country_id']) ||
329 ((int ) $params['country_id'] < 1000)
330 ) {
331 // CRM-3393 ( the hacky 1000 check)
332 $params['country_id'] = 'null';
333 }
334 }
335
336 // add state and country names from the ids
337 if (isset($params['state_province_id']) && is_numeric($params['state_province_id'])) {
338 $params['state_province'] = CRM_Core_PseudoConstant::stateProvinceAbbreviation($params['state_province_id']);
339 }
340
341 if (isset($params['country_id']) && is_numeric($params['country_id'])) {
342 $params['country'] = CRM_Core_PseudoConstant::country($params['country_id']);
343 }
344
345 $config = CRM_Core_Config::singleton();
346
aaffa79f 347 $asp = Civi::settings()->get('address_standardization_provider');
6a488035
TO
348 // clean up the address via USPS web services if enabled
349 if ($asp === 'USPS' &&
350 $params['country_id'] == 1228
351 ) {
352 CRM_Utils_Address_USPS::checkAddress($params);
353
354 // do street parsing again if enabled, since street address might have changed
6c552737
TO
355 $parseStreetAddress = CRM_Utils_Array::value(
356 'street_address_parsing',
357 CRM_Core_BAO_Setting::valueOptions(
358 CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
359 'address_options'
360 ),
361 FALSE
362 );
6a488035
TO
363
364 if ($parseStreetAddress && !empty($params['street_address'])) {
365 foreach (array(
353ffa53
TO
366 'street_number',
367 'street_name',
368 'street_unit',
af9b09df 369 'street_number_suffix',
353ffa53 370 ) as $fld) {
6a488035
TO
371 unset($params[$fld]);
372 }
373 // main parse string.
374 $parseString = CRM_Utils_Array::value('street_address', $params);
375 $parsedFields = CRM_Core_BAO_Address::parseStreetAddress($parseString);
376
377 // merge parse address in to main address block.
378 $params = array_merge($params, $parsedFields);
379 }
380 }
381
b48c1467
WDC
382 // check if geocode should be skipped (can be forced with an optional parameter through the api)
383 $skip_geocode = (isset($params['skip_geocode']) && $params['skip_geocode']) ? TRUE : FALSE;
384
6a488035 385 // add latitude and longitude and format address if needed
b48c1467 386 if (!$skip_geocode && !empty($config->geocodeMethod) && ($config->geocodeMethod != 'CRM_Utils_Geocode_OpenStreetMaps') && empty($params['manual_geo_code'])) {
6a488035
TO
387 $class = $config->geocodeMethod;
388 $class::format($params);
389 }
390 }
391
392 /**
fe482240 393 * Check if there is data to create the object.
6a488035 394 *
6a0b768e
TO
395 * @param array $params
396 * (reference ) an assoc array of name/value pairs.
6a488035 397 *
5c766a0b 398 * @return bool
6a488035 399 */
00be9182 400 public static function dataExists(&$params) {
6a488035
TO
401 //check if location type is set if not return false
402 if (!isset($params['location_type_id'])) {
403 return FALSE;
404 }
405
406 $config = CRM_Core_Config::singleton();
407 foreach ($params as $name => $value) {
408 if (in_array($name, array(
353ffa53
TO
409 'is_primary',
410 'location_type_id',
411 'id',
412 'contact_id',
413 'is_billing',
414 'display',
af9b09df 415 'master_id',
353ffa53 416 ))) {
6a488035
TO
417 continue;
418 }
419 elseif (!CRM_Utils_System::isNull($value)) {
420 // name could be country or country id
421 if (substr($name, 0, 7) == 'country') {
422 // make sure its different from the default country
423 // iso code
424 $defaultCountry = $config->defaultContactCountry();
425 // full name
426 $defaultCountryName = $config->defaultContactCountryName();
427
428 if ($defaultCountry) {
429 if ($value == $defaultCountry ||
430 $value == $defaultCountryName ||
431 $value == $config->defaultContactCountry
432 ) {
433 // do nothing
434 }
435 else {
436 return TRUE;
437 }
438 }
439 else {
440 // return if null default
441 return TRUE;
442 }
443 }
444 else {
445 return TRUE;
446 }
447 }
448 }
449
450 return FALSE;
451 }
452
453 /**
454 * Given the list of params in the params array, fetch the object
455 * and store the values in the values array
456 *
6a0b768e
TO
457 * @param array $entityBlock
458 * Associated array of fields.
459 * @param bool $microformat
460 * If microformat output is required.
e63aff1c 461 * @param int|string $fieldName conditional field name
6a488035 462 *
a6c01b45
CW
463 * @return array
464 * array with address fields
6a488035 465 */
00be9182 466 public static function &getValues($entityBlock, $microformat = FALSE, $fieldName = 'contact_id') {
6a488035
TO
467 if (empty($entityBlock)) {
468 return NULL;
469 }
470 $addresses = array();
471 $address = new CRM_Core_BAO_Address();
472
a7488080 473 if (empty($entityBlock['entity_table'])) {
6a488035
TO
474 $address->$fieldName = CRM_Utils_Array::value($fieldName, $entityBlock);
475 }
476 else {
477 $addressIds = array();
478 $addressIds = self::allEntityAddress($entityBlock);
479
480 if (!empty($addressIds[1])) {
481 $address->id = $addressIds[1];
482 }
483 else {
484 return $addresses;
485 }
486 }
001a6635
JV
487 if (isset($entityBlock['is_billing']) && $entityBlock['is_billing'] == 1) {
488 $address->orderBy('is_billing desc, id');
489 }
490 else {
491 //get primary address as a first block.
492 $address->orderBy('is_primary desc, id');
493 }
6a488035
TO
494
495 $address->find();
496
ac44bb1c 497 $locationTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id');
6a488035
TO
498 $count = 1;
499 while ($address->fetch()) {
500 // deprecate reference.
501 if ($count > 1) {
502 foreach (array(
353ffa53
TO
503 'state',
504 'state_name',
505 'country',
af9b09df 506 'world_region',
353ffa53 507 ) as $fld) {
4f99ca55
TO
508 if (isset($address->$fld)) {
509 unset($address->$fld);
2aa397bc 510 }
6a488035
TO
511 }
512 }
513 $stree = $address->street_address;
514 $values = array();
515 CRM_Core_DAO::storeValues($address, $values);
516
517 // add state and country information: CRM-369
ac44bb1c
WA
518 if (!empty($address->location_type_id)) {
519 $values['location_type'] = CRM_Utils_Array::value($address->location_type_id, $locationTypes);
520 }
6a488035
TO
521 if (!empty($address->state_province_id)) {
522 $address->state = CRM_Core_PseudoConstant::stateProvinceAbbreviation($address->state_province_id, FALSE);
523 $address->state_name = CRM_Core_PseudoConstant::stateProvince($address->state_province_id, FALSE);
524 }
525
526 if (!empty($address->country_id)) {
527 $address->country = CRM_Core_PseudoConstant::country($address->country_id);
528
529 //get world region
530 $regionId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Country', $address->country_id, 'region_id');
531
532 $address->world_region = CRM_Core_PseudoConstant::worldregion($regionId);
533 }
534
535 $address->addDisplay($microformat);
536
537 $values['display'] = $address->display;
538 $values['display_text'] = $address->display_text;
539
6b60d8a3 540 if (isset($address->master_id) && !CRM_Utils_System::isNull($address->master_id)) {
6a488035
TO
541 $values['use_shared_address'] = 1;
542 }
543
544 $addresses[$count] = $values;
545
96ca8376
MW
546 //There should never be more than one primary blocks, hence set is_primary = 0 other than first
547 // Calling functions expect the key is_primary to be set, so do not unset it here!
6a488035 548 if ($count > 1) {
96ca8376 549 $addresses[$count]['is_primary'] = 0;
6a488035
TO
550 }
551
552 $count++;
553 }
554
555 return $addresses;
556 }
557
558 /**
192d36c5 559 * Add the formatted address to $this-> display.
6a488035 560 *
2a6da8d7 561 * @param bool $microformat
192d36c5 562 * Unexplained parameter that I've always wondered about.
6a488035 563 */
00be9182 564 public function addDisplay($microformat = FALSE) {
6a488035
TO
565 $fields = array(
566 // added this for CRM 1200
567 'address_id' => $this->id,
568 // CRM-4003
569 'address_name' => str_replace('\ 1', ' ', $this->name),
570 'street_address' => $this->street_address,
571 'supplemental_address_1' => $this->supplemental_address_1,
572 'supplemental_address_2' => $this->supplemental_address_2,
207f62c6 573 'supplemental_address_3' => $this->supplemental_address_3,
6a488035
TO
574 'city' => $this->city,
575 'state_province_name' => isset($this->state_name) ? $this->state_name : "",
576 'state_province' => isset($this->state) ? $this->state : "",
577 'postal_code' => isset($this->postal_code) ? $this->postal_code : "",
578 'postal_code_suffix' => isset($this->postal_code_suffix) ? $this->postal_code_suffix : "",
579 'country' => isset($this->country) ? $this->country : "",
580 'world_region' => isset($this->world_region) ? $this->world_region : "",
581 );
582
583 if (isset($this->county_id) && $this->county_id) {
584 $fields['county'] = CRM_Core_PseudoConstant::county($this->county_id);
585 }
586 else {
587 $fields['county'] = NULL;
588 }
589
590 $this->display = CRM_Utils_Address::format($fields, NULL, $microformat);
591 $this->display_text = CRM_Utils_Address::format($fields);
592 }
593
594 /**
595 * Get all the addresses for a specified contact_id, with the primary address being first
596 *
6a0b768e
TO
597 * @param int $id
598 * The contact id.
6a488035 599 *
dfcbddc8
DG
600 * @param bool $updateBlankLocInfo
601 *
a6c01b45 602 * @return array
dfcbddc8 603 * the array of adrress data
6a488035 604 */
dfcbddc8 605 public static function allAddress($id, $updateBlankLocInfo = FALSE) {
6a488035
TO
606 if (!$id) {
607 return NULL;
608 }
609
610 $query = "
611SELECT civicrm_address.id as address_id, civicrm_address.location_type_id as location_type_id
612FROM civicrm_contact, civicrm_address
613WHERE civicrm_address.contact_id = civicrm_contact.id AND civicrm_contact.id = %1
614ORDER BY civicrm_address.is_primary DESC, address_id ASC";
76034cf5 615 $params = array(1 => array($id, 'Integer'));
dfcbddc8
DG
616
617 $addresses = array();
6a488035 618 $dao = CRM_Core_DAO::executeQuery($query, $params);
dfcbddc8 619 $count = 1;
6a488035 620 while ($dao->fetch()) {
dfcbddc8
DG
621 if ($updateBlankLocInfo) {
622 $addresses[$count++] = $dao->address_id;
623 }
624 else {
625 $addresses[$dao->location_type_id] = $dao->address_id;
626 }
6a488035
TO
627 }
628 return $addresses;
629 }
630
631 /**
632 * Get all the addresses for a specified location_block id, with the primary address being first
633 *
6a0b768e
TO
634 * @param array $entityElements
635 * The array containing entity_id and.
16b10e64 636 * entity_table name
6a488035 637 *
a6c01b45 638 * @return array
dfcbddc8 639 * the array of adrress data
6a488035 640 */
00be9182 641 public static function allEntityAddress(&$entityElements) {
c927c151 642 $addresses = array();
6a488035
TO
643 if (empty($entityElements)) {
644 return $addresses;
645 }
646
647 $entityId = $entityElements['entity_id'];
648 $entityTable = $entityElements['entity_table'];
649
650 $sql = "
dfcbddc8 651SELECT civicrm_address.id as address_id
6a488035
TO
652FROM civicrm_loc_block loc, civicrm_location_type ltype, civicrm_address, {$entityTable} ev
653WHERE ev.id = %1
654 AND loc.id = ev.loc_block_id
655 AND civicrm_address.id IN (loc.address_id, loc.address_2_id)
656 AND ltype.id = civicrm_address.location_type_id
657ORDER BY civicrm_address.is_primary DESC, civicrm_address.location_type_id DESC, address_id ASC ";
658
659 $params = array(1 => array($entityId, 'Integer'));
6a488035 660 $dao = CRM_Core_DAO::executeQuery($sql, $params);
dfcbddc8 661 $locationCount = 1;
6a488035 662 while ($dao->fetch()) {
dfcbddc8
DG
663 $addresses[$locationCount] = $dao->address_id;
664 $locationCount++;
6a488035
TO
665 }
666 return $addresses;
667 }
668
6a488035 669 /**
fe482240 670 * Get address sequence.
6a488035 671 *
a6c01b45 672 * @return array
16b10e64 673 * Array of address sequence.
6a488035 674 */
00be9182 675 public static function addressSequence() {
6a488035
TO
676 $config = CRM_Core_Config::singleton();
677 $addressSequence = $config->addressSequence();
678
679 $countryState = $cityPostal = FALSE;
680 foreach ($addressSequence as $key => $field) {
681 if (
682 in_array($field, array('country', 'state_province')) &&
683 !$countryState
684 ) {
685 $countryState = TRUE;
686 $addressSequence[$key] = 'country_state_province';
687 }
688 elseif (
689 in_array($field, array('city', 'postal_code')) &&
690 !$cityPostal
691 ) {
692 $cityPostal = TRUE;
693 $addressSequence[$key] = 'city_postal_code';
694 }
695 elseif (
353ffa53 696 in_array($field, array('country', 'state_province', 'city', 'postal_code'))
6a488035
TO
697 ) {
698 unset($addressSequence[$key]);
699 }
700 }
701
702 return $addressSequence;
703 }
704
705 /**
706 * Parse given street address string in to street_name,
707 * street_unit, street_number and street_number_suffix
708 * eg "54A Excelsior Ave. Apt 1C", or "917 1/2 Elm Street"
709 *
710 * NB: civic street formats for en_CA and fr_CA used by default if those locales are active
711 * otherwise en_US format is default action
712 *
6c552737
TO
713 * @param string $streetAddress
714 * Street address including number and apt.
715 * @param string $locale
716 * Locale used to parse address.
6a488035 717 *
a6c01b45
CW
718 * @return array
719 * parsed fields values.
6a488035 720 */
00be9182 721 public static function parseStreetAddress($streetAddress, $locale = NULL) {
6a488035
TO
722 $config = CRM_Core_Config::singleton();
723
724 /* locales supported include:
725 * en_US - http://pe.usps.com/cpim/ftp/pubs/pub28/pub28.pdf
726 * en_CA - http://www.canadapost.ca/tools/pg/manual/PGaddress-e.asp
727 * fr_CA - http://www.canadapost.ca/tools/pg/manual/PGaddress-f.asp
728 * NB: common use of comma after street number also supported
729 * default is en_US
730 */
731
732 $supportedLocalesForParsing = array('en_US', 'en_CA', 'fr_CA');
733 if (!$locale) {
734 $locale = $config->lcMessages;
735 }
736 // as different locale explicitly requested but is not available, display warning message and set $locale = 'en_US'
737 if (!in_array($locale, $supportedLocalesForParsing)) {
738 CRM_Core_Session::setStatus(ts('Unsupported locale specified to parseStreetAddress: %1. Proceeding with en_US locale.', array(1 => $locale)), ts('Unsupported Locale'), 'alert');
739 $locale = 'en_US';
740 }
689cecfd 741 $emptyParseFields = $parseFields = array(
6a488035
TO
742 'street_name' => '',
743 'street_unit' => '',
744 'street_number' => '',
745 'street_number_suffix' => '',
746 );
747
748 if (empty($streetAddress)) {
749 return $parseFields;
750 }
751
752 $streetAddress = trim($streetAddress);
753
754 $matches = array();
755 if (in_array($locale, array(
353ffa53 756 'en_CA',
af9b09df 757 'fr_CA',
353ffa53
TO
758 )) && preg_match('/^([A-Za-z0-9]+)[ ]*\-[ ]*/', $streetAddress, $matches)
759 ) {
6a488035
TO
760 $parseFields['street_unit'] = $matches[1];
761 // unset from rest of street address
762 $streetAddress = preg_replace('/^([A-Za-z0-9]+)[ ]*\-[ ]*/', '', $streetAddress);
763 }
764
765 // get street number and suffix.
766 $matches = array();
767 //alter street number/suffix handling so that we accept -digit
768 if (preg_match('/^[A-Za-z0-9]+([\S]+)/', $streetAddress, $matches)) {
769 // check that $matches[0] is numeric, else assume no street number
770 if (preg_match('/^(\d+)/', $matches[0])) {
771 $streetNumAndSuffix = $matches[0];
772
773 // get street number.
774 $matches = array();
775 if (preg_match('/^(\d+)/', $streetNumAndSuffix, $matches)) {
776 $parseFields['street_number'] = $matches[0];
777 $suffix = preg_replace('/^(\d+)/', '', $streetNumAndSuffix);
778 $parseFields['street_number_suffix'] = trim($suffix);
779 }
780
781 // unset from main street address.
782 $streetAddress = preg_replace('/^[A-Za-z0-9]+([\S]+)/', '', $streetAddress);
783 $streetAddress = trim($streetAddress);
784 }
785 }
786 elseif (preg_match('/^(\d+)/', $streetAddress, $matches)) {
787 $parseFields['street_number'] = $matches[0];
788 // unset from main street address.
789 $streetAddress = preg_replace('/^(\d+)/', '', $streetAddress);
790 $streetAddress = trim($streetAddress);
791 }
792
793 // suffix might be like 1/2
794 $matches = array();
795 if (preg_match('/^\d\/\d/', $streetAddress, $matches)) {
796 $parseFields['street_number_suffix'] .= $matches[0];
797
798 // unset from main street address.
799 $streetAddress = preg_replace('/^\d+\/\d+/', '', $streetAddress);
800 $streetAddress = trim($streetAddress);
801 }
802
803 // now get the street unit.
804 // supportable street unit formats.
805 $streetUnitFormats = array(
353ffa53
TO
806 'APT',
807 'APARTMENT',
808 'BSMT',
809 'BASEMENT',
810 'BLDG',
811 'BUILDING',
812 'DEPT',
813 'DEPARTMENT',
814 'FL',
815 'FLOOR',
816 'FRNT',
817 'FRONT',
818 'HNGR',
819 'HANGER',
820 'LBBY',
821 'LOBBY',
822 'LOWR',
823 'LOWER',
824 'OFC',
825 'OFFICE',
826 'PH',
827 'PENTHOUSE',
828 'TRLR',
829 'TRAILER',
830 'UPPR',
831 'RM',
832 'ROOM',
833 'SIDE',
834 'SLIP',
835 'KEY',
836 'LOT',
837 'PIER',
838 'REAR',
839 'SPC',
840 'SPACE',
841 'STOP',
842 'STE',
843 'SUITE',
844 'UNIT',
845 '#',
6a488035
TO
846 );
847
848 // overwriting $streetUnitFormats for 'en_CA' and 'fr_CA' locale
849 if (in_array($locale, array(
353ffa53 850 'en_CA',
af9b09df 851 'fr_CA',
353ffa53 852 ))) {
6a488035
TO
853 $streetUnitFormats = array('APT', 'APP', 'SUITE', 'BUREAU', 'UNIT');
854 }
689cecfd
EM
855 //@todo per CRM-14459 this regex picks up words with the string in them - e.g APT picks up
856 //Captain - presuming fixing regex (& adding test) to ensure a-z does not preced string will fix
6a488035
TO
857 $streetUnitPreg = '/(' . implode('|\s', $streetUnitFormats) . ')(.+)?/i';
858 $matches = array();
859 if (preg_match($streetUnitPreg, $streetAddress, $matches)) {
860 $parseFields['street_unit'] = trim($matches[0]);
861 $streetAddress = str_replace($matches[0], '', $streetAddress);
862 $streetAddress = trim($streetAddress);
863 }
864
865 // consider remaining string as street name.
866 $parseFields['street_name'] = $streetAddress;
867
868 //run parsed fields through stripSpaces to clean
869 foreach ($parseFields as $parseField => $value) {
870 $parseFields[$parseField] = CRM_Utils_String::stripSpaces($value);
871 }
689cecfd
EM
872 //CRM-14459 if the field is too long we should assume it didn't get it right & skip rather than allow
873 // the DB to fatal
874 $fields = CRM_Core_BAO_Address::fields();
875 foreach ($fields as $fieldname => $field) {
22e263ad 876 if (!empty($field['maxlength']) && strlen(CRM_Utils_Array::value($fieldname, $parseFields)) > $field['maxlength']) {
689cecfd
EM
877 return $emptyParseFields;
878 }
879 }
6a488035
TO
880
881 return $parseFields;
882 }
883
884 /**
eceb18cc 885 * Validate the address fields based on the address options enabled.
6a488035
TO
886 * in the Address Settings
887 *
6a0b768e
TO
888 * @param array $fields
889 * An array of importable/exportable contact fields.
6a488035 890 *
a6c01b45
CW
891 * @return array
892 * an array of contact fields and only the enabled address options
6a488035 893 */
00be9182 894 public static function validateAddressOptions($fields) {
6a488035
TO
895 static $addressOptions = NULL;
896 if (!$addressOptions) {
6c552737
TO
897 $addressOptions = CRM_Core_BAO_Setting::valueOptions(
898 CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
899 'address_options'
900 );
6a488035
TO
901 }
902
903 if (is_array($fields) && !empty($fields)) {
904 foreach ($addressOptions as $key => $value) {
905 if (!$value && isset($fields[$key])) {
906 unset($fields[$key]);
907 }
908 }
909 }
910 return $fields;
911 }
912
913 /**
fe482240 914 * Check if current address is used by any other contacts.
6a488035 915 *
6a0b768e
TO
916 * @param int $addressId
917 * Address id.
6a488035 918 *
72b3a70c
CW
919 * @return int
920 * count of contacts that use this shared address
6a488035 921 */
00be9182 922 public static function checkContactSharedAddress($addressId) {
6a488035
TO
923 $query = 'SELECT count(id) FROM civicrm_address WHERE master_id = %1';
924 return CRM_Core_DAO::singleValueQuery($query, array(1 => array($addressId, 'Integer')));
925 }
926
927 /**
fe482240 928 * Check if current address fields are shared with any other address.
6a488035 929 *
6a0b768e
TO
930 * @param array $fields
931 * Address fields in profile.
932 * @param int $contactId
933 * Contact id.
6a488035 934 *
6a488035 935 */
00be9182 936 public static function checkContactSharedAddressFields(&$fields, $contactId) {
6a488035
TO
937 if (!$contactId || !is_array($fields) || empty($fields)) {
938 return;
939 }
940
941 $sharedLocations = array();
942
943 $query = "
944SELECT is_primary,
945 location_type_id
946 FROM civicrm_address
947 WHERE contact_id = %1
948 AND master_id IS NOT NULL";
949
950 $dao = CRM_Core_DAO::executeQuery($query, array(1 => array($contactId, 'Positive')));
951 while ($dao->fetch()) {
952 $sharedLocations[$dao->location_type_id] = $dao->location_type_id;
953 if ($dao->is_primary) {
954 $sharedLocations['Primary'] = 'Primary';
955 }
956 }
957
958 //no need to process further.
959 if (empty($sharedLocations)) {
960 return;
961 }
962
963 $addressFields = array(
964 'city',
965 'county',
966 'country',
967 'geo_code_1',
968 'geo_code_2',
969 'postal_code',
970 'address_name',
971 'state_province',
972 'street_address',
973 'postal_code_suffix',
974 'supplemental_address_1',
975 'supplemental_address_2',
207f62c6 976 'supplemental_address_3',
6a488035
TO
977 );
978
979 foreach ($fields as $name => & $values) {
980 if (!is_array($values) || empty($values)) {
981 continue;
982 }
983
984 $nameVal = explode('-', $values['name']);
985 $fldName = CRM_Utils_Array::value(0, $nameVal);
986 $locType = CRM_Utils_Array::value(1, $nameVal);
a7488080 987 if (!empty($values['location_type_id'])) {
6a488035
TO
988 $locType = $values['location_type_id'];
989 }
990
991 if (in_array($fldName, $addressFields) &&
992 in_array($locType, $sharedLocations)
993 ) {
994 $values['is_shared'] = TRUE;
995 }
996 }
997 }
998
38e60804
D
999 /**
1000 * Fix the shared address if address is already shared
1001 * or if address will be shared with itself.
1002 *
1003 * @param array $params
1004 * Associated array of address params.
1005 */
1006 public static function fixSharedAddress(&$params) {
be41af0b
D
1007 // if address master address is shared, use its master (prevent chaining 1) CRM-21214
1008 $masterMasterId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Address', $params['master_id'], 'master_id');
1009 if ($masterMasterId > 0) {
1010 $params['master_id'] = $masterMasterId;
38e60804
D
1011 }
1012
be41af0b
D
1013 // prevent an endless chain between two shared addresses (prevent chaining 3) CRM-21214
1014 if (CRM_Utils_Array::value('id', $params) == $params['master_id']) {
68499476 1015 $params['master_id'] = NULL;
38e60804
D
1016 CRM_Core_Session::setStatus(ts("You can't connect an address to itself"), '', 'warning');
1017 }
1018 }
01853fc8 1019
6a488035 1020 /**
fe482240 1021 * Update the shared addresses if master address is modified.
6a488035 1022 *
6a0b768e
TO
1023 * @param int $addressId
1024 * Address id.
1025 * @param array $params
1026 * Associated array of address params.
6a488035 1027 */
00be9182 1028 public static function processSharedAddress($addressId, $params) {
810c57a2 1029 $query = 'SELECT id, contact_id FROM civicrm_address WHERE master_id = %1';
6a488035
TO
1030 $dao = CRM_Core_DAO::executeQuery($query, array(1 => array($addressId, 'Integer')));
1031
1032 // unset contact id
810c57a2 1033 $skipFields = array('is_primary', 'location_type_id', 'is_billing', 'contact_id');
6b60d8a3 1034 if (isset($params['master_id']) && !CRM_Utils_System::isNull($params['master_id'])) {
be41af0b 1035 // call the function to create a relationship for the new shared address
810c57a2 1036 self::processSharedAddressRelationship($params['master_id'], $params['contact_id']);
8156e86b
D
1037 }
1038 else {
be41af0b 1039 // else no new shares will be created, only update shared addresses
810c57a2
D
1040 $skipFields[] = 'master_id';
1041 }
6a488035
TO
1042 foreach ($skipFields as $value) {
1043 unset($params[$value]);
1044 }
1045
1046 $addressDAO = new CRM_Core_DAO_Address();
1047 while ($dao->fetch()) {
b18c70b3 1048 // call the function to update the relationship
6b60d8a3 1049 if (isset($params['master_id']) && !CRM_Utils_System::isNull($params['master_id'])) {
810c57a2
D
1050 self::processSharedAddressRelationship($params['master_id'], $dao->contact_id);
1051 }
6a488035
TO
1052 $addressDAO->copyValues($params);
1053 $addressDAO->id = $dao->id;
1054 $addressDAO->save();
1055 $addressDAO->free();
1056 }
1057 }
1058
8bdfc216 1059 /**
fe482240 1060 * Merge contacts with the Same address to get one shared label.
6a0b768e
TO
1061 * @param array $rows
1062 * Array[contact_id][contactDetails].
8bdfc216 1063 */
1064 public static function mergeSameAddress(&$rows) {
1065 $uniqueAddress = array();
1066 foreach (array_keys($rows) as $rowID) {
1067 // load complete address as array key
6c552737
TO
1068 $address = trim($rows[$rowID]['street_address'])
1069 . trim($rows[$rowID]['city'])
1070 . trim($rows[$rowID]['state_province'])
1071 . trim($rows[$rowID]['postal_code'])
1072 . trim($rows[$rowID]['country']);
8bdfc216 1073 if (isset($rows[$rowID]['last_name'])) {
1074 $name = $rows[$rowID]['last_name'];
1075 }
1076 else {
1077 $name = $rows[$rowID]['display_name'];
1078 }
1079
1080 // CRM-15120
1081 $formatted = array(
1082 'first_name' => $rows[$rowID]['first_name'],
21dfd5f5 1083 'individual_prefix' => $rows[$rowID]['individual_prefix'],
8bdfc216 1084 );
aaffa79f 1085 $format = Civi::settings()->get('display_name_format');
8bdfc216 1086 $firstNameWithPrefix = CRM_Utils_Address::format($formatted, $format, FALSE, FALSE, TRUE);
1087 $firstNameWithPrefix = trim($firstNameWithPrefix);
1088
1089 // fill uniqueAddress array with last/first name tree
1090 if (isset($uniqueAddress[$address])) {
1091 $uniqueAddress[$address]['names'][$name][$firstNameWithPrefix]['first_name'] = $rows[$rowID]['first_name'];
1092 $uniqueAddress[$address]['names'][$name][$firstNameWithPrefix]['addressee_display'] = $rows[$rowID]['addressee_display'];
1093 // drop unnecessary rows
1094 unset($rows[$rowID]);
1095 // this is the first listing at this address
1096 }
1097 else {
1098 $uniqueAddress[$address]['ID'] = $rowID;
1099 $uniqueAddress[$address]['names'][$name][$firstNameWithPrefix]['first_name'] = $rows[$rowID]['first_name'];
1100 $uniqueAddress[$address]['names'][$name][$firstNameWithPrefix]['addressee_display'] = $rows[$rowID]['addressee_display'];
1101 }
1102 }
1103 foreach ($uniqueAddress as $address => $data) {
1104 // copy data back to $rows
1105 $count = 0;
1106 // one last name list per row
1107 foreach ($data['names'] as $last_name => $first_names) {
1108 // too many to list
1109 if ($count > 2) {
1110 break;
1111 }
9b873358 1112 if (count($first_names) == 1) {
2aa397bc
TO
1113 $family = $first_names[current(array_keys($first_names))]['addressee_display'];
1114 }
1115 else {
1116 // collapse the tree to summarize
1117 $family = trim(implode(" & ", array_keys($first_names)) . " " . $last_name);
1118 }
1119 if ($count) {
1120 $processedNames .= "\n" . $family;
1121 }
1122 else {
1123 // build display_name string
1124 $processedNames = $family;
1125 }
8bdfc216 1126 $count++;
1127 }
1128 $rows[$data['ID']]['addressee'] = $rows[$data['ID']]['addressee_display'] = $rows[$data['ID']]['display_name'] = $processedNames;
1129 }
1130 }
1131
6a488035 1132 /**
fe482240 1133 * Create relationship between contacts who share an address.
6a488035 1134 *
810c57a2
D
1135 * Note that currently we create relationship between
1136 * Individual + Household and Individual + Organization
6a488035 1137 *
6a0b768e
TO
1138 * @param int $masterAddressId
1139 * Master address id.
810c57a2
D
1140 * @param int $currentContactId
1141 * Current contact id.
6a488035 1142 */
810c57a2 1143 public static function processSharedAddressRelationship($masterAddressId, $currentContactId) {
6a488035 1144 // get the contact type of contact being edited / created
810c57a2 1145 $currentContactType = CRM_Contact_BAO_Contact::getContactType($currentContactId);
6a488035
TO
1146
1147 // if current contact is not of type individual return
1148 if ($currentContactType != 'Individual') {
1149 return;
1150 }
1151
1152 // get the contact id and contact type of shared contact
1153 // check the contact type of shared contact, return if it is of type Individual
6a488035
TO
1154 $query = 'SELECT cc.id, cc.contact_type
1155 FROM civicrm_contact cc INNER JOIN civicrm_address ca ON cc.id = ca.contact_id
1156 WHERE ca.id = %1';
1157
1158 $dao = CRM_Core_DAO::executeQuery($query, array(1 => array($masterAddressId, 'Integer')));
6a488035
TO
1159 $dao->fetch();
1160
810c57a2 1161 // master address contact needs to be Household or Organization, otherwise return
6a488035
TO
1162 if ($dao->contact_type == 'Individual') {
1163 return;
1164 }
1165 $sharedContactType = $dao->contact_type;
1166 $sharedContactId = $dao->id;
1167
1168 // create relationship between ontacts who share an address
1169 if ($sharedContactType == 'Organization') {
1170 return CRM_Contact_BAO_Contact_Utils::createCurrentEmployerRelationship($currentContactId, $sharedContactId);
1171 }
6a488035 1172
82ffeed5 1173 // get the relationship type id of "Household Member of"
1174 $relTypeId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_RelationshipType', 'Household Member of', 'id', 'name_a_b');
6a488035
TO
1175
1176 if (!$relTypeId) {
82ffeed5 1177 CRM_Core_Error::fatal(ts("You seem to have deleted the relationship type 'Household Member of'"));
1178 }
1179
1180 $relParam = array(
1181 'is_active' => TRUE,
1182 'relationship_type_id' => $relTypeId,
1183 'contact_id_a' => $currentContactId,
1184 'contact_id_b' => $sharedContactId,
1185 );
1186
1187 // If already there is a relationship record of $relParam criteria, avoid creating relationship again or else
1188 // it will casue CRM-16588 as the Duplicate Relationship Exception will revert other contact field values on update
9272d8b5 1189 if (CRM_Contact_BAO_Relationship::checkDuplicateRelationship($relParam, $currentContactId, $sharedContactId)) {
82ffeed5 1190 return;
6a488035
TO
1191 }
1192
a7ef8c9d
EM
1193 try {
1194 // create relationship
82ffeed5 1195 civicrm_api3('relationship', 'create', $relParam);
a7ef8c9d
EM
1196 }
1197 catch (CiviCRM_API3_Exception $e) {
1198 // We catch and ignore here because this has historically been a best-effort relationship create call.
1199 // presumably it could refuse due to duplication or similar and we would ignore that.
1200 }
6a488035
TO
1201 }
1202
1203 /**
fe482240 1204 * Check and set the status for shared address delete.
6a488035 1205 *
6a0b768e
TO
1206 * @param int $addressId
1207 * Address id.
1208 * @param int $contactId
1209 * Contact id.
1210 * @param bool $returnStatus
1211 * By default false.
6a488035 1212 *
a6c01b45 1213 * @return string
6a488035 1214 */
00be9182 1215 public static function setSharedAddressDeleteStatus($addressId = NULL, $contactId = NULL, $returnStatus = FALSE) {
6a488035
TO
1216 // check if address that is being deleted has any shared
1217 if ($addressId) {
1218 $entityId = $addressId;
1219 $query = 'SELECT cc.id, cc.display_name
1220 FROM civicrm_contact cc INNER JOIN civicrm_address ca ON cc.id = ca.contact_id
1221 WHERE ca.master_id = %1';
1222 }
1223 else {
1224 $entityId = $contactId;
1225 $query = 'SELECT cc.id, cc.display_name
1226 FROM civicrm_address ca1
1227 INNER JOIN civicrm_address ca2 ON ca1.id = ca2.master_id
1228 INNER JOIN civicrm_contact cc ON ca2.contact_id = cc.id
1229 WHERE ca1.contact_id = %1';
1230 }
1231
1232 $dao = CRM_Core_DAO::executeQuery($query, array(1 => array($entityId, 'Integer')));
1233
1234 $deleteStatus = array();
1235 $sharedContactList = array();
1236 $statusMessage = NULL;
1237 $addressCount = 0;
1238 while ($dao->fetch()) {
1239 if (empty($deleteStatus)) {
1240 $deleteStatus[] = ts('The following contact(s) have address records which were shared with the address you removed from this contact. These address records are no longer shared - but they have not been removed or altered.');
1241 }
1242
1243 $contactViewUrl = CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$dao->id}");
1244 $sharedContactList[] = "<a href='{$contactViewUrl}'>{$dao->display_name}</a>";
1245 $deleteStatus[] = "<a href='{$contactViewUrl}'>{$dao->display_name}</a>";
1246
1247 $addressCount++;
1248 }
1249
1250 if (!empty($deleteStatus)) {
1251 $statusMessage = implode('<br/>', $deleteStatus) . '<br/>';
1252 }
1253
1254 if (!$returnStatus) {
1255 CRM_Core_Session::setStatus($statusMessage, '', 'info');
1256 }
1257 else {
1258 return array(
1259 'contactList' => $sharedContactList,
1260 'count' => $addressCount,
1261 );
1262 }
1263 }
12445e1c
CW
1264
1265 /**
fe482240 1266 * Call common delete function.
ad37ac8e 1267 *
1268 * @param int $id
1269 *
1270 * @return bool
12445e1c 1271 */
00be9182 1272 public static function del($id) {
a65e2e55 1273 return CRM_Contact_BAO_Contact::deleteObjectWithPrimary('Address', $id);
12445e1c 1274 }
dc86f881
CW
1275
1276 /**
1277 * Get options for a given address field.
1278 * @see CRM_Core_DAO::buildOptions
1279 *
1280 * TODO: Should we always assume chainselect? What fn should be responsible for controlling that flow?
1281 * TODO: In context of chainselect, what to return if e.g. a country has no states?
1282 *
6a0b768e
TO
1283 * @param string $fieldName
1284 * @param string $context
a1a2a83d 1285 * @see CRM_Core_DAO::buildOptionsContext
6a0b768e 1286 * @param array $props
16b10e64 1287 * whatever is known about this dao object.
77b97be7 1288 *
5c766a0b 1289 * @return array|bool
dc86f881
CW
1290 */
1291 public static function buildOptions($fieldName, $context = NULL, $props = array()) {
1292 $params = array();
1293 // Special logic for fields whose options depend on context or properties
1294 switch ($fieldName) {
1295 // Filter state_province list based on chosen country or site defaults
1296 case 'state_province_id':
d0bfb983 1297 case 'state_province_name':
1298 case 'state_province':
1299 // change $fieldName to DB specific names.
1300 $fieldName = 'state_province_id';
dc86f881
CW
1301 if (empty($props['country_id'])) {
1302 $config = CRM_Core_Config::singleton();
1303 if (!empty($config->provinceLimit)) {
1304 $props['country_id'] = $config->provinceLimit;
1305 }
1306 else {
1307 $props['country_id'] = $config->defaultContactCountry;
1308 }
1309 }
578d346d 1310 if (!empty($props['country_id']) && $context !== 'validate') {
dc86f881
CW
1311 $params['condition'] = 'country_id IN (' . implode(',', (array) $props['country_id']) . ')';
1312 }
1313 break;
2aa397bc 1314
dc86f881
CW
1315 // Filter country list based on site defaults
1316 case 'country_id':
d0bfb983 1317 case 'country':
1318 // change $fieldName to DB specific names.
1319 $fieldName = 'country_id';
786ad6e1
CW
1320 if ($context != 'get' && $context != 'validate') {
1321 $config = CRM_Core_Config::singleton();
1322 if (!empty($config->countryLimit) && is_array($config->countryLimit)) {
1323 $params['condition'] = 'id IN (' . implode(',', $config->countryLimit) . ')';
1324 }
dc86f881
CW
1325 }
1326 break;
2aa397bc 1327
dc86f881
CW
1328 // Filter county list based on chosen state
1329 case 'county_id':
1330 if (!empty($props['state_province_id'])) {
1331 $params['condition'] = 'state_province_id IN (' . implode(',', (array) $props['state_province_id']) . ')';
1332 }
1333 break;
2aa397bc 1334
c7130c3e
CW
1335 // Not a real field in this entity
1336 case 'world_region':
3493947a 1337 case 'worldregion':
1338 case 'worldregion_id':
c7130c3e 1339 return CRM_Core_PseudoConstant::worldRegion();
dc86f881 1340 }
786ad6e1 1341 return CRM_Core_PseudoConstant::get(__CLASS__, $fieldName, $params, $context);
dc86f881 1342 }
96025800 1343
a7488080 1344}