Merge pull request #18536 from eileenmcnaughton/main
[civicrm-core.git] / CRM / Core / BAO / Location.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
10 */
11
12 /**
13 *
14 * @package CRM
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
16 */
17
18 /**
19 * This class handle creation of location block elements.
20 */
21 class CRM_Core_BAO_Location extends CRM_Core_DAO {
22
23 /**
24 * Location block element array.
25 * @var array
26 */
27 public static $blocks = ['phone', 'email', 'im', 'openid', 'address'];
28
29 /**
30 * Create various elements of location block.
31 *
32 * @param array $params
33 * (reference ) an assoc array of name/value pairs.
34 * @param bool $fixAddress
35 * True if you need to fix (format) address values.
36 * before inserting in db
37 *
38 * @return array
39 */
40 public static function create(&$params, $fixAddress = TRUE) {
41 $location = [];
42 if (!self::dataExists($params)) {
43 return $location;
44 }
45
46 // create location blocks.
47 foreach (self::$blocks as $block) {
48 if ($block != 'address') {
49 $location[$block] = CRM_Core_BAO_Block::create($block, $params);
50 }
51 else {
52 $location[$block] = CRM_Core_BAO_Address::create($params, $fixAddress);
53 }
54 }
55
56 // when we come from a form which displays all the location elements (like the edit form or the inline block
57 // elements, we can skip the below check. The below check adds quite a feq queries to an already overloaded
58 // form
59 if (empty($params['updateBlankLocInfo'])) {
60 // make sure contact should have only one primary block, CRM-5051
61 self::checkPrimaryBlocks(CRM_Utils_Array::value('contact_id', $params));
62 }
63
64 return $location;
65 }
66
67 /**
68 * Creates the entry in the civicrm_loc_block.
69 *
70 * @param array $location
71 * @param array $entityElements
72 *
73 * @return int
74 */
75 public static function createLocBlock($location, $entityElements) {
76 CRM_Core_Error::deprecatedFunctionWarning('Use LocBlock api');
77 $locId = self::findExisting($entityElements);
78 $locBlock = [];
79
80 if ($locId) {
81 $locBlock['id'] = $locId;
82 }
83
84 foreach ([
85 'phone',
86 'email',
87 'im',
88 'address',
89 ] as $loc) {
90 $locBlock["{$loc}_id"] = !empty($location["$loc"][0]) ? $location["$loc"][0]->id : NULL;
91 $locBlock["{$loc}_2_id"] = !empty($location["$loc"][1]) ? $location["$loc"][1]->id : NULL;
92 }
93
94 $countNull = 0;
95 foreach ($locBlock as $key => $block) {
96 if (empty($locBlock[$key])) {
97 $locBlock[$key] = 'null';
98 $countNull++;
99 }
100 }
101
102 if (count($locBlock) == $countNull) {
103 // implies nothing is set.
104 return NULL;
105 }
106
107 return self::addLocBlock($locBlock)->id;
108 }
109
110 /**
111 * Takes an entity array and finds the existing location block.
112 *
113 * @param array $entityElements
114 *
115 * @return int
116 */
117 public static function findExisting($entityElements) {
118 $eid = $entityElements['entity_id'];
119 $etable = $entityElements['entity_table'];
120 $query = "
121 SELECT e.loc_block_id as locId
122 FROM {$etable} e
123 WHERE e.id = %1";
124
125 $params = [1 => [$eid, 'Integer']];
126 $dao = CRM_Core_DAO::executeQuery($query, $params);
127 while ($dao->fetch()) {
128 $locBlockId = $dao->locId;
129 }
130 return $locBlockId;
131 }
132
133 /**
134 * Takes an associative array and adds location block.
135 *
136 * @param array $params
137 *
138 * @return CRM_Core_DAO_LocBlock
139 * Object on success, null otherwise
140 */
141 public static function addLocBlock($params) {
142 $locBlock = new CRM_Core_DAO_LocBlock();
143 $locBlock->copyValues($params);
144 $locBlock->save();
145 return $locBlock;
146 }
147
148 /**
149 * Delete the Location Block.
150 *
151 * @param int $locBlockId
152 * Id of the Location Block.
153 */
154 public static function deleteLocBlock($locBlockId) {
155 if (!$locBlockId) {
156 return;
157 }
158
159 $locBlock = new CRM_Core_DAO_LocBlock();
160 $locBlock->id = $locBlockId;
161
162 $locBlock->find(TRUE);
163
164 //resolve conflict of having same ids for multiple blocks
165 $store = [
166 'IM_1' => $locBlock->im_id,
167 'IM_2' => $locBlock->im_2_id,
168 'Email_1' => $locBlock->email_id,
169 'Email_2' => $locBlock->email_2_id,
170 'Phone_1' => $locBlock->phone_id,
171 'Phone_2' => $locBlock->phone_2_id,
172 'Address_1' => $locBlock->address_id,
173 'Address_2' => $locBlock->address_2_id,
174 ];
175 $locBlock->delete();
176 foreach ($store as $daoName => $id) {
177 if ($id) {
178 $daoName = 'CRM_Core_DAO_' . substr($daoName, 0, -2);
179 $dao = new $daoName();
180 $dao->id = $id;
181 $dao->find(TRUE);
182 $dao->delete();
183 }
184 }
185 }
186
187 /**
188 * Check if there is data to create the object.
189 *
190 * @param array $params
191 * (reference ) an assoc array of name/value pairs.
192 *
193 * @return bool
194 */
195 public static function dataExists(&$params) {
196 // return if no data present
197 $dataExists = FALSE;
198 foreach (self::$blocks as $block) {
199 if (array_key_exists($block, $params)) {
200 $dataExists = TRUE;
201 break;
202 }
203 }
204
205 return $dataExists;
206 }
207
208 /**
209 * Get values.
210 *
211 * @param array $entityBlock
212 * @param bool $microformat
213 *
214 * @return CRM_Core_BAO_Location[]|NULL
215 */
216 public static function getValues($entityBlock, $microformat = FALSE) {
217 if (empty($entityBlock)) {
218 return NULL;
219 }
220 $blocks = [];
221 $name_map = [
222 'im' => 'IM',
223 'openid' => 'OpenID',
224 ];
225 $blocks = [];
226 //get all the blocks for this contact
227 foreach (self::$blocks as $block) {
228 if (array_key_exists($block, $name_map)) {
229 $name = $name_map[$block];
230 }
231 else {
232 $name = ucfirst($block);
233 }
234 $baoString = 'CRM_Core_BAO_' . $name;
235 $blocks[$block] = $baoString::getValues($entityBlock, $microformat);
236 }
237 return $blocks;
238 }
239
240 /**
241 * Delete all the block associated with the location.
242 *
243 * @param int $contactId
244 * Contact id.
245 * @param int $locationTypeId
246 * Id of the location to delete.
247 * @throws CRM_Core_Exception
248 */
249 public static function deleteLocationBlocks($contactId, $locationTypeId) {
250 // ensure that contactId has a value
251 if (empty($contactId) ||
252 !CRM_Utils_Rule::positiveInteger($contactId)
253 ) {
254 throw new CRM_Core_Exception('Incorrect contact id parameter passed to deleteLocationBlocks');
255 }
256
257 if (empty($locationTypeId) ||
258 !CRM_Utils_Rule::positiveInteger($locationTypeId)
259 ) {
260 // so we only delete the blocks which DO NOT have a location type Id
261 // CRM-3581
262 $locationTypeId = 'null';
263 }
264
265 static $blocks = ['Address', 'Phone', 'IM', 'OpenID', 'Email'];
266
267 $params = ['contact_id' => $contactId, 'location_type_id' => $locationTypeId];
268 foreach ($blocks as $name) {
269 CRM_Core_BAO_Block::blockDelete($name, $params);
270 }
271 }
272
273 /**
274 * Make sure contact should have only one primary block, CRM-5051.
275 *
276 * @param int $contactId
277 * Contact id.
278 */
279 public static function checkPrimaryBlocks($contactId) {
280 if (!$contactId) {
281 return;
282 }
283
284 // get the loc block ids.
285 $primaryLocBlockIds = CRM_Contact_BAO_Contact::getLocBlockIds($contactId, ['is_primary' => 1]);
286 $nonPrimaryBlockIds = CRM_Contact_BAO_Contact::getLocBlockIds($contactId, ['is_primary' => 0]);
287
288 foreach ([
289 'Email',
290 'IM',
291 'Phone',
292 'Address',
293 'OpenID',
294 ] as $block) {
295 $name = strtolower($block);
296 if (array_key_exists($name, $primaryLocBlockIds) &&
297 !CRM_Utils_System::isNull($primaryLocBlockIds[$name])
298 ) {
299 if (count($primaryLocBlockIds[$name]) > 1) {
300 // keep only single block as primary.
301 $primaryId = array_pop($primaryLocBlockIds[$name]);
302 $resetIds = "(" . implode(',', $primaryLocBlockIds[$name]) . ")";
303 // reset all primary except one.
304 CRM_Core_DAO::executeQuery("UPDATE civicrm_$name SET is_primary = 0 WHERE id IN $resetIds");
305 }
306 }
307 elseif (array_key_exists($name, $nonPrimaryBlockIds) &&
308 !CRM_Utils_System::isNull($nonPrimaryBlockIds[$name])
309 ) {
310 // data exists and no primary block - make one primary.
311 CRM_Core_DAO::setFieldValue("CRM_Core_DAO_" . $block,
312 array_pop($nonPrimaryBlockIds[$name]), 'is_primary', 1
313 );
314 }
315 }
316 }
317
318 /**
319 * Get chain select values (whatever that means!).
320 *
321 * @param mixed $values
322 * @param string $valueType
323 * @param bool $flatten
324 *
325 * @return array
326 */
327 public static function getChainSelectValues($values, $valueType, $flatten = FALSE) {
328 if (!$values) {
329 return [];
330 }
331 $values = array_filter((array) $values);
332 $elements = [];
333 $list = &$elements;
334 $method = $valueType == 'country' ? 'stateProvinceForCountry' : 'countyForState';
335 foreach ($values as $val) {
336 $result = CRM_Core_PseudoConstant::$method($val);
337
338 // Format for quickform
339 if ($flatten) {
340 // Option-groups for multiple categories
341 if ($result && count($values) > 1) {
342 $elements["crm_optgroup_$val"] = CRM_Core_PseudoConstant::$valueType($val, FALSE);
343 }
344 $elements += $result;
345 }
346
347 // Format for js
348 else {
349 // Option-groups for multiple categories
350 if ($result && count($values) > 1) {
351 $elements[] = [
352 'value' => CRM_Core_PseudoConstant::$valueType($val, FALSE),
353 'children' => [],
354 ];
355 $list = &$elements[count($elements) - 1]['children'];
356 }
357 foreach ($result as $id => $name) {
358 $list[] = [
359 'value' => $name,
360 'key' => $id,
361 ];
362 }
363 }
364 }
365 return $elements;
366 }
367
368 }