Commit | Line | Data |
---|---|---|
6a488035 TO |
1 | <?php |
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 | /** | |
50bfb460 | 29 | * Address Utilities |
6a488035 TO |
30 | * |
31 | * @package CRM | |
0f03f337 | 32 | * @copyright CiviCRM LLC (c) 2004-2017 |
6a488035 TO |
33 | */ |
34 | class CRM_Utils_Address { | |
35 | ||
36 | /** | |
fe482240 | 37 | * Format an address string from address fields and a format string. |
6a488035 TO |
38 | * |
39 | * Format an address basing on the address fields provided. | |
40 | * Use Setting's address_format if there's no format specified. | |
41 | * | |
77855840 TO |
42 | * @param array $fields |
43 | * The address fields. | |
44 | * @param string $format | |
45 | * The desired address format. | |
46 | * @param bool $microformat | |
47 | * If true indicates, the address to be built in hcard-microformat standard. | |
48 | * @param bool $mailing | |
49 | * If true indicates, the call has been made from mailing label. | |
50 | * @param bool $individualFormat | |
51 | * If true indicates, the call has been made for the contact of type 'individual'. | |
f4aaa82a EM |
52 | * |
53 | * @param null $tokenFields | |
6a488035 | 54 | * |
a6c01b45 CW |
55 | * @return string |
56 | * formatted address string | |
6a488035 | 57 | * |
6a488035 | 58 | */ |
389bcebf | 59 | public static function format( |
6a488035 | 60 | $fields, |
e7292422 TO |
61 | $format = NULL, |
62 | $microformat = FALSE, | |
63 | $mailing = FALSE, | |
6a488035 | 64 | $individualFormat = FALSE, |
e7292422 | 65 | $tokenFields = NULL |
6a488035 TO |
66 | ) { |
67 | static $config = NULL; | |
68 | ||
69 | if (!$format) { | |
aaffa79f | 70 | $format = Civi::settings()->get('address_format'); |
6a488035 TO |
71 | } |
72 | ||
73 | if ($mailing) { | |
aaffa79f | 74 | $format = Civi::settings()->get('mailing_format'); |
6a488035 TO |
75 | } |
76 | ||
77 | $formatted = $format; | |
78 | ||
79 | $fullPostalCode = CRM_Utils_Array::value('postal_code', $fields); | |
80 | if (!empty($fields['postal_code_suffix'])) { | |
81 | $fullPostalCode .= "-$fields[postal_code_suffix]"; | |
82 | } | |
83 | ||
84 | // make sure that some of the fields do have values | |
85 | $emptyFields = array( | |
86 | 'supplemental_address_1', | |
87 | 'supplemental_address_2', | |
207f62c6 | 88 | 'supplemental_address_3', |
6a488035 TO |
89 | 'state_province_name', |
90 | 'county', | |
91 | ); | |
92 | foreach ($emptyFields as $f) { | |
93 | if (!isset($fields[$f])) { | |
94 | $fields[$f] = NULL; | |
95 | } | |
96 | } | |
97 | ||
61ca7d1f | 98 | //CRM-16876 Display countries in all caps when in mailing mode. |
04c56532 SL |
99 | if ($mailing && !empty($fields['country'])) { |
100 | if (Civi::settings()->get('hideCountryMailingLabels')) { | |
101 | $domain = CRM_Core_BAO_Domain::getDomain(); | |
18d6a475 | 102 | $domainLocation = CRM_Core_BAO_Location::getValues(array('contact_id' => $domain->contact_id)); |
04c56532 SL |
103 | $domainAddress = $domainLocation['address'][1]; |
104 | $domainCountryId = $domainAddress['country_id']; | |
105 | if ($fields['country'] == CRM_Core_PseudoConstant::country($domainCountryId)) { | |
106 | $fields['country'] = NULL; | |
107 | } | |
e22e10f5 | 108 | else { |
e8bbf756 | 109 | //Capitalization display on uppercase to contries with special characters |
ed3d77d5 | 110 | $fields['country'] = mb_convert_case($fields['country'], MB_CASE_UPPER, "UTF-8"); |
e22e10f5 | 111 | } |
04c56532 SL |
112 | } |
113 | else { | |
4c733767 | 114 | $fields['country'] = mb_convert_case($fields['country'], MB_CASE_UPPER, "UTF-8"); |
04c56532 SL |
115 | } |
116 | } | |
117 | ||
6a488035 TO |
118 | $contactName = CRM_Utils_Array::value('display_name', $fields); |
119 | if (!$individualFormat) { | |
120 | if (isset($fields['id'])) { | |
121 | $type = CRM_Contact_BAO_Contact::getContactType($fields['id']); | |
122 | } | |
123 | else { | |
124 | $type = 'Individual'; | |
125 | } | |
126 | ||
127 | if ($type == 'Individual') { | |
128 | $contactName = CRM_Utils_Array::value('addressee_display', $fields); | |
129 | } | |
130 | } | |
131 | ||
132 | if (!$microformat) { | |
e7292422 | 133 | // replacements in case of Individual Name Format |
6a488035 TO |
134 | $replacements = array( |
135 | 'contact.display_name' => CRM_Utils_Array::value('display_name', $fields), | |
136 | 'contact.individual_prefix' => CRM_Utils_Array::value('individual_prefix', $fields), | |
e171748b | 137 | 'contact.formal_title' => CRM_Utils_Array::value('formal_title', $fields), |
6a488035 TO |
138 | 'contact.first_name' => CRM_Utils_Array::value('first_name', $fields), |
139 | 'contact.middle_name' => CRM_Utils_Array::value('middle_name', $fields), | |
140 | 'contact.last_name' => CRM_Utils_Array::value('last_name', $fields), | |
141 | 'contact.individual_suffix' => CRM_Utils_Array::value('individual_suffix', $fields), | |
142 | 'contact.address_name' => CRM_Utils_Array::value('address_name', $fields), | |
143 | 'contact.street_address' => CRM_Utils_Array::value('street_address', $fields), | |
144 | 'contact.supplemental_address_1' => CRM_Utils_Array::value('supplemental_address_1', $fields), | |
145 | 'contact.supplemental_address_2' => CRM_Utils_Array::value('supplemental_address_2', $fields), | |
207f62c6 | 146 | 'contact.supplemental_address_3' => CRM_Utils_Array::value('supplemental_address_3', $fields), |
6a488035 TO |
147 | 'contact.city' => CRM_Utils_Array::value('city', $fields), |
148 | 'contact.state_province_name' => CRM_Utils_Array::value('state_province_name', $fields), | |
149 | 'contact.county' => CRM_Utils_Array::value('county', $fields), | |
150 | 'contact.state_province' => CRM_Utils_Array::value('state_province', $fields), | |
151 | 'contact.postal_code' => $fullPostalCode, | |
152 | 'contact.country' => CRM_Utils_Array::value('country', $fields), | |
153 | 'contact.world_region' => CRM_Utils_Array::value('world_region', $fields), | |
154 | 'contact.geo_code_1' => CRM_Utils_Array::value('geo_code_1', $fields), | |
155 | 'contact.geo_code_2' => CRM_Utils_Array::value('geo_code_2', $fields), | |
156 | 'contact.current_employer' => CRM_Utils_Array::value('current_employer', $fields), | |
157 | 'contact.nick_name' => CRM_Utils_Array::value('nick_name', $fields), | |
158 | 'contact.email' => CRM_Utils_Array::value('email', $fields), | |
159 | 'contact.im' => CRM_Utils_Array::value('im', $fields), | |
160 | 'contact.do_not_email' => CRM_Utils_Array::value('do_not_email', $fields), | |
161 | 'contact.do_not_phone' => CRM_Utils_Array::value('do_not_phone', $fields), | |
162 | 'contact.do_not_mail' => CRM_Utils_Array::value('do_not_mail', $fields), | |
163 | 'contact.do_not_sms' => CRM_Utils_Array::value('do_not_sms', $fields), | |
164 | 'contact.do_not_trade' => CRM_Utils_Array::value('do_not_trade', $fields), | |
165 | 'contact.job_title' => CRM_Utils_Array::value('job_title', $fields), | |
166 | 'contact.birth_date' => CRM_Utils_Array::value('birth_date', $fields), | |
167 | 'contact.gender' => CRM_Utils_Array::value('gender', $fields), | |
168 | 'contact.is_opt_out' => CRM_Utils_Array::value('is_opt_out', $fields), | |
6a488035 TO |
169 | 'contact.preferred_mail_format' => CRM_Utils_Array::value('preferred_mail_format', $fields), |
170 | 'contact.phone' => CRM_Utils_Array::value('phone', $fields), | |
171 | 'contact.home_URL' => CRM_Utils_Array::value('home_URL', $fields), | |
172 | 'contact.contact_source' => CRM_Utils_Array::value('contact_source', $fields), | |
173 | 'contact.external_identifier' => CRM_Utils_Array::value('external_identifier', $fields), | |
174 | 'contact.contact_id' => CRM_Utils_Array::value('id', $fields), | |
175 | 'contact.household_name' => CRM_Utils_Array::value('display_name', $fields), | |
176 | 'contact.organization_name' => CRM_Utils_Array::value('display_name', $fields), | |
177 | 'contact.legal_name' => CRM_Utils_Array::value('legal_name', $fields), | |
178 | 'contact.preferred_communication_method' => CRM_Utils_Array::value('preferred_communication_method', $fields), | |
aa62b355 | 179 | 'contact.communication_style' => CRM_Utils_Array::value('communication_style', $fields), |
6a488035 TO |
180 | 'contact.addressee' => CRM_Utils_Array::value('addressee_display', $fields), |
181 | 'contact.email_greeting' => CRM_Utils_Array::value('email_greeting_display', $fields), | |
182 | 'contact.postal_greeting' => CRM_Utils_Array::value('postal_greeting_display', $fields), | |
183 | ); | |
184 | } | |
185 | else { | |
186 | $replacements = array( | |
187 | 'contact.address_name' => "<span class=\"address-name\">" . $fields['address_name'] . "</span>", | |
188 | 'contact.street_address' => "<span class=\"street-address\">" . $fields['street_address'] . "</span>", | |
189 | 'contact.supplemental_address_1' => "<span class=\"extended-address\">" . $fields['supplemental_address_1'] . "</span>", | |
190 | 'contact.supplemental_address_2' => $fields['supplemental_address_2'], | |
207f62c6 | 191 | 'contact.supplemental_address_3' => $fields['supplemental_address_3'], |
6a488035 TO |
192 | 'contact.city' => "<span class=\"locality\">" . $fields['city'] . "</span>", |
193 | 'contact.state_province_name' => "<span class=\"region\">" . $fields['state_province_name'] . "</span>", | |
194 | 'contact.county' => "<span class=\"region\">" . $fields['county'], | |
195 | 'contact.state_province' => "<span class=\"region\">" . $fields['state_province'] . "</span>", | |
196 | 'contact.postal_code' => "<span class=\"postal-code\">" . $fullPostalCode . "</span>", | |
197 | 'contact.country' => "<span class=\"country-name\">" . $fields['country'] . "</span>", | |
198 | 'contact.world_region' => "<span class=\"region\">" . $fields['world_region'] . "</span>", | |
199 | ); | |
200 | ||
201 | // erase all empty ones, so we dont get blank lines | |
202 | foreach (array_keys($replacements) as $key) { | |
203 | $exactKey = substr($key, 0, 8) == 'contact.' ? substr($key, 8) : $key; | |
204 | if ($key != 'contact.postal_code' && | |
205 | CRM_Utils_Array::value($exactKey, $fields) == NULL | |
206 | ) { | |
207 | $replacements[$key] = ''; | |
208 | } | |
209 | } | |
210 | if (empty($fullPostalCode)) { | |
211 | $replacements['contact.postal_code'] = ''; | |
212 | } | |
213 | } | |
214 | ||
215 | // replacements in case of Custom Token | |
216 | if (stristr($formatted, 'custom_')) { | |
217 | $customToken = array_keys($fields); | |
218 | foreach ($customToken as $value) { | |
219 | if (substr($value, 0, 7) == 'custom_') { | |
220 | $replacements["contact.{$value}"] = $fields["{$value}"]; | |
221 | } | |
222 | } | |
223 | } | |
224 | ||
225 | // also sub all token fields | |
226 | if ($tokenFields) { | |
227 | foreach ($tokenFields as $token) { | |
228 | $replacements["{$token}"] = CRM_Utils_Array::value("{$token}", $fields); | |
229 | } | |
230 | } | |
231 | ||
232 | // for every token, replace {fooTOKENbar} with fooVALUEbar if | |
233 | // the value is not empty, otherwise drop the whole {fooTOKENbar} | |
234 | foreach ($replacements as $token => $value) { | |
785374a6 | 235 | if ($value && is_string($value) || is_numeric($value)) { |
6a488035 TO |
236 | $formatted = preg_replace("/{([^{}]*)\b{$token}\b([^{}]*)}/u", "\${1}{$value}\${2}", $formatted); |
237 | } | |
238 | else { | |
239 | $formatted = preg_replace("/{[^{}]*\b{$token}\b[^{}]*}/u", '', $formatted); | |
240 | } | |
241 | } | |
242 | ||
243 | // drop any {...} constructs from lines' ends | |
244 | if (!$microformat) { | |
245 | $formatted = "\n$formatted\n"; | |
246 | } | |
247 | else { | |
248 | if ($microformat == 1) { | |
249 | $formatted = "\n<div class=\"location vcard\"><span class=\"adr\">\n$formatted</span></div>\n"; | |
250 | } | |
251 | else { | |
252 | $formatted = "\n<div class=\"vcard\"><span class=\"adr\">$formatted</span></div>\n"; | |
253 | } | |
254 | } | |
255 | ||
256 | $formatted = preg_replace('/\n{[^{}]*}/u', "\n", $formatted); | |
257 | $formatted = preg_replace('/{[^{}]*}\n/u', "\n", $formatted); | |
258 | ||
259 | // if there are any 'sibling' {...} constructs, replace them with the | |
260 | // contents of the first one; for example, when there's no state_province: | |
261 | // 1. {city}{, }{state_province}{ }{postal_code} | |
262 | // 2. San Francisco{, }{ }12345 | |
263 | // 3. San Francisco, 12345 | |
264 | $formatted = preg_replace('/{([^{}]*)}({[^{}]*})+/u', '\1', $formatted); | |
265 | ||
266 | // drop any remaining curly braces leaving their contents | |
267 | $formatted = str_replace(array('{', '}'), '', $formatted); | |
268 | ||
269 | // drop any empty lines left after the replacements | |
270 | $formatted = preg_replace('/^[ \t]*[\r\n]+/m', '', $formatted); | |
271 | ||
272 | if (!$microformat) { | |
273 | $finalFormatted = $formatted; | |
274 | } | |
275 | else { | |
276 | // remove \n from each line and only add at the end | |
277 | // this hack solves formatting issue, when we convert nl2br | |
353ffa53 TO |
278 | $lines = array(); |
279 | $count = 1; | |
6a488035 TO |
280 | $finalFormatted = NULL; |
281 | $formattedArray = explode("\n", $formatted); | |
282 | $formattedArray = array_filter($formattedArray); | |
283 | ||
284 | foreach ($formattedArray as $line) { | |
285 | $line = trim($line); | |
286 | if ($line) { | |
287 | if ($count > 1 && $count < count($formattedArray)) { | |
288 | $line = "$line\n"; | |
289 | } | |
290 | $finalFormatted .= $line; | |
291 | $count++; | |
292 | } | |
293 | } | |
294 | } | |
295 | return $finalFormatted; | |
296 | } | |
297 | ||
5bc392e6 EM |
298 | /** |
299 | * @param $format | |
300 | * | |
301 | * @return array | |
302 | */ | |
00be9182 | 303 | public static function sequence($format) { |
6a488035 TO |
304 | // also compute and store the address sequence |
305 | $addressSequence = array( | |
306 | 'address_name', | |
307 | 'street_address', | |
308 | 'supplemental_address_1', | |
309 | 'supplemental_address_2', | |
207f62c6 | 310 | 'supplemental_address_3', |
6a488035 TO |
311 | 'city', |
312 | 'county', | |
313 | 'state_province', | |
314 | 'postal_code', | |
315 | 'country', | |
316 | ); | |
317 | ||
318 | // get the field sequence from the format | |
319 | $newSequence = array(); | |
320 | foreach ($addressSequence as $field) { | |
321 | if (substr_count($format, $field)) { | |
322 | $newSequence[strpos($format, $field)] = $field; | |
323 | } | |
324 | } | |
325 | ksort($newSequence); | |
326 | ||
327 | // add the addressSequence fields that are missing in the addressFormat | |
328 | // to the end of the list, so that (for example) if state_province is not | |
329 | // specified in the addressFormat it's still in the address-editing form | |
330 | $newSequence = array_merge($newSequence, $addressSequence); | |
331 | $newSequence = array_unique($newSequence); | |
332 | return $newSequence; | |
333 | } | |
96025800 | 334 | |
d90ab525 SL |
335 | /** |
336 | * Extract the billing fields from the form submission and format them for display. | |
337 | * | |
338 | * @param array $params | |
339 | * @param int $billingLocationTypeID | |
340 | * | |
341 | * @return string | |
342 | */ | |
343 | public static function getFormattedBillingAddressFieldsFromParameters($params, $billingLocationTypeID) { | |
344 | $addressParts = array( | |
345 | "street_address" => "billing_street_address-{$billingLocationTypeID}", | |
346 | "city" => "billing_city-{$billingLocationTypeID}", | |
347 | "postal_code" => "billing_postal_code-{$billingLocationTypeID}", | |
348 | "state_province" => "state_province-{$billingLocationTypeID}", | |
349 | "country" => "country-{$billingLocationTypeID}", | |
350 | ); | |
351 | ||
352 | $addressFields = array(); | |
353 | foreach ($addressParts as $name => $field) { | |
9c86599c | 354 | $value = CRM_Utils_Array::value($field, $params); |
355 | $alternateName = 'billing_' . $name . '_id-' . $billingLocationTypeID; | |
356 | $alternate2 = 'billing_' . $name . '-' . $billingLocationTypeID; | |
357 | if (isset($params[$alternate2]) && !isset($params[$alternateName])) { | |
358 | $alternateName = $alternate2; | |
359 | } | |
dd22a911 | 360 | //Include values which prepend 'billing_' to country and state_province. |
9c86599c | 361 | if (CRM_Utils_Array::value($alternateName, $params)) { |
362 | if (empty($value) || !is_numeric($value)) { | |
363 | $value = $params[$alternateName]; | |
364 | } | |
365 | } | |
1ac900b2 | 366 | if (is_numeric($value) && ($name == 'state_province' || $name == 'country')) { |
9c86599c | 367 | if ($name == 'state_province') { |
368 | $addressFields[$name] = CRM_Core_PseudoConstant::stateProvinceAbbreviation($value); | |
369 | } | |
370 | if ($name == 'country') { | |
371 | $addressFields[$name] = CRM_Core_PseudoConstant::countryIsoCode($value); | |
372 | } | |
373 | } | |
374 | else { | |
375 | $addressFields[$name] = $value; | |
dd22a911 | 376 | } |
d90ab525 SL |
377 | } |
378 | return CRM_Utils_Address::format($addressFields); | |
379 | } | |
380 | ||
6a488035 | 381 | } |