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