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