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