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