Merge pull request #16671 from eileenmcnaughton/acl
[civicrm-core.git] / CRM / Core / BAO / Location.php
CommitLineData
6a488035
TO
1<?php
2/*
bc77d7c0
TO
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 +--------------------------------------------------------------------+
e70a7fc0 10 */
6a488035
TO
11
12/**
13 *
14 * @package CRM
ca5cec67 15 * @copyright CiviCRM LLC https://civicrm.org/licensing
6a488035
TO
16 */
17
18/**
192d36c5 19 * This class handle creation of location block elements.
6a488035
TO
20 */
21class CRM_Core_BAO_Location extends CRM_Core_DAO {
22
23 /**
fe482240 24 * Location block element array.
518fa0ee 25 * @var array
6a488035 26 */
518fa0ee 27 public static $blocks = ['phone', 'email', 'im', 'openid', 'address'];
6a488035
TO
28
29 /**
fe482240 30 * Create various elements of location block.
6a488035 31 *
6a0b768e
TO
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.
6a488035
TO
36 * before inserting in db
37 *
77b97be7
EM
38 * @param null $entity
39 *
a6c01b45 40 * @return array
6a488035 41 */
00be9182 42 public static function create(&$params, $fixAddress = TRUE, $entity = NULL) {
be2fb01f 43 $location = [];
6a488035
TO
44 if (!self::dataExists($params)) {
45 return $location;
46 }
47
48 // create location blocks.
49 foreach (self::$blocks as $block) {
50 if ($block != 'address') {
481a74f4 51 $location[$block] = CRM_Core_BAO_Block::create($block, $params, $entity);
6a488035
TO
52 }
53 else {
54 $location[$block] = CRM_Core_BAO_Address::create($params, $fixAddress, $entity);
55 }
56 }
57
58 if ($entity) {
59 // this is a special case for adding values in location block table
be2fb01f 60 $entityElements = [
6a488035
TO
61 'entity_table' => $params['entity_table'],
62 'entity_id' => $params['entity_id'],
be2fb01f 63 ];
6a488035
TO
64
65 $location['id'] = self::createLocBlock($location, $entityElements);
66 }
67 else {
68 // when we come from a form which displays all the location elements (like the edit form or the inline block
69 // elements, we can skip the below check. The below check adds quite a feq queries to an already overloaded
70 // form
de6c59ca 71 if (empty($params['updateBlankLocInfo'])) {
6a488035
TO
72 // make sure contact should have only one primary block, CRM-5051
73 self::checkPrimaryBlocks(CRM_Utils_Array::value('contact_id', $params));
74 }
75 }
76
77 return $location;
78 }
79
80 /**
fe482240 81 * Creates the entry in the civicrm_loc_block.
ad37ac8e 82 *
83 * @param string $location
84 * @param array $entityElements
85 *
86 * @return int
6a488035 87 */
00be9182 88 public static function createLocBlock(&$location, &$entityElements) {
6a488035 89 $locId = self::findExisting($entityElements);
be2fb01f 90 $locBlock = [];
6a488035
TO
91
92 if ($locId) {
93 $locBlock['id'] = $locId;
94 }
95
be2fb01f 96 foreach ([
518fa0ee
SL
97 'phone',
98 'email',
99 'im',
100 'address',
101 ] as $loc) {
0d8afee2
CW
102 $locBlock["{$loc}_id"] = !empty($location["$loc"][0]) ? $location["$loc"][0]->id : NULL;
103 $locBlock["{$loc}_2_id"] = !empty($location["$loc"][1]) ? $location["$loc"][1]->id : NULL;
6a488035
TO
104 }
105
106 $countNull = 0;
107 foreach ($locBlock as $key => $block) {
108 if (empty($locBlock[$key])) {
109 $locBlock[$key] = 'null';
110 $countNull++;
111 }
112 }
113
114 if (count($locBlock) == $countNull) {
115 // implies nothing is set.
116 return NULL;
117 }
118
119 $locBlockInfo = self::addLocBlock($locBlock);
120 return $locBlockInfo->id;
121 }
122
123 /**
fe482240 124 * Takes an entity array and finds the existing location block.
ad37ac8e 125 *
126 * @param array $entityElements
127 *
128 * @return int
6a488035 129 */
00be9182 130 public static function findExisting($entityElements) {
353ffa53 131 $eid = $entityElements['entity_id'];
6a488035 132 $etable = $entityElements['entity_table'];
353ffa53 133 $query = "
6a488035
TO
134SELECT e.loc_block_id as locId
135FROM {$etable} e
136WHERE e.id = %1";
137
be2fb01f 138 $params = [1 => [$eid, 'Integer']];
6a488035
TO
139 $dao = CRM_Core_DAO::executeQuery($query, $params);
140 while ($dao->fetch()) {
141 $locBlockId = $dao->locId;
142 }
143 return $locBlockId;
144 }
145
146 /**
fe482240 147 * Takes an associative array and adds location block.
6a488035 148 *
6a0b768e
TO
149 * @param array $params
150 * (reference ) an assoc array of name/value pairs.
6a488035 151 *
ad37ac8e 152 * @return CRM_Core_BAO_locBlock
153 * Object on success, null otherwise
6a488035 154 */
00be9182 155 public static function addLocBlock(&$params) {
6a488035
TO
156 $locBlock = new CRM_Core_DAO_LocBlock();
157
158 $locBlock->copyValues($params);
159
160 return $locBlock->save();
161 }
162
163 /**
fe482240 164 * Delete the Location Block.
6a488035 165 *
6a0b768e
TO
166 * @param int $locBlockId
167 * Id of the Location Block.
6a488035
TO
168 */
169 public static function deleteLocBlock($locBlockId) {
170 if (!$locBlockId) {
171 return;
172 }
173
174 $locBlock = new CRM_Core_DAO_LocBlock();
175 $locBlock->id = $locBlockId;
176
177 $locBlock->find(TRUE);
178
179 //resolve conflict of having same ids for multiple blocks
be2fb01f 180 $store = [
6a488035
TO
181 'IM_1' => $locBlock->im_id,
182 'IM_2' => $locBlock->im_2_id,
183 'Email_1' => $locBlock->email_id,
184 'Email_2' => $locBlock->email_2_id,
185 'Phone_1' => $locBlock->phone_id,
186 'Phone_2' => $locBlock->phone_2_id,
187 'Address_1' => $locBlock->address_id,
188 'Address_2' => $locBlock->address_2_id,
be2fb01f 189 ];
6a488035
TO
190 $locBlock->delete();
191 foreach ($store as $daoName => $id) {
192 if ($id) {
4d5c2eb5 193 $daoName = 'CRM_Core_DAO_' . substr($daoName, 0, -2);
194 $dao = new $daoName();
6a488035
TO
195 $dao->id = $id;
196 $dao->find(TRUE);
197 $dao->delete();
6a488035
TO
198 }
199 }
200 }
201
202 /**
fe482240 203 * Check if there is data to create the object.
6a488035 204 *
6a0b768e
TO
205 * @param array $params
206 * (reference ) an assoc array of name/value pairs.
6a488035 207 *
acb1052e 208 * @return bool
6a488035 209 */
00be9182 210 public static function dataExists(&$params) {
6a488035
TO
211 // return if no data present
212 $dataExists = FALSE;
213 foreach (self::$blocks as $block) {
214 if (array_key_exists($block, $params)) {
215 $dataExists = TRUE;
216 break;
217 }
218 }
219
220 return $dataExists;
221 }
222
223 /**
ad37ac8e 224 * Get values.
225 *
226 * @param array $entityBlock
fd31fa4c
EM
227 * @param bool $microformat
228 *
a6c01b45
CW
229 * @return array
230 * array of objects(CRM_Core_BAO_Location)
6a488035 231 */
00be9182 232 public static function &getValues($entityBlock, $microformat = FALSE) {
6a488035
TO
233 if (empty($entityBlock)) {
234 return NULL;
235 }
be2fb01f
CW
236 $blocks = [];
237 $name_map = [
6a488035
TO
238 'im' => 'IM',
239 'openid' => 'OpenID',
be2fb01f
CW
240 ];
241 $blocks = [];
6a488035
TO
242 //get all the blocks for this contact
243 foreach (self::$blocks as $block) {
244 if (array_key_exists($block, $name_map)) {
245 $name = $name_map[$block];
246 }
247 else {
248 $name = ucfirst($block);
249 }
4d5c2eb5 250 $baoString = 'CRM_Core_BAO_' . $name;
c490a46a 251 $blocks[$block] = $baoString::getValues($entityBlock, $microformat);
6a488035
TO
252 }
253 return $blocks;
254 }
255
256 /**
fe482240 257 * Delete all the block associated with the location.
6a488035 258 *
6a0b768e
TO
259 * @param int $contactId
260 * Contact id.
261 * @param int $locationTypeId
262 * Id of the location to delete.
6a488035 263 */
00be9182 264 public static function deleteLocationBlocks($contactId, $locationTypeId) {
6a488035
TO
265 // ensure that contactId has a value
266 if (empty($contactId) ||
267 !CRM_Utils_Rule::positiveInteger($contactId)
268 ) {
269 CRM_Core_Error::fatal();
270 }
271
272 if (empty($locationTypeId) ||
273 !CRM_Utils_Rule::positiveInteger($locationTypeId)
274 ) {
275 // so we only delete the blocks which DO NOT have a location type Id
276 // CRM-3581
277 $locationTypeId = 'null';
278 }
279
be2fb01f 280 static $blocks = ['Address', 'Phone', 'IM', 'OpenID', 'Email'];
6a488035 281
be2fb01f 282 $params = ['contact_id' => $contactId, 'location_type_id' => $locationTypeId];
6a488035
TO
283 foreach ($blocks as $name) {
284 CRM_Core_BAO_Block::blockDelete($name, $params);
285 }
286 }
287
c490a46a
CW
288 /**
289 * Copy or update location block.
6a488035 290 *
6a0b768e
TO
291 * @param int $locBlockId
292 * Location block id.
293 * @param int $updateLocBlockId
294 * Update location block id.
b5c2afd0 295 *
a6c01b45
CW
296 * @return int
297 * newly created/updated location block id.
b5c2afd0 298 */
00be9182 299 public static function copyLocBlock($locBlockId, $updateLocBlockId = NULL) {
3fec1adc 300 CRM_Core_Error::deprecatedFunctionWarning('unused function which will be removed');
6a488035 301 //get the location info.
be2fb01f
CW
302 $defaults = $updateValues = [];
303 $locBlock = ['id' => $locBlockId];
6a488035
TO
304 CRM_Core_DAO::commonRetrieve('CRM_Core_DAO_LocBlock', $locBlock, $defaults);
305
306 if ($updateLocBlockId) {
307 //get the location info for update.
be2fb01f 308 $copyLocationParams = ['id' => $updateLocBlockId];
6a488035
TO
309 CRM_Core_DAO::commonRetrieve('CRM_Core_DAO_LocBlock', $copyLocationParams, $updateValues);
310 foreach ($updateValues as $key => $value) {
311 if ($key != 'id') {
312 $copyLocationParams[$key] = 'null';
313 }
314 }
315 }
316
317 //copy all location blocks (email, phone, address, etc)
318 foreach ($defaults as $key => $value) {
319 if ($key != 'id') {
353ffa53
TO
320 $tbl = explode("_", $key);
321 $name = ucfirst($tbl[0]);
6a488035
TO
322 $updateParams = NULL;
323 if ($updateId = CRM_Utils_Array::value($key, $updateValues)) {
be2fb01f 324 $updateParams = ['id' => $updateId];
6a488035
TO
325 }
326
be2fb01f 327 $copy = CRM_Core_DAO::copyGeneric('CRM_Core_DAO_' . $name, ['id' => $value], $updateParams);
6a488035
TO
328 $copyLocationParams[$key] = $copy->id;
329 }
330 }
331
3fec1adc 332 $copyLocation = CRM_Core_DAO::copyGeneric('CRM_Core_DAO_LocBlock',
be2fb01f 333 ['id' => $locBlock['id']],
6a488035
TO
334 $copyLocationParams
335 );
336 return $copyLocation->id;
337 }
338
339 /**
ad37ac8e 340 * Make sure contact should have only one primary block, CRM-5051.
6a488035 341 *
6a0b768e
TO
342 * @param int $contactId
343 * Contact id.
6a488035 344 */
00be9182 345 public static function checkPrimaryBlocks($contactId) {
6a488035
TO
346 if (!$contactId) {
347 return;
348 }
349
350 // get the loc block ids.
be2fb01f
CW
351 $primaryLocBlockIds = CRM_Contact_BAO_Contact::getLocBlockIds($contactId, ['is_primary' => 1]);
352 $nonPrimaryBlockIds = CRM_Contact_BAO_Contact::getLocBlockIds($contactId, ['is_primary' => 0]);
6a488035 353
be2fb01f 354 foreach ([
518fa0ee
SL
355 'Email',
356 'IM',
357 'Phone',
358 'Address',
359 'OpenID',
360 ] as $block) {
6a488035
TO
361 $name = strtolower($block);
362 if (array_key_exists($name, $primaryLocBlockIds) &&
363 !CRM_Utils_System::isNull($primaryLocBlockIds[$name])
364 ) {
365 if (count($primaryLocBlockIds[$name]) > 1) {
366 // keep only single block as primary.
367 $primaryId = array_pop($primaryLocBlockIds[$name]);
368 $resetIds = "(" . implode(',', $primaryLocBlockIds[$name]) . ")";
369 // reset all primary except one.
370 CRM_Core_DAO::executeQuery("UPDATE civicrm_$name SET is_primary = 0 WHERE id IN $resetIds");
371 }
372 }
373 elseif (array_key_exists($name, $nonPrimaryBlockIds) &&
374 !CRM_Utils_System::isNull($nonPrimaryBlockIds[$name])
375 ) {
376 // data exists and no primary block - make one primary.
377 CRM_Core_DAO::setFieldValue("CRM_Core_DAO_" . $block,
378 array_pop($nonPrimaryBlockIds[$name]), 'is_primary', 1
379 );
380 }
381 }
382 }
1d07e7ab
CW
383
384 /**
ad37ac8e 385 * Get chain select values (whatever that means!).
386 *
1d07e7ab
CW
387 * @param mixed $values
388 * @param string $valueType
389 * @param bool $flatten
390 *
391 * @return array
392 */
00be9182 393 public static function getChainSelectValues($values, $valueType, $flatten = FALSE) {
1d07e7ab 394 if (!$values) {
be2fb01f 395 return [];
1d07e7ab 396 }
bc999cd1 397 $values = array_filter((array) $values);
be2fb01f 398 $elements = [];
1d07e7ab
CW
399 $list = &$elements;
400 $method = $valueType == 'country' ? 'stateProvinceForCountry' : 'countyForState';
401 foreach ($values as $val) {
402 $result = CRM_Core_PseudoConstant::$method($val);
403
404 // Format for quickform
405 if ($flatten) {
406 // Option-groups for multiple categories
407 if ($result && count($values) > 1) {
408 $elements["crm_optgroup_$val"] = CRM_Core_PseudoConstant::$valueType($val, FALSE);
409 }
410 $elements += $result;
411 }
412
413 // Format for js
414 else {
353ffa53 415 // Option-groups for multiple categories
1d07e7ab 416 if ($result && count($values) > 1) {
be2fb01f 417 $elements[] = [
1d07e7ab 418 'value' => CRM_Core_PseudoConstant::$valueType($val, FALSE),
be2fb01f
CW
419 'children' => [],
420 ];
353ffa53 421 $list = &$elements[count($elements) - 1]['children'];
1d07e7ab
CW
422 }
423 foreach ($result as $id => $name) {
be2fb01f 424 $list[] = [
1d07e7ab
CW
425 'value' => $name,
426 'key' => $id,
be2fb01f 427 ];
1d07e7ab
CW
428 }
429 }
430 }
431 return $elements;
432 }
96025800 433
6a488035 434}