Merge pull request #14128 from agileware/CIVICRM-1143
[civicrm-core.git] / CRM / Case / XMLProcessor / Process.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2019 |
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-2019
32 */
33 class CRM_Case_XMLProcessor_Process extends CRM_Case_XMLProcessor {
34 protected $defaultAssigneeOptionsValues = [];
35
36 /**
37 * Run.
38 *
39 * @param string $caseType
40 * @param array $params
41 *
42 * @return bool
43 * @throws Exception
44 */
45 public function run($caseType, &$params) {
46 $xml = $this->retrieve($caseType);
47
48 if ($xml === FALSE) {
49 $docLink = CRM_Utils_System::docURL2("user/case-management/set-up");
50 CRM_Core_Error::fatal(ts("Configuration file could not be retrieved for case type = '%1' %2.",
51 [1 => $caseType, 2 => $docLink]
52 ));
53 return FALSE;
54 }
55
56 $xmlProcessorProcess = new CRM_Case_XMLProcessor_Process();
57 $this->_isMultiClient = $xmlProcessorProcess->getAllowMultipleCaseClients();
58
59 $this->process($xml, $params);
60 }
61
62 /**
63 * @param $caseType
64 * @param $fieldSet
65 * @param bool $isLabel
66 * @param bool $maskAction
67 *
68 * @return array|bool|mixed
69 * @throws Exception
70 */
71 public function get($caseType, $fieldSet, $isLabel = FALSE, $maskAction = FALSE) {
72 $xml = $this->retrieve($caseType);
73 if ($xml === FALSE) {
74 $docLink = CRM_Utils_System::docURL2("user/case-management/set-up");
75 CRM_Core_Error::fatal(ts("Unable to load configuration file for the referenced case type: '%1' %2.",
76 [1 => $caseType, 2 => $docLink]
77 ));
78 return FALSE;
79 }
80
81 switch ($fieldSet) {
82 case 'CaseRoles':
83 return $this->caseRoles($xml->CaseRoles);
84
85 case 'ActivitySets':
86 return $this->activitySets($xml->ActivitySets);
87
88 case 'ActivityTypes':
89 return $this->activityTypes($xml->ActivityTypes, FALSE, $isLabel, $maskAction);
90 }
91 }
92
93 /**
94 * @param $xml
95 * @param array $params
96 *
97 * @throws Exception
98 */
99 public function process($xml, &$params) {
100 $standardTimeline = CRM_Utils_Array::value('standardTimeline', $params);
101 $activitySetName = CRM_Utils_Array::value('activitySetName', $params);
102
103 if ('Open Case' == CRM_Utils_Array::value('activityTypeName', $params)) {
104 // create relationships for the ones that are required
105 foreach ($xml->CaseRoles as $caseRoleXML) {
106 foreach ($caseRoleXML->RelationshipType as $relationshipTypeXML) {
107 if ((int ) $relationshipTypeXML->creator == 1) {
108 if (!$this->createRelationships((string ) $relationshipTypeXML->name,
109 $params
110 )
111 ) {
112 CRM_Core_Error::fatal();
113 return FALSE;
114 }
115 }
116 }
117 }
118 }
119
120 if ('Change Case Start Date' == CRM_Utils_Array::value('activityTypeName', $params)) {
121 // delete all existing activities which are non-empty
122 $this->deleteEmptyActivity($params);
123 }
124
125 foreach ($xml->ActivitySets as $activitySetsXML) {
126 foreach ($activitySetsXML->ActivitySet as $activitySetXML) {
127 if ($standardTimeline) {
128 if ((boolean ) $activitySetXML->timeline) {
129 return $this->processStandardTimeline($activitySetXML,
130 $params
131 );
132 }
133 }
134 elseif ($activitySetName) {
135 $name = (string ) $activitySetXML->name;
136 if ($name == $activitySetName) {
137 return $this->processActivitySet($activitySetXML,
138 $params
139 );
140 }
141 }
142 }
143 }
144 }
145
146 /**
147 * @param $activitySetXML
148 * @param array $params
149 */
150 public function processStandardTimeline($activitySetXML, &$params) {
151 if ('Change Case Type' == CRM_Utils_Array::value('activityTypeName', $params)
152 && CRM_Utils_Array::value('resetTimeline', $params, TRUE)
153 ) {
154 // delete all existing activities which are non-empty
155 $this->deleteEmptyActivity($params);
156 }
157
158 foreach ($activitySetXML->ActivityTypes as $activityTypesXML) {
159 foreach ($activityTypesXML as $activityTypeXML) {
160 $this->createActivity($activityTypeXML, $params);
161 }
162 }
163 }
164
165 /**
166 * @param $activitySetXML
167 * @param array $params
168 */
169 public function processActivitySet($activitySetXML, &$params) {
170 foreach ($activitySetXML->ActivityTypes as $activityTypesXML) {
171 foreach ($activityTypesXML as $activityTypeXML) {
172 $this->createActivity($activityTypeXML, $params);
173 }
174 }
175 }
176
177 /**
178 * @param $caseRolesXML
179 * @param bool $isCaseManager
180 *
181 * @return array|mixed
182 */
183 public function &caseRoles($caseRolesXML, $isCaseManager = FALSE) {
184 $relationshipTypes = &$this->allRelationshipTypes();
185
186 $result = [];
187 foreach ($caseRolesXML as $caseRoleXML) {
188 foreach ($caseRoleXML->RelationshipType as $relationshipTypeXML) {
189 $relationshipTypeName = (string ) $relationshipTypeXML->name;
190 $relationshipTypeID = array_search($relationshipTypeName,
191 $relationshipTypes
192 );
193 if ($relationshipTypeID === FALSE) {
194 continue;
195 }
196
197 if (!$isCaseManager) {
198 $result[$relationshipTypeID] = $relationshipTypeName;
199 }
200 elseif ($relationshipTypeXML->manager == 1) {
201 return $relationshipTypeID;
202 }
203 }
204 }
205 return $result;
206 }
207
208 /**
209 * @param string $relationshipTypeName
210 * @param array $params
211 *
212 * @return bool
213 * @throws Exception
214 */
215 public function createRelationships($relationshipTypeName, &$params) {
216 $relationshipTypes = &$this->allRelationshipTypes();
217 // get the relationship id
218 $relationshipTypeID = array_search($relationshipTypeName, $relationshipTypes);
219
220 if ($relationshipTypeID === FALSE) {
221 $docLink = CRM_Utils_System::docURL2("user/case-management/set-up");
222 CRM_Core_Error::fatal(ts('Relationship type %1, found in case configuration file, is not present in the database %2',
223 [1 => $relationshipTypeName, 2 => $docLink]
224 ));
225 return FALSE;
226 }
227
228 $client = $params['clientID'];
229 if (!is_array($client)) {
230 $client = [$client];
231 }
232
233 foreach ($client as $key => $clientId) {
234 $relationshipParams = [
235 'relationship_type_id' => $relationshipTypeID,
236 'contact_id_a' => $clientId,
237 'contact_id_b' => $params['creatorID'],
238 'is_active' => 1,
239 'case_id' => $params['caseID'],
240 'start_date' => date("Ymd"),
241 'end_date' => CRM_Utils_Array::value('relationship_end_date', $params),
242 ];
243
244 if (!$this->createRelationship($relationshipParams)) {
245 CRM_Core_Error::fatal();
246 return FALSE;
247 }
248 }
249 return TRUE;
250 }
251
252 /**
253 * @param array $params
254 *
255 * @return bool
256 */
257 public function createRelationship(&$params) {
258 $dao = new CRM_Contact_DAO_Relationship();
259 $dao->copyValues($params);
260 // only create a relationship if it does not exist
261 if (!$dao->find(TRUE)) {
262 $dao->save();
263 }
264 return TRUE;
265 }
266
267 /**
268 * @param $activityTypesXML
269 * @param bool $maxInst
270 * @param bool $isLabel
271 * @param bool $maskAction
272 *
273 * @return array
274 */
275 public function activityTypes($activityTypesXML, $maxInst = FALSE, $isLabel = FALSE, $maskAction = FALSE) {
276 $activityTypes = &$this->allActivityTypes(TRUE, TRUE);
277 $result = [];
278 foreach ($activityTypesXML as $activityTypeXML) {
279 foreach ($activityTypeXML as $recordXML) {
280 $activityTypeName = (string ) $recordXML->name;
281 $maxInstances = (string ) $recordXML->max_instances;
282 $activityTypeInfo = CRM_Utils_Array::value($activityTypeName, $activityTypes);
283
284 if ($activityTypeInfo['id']) {
285 if ($maskAction) {
286 if ($maskAction == 'edit' && '0' === (string ) $recordXML->editable) {
287 $result[$maskAction][] = $activityTypeInfo['id'];
288 }
289 }
290 else {
291 if (!$maxInst) {
292 //if we want,labels of activities should be returned.
293 if ($isLabel) {
294 $result[$activityTypeInfo['id']] = $activityTypeInfo['label'];
295 }
296 else {
297 $result[$activityTypeInfo['id']] = $activityTypeName;
298 }
299 }
300 else {
301 if ($maxInstances) {
302 $result[$activityTypeName] = $maxInstances;
303 }
304 }
305 }
306 }
307 }
308 }
309
310 // call option value hook
311 CRM_Utils_Hook::optionValues($result, 'case_activity_type');
312
313 return $result;
314 }
315
316 /**
317 * @param SimpleXMLElement $caseTypeXML
318 *
319 * @return array<string> symbolic activity-type names
320 */
321 public function getDeclaredActivityTypes($caseTypeXML) {
322 $result = [];
323
324 if (!empty($caseTypeXML->ActivityTypes) && $caseTypeXML->ActivityTypes->ActivityType) {
325 foreach ($caseTypeXML->ActivityTypes->ActivityType as $activityTypeXML) {
326 $result[] = (string) $activityTypeXML->name;
327 }
328 }
329
330 if (!empty($caseTypeXML->ActivitySets) && $caseTypeXML->ActivitySets->ActivitySet) {
331 foreach ($caseTypeXML->ActivitySets->ActivitySet as $activitySetXML) {
332 if ($activitySetXML->ActivityTypes && $activitySetXML->ActivityTypes->ActivityType) {
333 foreach ($activitySetXML->ActivityTypes->ActivityType as $activityTypeXML) {
334 $result[] = (string) $activityTypeXML->name;
335 }
336 }
337 }
338 }
339
340 $result = array_unique($result);
341 sort($result);
342 return $result;
343 }
344
345 /**
346 * @param SimpleXMLElement $caseTypeXML
347 *
348 * @return array<string> symbolic relationship-type names
349 */
350 public function getDeclaredRelationshipTypes($caseTypeXML) {
351 $result = [];
352
353 if (!empty($caseTypeXML->CaseRoles) && $caseTypeXML->CaseRoles->RelationshipType) {
354 foreach ($caseTypeXML->CaseRoles->RelationshipType as $relTypeXML) {
355 $result[] = (string) $relTypeXML->name;
356 }
357 }
358
359 $result = array_unique($result);
360 sort($result);
361 return $result;
362 }
363
364 /**
365 * @param array $params
366 */
367 public function deleteEmptyActivity(&$params) {
368 $activityContacts = CRM_Activity_BAO_ActivityContact::buildOptions('record_type_id', 'validate');
369 $targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts);
370
371 $query = "
372 DELETE a
373 FROM civicrm_activity a
374 INNER JOIN civicrm_activity_contact t ON t.activity_id = a.id
375 INNER JOIN civicrm_case_activity ca on ca.activity_id = a.id
376 WHERE t.contact_id = %1
377 AND t.record_type_id = $targetID
378 AND a.is_auto = 1
379 AND a.is_current_revision = 1
380 AND ca.case_id = %2
381 ";
382 $sqlParams = [1 => [$params['clientID'], 'Integer'], 2 => [$params['caseID'], 'Integer']];
383 CRM_Core_DAO::executeQuery($query, $sqlParams);
384 }
385
386 /**
387 * @param array $params
388 *
389 * @return bool
390 */
391 public function isActivityPresent(&$params) {
392 $query = "
393 SELECT count(a.id)
394 FROM civicrm_activity a
395 INNER JOIN civicrm_case_activity ca on ca.activity_id = a.id
396 WHERE a.activity_type_id = %1
397 AND ca.case_id = %2
398 AND a.is_deleted = 0
399 ";
400
401 $sqlParams = [
402 1 => [$params['activityTypeID'], 'Integer'],
403 2 => [$params['caseID'], 'Integer'],
404 ];
405 $count = CRM_Core_DAO::singleValueQuery($query, $sqlParams);
406
407 // check for max instance
408 $caseType = CRM_Case_BAO_Case::getCaseType($params['caseID'], 'name');
409 $maxInstance = self::getMaxInstance($caseType, $params['activityTypeName']);
410
411 return $maxInstance ? ($count < $maxInstance ? FALSE : TRUE) : FALSE;
412 }
413
414 /**
415 * @param $activityTypeXML
416 * @param array $params
417 *
418 * @return bool
419 * @throws CRM_Core_Exception
420 * @throws Exception
421 */
422 public function createActivity($activityTypeXML, &$params) {
423 $activityTypeName = (string) $activityTypeXML->name;
424 $activityTypes = &$this->allActivityTypes(TRUE, TRUE);
425 $activityTypeInfo = CRM_Utils_Array::value($activityTypeName, $activityTypes);
426
427 if (!$activityTypeInfo) {
428 $docLink = CRM_Utils_System::docURL2("user/case-management/set-up");
429 CRM_Core_Error::fatal(ts('Activity type %1, found in case configuration file, is not present in the database %2',
430 [1 => $activityTypeName, 2 => $docLink]
431 ));
432 return FALSE;
433 }
434
435 $activityTypeID = $activityTypeInfo['id'];
436
437 if (isset($activityTypeXML->status)) {
438 $statusName = (string) $activityTypeXML->status;
439 }
440 else {
441 $statusName = 'Scheduled';
442 }
443
444 $client = (array) $params['clientID'];
445
446 //set order
447 $orderVal = '';
448 if (isset($activityTypeXML->order)) {
449 $orderVal = (string) $activityTypeXML->order;
450 }
451
452 if ($activityTypeName == 'Open Case') {
453 $activityParams = [
454 'activity_type_id' => $activityTypeID,
455 'source_contact_id' => $params['creatorID'],
456 'is_auto' => FALSE,
457 'is_current_revision' => 1,
458 'subject' => CRM_Utils_Array::value('subject', $params) ? $params['subject'] : $activityTypeName,
459 'status_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_status_id', $statusName),
460 'target_contact_id' => $client,
461 'medium_id' => CRM_Utils_Array::value('medium_id', $params),
462 'location' => CRM_Utils_Array::value('location', $params),
463 'details' => CRM_Utils_Array::value('details', $params),
464 'duration' => CRM_Utils_Array::value('duration', $params),
465 'weight' => $orderVal,
466 ];
467 }
468 else {
469 $activityParams = [
470 'activity_type_id' => $activityTypeID,
471 'source_contact_id' => $params['creatorID'],
472 'is_auto' => TRUE,
473 'is_current_revision' => 1,
474 'status_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_status_id', $statusName),
475 'target_contact_id' => $client,
476 'weight' => $orderVal,
477 ];
478 }
479
480 $activityParams['assignee_contact_id'] = $this->getDefaultAssigneeForActivity($activityParams, $activityTypeXML);
481
482 //parsing date to default preference format
483 $params['activity_date_time'] = CRM_Utils_Date::processDate($params['activity_date_time']);
484
485 if ($activityTypeName == 'Open Case') {
486 // we don't set activity_date_time for auto generated
487 // activities, but we want it to be set for open case.
488 $activityParams['activity_date_time'] = $params['activity_date_time'];
489 if (array_key_exists('custom', $params) && is_array($params['custom'])) {
490 $activityParams['custom'] = $params['custom'];
491 }
492
493 // Add parameters for attachments
494
495 $numAttachments = Civi::settings()->get('max_attachments');
496 for ($i = 1; $i <= $numAttachments; $i++) {
497 $attachName = "attachFile_$i";
498 if (isset($params[$attachName]) && !empty($params[$attachName])) {
499 $activityParams[$attachName] = $params[$attachName];
500 }
501 }
502 }
503 else {
504 $activityDate = NULL;
505 //get date of reference activity if set.
506 if ($referenceActivityName = (string) $activityTypeXML->reference_activity) {
507
508 //we skip open case as reference activity.CRM-4374.
509 if (!empty($params['resetTimeline']) && $referenceActivityName == 'Open Case') {
510 $activityDate = $params['activity_date_time'];
511 }
512 else {
513 $referenceActivityInfo = CRM_Utils_Array::value($referenceActivityName, $activityTypes);
514 if ($referenceActivityInfo['id']) {
515 $caseActivityParams = ['activity_type_id' => $referenceActivityInfo['id']];
516
517 //if reference_select is set take according activity.
518 if ($referenceSelect = (string) $activityTypeXML->reference_select) {
519 $caseActivityParams[$referenceSelect] = 1;
520 }
521
522 $referenceActivity = CRM_Case_BAO_Case::getCaseActivityDates($params['caseID'], $caseActivityParams, TRUE);
523
524 if (is_array($referenceActivity)) {
525 foreach ($referenceActivity as $aId => $details) {
526 $activityDate = CRM_Utils_Array::value('activity_date', $details);
527 break;
528 }
529 }
530 }
531 }
532 }
533 if (!$activityDate) {
534 $activityDate = $params['activity_date_time'];
535 }
536 list($activity_date, $activity_time) = CRM_Utils_Date::setDateDefaults($activityDate);
537 $activityDateTime = CRM_Utils_Date::processDate($activity_date, $activity_time);
538 //add reference offset to date.
539 if ((int) $activityTypeXML->reference_offset) {
540 $activityDateTime = CRM_Utils_Date::intervalAdd('day', (int) $activityTypeXML->reference_offset,
541 $activityDateTime
542 );
543 }
544
545 $activityParams['activity_date_time'] = CRM_Utils_Date::format($activityDateTime);
546 }
547
548 // if same activity is already there, skip and dont touch
549 $params['activityTypeID'] = $activityTypeID;
550 $params['activityTypeName'] = $activityTypeName;
551 if ($this->isActivityPresent($params)) {
552 return TRUE;
553 }
554 $activityParams['case_id'] = $params['caseID'];
555 if (!empty($activityParams['is_auto'])) {
556 $activityParams['skipRecentView'] = TRUE;
557 }
558
559 // @todo - switch to using api & remove the parameter pre-wrangling above.
560 $activity = CRM_Activity_BAO_Activity::create($activityParams);
561
562 if (!$activity) {
563 CRM_Core_Error::fatal();
564 return FALSE;
565 }
566
567 // create case activity record
568 $caseParams = [
569 'activity_id' => $activity->id,
570 'case_id' => $params['caseID'],
571 ];
572 CRM_Case_BAO_Case::processCaseActivity($caseParams);
573 return TRUE;
574 }
575
576 /**
577 * Return the default assignee contact for the activity.
578 *
579 * @param array $activityParams
580 * @param object $activityTypeXML
581 *
582 * @return int|null the ID of the default assignee contact or null if none.
583 */
584 protected function getDefaultAssigneeForActivity($activityParams, $activityTypeXML) {
585 if (!isset($activityTypeXML->default_assignee_type)) {
586 return NULL;
587 }
588
589 $defaultAssigneeOptionsValues = $this->getDefaultAssigneeOptionValues();
590
591 switch ($activityTypeXML->default_assignee_type) {
592 case $defaultAssigneeOptionsValues['BY_RELATIONSHIP']:
593 return $this->getDefaultAssigneeByRelationship($activityParams, $activityTypeXML);
594
595 break;
596 case $defaultAssigneeOptionsValues['SPECIFIC_CONTACT']:
597 return $this->getDefaultAssigneeBySpecificContact($activityTypeXML);
598
599 break;
600 case $defaultAssigneeOptionsValues['USER_CREATING_THE_CASE']:
601 return $activityParams['source_contact_id'];
602
603 break;
604 case $defaultAssigneeOptionsValues['NONE']:
605 default:
606 return NULL;
607 }
608 }
609
610 /**
611 * Fetches and caches the activity's default assignee options.
612 *
613 * @return array
614 */
615 protected function getDefaultAssigneeOptionValues() {
616 if (!empty($this->defaultAssigneeOptionsValues)) {
617 return $this->defaultAssigneeOptionsValues;
618 }
619
620 $defaultAssigneeOptions = civicrm_api3('OptionValue', 'get', [
621 'option_group_id' => 'activity_default_assignee',
622 'options' => ['limit' => 0],
623 ]);
624
625 foreach ($defaultAssigneeOptions['values'] as $option) {
626 $this->defaultAssigneeOptionsValues[$option['name']] = $option['value'];
627 }
628
629 return $this->defaultAssigneeOptionsValues;
630 }
631
632 /**
633 * Returns the default assignee for the activity by searching for the target's
634 * contact relationship type defined in the activity's details.
635 *
636 * @param array $activityParams
637 * @param object $activityTypeXML
638 *
639 * @return int|null the ID of the default assignee contact or null if none.
640 */
641 protected function getDefaultAssigneeByRelationship($activityParams, $activityTypeXML) {
642 $isDefaultRelationshipDefined = isset($activityTypeXML->default_assignee_relationship)
643 && preg_match('/\d+_[ab]_[ab]/', $activityTypeXML->default_assignee_relationship);
644
645 if (!$isDefaultRelationshipDefined) {
646 return NULL;
647 }
648
649 $targetContactId = is_array($activityParams['target_contact_id'])
650 ? CRM_Utils_Array::first($activityParams['target_contact_id'])
651 : $activityParams['target_contact_id'];
652 list($relTypeId, $a, $b) = explode('_', $activityTypeXML->default_assignee_relationship);
653
654 $params = [
655 'relationship_type_id' => $relTypeId,
656 "contact_id_$b" => $targetContactId,
657 'is_active' => 1,
658 ];
659
660 if ($this->isBidirectionalRelationshipType($relTypeId)) {
661 $params["contact_id_$a"] = $targetContactId;
662 $params['options']['or'] = [['contact_id_a', 'contact_id_b']];
663 }
664
665 $relationships = civicrm_api3('Relationship', 'get', $params);
666
667 if ($relationships['count']) {
668 $relationship = CRM_Utils_Array::first($relationships['values']);
669
670 // returns the contact id on the other side of the relationship:
671 return (int) $relationship['contact_id_a'] === (int) $targetContactId
672 ? $relationship['contact_id_b']
673 : $relationship['contact_id_a'];
674 }
675 else {
676 return NULL;
677 }
678 }
679
680 /**
681 * Determines if the given relationship type is bidirectional or not by
682 * comparing their labels.
683 *
684 * @return bool
685 */
686 protected function isBidirectionalRelationshipType($relationshipTypeId) {
687 $relationshipTypeResult = civicrm_api3('RelationshipType', 'get', [
688 'id' => $relationshipTypeId,
689 'options' => ['limit' => 1],
690 ]);
691
692 if ($relationshipTypeResult['count'] === 0) {
693 return FALSE;
694 }
695
696 $relationshipType = CRM_Utils_Array::first($relationshipTypeResult['values']);
697
698 return $relationshipType['label_b_a'] === $relationshipType['label_a_b'];
699 }
700
701 /**
702 * Returns the activity's default assignee for a specific contact if the contact exists,
703 * otherwise returns null.
704 *
705 * @param object $activityTypeXML
706 *
707 * @return int|null
708 */
709 protected function getDefaultAssigneeBySpecificContact($activityTypeXML) {
710 if (!$activityTypeXML->default_assignee_contact) {
711 return NULL;
712 }
713
714 $contact = civicrm_api3('Contact', 'get', [
715 'id' => $activityTypeXML->default_assignee_contact,
716 ]);
717
718 if ($contact['count'] == 1) {
719 return $activityTypeXML->default_assignee_contact;
720 }
721
722 return NULL;
723 }
724
725 /**
726 * @param $activitySetsXML
727 *
728 * @return array
729 */
730 public static function activitySets($activitySetsXML) {
731 $result = [];
732 foreach ($activitySetsXML as $activitySetXML) {
733 foreach ($activitySetXML as $recordXML) {
734 $activitySetName = (string ) $recordXML->name;
735 $activitySetLabel = (string ) $recordXML->label;
736 $result[$activitySetName] = $activitySetLabel;
737 }
738 }
739
740 return $result;
741 }
742
743 /**
744 * @param $caseType
745 * @param null $activityTypeName
746 *
747 * @return array|bool|mixed
748 * @throws Exception
749 */
750 public function getMaxInstance($caseType, $activityTypeName = NULL) {
751 $xml = $this->retrieve($caseType);
752
753 if ($xml === FALSE) {
754 CRM_Core_Error::fatal();
755 return FALSE;
756 }
757
758 $activityInstances = $this->activityTypes($xml->ActivityTypes, TRUE);
759 return $activityTypeName ? CRM_Utils_Array::value($activityTypeName, $activityInstances) : $activityInstances;
760 }
761
762 /**
763 * @param $caseType
764 *
765 * @return array|mixed
766 */
767 public function getCaseManagerRoleId($caseType) {
768 $xml = $this->retrieve($caseType);
769 return $this->caseRoles($xml->CaseRoles, TRUE);
770 }
771
772 /**
773 * @param string $caseType
774 *
775 * @return array<\Civi\CCase\CaseChangeListener>
776 */
777 public function getListeners($caseType) {
778 $xml = $this->retrieve($caseType);
779 $listeners = [];
780 if ($xml->Listeners && $xml->Listeners->Listener) {
781 foreach ($xml->Listeners->Listener as $listenerXML) {
782 $class = (string) $listenerXML;
783 $listeners[] = new $class();
784 }
785 }
786 return $listeners;
787 }
788
789 /**
790 * @return int
791 */
792 public function getRedactActivityEmail() {
793 return $this->getBoolSetting('civicaseRedactActivityEmail', 'RedactActivityEmail');
794 }
795
796 /**
797 * Retrieves AllowMultipleCaseClients setting.
798 *
799 * @return string
800 * 1 if allowed, 0 if not
801 */
802 public function getAllowMultipleCaseClients() {
803 return $this->getBoolSetting('civicaseAllowMultipleClients', 'AllowMultipleCaseClients');
804 }
805
806 /**
807 * Retrieves NaturalActivityTypeSort setting.
808 *
809 * @return string
810 * 1 if natural, 0 if alphabetic
811 */
812 public function getNaturalActivityTypeSort() {
813 return $this->getBoolSetting('civicaseNaturalActivityTypeSort', 'NaturalActivityTypeSort');
814 }
815
816 /**
817 * @param string $settingKey
818 * @param string $xmlTag
819 * @param mixed $default
820 *
821 * @return int
822 */
823 private function getBoolSetting($settingKey, $xmlTag, $default = 0) {
824 $setting = Civi::settings()->get($settingKey);
825 if ($setting !== 'default') {
826 return (int) $setting;
827 }
828 if ($xml = $this->retrieve("Settings")) {
829 return (string) $xml->{$xmlTag} ? 1 : 0;
830 }
831 return $default;
832 }
833
834 }