Commit | Line | Data |
---|---|---|
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 | /** | |
50bfb460 | 13 | * Address Utilities |
6a488035 TO |
14 | * |
15 | * @package CRM | |
ca5cec67 | 16 | * @copyright CiviCRM LLC https://civicrm.org/licensing |
6a488035 TO |
17 | */ |
18 | class CRM_Utils_Address { | |
19 | ||
20 | /** | |
fe482240 | 21 | * Format an address string from address fields and a format string. |
6a488035 TO |
22 | * |
23 | * Format an address basing on the address fields provided. | |
24 | * Use Setting's address_format if there's no format specified. | |
25 | * | |
4c49535e J |
26 | * This function is also used to generate a contact's display_name and |
27 | * sort_name. | |
28 | * | |
77855840 TO |
29 | * @param array $fields |
30 | * The address fields. | |
31 | * @param string $format | |
32 | * The desired address format. | |
33 | * @param bool $microformat | |
34 | * If true indicates, the address to be built in hcard-microformat standard. | |
35 | * @param bool $mailing | |
68c1b1f5 | 36 | * Should ALWAYS be false. |
a2f24340 | 37 | * @param string[] $tokenFields |
6a488035 | 38 | * |
a6c01b45 CW |
39 | * @return string |
40 | * formatted address string | |
6a488035 | 41 | * |
6a488035 | 42 | */ |
389bcebf | 43 | public static function format( |
6a488035 | 44 | $fields, |
e7292422 TO |
45 | $format = NULL, |
46 | $microformat = FALSE, | |
47 | $mailing = FALSE, | |
e7292422 | 48 | $tokenFields = NULL |
6a488035 TO |
49 | ) { |
50 | static $config = NULL; | |
68c1b1f5 EM |
51 | $mailing = FALSE; |
52 | ||
53 | if (!$format) { | |
54 | $format = Civi::settings()->get('address_format'); | |
55 | } | |
56 | ||
57 | if ($mailing) { | |
58 | $format = Civi::settings()->get('mailing_format'); | |
59 | } | |
60 | ||
61 | $formatted = $format; | |
62 | ||
63 | $fullPostalCode = $fields['postal_code'] ?? NULL; | |
64 | if (!empty($fields['postal_code_suffix'])) { | |
65 | $fullPostalCode .= "-$fields[postal_code_suffix]"; | |
66 | } | |
67 | ||
68 | // make sure that some of the fields do have values | |
69 | $emptyFields = [ | |
70 | 'supplemental_address_1', | |
71 | 'supplemental_address_2', | |
72 | 'supplemental_address_3', | |
73 | 'state_province_name', | |
74 | 'county', | |
75 | ]; | |
76 | foreach ($emptyFields as $f) { | |
77 | if (!isset($fields[$f])) { | |
78 | $fields[$f] = NULL; | |
79 | } | |
80 | } | |
81 | ||
82 | //CRM-16876 Display countries in all caps when in mailing mode. | |
83 | if ($mailing && !empty($fields['country'])) { | |
84 | if (Civi::settings()->get('hideCountryMailingLabels')) { | |
85 | $domain = CRM_Core_BAO_Domain::getDomain(); | |
86 | $domainLocation = CRM_Core_BAO_Location::getValues(['contact_id' => $domain->contact_id]); | |
87 | $domainAddress = $domainLocation['address'][1]; | |
88 | $domainCountryId = $domainAddress['country_id']; | |
89 | if ($fields['country'] == CRM_Core_PseudoConstant::country($domainCountryId)) { | |
90 | $fields['country'] = NULL; | |
91 | } | |
92 | else { | |
93 | //Capitalization display on uppercase to contries with special characters | |
94 | $fields['country'] = mb_convert_case($fields['country'], MB_CASE_UPPER, "UTF-8"); | |
95 | } | |
96 | } | |
97 | else { | |
98 | $fields['country'] = mb_convert_case($fields['country'], MB_CASE_UPPER, "UTF-8"); | |
99 | } | |
100 | } | |
101 | ||
102 | if (!$microformat) { | |
103 | // replacements in case of Individual Name Format | |
104 | $replacements = [ | |
105 | 'contact.display_name' => $fields['display_name'] ?? NULL, | |
106 | 'contact.individual_prefix' => $fields['individual_prefix'] ?? NULL, | |
107 | 'contact.formal_title' => $fields['formal_title'] ?? NULL, | |
108 | 'contact.first_name' => $fields['first_name'] ?? NULL, | |
109 | 'contact.middle_name' => $fields['middle_name'] ?? NULL, | |
110 | 'contact.last_name' => $fields['last_name'] ?? NULL, | |
111 | 'contact.individual_suffix' => $fields['individual_suffix'] ?? NULL, | |
112 | 'contact.address_name' => $fields['address_name'] ?? NULL, | |
113 | 'contact.street_address' => $fields['street_address'] ?? NULL, | |
114 | 'contact.supplemental_address_1' => $fields['supplemental_address_1'] ?? NULL, | |
115 | 'contact.supplemental_address_2' => $fields['supplemental_address_2'] ?? NULL, | |
116 | 'contact.supplemental_address_3' => $fields['supplemental_address_3'] ?? NULL, | |
117 | 'contact.city' => $fields['city'] ?? NULL, | |
118 | 'contact.state_province_name' => $fields['state_province_name'] ?? NULL, | |
119 | 'contact.county' => $fields['county'] ?? NULL, | |
120 | 'contact.state_province' => $fields['state_province'] ?? NULL, | |
121 | 'contact.postal_code' => $fullPostalCode, | |
122 | 'contact.country' => $fields['country'] ?? NULL, | |
123 | 'contact.world_region' => $fields['world_region'] ?? NULL, | |
124 | 'contact.geo_code_1' => $fields['geo_code_1'] ?? NULL, | |
125 | 'contact.geo_code_2' => $fields['geo_code_2'] ?? NULL, | |
126 | 'contact.current_employer' => $fields['current_employer'] ?? NULL, | |
127 | 'contact.nick_name' => $fields['nick_name'] ?? NULL, | |
128 | 'contact.email' => $fields['email'] ?? NULL, | |
129 | 'contact.im' => $fields['im'] ?? NULL, | |
130 | 'contact.do_not_email' => $fields['do_not_email'] ?? NULL, | |
131 | 'contact.do_not_phone' => $fields['do_not_phone'] ?? NULL, | |
132 | 'contact.do_not_mail' => $fields['do_not_mail'] ?? NULL, | |
133 | 'contact.do_not_sms' => $fields['do_not_sms'] ?? NULL, | |
134 | 'contact.do_not_trade' => $fields['do_not_trade'] ?? NULL, | |
135 | 'contact.job_title' => $fields['job_title'] ?? NULL, | |
136 | 'contact.birth_date' => $fields['birth_date'] ?? NULL, | |
137 | 'contact.gender' => $fields['gender'] ?? NULL, | |
138 | 'contact.is_opt_out' => $fields['is_opt_out'] ?? NULL, | |
139 | 'contact.preferred_mail_format' => $fields['preferred_mail_format'] ?? NULL, | |
140 | 'contact.phone' => $fields['phone'] ?? NULL, | |
141 | 'contact.home_URL' => $fields['home_URL'] ?? NULL, | |
142 | 'contact.contact_source' => $fields['contact_source'] ?? NULL, | |
143 | 'contact.external_identifier' => $fields['external_identifier'] ?? NULL, | |
144 | 'contact.contact_id' => $fields['id'] ?? NULL, | |
145 | 'contact.household_name' => $fields['household_name'] ?? NULL, | |
146 | 'contact.organization_name' => $fields['organization_name'] ?? NULL, | |
147 | 'contact.legal_name' => $fields['legal_name'] ?? NULL, | |
148 | 'contact.preferred_communication_method' => $fields['preferred_communication_method'] ?? NULL, | |
149 | 'contact.communication_style' => $fields['communication_style'] ?? NULL, | |
150 | 'contact.addressee' => $fields['addressee_display'] ?? NULL, | |
151 | 'contact.email_greeting' => $fields['email_greeting_display'] ?? NULL, | |
152 | 'contact.postal_greeting' => $fields['postal_greeting_display'] ?? NULL, | |
153 | ]; | |
154 | } | |
155 | else { | |
156 | $replacements = [ | |
157 | 'contact.address_name' => "<span class=\"address-name\">" . $fields['address_name'] . "</span>", | |
158 | 'contact.street_address' => "<span class=\"street-address\">" . $fields['street_address'] . "</span>", | |
159 | 'contact.supplemental_address_1' => "<span class=\"extended-address\">" . $fields['supplemental_address_1'] . "</span>", | |
160 | 'contact.supplemental_address_2' => $fields['supplemental_address_2'], | |
161 | 'contact.supplemental_address_3' => $fields['supplemental_address_3'], | |
162 | 'contact.city' => "<span class=\"locality\">" . $fields['city'] . "</span>", | |
163 | 'contact.state_province_name' => "<span class=\"region\">" . $fields['state_province_name'] . "</span>", | |
164 | 'contact.county' => "<span class=\"region\">" . $fields['county'], | |
165 | 'contact.state_province' => "<span class=\"region\">" . $fields['state_province'] . "</span>", | |
166 | 'contact.postal_code' => "<span class=\"postal-code\">" . $fullPostalCode . "</span>", | |
167 | 'contact.country' => "<span class=\"country-name\">" . $fields['country'] . "</span>", | |
168 | 'contact.world_region' => "<span class=\"region\">" . $fields['world_region'] . "</span>", | |
169 | ]; | |
170 | ||
171 | // erase all empty ones, so we dont get blank lines | |
172 | foreach (array_keys($replacements) as $key) { | |
173 | $exactKey = substr($key, 0, 8) == 'contact.' ? substr($key, 8) : $key; | |
174 | if ($key != 'contact.postal_code' && | |
175 | CRM_Utils_Array::value($exactKey, $fields) == NULL | |
176 | ) { | |
177 | $replacements[$key] = ''; | |
178 | } | |
179 | } | |
180 | if (empty($fullPostalCode)) { | |
181 | $replacements['contact.postal_code'] = ''; | |
182 | } | |
183 | } | |
184 | ||
185 | // replacements in case of Custom Token | |
186 | if (stristr($formatted, 'custom_')) { | |
187 | $customToken = array_keys($fields); | |
188 | foreach ($customToken as $value) { | |
189 | if (substr($value, 0, 7) == 'custom_') { | |
190 | $replacements["contact.{$value}"] = $fields["{$value}"]; | |
191 | } | |
192 | } | |
193 | } | |
194 | ||
195 | // also sub all token fields | |
196 | if ($tokenFields) { | |
197 | foreach ($tokenFields as $token) { | |
198 | $replacements["{$token}"] = $fields["{$token}"] ?? NULL; | |
199 | } | |
200 | } | |
201 | ||
202 | // for every token, replace {fooTOKENbar} with fooVALUEbar if | |
203 | // the value is not empty, otherwise drop the whole {fooTOKENbar} | |
204 | foreach ($replacements as $token => $value) { | |
205 | if ($value && is_string($value) || is_numeric($value)) { | |
206 | $formatted = preg_replace("/{([^{}]*)\b{$token}\b([^{}]*)}/u", "\${1}{$value}\${2}", $formatted); | |
207 | } | |
208 | else { | |
209 | $formatted = preg_replace("/{[^{}]*\b{$token}\b[^{}]*}/u", '', $formatted); | |
210 | } | |
211 | } | |
212 | ||
213 | // drop any {...} constructs from lines' ends | |
214 | if (!$microformat) { | |
215 | $formatted = "\n$formatted\n"; | |
216 | } | |
217 | else { | |
218 | if ($microformat == 1) { | |
219 | $formatted = "\n<div class=\"location vcard\"><span class=\"adr\">\n$formatted</span></div>\n"; | |
220 | } | |
221 | else { | |
222 | $formatted = "\n<div class=\"vcard\"><span class=\"adr\">$formatted</span></div>\n"; | |
223 | } | |
224 | } | |
225 | ||
226 | $formatted = preg_replace('/\n{[^{}]*}/u', "\n", $formatted); | |
227 | $formatted = preg_replace('/{[^{}]*}\n/u', "\n", $formatted); | |
228 | ||
229 | // if there are any 'sibling' {...} constructs, replace them with the | |
230 | // contents of the first one; for example, when there's no state_province: | |
231 | // 1. {city}{, }{state_province}{ }{postal_code} | |
232 | // 2. San Francisco{, }{ }12345 | |
233 | // 3. San Francisco, 12345 | |
234 | $formatted = preg_replace('/{([^{}]*)}({[^{}]*})+/u', '\1', $formatted); | |
235 | ||
236 | // drop any remaining curly braces leaving their contents | |
237 | $formatted = str_replace(['{', '}'], '', $formatted); | |
238 | ||
239 | // drop any empty lines left after the replacements | |
240 | $formatted = preg_replace('/^[ \t]*[\r\n]+/m', '', $formatted); | |
241 | ||
242 | if (!$microformat) { | |
243 | $finalFormatted = $formatted; | |
244 | } | |
245 | else { | |
246 | // remove \n from each line and only add at the end | |
247 | // this hack solves formatting issue, when we convert nl2br | |
248 | $lines = []; | |
249 | $count = 1; | |
250 | $finalFormatted = NULL; | |
251 | $formattedArray = explode("\n", $formatted); | |
252 | $formattedArray = array_filter($formattedArray); | |
253 | ||
254 | foreach ($formattedArray as $line) { | |
255 | $line = trim($line); | |
256 | if ($line) { | |
257 | if ($count > 1 && $count < count($formattedArray)) { | |
258 | $line = "$line\n"; | |
259 | } | |
260 | $finalFormatted .= $line; | |
261 | $count++; | |
262 | } | |
263 | } | |
264 | } | |
265 | return $finalFormatted; | |
266 | } | |
267 | ||
268 | /** | |
269 | * Format a mailing label. | |
270 | * | |
271 | * @internal | |
272 | * | |
273 | * This function is split off from format() which is doing too much for cleanup. | |
274 | * | |
275 | * It is ONLY called from 2 label task classes and MUST NOT be called from | |
276 | * anywhere else as it is changing. | |
277 | * | |
278 | * @param array $fields | |
279 | * The address fields. | |
280 | * @param string $format | |
281 | * The desired address format. | |
282 | * @param bool $microformat | |
283 | * If true indicates, the address to be built in hcard-microformat standard. | |
284 | * @param bool $mailing | |
285 | * If true indicates, the call has been made from mailing label. | |
286 | * @param null $tokenFields | |
287 | * | |
288 | * @return string | |
289 | * formatted address string | |
290 | * | |
291 | */ | |
292 | public static function formatMailingLabel( | |
293 | $fields, | |
294 | $format = NULL, | |
295 | $microformat = FALSE, | |
296 | $mailing = FALSE, | |
297 | $tokenFields = NULL | |
298 | ) { | |
299 | static $config = NULL; | |
300 | $microformat = FALSE; | |
6a488035 TO |
301 | |
302 | if (!$format) { | |
aaffa79f | 303 | $format = Civi::settings()->get('address_format'); |
6a488035 TO |
304 | } |
305 | ||
306 | if ($mailing) { | |
aaffa79f | 307 | $format = Civi::settings()->get('mailing_format'); |
6a488035 TO |
308 | } |
309 | ||
310 | $formatted = $format; | |
311 | ||
9c1bc317 | 312 | $fullPostalCode = $fields['postal_code'] ?? NULL; |
6a488035 TO |
313 | if (!empty($fields['postal_code_suffix'])) { |
314 | $fullPostalCode .= "-$fields[postal_code_suffix]"; | |
315 | } | |
316 | ||
317 | // make sure that some of the fields do have values | |
be2fb01f | 318 | $emptyFields = [ |
6a488035 TO |
319 | 'supplemental_address_1', |
320 | 'supplemental_address_2', | |
207f62c6 | 321 | 'supplemental_address_3', |
6a488035 TO |
322 | 'state_province_name', |
323 | 'county', | |
be2fb01f | 324 | ]; |
6a488035 TO |
325 | foreach ($emptyFields as $f) { |
326 | if (!isset($fields[$f])) { | |
327 | $fields[$f] = NULL; | |
328 | } | |
329 | } | |
330 | ||
61ca7d1f | 331 | //CRM-16876 Display countries in all caps when in mailing mode. |
04c56532 SL |
332 | if ($mailing && !empty($fields['country'])) { |
333 | if (Civi::settings()->get('hideCountryMailingLabels')) { | |
334 | $domain = CRM_Core_BAO_Domain::getDomain(); | |
be2fb01f | 335 | $domainLocation = CRM_Core_BAO_Location::getValues(['contact_id' => $domain->contact_id]); |
04c56532 SL |
336 | $domainAddress = $domainLocation['address'][1]; |
337 | $domainCountryId = $domainAddress['country_id']; | |
338 | if ($fields['country'] == CRM_Core_PseudoConstant::country($domainCountryId)) { | |
339 | $fields['country'] = NULL; | |
340 | } | |
e22e10f5 | 341 | else { |
e8bbf756 | 342 | //Capitalization display on uppercase to contries with special characters |
ed3d77d5 | 343 | $fields['country'] = mb_convert_case($fields['country'], MB_CASE_UPPER, "UTF-8"); |
e22e10f5 | 344 | } |
04c56532 SL |
345 | } |
346 | else { | |
4c733767 | 347 | $fields['country'] = mb_convert_case($fields['country'], MB_CASE_UPPER, "UTF-8"); |
04c56532 SL |
348 | } |
349 | } | |
350 | ||
6a488035 | 351 | if (!$microformat) { |
e7292422 | 352 | // replacements in case of Individual Name Format |
be2fb01f | 353 | $replacements = [ |
6b409353 CW |
354 | 'contact.display_name' => $fields['display_name'] ?? NULL, |
355 | 'contact.individual_prefix' => $fields['individual_prefix'] ?? NULL, | |
356 | 'contact.formal_title' => $fields['formal_title'] ?? NULL, | |
357 | 'contact.first_name' => $fields['first_name'] ?? NULL, | |
358 | 'contact.middle_name' => $fields['middle_name'] ?? NULL, | |
359 | 'contact.last_name' => $fields['last_name'] ?? NULL, | |
360 | 'contact.individual_suffix' => $fields['individual_suffix'] ?? NULL, | |
361 | 'contact.address_name' => $fields['address_name'] ?? NULL, | |
362 | 'contact.street_address' => $fields['street_address'] ?? NULL, | |
363 | 'contact.supplemental_address_1' => $fields['supplemental_address_1'] ?? NULL, | |
364 | 'contact.supplemental_address_2' => $fields['supplemental_address_2'] ?? NULL, | |
365 | 'contact.supplemental_address_3' => $fields['supplemental_address_3'] ?? NULL, | |
366 | 'contact.city' => $fields['city'] ?? NULL, | |
367 | 'contact.state_province_name' => $fields['state_province_name'] ?? NULL, | |
368 | 'contact.county' => $fields['county'] ?? NULL, | |
369 | 'contact.state_province' => $fields['state_province'] ?? NULL, | |
6a488035 | 370 | 'contact.postal_code' => $fullPostalCode, |
6b409353 CW |
371 | 'contact.country' => $fields['country'] ?? NULL, |
372 | 'contact.world_region' => $fields['world_region'] ?? NULL, | |
373 | 'contact.geo_code_1' => $fields['geo_code_1'] ?? NULL, | |
374 | 'contact.geo_code_2' => $fields['geo_code_2'] ?? NULL, | |
375 | 'contact.current_employer' => $fields['current_employer'] ?? NULL, | |
376 | 'contact.nick_name' => $fields['nick_name'] ?? NULL, | |
377 | 'contact.email' => $fields['email'] ?? NULL, | |
378 | 'contact.im' => $fields['im'] ?? NULL, | |
379 | 'contact.do_not_email' => $fields['do_not_email'] ?? NULL, | |
380 | 'contact.do_not_phone' => $fields['do_not_phone'] ?? NULL, | |
381 | 'contact.do_not_mail' => $fields['do_not_mail'] ?? NULL, | |
382 | 'contact.do_not_sms' => $fields['do_not_sms'] ?? NULL, | |
383 | 'contact.do_not_trade' => $fields['do_not_trade'] ?? NULL, | |
384 | 'contact.job_title' => $fields['job_title'] ?? NULL, | |
385 | 'contact.birth_date' => $fields['birth_date'] ?? NULL, | |
386 | 'contact.gender' => $fields['gender'] ?? NULL, | |
387 | 'contact.is_opt_out' => $fields['is_opt_out'] ?? NULL, | |
388 | 'contact.preferred_mail_format' => $fields['preferred_mail_format'] ?? NULL, | |
389 | 'contact.phone' => $fields['phone'] ?? NULL, | |
390 | 'contact.home_URL' => $fields['home_URL'] ?? NULL, | |
391 | 'contact.contact_source' => $fields['contact_source'] ?? NULL, | |
392 | 'contact.external_identifier' => $fields['external_identifier'] ?? NULL, | |
393 | 'contact.contact_id' => $fields['id'] ?? NULL, | |
4582e7ed MD |
394 | 'contact.household_name' => $fields['household_name'] ?? NULL, |
395 | 'contact.organization_name' => $fields['organization_name'] ?? NULL, | |
6b409353 CW |
396 | 'contact.legal_name' => $fields['legal_name'] ?? NULL, |
397 | 'contact.preferred_communication_method' => $fields['preferred_communication_method'] ?? NULL, | |
398 | 'contact.communication_style' => $fields['communication_style'] ?? NULL, | |
399 | 'contact.addressee' => $fields['addressee_display'] ?? NULL, | |
400 | 'contact.email_greeting' => $fields['email_greeting_display'] ?? NULL, | |
401 | 'contact.postal_greeting' => $fields['postal_greeting_display'] ?? NULL, | |
be2fb01f | 402 | ]; |
6a488035 TO |
403 | } |
404 | else { | |
be2fb01f | 405 | $replacements = [ |
6a488035 TO |
406 | 'contact.address_name' => "<span class=\"address-name\">" . $fields['address_name'] . "</span>", |
407 | 'contact.street_address' => "<span class=\"street-address\">" . $fields['street_address'] . "</span>", | |
408 | 'contact.supplemental_address_1' => "<span class=\"extended-address\">" . $fields['supplemental_address_1'] . "</span>", | |
409 | 'contact.supplemental_address_2' => $fields['supplemental_address_2'], | |
207f62c6 | 410 | 'contact.supplemental_address_3' => $fields['supplemental_address_3'], |
6a488035 TO |
411 | 'contact.city' => "<span class=\"locality\">" . $fields['city'] . "</span>", |
412 | 'contact.state_province_name' => "<span class=\"region\">" . $fields['state_province_name'] . "</span>", | |
413 | 'contact.county' => "<span class=\"region\">" . $fields['county'], | |
414 | 'contact.state_province' => "<span class=\"region\">" . $fields['state_province'] . "</span>", | |
415 | 'contact.postal_code' => "<span class=\"postal-code\">" . $fullPostalCode . "</span>", | |
416 | 'contact.country' => "<span class=\"country-name\">" . $fields['country'] . "</span>", | |
417 | 'contact.world_region' => "<span class=\"region\">" . $fields['world_region'] . "</span>", | |
be2fb01f | 418 | ]; |
6a488035 TO |
419 | |
420 | // erase all empty ones, so we dont get blank lines | |
421 | foreach (array_keys($replacements) as $key) { | |
422 | $exactKey = substr($key, 0, 8) == 'contact.' ? substr($key, 8) : $key; | |
423 | if ($key != 'contact.postal_code' && | |
424 | CRM_Utils_Array::value($exactKey, $fields) == NULL | |
425 | ) { | |
426 | $replacements[$key] = ''; | |
427 | } | |
428 | } | |
429 | if (empty($fullPostalCode)) { | |
430 | $replacements['contact.postal_code'] = ''; | |
431 | } | |
432 | } | |
433 | ||
434 | // replacements in case of Custom Token | |
435 | if (stristr($formatted, 'custom_')) { | |
436 | $customToken = array_keys($fields); | |
437 | foreach ($customToken as $value) { | |
438 | if (substr($value, 0, 7) == 'custom_') { | |
439 | $replacements["contact.{$value}"] = $fields["{$value}"]; | |
440 | } | |
441 | } | |
442 | } | |
443 | ||
444 | // also sub all token fields | |
445 | if ($tokenFields) { | |
446 | foreach ($tokenFields as $token) { | |
9c1bc317 | 447 | $replacements["{$token}"] = $fields["{$token}"] ?? NULL; |
6a488035 TO |
448 | } |
449 | } | |
450 | ||
451 | // for every token, replace {fooTOKENbar} with fooVALUEbar if | |
452 | // the value is not empty, otherwise drop the whole {fooTOKENbar} | |
453 | foreach ($replacements as $token => $value) { | |
785374a6 | 454 | if ($value && is_string($value) || is_numeric($value)) { |
6a488035 TO |
455 | $formatted = preg_replace("/{([^{}]*)\b{$token}\b([^{}]*)}/u", "\${1}{$value}\${2}", $formatted); |
456 | } | |
457 | else { | |
458 | $formatted = preg_replace("/{[^{}]*\b{$token}\b[^{}]*}/u", '', $formatted); | |
459 | } | |
460 | } | |
461 | ||
462 | // drop any {...} constructs from lines' ends | |
463 | if (!$microformat) { | |
464 | $formatted = "\n$formatted\n"; | |
465 | } | |
466 | else { | |
467 | if ($microformat == 1) { | |
468 | $formatted = "\n<div class=\"location vcard\"><span class=\"adr\">\n$formatted</span></div>\n"; | |
469 | } | |
470 | else { | |
471 | $formatted = "\n<div class=\"vcard\"><span class=\"adr\">$formatted</span></div>\n"; | |
472 | } | |
473 | } | |
474 | ||
475 | $formatted = preg_replace('/\n{[^{}]*}/u', "\n", $formatted); | |
476 | $formatted = preg_replace('/{[^{}]*}\n/u', "\n", $formatted); | |
477 | ||
478 | // if there are any 'sibling' {...} constructs, replace them with the | |
479 | // contents of the first one; for example, when there's no state_province: | |
480 | // 1. {city}{, }{state_province}{ }{postal_code} | |
481 | // 2. San Francisco{, }{ }12345 | |
482 | // 3. San Francisco, 12345 | |
483 | $formatted = preg_replace('/{([^{}]*)}({[^{}]*})+/u', '\1', $formatted); | |
484 | ||
485 | // drop any remaining curly braces leaving their contents | |
be2fb01f | 486 | $formatted = str_replace(['{', '}'], '', $formatted); |
6a488035 TO |
487 | |
488 | // drop any empty lines left after the replacements | |
489 | $formatted = preg_replace('/^[ \t]*[\r\n]+/m', '', $formatted); | |
490 | ||
491 | if (!$microformat) { | |
492 | $finalFormatted = $formatted; | |
493 | } | |
494 | else { | |
495 | // remove \n from each line and only add at the end | |
496 | // this hack solves formatting issue, when we convert nl2br | |
be2fb01f | 497 | $lines = []; |
353ffa53 | 498 | $count = 1; |
6a488035 TO |
499 | $finalFormatted = NULL; |
500 | $formattedArray = explode("\n", $formatted); | |
501 | $formattedArray = array_filter($formattedArray); | |
502 | ||
503 | foreach ($formattedArray as $line) { | |
504 | $line = trim($line); | |
505 | if ($line) { | |
506 | if ($count > 1 && $count < count($formattedArray)) { | |
507 | $line = "$line\n"; | |
508 | } | |
509 | $finalFormatted .= $line; | |
510 | $count++; | |
511 | } | |
512 | } | |
513 | } | |
514 | return $finalFormatted; | |
515 | } | |
516 | ||
5bc392e6 | 517 | /** |
a2f24340 | 518 | * @param string $format |
5bc392e6 EM |
519 | * |
520 | * @return array | |
521 | */ | |
00be9182 | 522 | public static function sequence($format) { |
6a488035 | 523 | // also compute and store the address sequence |
be2fb01f | 524 | $addressSequence = [ |
6a488035 TO |
525 | 'address_name', |
526 | 'street_address', | |
527 | 'supplemental_address_1', | |
528 | 'supplemental_address_2', | |
207f62c6 | 529 | 'supplemental_address_3', |
6a488035 TO |
530 | 'city', |
531 | 'county', | |
532 | 'state_province', | |
533 | 'postal_code', | |
534 | 'country', | |
be2fb01f | 535 | ]; |
6a488035 TO |
536 | |
537 | // get the field sequence from the format | |
be2fb01f | 538 | $newSequence = []; |
6a488035 TO |
539 | foreach ($addressSequence as $field) { |
540 | if (substr_count($format, $field)) { | |
541 | $newSequence[strpos($format, $field)] = $field; | |
542 | } | |
543 | } | |
544 | ksort($newSequence); | |
545 | ||
546 | // add the addressSequence fields that are missing in the addressFormat | |
547 | // to the end of the list, so that (for example) if state_province is not | |
548 | // specified in the addressFormat it's still in the address-editing form | |
549 | $newSequence = array_merge($newSequence, $addressSequence); | |
550 | $newSequence = array_unique($newSequence); | |
551 | return $newSequence; | |
552 | } | |
96025800 | 553 | |
d90ab525 SL |
554 | /** |
555 | * Extract the billing fields from the form submission and format them for display. | |
556 | * | |
557 | * @param array $params | |
558 | * @param int $billingLocationTypeID | |
559 | * | |
560 | * @return string | |
561 | */ | |
562 | public static function getFormattedBillingAddressFieldsFromParameters($params, $billingLocationTypeID) { | |
be2fb01f | 563 | $addressParts = [ |
d90ab525 SL |
564 | "street_address" => "billing_street_address-{$billingLocationTypeID}", |
565 | "city" => "billing_city-{$billingLocationTypeID}", | |
566 | "postal_code" => "billing_postal_code-{$billingLocationTypeID}", | |
567 | "state_province" => "state_province-{$billingLocationTypeID}", | |
568 | "country" => "country-{$billingLocationTypeID}", | |
be2fb01f | 569 | ]; |
d90ab525 | 570 | |
be2fb01f | 571 | $addressFields = []; |
d90ab525 | 572 | foreach ($addressParts as $name => $field) { |
9c1bc317 | 573 | $value = $params[$field] ?? NULL; |
9c86599c | 574 | $alternateName = 'billing_' . $name . '_id-' . $billingLocationTypeID; |
575 | $alternate2 = 'billing_' . $name . '-' . $billingLocationTypeID; | |
576 | if (isset($params[$alternate2]) && !isset($params[$alternateName])) { | |
577 | $alternateName = $alternate2; | |
578 | } | |
dd22a911 | 579 | //Include values which prepend 'billing_' to country and state_province. |
de6c59ca | 580 | if (!empty($params[$alternateName])) { |
9c86599c | 581 | if (empty($value) || !is_numeric($value)) { |
582 | $value = $params[$alternateName]; | |
583 | } | |
584 | } | |
8568b05c | 585 | if (is_numeric($value) && ($name == 'state_province' || $name == 'country')) { |
9c86599c | 586 | if ($name == 'state_province') { |
587 | $addressFields[$name] = CRM_Core_PseudoConstant::stateProvinceAbbreviation($value); | |
8568b05c | 588 | $addressFields[$name . '_name'] = CRM_Core_PseudoConstant::stateProvince($value); |
b6fe7f06 | 589 | } |
9c86599c | 590 | if ($name == 'country') { |
591 | $addressFields[$name] = CRM_Core_PseudoConstant::countryIsoCode($value); | |
592 | } | |
593 | } | |
594 | else { | |
595 | $addressFields[$name] = $value; | |
dd22a911 | 596 | } |
d90ab525 SL |
597 | } |
598 | return CRM_Utils_Address::format($addressFields); | |
599 | } | |
600 | ||
6a488035 | 601 | } |