CRM-15181, setdefault fixes for state/country
[civicrm-core.git] / CRM / Contact / BAO / ContactType.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
06b69b18 4 | CiviCRM version 4.5 |
6a488035 5 +--------------------------------------------------------------------+
06b69b18 6 | Copyright CiviCRM LLC (c) 2004-2014 |
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 +--------------------------------------------------------------------+
26*/
27
28/**
29 *
30 * @package CRM
06b69b18 31 * @copyright CiviCRM LLC (c) 2004-2014
6a488035
TO
32 * $Id$
33 *
34 */
35class CRM_Contact_BAO_ContactType extends CRM_Contact_DAO_ContactType {
36
37 /**
38 * Takes a bunch of params that are needed to match certain criteria and
39 * retrieves the relevant objects. Typically the valid params are only
40 * contact_id. We'll tweak this function to be more full featured over a period
41 * of time. This is the inverse function of create. It also stores all the retrieved
42 * values in the default array
43 *
44 * @param array $params (reference ) an assoc array of name/value pairs
45 * @param array $defaults (reference ) an assoc array to hold the flattened values
46 *
47 * @return object CRM_Contact_BAO_ContactType object on success, null otherwise
48 * @access public
49 * @static
50 */
51 static function retrieve(&$params, &$defaults) {
52 $contactType = new CRM_Contact_DAO_ContactType();
53 $contactType->copyValues($params);
54 if ($contactType->find(TRUE)) {
55 CRM_Core_DAO::storeValues($contactType, $defaults);
56 return $contactType;
57 }
58 return NULL;
59 }
60
86538308
EM
61 /**
62 * @param $contactType
63 *
64 * @return bool
65 */
6a488035
TO
66 static function isActive($contactType) {
67 $contact = self::contactTypeInfo(FALSE);
68 $active = array_key_exists($contactType, $contact) ? TRUE : FALSE;
69 return $active;
70 }
71
72 /**
73 *
74 *function to retrieve basic contact type information.
75 *
dd244018 76 * @param bool $all
6a488035 77 *
dd244018
EM
78 * @return array of basic contact types information.
79 * @static
6a488035
TO
80 */
81 static function &basicTypeInfo($all = FALSE) {
82 static $_cache = NULL;
83
84 if ($_cache === NULL) {
85 $_cache = array();
86 }
87
88 $argString = $all ? 'CRM_CT_BTI_1' : 'CRM_CT_BTI_0';
89 if (!array_key_exists($argString, $_cache)) {
90 $cache = CRM_Utils_Cache::singleton();
91 $_cache[$argString] = $cache->get($argString);
92 if (!$_cache[$argString]) {
93 $sql = "
94SELECT *
95FROM civicrm_contact_type
96WHERE parent_id IS NULL
97";
98 if ($all === FALSE) {
99 $sql .= " AND is_active = 1";
100 }
101
102 $dao = CRM_Core_DAO::executeQuery($sql,
103 CRM_Core_DAO::$_nullArray,
104 FALSE,
105 'CRM_Contact_DAO_ContactType'
106 );
107 while ($dao->fetch()) {
108 $value = array();
109 CRM_Core_DAO::storeValues($dao, $value);
110 $_cache[$argString][$dao->name] = $value;
111 }
112
113 $cache->set($argString, $_cache[$argString]);
114 }
115 }
116 return $_cache[$argString];
117 }
118
119 /**
120 *
121 *function to retrieve all basic contact types.
122 *
da6b46f4 123 * @param bool $all
6a488035 124 *
da6b46f4
EM
125 * @return array of basic contact types
126 * @static
6a488035
TO
127 */
128 static function basicTypes($all = FALSE) {
129 return array_keys(self::basicTypeInfo($all));
130 }
131
86538308
EM
132 /**
133 * @param bool $all
134 * @param string $key
135 *
136 * @return array
137 */
6a488035
TO
138 static function basicTypePairs($all = FALSE, $key = 'name') {
139 $subtypes = self::basicTypeInfo($all);
140
141 $pairs = array();
142 foreach ($subtypes as $name => $info) {
143 $index = ($key == 'name') ? $name : $info[$key];
144 $pairs[$index] = $info['label'];
145 }
146 return $pairs;
147 }
148
149 /**
150 *
151 *function to retrieve all subtypes Information.
152 *
fd31fa4c
EM
153 * @param array $contactType .
154 * @param bool $all
155 * @param bool $ignoreCache
156 * @param bool $reset
6a488035 157 *
fd31fa4c
EM
158 * @return array of sub type information
159 * @static
6a488035
TO
160 */
161 static function &subTypeInfo($contactType = NULL, $all = FALSE, $ignoreCache = FALSE, $reset = FALSE) {
162 static $_cache = NULL;
163
164 if ($reset === TRUE) {
165 $_cache = NULL;
166 }
167
168 if ($_cache === NULL) {
169 $_cache = array();
170 }
171 if ($contactType && !is_array($contactType)) {
172 $contactType = array($contactType);
173 }
174
175 $argString = $all ? 'CRM_CT_STI_1_' : 'CRM_CT_STI_0_';
176 if (!empty($contactType)) {
177 $argString .= implode('_', $contactType);
178 }
179
180 if ((!array_key_exists($argString, $_cache)) || $ignoreCache) {
181 $cache = CRM_Utils_Cache::singleton();
182 $_cache[$argString] = $cache->get($argString);
183 if (!$_cache[$argString] || $ignoreCache) {
184 $_cache[$argString] = array();
185
186 $ctWHERE = '';
187 if (!empty($contactType)) {
188 $ctWHERE = " AND parent.name IN ('" . implode("','", $contactType) . "')";
189 }
190
191 $sql = "
192SELECT subtype.*, parent.name as parent, parent.label as parent_label
193FROM civicrm_contact_type subtype
194INNER JOIN civicrm_contact_type parent ON subtype.parent_id = parent.id
195WHERE subtype.name IS NOT NULL AND subtype.parent_id IS NOT NULL {$ctWHERE}
196";
197 if ($all === FALSE) {
198 $sql .= " AND subtype.is_active = 1 AND parent.is_active = 1 ORDER BY parent.id";
199 }
200 $dao = CRM_Core_DAO::executeQuery($sql, array(),
201 FALSE, 'CRM_Contact_DAO_ContactType'
202 );
203 while ($dao->fetch()) {
204 $value = array();
205 CRM_Core_DAO::storeValues($dao, $value);
206 $value['parent'] = $dao->parent;
207 $value['parent_label'] = $dao->parent_label;
208 $_cache[$argString][$dao->name] = $value;
209 }
210
211 $cache->set($argString, $_cache[$argString]);
212 }
213 }
214 return $_cache[$argString];
215 }
216
217 /**
218 *
219 *function to retrieve all subtypes
220 *
f4aaa82a
EM
221 * @param array $contactType .
222 * @param bool $all
223 * @param string $columnName
224 * @param bool $ignoreCache
6a488035 225 *
f4aaa82a
EM
226 * @return array of all subtypes OR list of subtypes associated to
227 *a given basic contact type
228 * @static
6a488035
TO
229 */
230 static function subTypes($contactType = NULL, $all = FALSE, $columnName = 'name', $ignoreCache = FALSE) {
231 if ($columnName == 'name') {
232 return array_keys(self::subTypeInfo($contactType, $all, $ignoreCache));
233 }
234 else {
235 return array_values(self::subTypePairs($contactType, FALSE, NULL, $ignoreCache));
236 }
237 }
238
239 /**
240 *
241 *function to retrieve subtype pairs with name as 'subtype-name' and 'label' as value
242 *
f4aaa82a
EM
243 * @param array $contactType .
244 * @param bool $all
245 * @param string $labelPrefix
246 * @param bool $ignoreCache
6a488035 247 *
f4aaa82a
EM
248 * @return list of subtypes with name as 'subtype-name' and 'label' as value
249 * @static
6a488035
TO
250 */
251 static function subTypePairs($contactType = NULL, $all = FALSE, $labelPrefix = '- ', $ignoreCache = FALSE) {
252 $subtypes = self::subTypeInfo($contactType, $all, $ignoreCache);
253
254 $pairs = array();
255 foreach ($subtypes as $name => $info) {
256 $pairs[$name] = $labelPrefix . $info['label'];
257 }
258 return $pairs;
259 }
260
261 /**
262 *
263 *function to retrieve list of all types i.e basic + subtypes.
264 *
f4aaa82a 265 * @param bool $all
6a488035 266 *
f4aaa82a
EM
267 * @return array of basic types + all subtypes.
268 * @static
6a488035
TO
269 */
270 static function contactTypes($all = FALSE) {
271 return array_keys(self::contactTypeInfo($all));
272 }
273
274 /**
275 *
276 *function to retrieve info array about all types i.e basic + subtypes.
277 *
f4aaa82a
EM
278 * @param bool $all
279 * @param bool $reset
6a488035 280 *
f4aaa82a
EM
281 * @return array of basic types + all subtypes.
282 * @static
6a488035
TO
283 */
284 static function contactTypeInfo($all = FALSE, $reset = FALSE) {
285 static $_cache = NULL;
286
287 if ($reset === TRUE) {
288 $_cache = NULL;
289 }
290
291 if ($_cache === NULL) {
292 $_cache = array();
293 }
294
295 $argString = $all ? 'CRM_CT_CTI_1' : 'CRM_CT_CTI_0';
296 if (!array_key_exists($argString, $_cache)) {
297 $cache = CRM_Utils_Cache::singleton();
298 $_cache[$argString] = $cache->get($argString);
299 if (!$_cache[$argString]) {
300 $_cache[$argString] = array();
301
302 $sql = "
303SELECT type.*, parent.name as parent, parent.label as parent_label
304FROM civicrm_contact_type type
305LEFT JOIN civicrm_contact_type parent ON type.parent_id = parent.id
306WHERE type.name IS NOT NULL
307";
308 if ($all === FALSE) {
309 $sql .= " AND type.is_active = 1";
310 }
311
312 $dao = CRM_Core_DAO::executeQuery($sql,
313 CRM_Core_DAO::$_nullArray,
314 FALSE,
315 'CRM_Contact_DAO_ContactType'
316 );
317 while ($dao->fetch()) {
318 $value = array();
319 CRM_Core_DAO::storeValues($dao, $value);
320 if (array_key_exists('parent_id', $value)) {
321 $value['parent'] = $dao->parent;
322 $value['parent_label'] = $dao->parent_label;
323 }
324 $_cache[$argString][$dao->name] = $value;
325 }
326
327 $cache->set($argString, $_cache[$argString]);
328 }
329 }
330
331 return $_cache[$argString];
332 }
333
334 /**
335 *
336 *function to retrieve basic type pairs with name as 'built-in name' and 'label' as value
337 *
f4aaa82a
EM
338 * @param bool $all
339 * @param null $typeName
340 * @param null $delimiter
6a488035 341 *
f4aaa82a
EM
342 * @internal param array $contactType .
343 * @return list of basictypes with name as 'built-in name' and 'label' as value
344 * @static
6a488035
TO
345 */
346 static function contactTypePairs($all = FALSE, $typeName = NULL, $delimiter = NULL) {
347 $types = self::contactTypeInfo($all);
348
349 if ($typeName && !is_array($typeName)) {
350 $typeName = explode(CRM_Core_DAO::VALUE_SEPARATOR, trim($typeName, CRM_Core_DAO::VALUE_SEPARATOR));
351 }
352
353 $pairs = array();
354 if ($typeName) {
355 foreach ($typeName as $type) {
356 if (array_key_exists($type, $types)) {
357 $pairs[$type] = $types[$type]['label'];
358 }
359 }
360 }
361 else {
362 foreach ($types as $name => $info) {
363 $pairs[$name] = $info['label'];
364 }
365 }
366
367 return !$delimiter ? $pairs : implode($delimiter, $pairs);
368 }
369
b500fbea
EM
370 /**
371 * Get a list of elements for select box
372 * Note that this used to default to using the hex(01) character - which results in an invalid character being used in form fields
373 * which was not handled well be anything that loaded & resaved the html (outside core)
374 * The use of this separator is now explicit in the calling functions as a step towards it's removal
375 *
376 * @param bool $all
377 * @param bool $isSeparator
378 * @param string $separator
379 *
380 * @return mixed
381 */
382 static function getSelectElements($all = FALSE,
383 $isSeparator = TRUE,
384 $separator = '__'
6a488035
TO
385 ) {
386 static $_cache = NULL;
387
388 if ($_cache === NULL) {
389 $_cache = array();
390 }
391
392 $argString = $all ? 'CRM_CT_GSE_1' : 'CRM_CT_GSE_0';
b500fbea 393 $argString .= $isSeparator ? '_1' : '_0';
6a488035
TO
394 if (!array_key_exists($argString, $_cache)) {
395 $cache = CRM_Utils_Cache::singleton();
396 $_cache[$argString] = $cache->get($argString);
397
398 if (!$_cache[$argString]) {
399 $_cache[$argString] = array();
400
401 $sql = "
402SELECT c.name as child_name , c.label as child_label , c.id as child_id,
403 p.name as parent_name, p.label as parent_label, p.id as parent_id
404FROM civicrm_contact_type c
405LEFT JOIN civicrm_contact_type p ON ( c.parent_id = p.id )
406WHERE ( c.name IS NOT NULL )
407";
408
409 if ($all === FALSE) {
410 $sql .= "
411AND c.is_active = 1
412AND ( p.is_active = 1 OR p.id IS NULL )
413";
414 }
415 $sql .= " ORDER BY c.id";
416
417 $values = array();
418 $dao = CRM_Core_DAO::executeQuery($sql);
419 while ($dao->fetch()) {
420 if (!empty($dao->parent_id)) {
b500fbea 421 $key = $isSeparator ? $dao->parent_name . $separator . $dao->child_name : $dao->child_name;
6a488035
TO
422 $label = "-&nbsp;{$dao->child_label}";
423 $pName = $dao->parent_name;
424 }
425 else {
426 $key = $dao->child_name;
427 $label = $dao->child_label;
428 $pName = $dao->child_name;
429 }
430
431 if (!isset($values[$pName])) {
432 $values[$pName] = array();
433 }
434 $values[$pName][] = array('key' => $key, 'label' => $label);
435 }
436
437 $selectElements = array();
438 foreach ($values as $pName => $elements) {
439 foreach ($elements as $element) {
440 $selectElements[$element['key']] = $element['label'];
441 }
442 }
443 $_cache[$argString] = $selectElements;
444
445 $cache->set($argString, $_cache[$argString]);
446 }
447 }
448 return $_cache[$argString];
449 }
450
451 /**
452 * function to check if a given type is a subtype
453 *
f4aaa82a
EM
454 * @param string $subType contact subType.
455 * @param bool $ignoreCache
6a488035 456 *
f4aaa82a
EM
457 * @return boolean true if subType, false otherwise.
458 * @static
6a488035
TO
459 */
460 static function isaSubType($subType, $ignoreCache = FALSE) {
461 return in_array($subType, self::subTypes(NULL, TRUE, 'name', $ignoreCache));
462 }
463
464 /**
465 *function to retrieve the basic contact type associated with
466 *given subType.
467 *
468 *@param array/string $subType contact subType.
469 *@return array/string of basicTypes.
470 *@static
471 *
472 */
473 static function getBasicType($subType) {
474 static $_cache = NULL;
475 if ($_cache === NULL) {
476 $_cache = array();
477 }
478
479 $isArray = TRUE;
480 if ($subType && !is_array($subType)) {
481 $subType = array($subType);
482 $isArray = FALSE;
483 }
484 $argString = implode('_', $subType);
485
486 if (!array_key_exists($argString, $_cache)) {
487 $_cache[$argString] = array();
488
489 $sql = "
490SELECT subtype.name as contact_subtype, type.name as contact_type
491FROM civicrm_contact_type subtype
492INNER JOIN civicrm_contact_type type ON ( subtype.parent_id = type.id )
493WHERE subtype.name IN ('" . implode("','", $subType) . "' )";
494 $dao = CRM_Core_DAO::executeQuery($sql);
495 while ($dao->fetch()) {
496 if (!$isArray) {
497 $_cache[$argString] = $dao->contact_type;
498 break;
499 }
500 $_cache[$argString][$dao->contact_subtype] = $dao->contact_type;
501 }
502 }
503 return $_cache[$argString];
504 }
505
506 /**
507 *
508 *function to suppress all subtypes present in given array.
509 *
f4aaa82a
EM
510 * @param $subTypes
511 * @param bool $ignoreCache
6a488035 512 *
f4aaa82a
EM
513 * @internal param array $subType contact subType.
514 * @return array of suppresssubTypes .
515 * @static
6a488035
TO
516 */
517 static function suppressSubTypes(&$subTypes, $ignoreCache = FALSE) {
518 $subTypes = array_diff($subTypes, self::subTypes(NULL, TRUE, 'name', $ignoreCache));
519 return $subTypes;
520 }
521
522 /**
523 *
524 *function to verify if a given subtype is associated with a given basic contact type.
525 *
f4aaa82a
EM
526 * @param string $subType contact subType
527 * @param string $contactType contact Type
528 * @param bool $ignoreCache
529 * @param string $columnName
6a488035 530 *
f4aaa82a
EM
531 * @return boolean true if contact extends, false otherwise.
532 * @static
6a488035
TO
533 */
534 static function isExtendsContactType($subType, $contactType, $ignoreCache = FALSE, $columnName = 'name') {
535 if (!is_array($subType)) {
536 $subType = explode(CRM_Core_DAO::VALUE_SEPARATOR, trim($subType, CRM_Core_DAO::VALUE_SEPARATOR));
537 }
538 $subtypeList = self::subTypes($contactType, TRUE, $columnName, $ignoreCache);
539 $intersection = array_intersect($subType, $subtypeList);
540 return $subType == $intersection;
541 }
542
543 /**
544 *
545 *function to create shortcuts menu for contactTypes
546 *
547 *@return array of contactTypes
548 *@static
549 *
550 */
551 static function getCreateNewList() {
552 $shortCuts = array();
b500fbea
EM
553 //@todo FIXME - using the CRM_Core_DAO::VALUE_SEPARATOR creates invalid html - if you can find the form
554 // this is loaded onto then replace with something like '__' & test
555 $separator = CRM_Core_DAO::VALUE_SEPARATOR;
556 $contactTypes = self::getSelectElements(FALSE, TRUE, $separator);
6a488035
TO
557 foreach ($contactTypes as $key => $value) {
558 if ($key) {
559 $typeValue = explode(CRM_Core_DAO::VALUE_SEPARATOR, $key);
7926b999 560 $cType = CRM_Utils_Array::value('0', $typeValue);
561 $typeUrl = 'ct=' . $cType;
6a488035
TO
562 if ($csType = CRM_Utils_Array::value('1', $typeValue)) {
563 $typeUrl .= "&cst=$csType";
564 }
7926b999 565 $shortCut = array(
6a488035
TO
566 'path' => 'civicrm/contact/add',
567 'query' => "$typeUrl&reset=1",
568 'ref' => "new-$value",
569 'title' => $value,
570 );
7926b999 571 if ($csType = CRM_Utils_Array::value('1', $typeValue)) {
572 $shortCuts[$cType]['shortCuts'][] = $shortCut;
573 }
574 else {
575 $shortCuts[$cType] = $shortCut;
576 }
6a488035
TO
577 }
578 }
579 return $shortCuts;
580 }
581
582 /**
583 * Function to delete Contact SubTypes
584 *
f4aaa82a 585 * @param int $contactTypeId ID of the Contact Subtype to be deleted.
6a488035 586 *
f4aaa82a 587 * @return bool
6a488035
TO
588 * @access public
589 * @static
590 */
591 static function del($contactTypeId) {
592
593 if (!$contactTypeId) {
594 return FALSE;
595 }
596
597 $params = array('id' => $contactTypeId);
598 self::retrieve($params, $typeInfo);
599 $name = $typeInfo['name'];
600 // check if any custom group
601 $custom = new CRM_Core_DAO_CustomGroup();
602 $custom->whereAdd("extends_entity_column_value LIKE '%" .
603 CRM_Core_DAO::VALUE_SEPARATOR .
604 $name .
605 CRM_Core_DAO::VALUE_SEPARATOR . "%'"
606 );
607 if ($custom->find()) {
608 return FALSE;
609 }
610
611 // remove subtype for existing contacts
612 $sql = "
613UPDATE civicrm_contact SET contact_sub_type = NULL
614WHERE contact_sub_type = '$name'";
615 CRM_Core_DAO::executeQuery($sql);
616
617 // remove subtype from contact type table
618 $contactType = new CRM_Contact_DAO_ContactType();
619 $contactType->id = $contactTypeId;
620 $contactType->delete();
621
622 // remove navigation entry if any
623 if ($name) {
624 $sql = "
625DELETE
626FROM civicrm_navigation
627WHERE name = %1";
628 $params = array(1 => array("New $name", 'String'));
629 $dao = CRM_Core_DAO::executeQuery($sql, $params);
630 CRM_Core_BAO_Navigation::resetNavigation();
631 }
632 return TRUE;
633 }
634
635 /**
636 * Function to add or update Contact SubTypes
637 *
638 * @param array $params an assoc array of name/value pairs
639 *
640 * @return object
641 * @access public
642 * @static
643 */
644 static function add($params) {
645
646 // label or name
a7488080 647 if (empty($params['label'])) {
6a488035
TO
648 return;
649 }
a7488080 650 if (!empty($params['parent_id']) &&
6a488035
TO
651 !CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_ContactType', $params['parent_id'])
652 ) {
653 return;
654 }
655
656 $contactType = new CRM_Contact_DAO_ContactType();
657 $contactType->copyValues($params);
658 $contactType->id = CRM_Utils_Array::value('id', $params);
659 $contactType->is_active = CRM_Utils_Array::value('is_active', $params, 0);
660
6a488035
TO
661 $contactType->save();
662 if ($contactType->find(TRUE)) {
663 $contactName = $contactType->name;
664 $contact = ucfirst($contactType->label);
665 $active = $contactType->is_active;
666 }
667
a7488080 668 if (!empty($params['id'])) {
6a488035
TO
669 $params = array('name' => "New $contactName");
670 $newParams = array(
671 'label' => "New $contact",
672 'is_active' => $active,
673 );
674 CRM_Core_BAO_Navigation::processUpdate($params, $newParams);
675 }
676 else {
677 $name = self::getBasicType($contactName);
678 if (!$name) {
679 return;
680 }
681 $value = array('name' => "New $name");
682 CRM_Core_BAO_Navigation::retrieve($value, $navinfo);
683 $navigation = array(
684 'label' => "New $contact",
685 'name' => "New $contactName",
15a7ea79 686 'url' => "civicrm/contact/add?ct=$name&cst=$contactName&reset=1",
6a488035
TO
687 'permission' => 'add contacts',
688 'parent_id' => $navinfo['id'],
689 'is_active' => $active,
690 );
691 CRM_Core_BAO_Navigation::add($navigation);
692 }
693 CRM_Core_BAO_Navigation::resetNavigation();
694
695 // reset the cache after adding
696 self::subTypeInfo(NULL, FALSE, FALSE, TRUE);
697
698 return $contactType;
699 }
700
701 /**
702 * update the is_active flag in the db
703 *
704 * @param int $id id of the database record
705 * @param boolean $is_active value we want to set the is_active field
706 *
707 * @return Object DAO object on success, null otherwise
708 * @static
709 */
710 static function setIsActive($id, $is_active) {
711 $params = array('id' => $id);
712 self::retrieve($params, $contactinfo);
713 $params = array('name' => "New $contactinfo[name]");
714 $newParams = array('is_active' => $is_active);
715 CRM_Core_BAO_Navigation::processUpdate($params, $newParams);
716 CRM_Core_BAO_Navigation::resetNavigation();
717 return CRM_Core_DAO::setFieldValue('CRM_Contact_DAO_ContactType', $id,
718 'is_active', $is_active
719 );
720 }
721
86538308
EM
722 /**
723 * @param $typeName
724 *
725 * @return mixed
726 */
6a488035
TO
727 static function getLabel($typeName) {
728 $types = self::contactTypeInfo(TRUE);
729
730 if (array_key_exists($typeName, $types)) {
731 return $types[$typeName]['label'];
732 }
733 return $typeName;
734 }
735
736 /**
737 * Function to check whether allow to change any contact's subtype
738 * on the basis of custom data and relationship of specific subtype
739 * currently used in contact/edit form amd in import validation
740 *
741 * @param int $contactId contact id.
742 * @param string $subType subtype.
743 *
744 * @return boolean true/false.
745 * @static
746 */
747 static function isAllowEdit($contactId, $subType = NULL) {
748
749 if (!$contactId) {
750 return TRUE;
751 }
752
753 if (empty($subType)) {
754 $subType = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact',
755 $contactId,
756 'contact_sub_type'
757 );
758 }
759
760 if (self::hasCustomData($subType, $contactId) || self::hasRelationships($contactId, $subType)) {
761 return FALSE;
762 }
763
764 return TRUE;
765 }
766
86538308
EM
767 /**
768 * @param $contactType
769 * @param null $contactId
770 *
771 * @return bool
772 */
6a488035
TO
773 static function hasCustomData($contactType, $contactId = NULL) {
774 $subTypeClause = '';
775
776 if (self::isaSubType($contactType)) {
777 $subType = $contactType;
778 $contactType = self::getBasicType($subType);
779
780 // check for empty custom data which extends subtype
781 $subTypeValue = CRM_Core_DAO::VALUE_SEPARATOR . $subType . CRM_Core_DAO::VALUE_SEPARATOR;
782 $subTypeClause = " AND extends_entity_column_value LIKE '%{$subTypeValue}%' ";
783 }
784 $query = "SELECT table_name FROM civicrm_custom_group WHERE extends = '{$contactType}' {$subTypeClause}";
785
786 $dao = CRM_Core_DAO::executeQuery($query);
787 while ($dao->fetch()) {
788 $sql = "SELECT count(id) FROM {$dao->table_name}";
789 if ($contactId) {
790 $sql .= " WHERE entity_id = {$contactId}";
791 }
792 $sql .= " LIMIT 1";
793
794 $customDataCount = CRM_Core_DAO::singleValueQuery($sql);
795 if (!empty($customDataCount)) {
796 $dao->free();
797 return TRUE;
798 }
799 }
800 return FALSE;
801 }
802
f4aaa82a
EM
803 /**
804 * @todo what does this function do?
805 * @param $contactId
806 * @param $contactType
807 *
808 * @return bool
809 */
6a488035
TO
810 static function hasRelationships($contactId, $contactType) {
811 $subTypeClause = NULL;
812 if (self::isaSubType($contactType)) {
813 $subType = $contactType;
814 $contactType = self::getBasicType($subType);
815 $subTypeClause = " AND ( ( crt.contact_type_a = '{$contactType}' AND crt.contact_sub_type_a = '{$subType}') OR
816 ( crt.contact_type_b = '{$contactType}' AND crt.contact_sub_type_b = '{$subType}') ) ";
817 }
818 else {
819 $subTypeClause = " AND ( crt.contact_type_a = '{$contactType}' OR crt.contact_type_b = '{$contactType}' ) ";
820 }
821
822 // check relationships for
823 $relationshipQuery = "
824SELECT count(cr.id) FROM civicrm_relationship cr
825INNER JOIN civicrm_relationship_type crt ON
826( cr.relationship_type_id = crt.id {$subTypeClause} )
827WHERE ( cr.contact_id_a = {$contactId} OR cr.contact_id_b = {$contactId} )
828LIMIT 1";
829
830 $relationshipCount = CRM_Core_DAO::singleValueQuery($relationshipQuery);
831
832 if (!empty($relationshipCount)) {
833 return TRUE;
834 }
835
836 return FALSE;
837 }
838
f4aaa82a
EM
839 /**
840 * @todo what does this function do?
841 * @param $contactType
842 * @param array $subtypeSet
843 *
844 * @return array
845 */
6a488035
TO
846 static function getSubtypeCustomPair($contactType, $subtypeSet = array(
847 )) {
848 if (empty($subtypeSet)) {
849 return $subtypeSet;
850 }
851
852 $customSet = $subTypeClause = array();
853 foreach ($subtypeSet as $subtype) {
854 $subtype = CRM_Utils_Type::escape($subtype, 'String');
855 $subType = CRM_Core_DAO::VALUE_SEPARATOR . $subtype . CRM_Core_DAO::VALUE_SEPARATOR;
856 $subTypeClause[] = "extends_entity_column_value LIKE '%{$subtype}%' ";
857 }
858 $query = "SELECT table_name
859FROM civicrm_custom_group
860WHERE extends = %1 AND " . implode(" OR ", $subTypeClause);
861 $dao = CRM_Core_DAO::executeQuery($query, array(1 => array($contactType, 'String')));
862 while ($dao->fetch()) {
863 $customSet[] = $dao->table_name;
864 }
865 return array_unique($customSet);
866 }
867
f4aaa82a
EM
868 /**
869 * Function that does something
870 * @todo what does this function do?
871 *
872 * @param $contactID
873 * @param $contactType
874 * @param array $oldSubtypeSet
875 * @param array $newSubtypeSet
876 *
877 * @return bool
878 */
6a488035
TO
879 static function deleteCustomSetForSubtypeMigration($contactID,
880 $contactType,
881 $oldSubtypeSet = array(),
882 $newSubtypeSet = array()
883 ) {
884 $oldCustomSet = self::getSubtypeCustomPair($contactType, $oldSubtypeSet);
885 $newCustomSet = self::getSubtypeCustomPair($contactType, $newSubtypeSet);
886
887 $customToBeRemoved = array_diff($oldCustomSet, $newCustomSet);
888 foreach ($customToBeRemoved as $customTable) {
889 self::deleteCustomRowsForEntityID($customTable, $contactID);
890 }
891 return TRUE;
892 }
893
894 /**
895 * Delete content / rows of a custom table specific to a subtype for a given custom-group.
896 * This function currently works for contact subtypes only and could be later improved / genralized
897 * to work for other subtypes as well.
898 *
899 * @param int $gID - custom group id.
900 * @param array $subtypes - list of subtypes related to which entry is to be removed.
901 *
902 * @return void
903 * @access public
904 */
66ed0bee 905 public static function deleteCustomRowsOfSubtype($gID, $subtypes = array()) {
6a488035
TO
906 if (!$gID or empty($subtypes)) {
907 return FALSE;
908 }
909
910 $tableName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $gID, 'table_name');
911
66ed0bee 912 // drop triggers CRM-13587
913 CRM_Core_DAO::dropTriggers($tableName);
914
6a488035
TO
915 $subtypeClause = array();
916 foreach ($subtypes as $subtype) {
917 $subtype = CRM_Utils_Type::escape($subtype, 'String');
918 $subtypeClause[] = "civicrm_contact.contact_sub_type LIKE '%" . CRM_Core_DAO::VALUE_SEPARATOR . $subtype . CRM_Core_DAO::VALUE_SEPARATOR . "%'";
919 }
920 $subtypeClause = implode(' OR ', $subtypeClause);
921
922 $query = "DELETE custom.*
923FROM {$tableName} custom
924INNER JOIN civicrm_contact ON civicrm_contact.id = custom.entity_id
925WHERE ($subtypeClause)";
66ed0bee 926
927 CRM_Core_DAO::singleValueQuery($query);
928
929 // rebuild triggers CRM-13587
930 CRM_Core_DAO::triggerRebuild($tableName);
6a488035
TO
931 }
932
933 /**
934 * Delete content / rows of a custom table specific entity-id for a given custom-group table.
935 *
936 * @param int $customTable - custom table name.
937 * @param int $entityID - entity id.
938 *
939 * @return void
940 * @access public
941 */
942 function deleteCustomRowsForEntityID($customTable, $entityID) {
943 $customTable = CRM_Utils_Type::escape($customTable, 'String');
944 $query = "DELETE FROM {$customTable} WHERE entity_id = %1";
945 return CRM_Core_DAO::singleValueQuery($query, array(1 => array($entityID, 'Integer')));
946 }
947}
948