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