Merge pull request #17751 from civicrm/5.28
[civicrm-core.git] / CRM / Case / Audit / Audit.php
1 <?php
2
3 /**
4 * Class CRM_Case_Audit_Audit
5 */
6 class CRM_Case_Audit_Audit {
7 private $auditConfig;
8 private $xmlString;
9
10 /**
11 * @param $xmlString
12 * @param string $confFilename
13 */
14 public function __construct($xmlString, $confFilename) {
15 $this->xmlString = $xmlString;
16 $this->auditConfig = new CRM_Case_Audit_AuditConfig($confFilename);
17 }
18
19 /**
20 * @param bool $printReport
21 *
22 * @return array
23 */
24 public function getActivities($printReport = FALSE) {
25 $retval = [];
26
27 /*
28 * Loop through the activities in the file and add them to the appropriate region array.
29 */
30
31 $doc = new DOMDocument();
32
33 if ($doc->loadXML($this->xmlString)) {
34 $regionList = $this->auditConfig->getRegions();
35
36 $ifBlanks = $this->auditConfig->getIfBlanks();
37
38 $includeAll = $doc->getElementsByTagName("IncludeActivities")->item(0)->nodeValue;
39 $includeAll = ($includeAll == 'All');
40
41 $activityindex = 0;
42 $activityList = $doc->getElementsByTagName("Activity");
43
44 $caseActivities = [];
45 $activityStatusType = [];
46
47 foreach ($activityList as $activity) {
48 $retval[$activityindex] = [];
49
50 $ifBlankReplacements = [];
51
52 $completed = FALSE;
53 $sortValues = ['1970-01-01'];
54 $category = '';
55 $fieldindex = 1;
56 $fields = $activity->getElementsByTagName("Field");
57 foreach ($fields as $field) {
58 $datatype_elements = $field->getElementsByTagName("Type");
59 $datatype = $datatype_elements->item(0)->nodeValue;
60
61 $name_elements = $field->getElementsByTagName("Name");
62 $name = $name_elements->item(0)->nodeValue;
63
64 $label_elements = $field->getElementsByTagName("Label");
65 $label = $label_elements->item(0)->nodeValue;
66
67 $value_elements = $field->getElementsByTagName("Value");
68 $value = $value_elements->item(0)->nodeValue;
69
70 $category_elements = $field->getElementsByTagName("Category");
71 if (!empty($category_elements->length)) {
72 $category = $category_elements->item(0)->nodeValue;
73 }
74
75 // Based on the config file, does this field's label and value indicate a completed activity?
76 if ($label == $this->auditConfig->getCompletionLabel() && $value == $this->auditConfig->getCompletionValue()) {
77 $completed = TRUE;
78 }
79
80 // Based on the config file, does this field's label match the one to use for sorting activities?
81 if (in_array($label, $this->auditConfig->getSortByLabels())) {
82 $sortValues[$label] = $value;
83 }
84
85 foreach ($regionList as $region) {
86 // Based on the config file, is this field a potential replacement for another?
87 if (!empty($ifBlanks[$region])) {
88 if (in_array($label, $ifBlanks[$region])) {
89 $ifBlankReplacements[$label] = $value;
90 }
91 }
92
93 if ($this->auditConfig->includeInRegion($label, $region)) {
94 $retval[$activityindex][$region][$fieldindex] = [];
95 $retval[$activityindex][$region][$fieldindex]['name'] = $name;
96 $retval[$activityindex][$region][$fieldindex]['label'] = $label;
97 $retval[$activityindex][$region][$fieldindex]['datatype'] = $datatype;
98 $retval[$activityindex][$region][$fieldindex]['value'] = $value;
99 if ($datatype == 'Date') {
100 $retval[$activityindex][$region][$fieldindex]['includeTime'] = $this->auditConfig->includeTime($label, $region);
101 }
102
103 //CRM-4570
104 if ($printReport) {
105 if (!in_array($label, [
106 'Activity Type',
107 'Status',
108 ])
109 ) {
110 $caseActivities[$activityindex][$fieldindex] = [];
111 $caseActivities[$activityindex][$fieldindex]['name'] = $name;
112 $caseActivities[$activityindex][$fieldindex]['label'] = $label;
113 $caseActivities[$activityindex][$fieldindex]['datatype'] = $datatype;
114 $caseActivities[$activityindex][$fieldindex]['value'] = $value;
115 }
116 else {
117 $activityStatusType[$activityindex][$fieldindex] = [];
118 $activityStatusType[$activityindex][$fieldindex]['name'] = $name;
119 $activityStatusType[$activityindex][$fieldindex]['label'] = $label;
120 $activityStatusType[$activityindex][$fieldindex]['datatype'] = $datatype;
121 $activityStatusType[$activityindex][$fieldindex]['value'] = $value;
122 }
123 }
124 }
125 }
126
127 $fieldindex++;
128 }
129
130 if ($printReport) {
131 $caseActivities[$activityindex] = CRM_Utils_Array::crmArrayMerge($activityStatusType[$activityindex], $caseActivities[$activityindex]);
132 $caseActivities[$activityindex]['sortValues'] = $sortValues;
133 }
134
135 if ($includeAll || !$completed) {
136 $retval[$activityindex]['completed'] = $completed;
137 $retval[$activityindex]['category'] = $category;
138 $retval[$activityindex]['sortValues'] = $sortValues;
139
140 // Now sort the fields based on the order in the config file.
141 foreach ($regionList as $region) {
142 $this->auditConfig->sort($retval[$activityindex][$region], $region);
143 }
144
145 $retval[$activityindex]['editurl'] = $activity->getElementsByTagName("EditURL")->item(0)->nodeValue;
146
147 // If there are any fields with ifBlank specified, replace their values.
148 // We need to do this as a second pass because if we do it while looping through fields we might not have come across the field we need yet.
149 foreach ($regionList as $region) {
150 foreach ($retval[$activityindex][$region] as & $v) {
151 $vlabel = $v['label'];
152 if (trim($v['value']) == '' && !empty($ifBlanks[$region][$vlabel])) {
153 if (!empty($ifBlankReplacements[$ifBlanks[$region][$vlabel]])) {
154 $v['value'] = $ifBlankReplacements[$ifBlanks[$region][$vlabel]];
155 }
156 }
157 }
158 unset($v);
159 }
160
161 $activityindex++;
162 }
163 else {
164 /* This is a little bit inefficient, but the alternative is to do two passes
165 because we don't know until we've examined all the field values whether the activity
166 is completed, since the field that determines it and its value is configurable,
167 so either way isn't ideal. */
168
169 unset($retval[$activityindex]);
170 unset($caseActivities[$activityindex]);
171 }
172 }
173
174 if ($printReport) {
175 @uasort($caseActivities, [$this, "compareActivities"]);
176 }
177 else {
178 @uasort($retval, [$this, "compareActivities"]);
179 }
180 }
181
182 if ($printReport) {
183 return $caseActivities;
184 }
185 else {
186 return $retval;
187 }
188 }
189
190 /* compareActivities
191 *
192 * This is intended to be called as a sort callback function, returning whether an activity's date is earlier or later than another's.
193 * The type of date to use is specified in the config.
194 */
195
196 /**
197 * @param $a
198 * @param $b
199 *
200 * @return int
201 */
202 public function compareActivities($a, $b) {
203 // This should work
204 foreach ($this->auditConfig->getSortByLabels() as $label) {
205 $aval .= empty($a['sortValues']) ? "" : (empty($a['sortValues'][$label]) ? "" : $a['sortValues'][$label]);
206 $bval .= empty($b['sortValues']) ? "" : (empty($b['sortValues'][$label]) ? "" : $b['sortValues'][$label]);
207 }
208
209 if ($aval < $bval) {
210 return -1;
211 }
212 elseif ($aval > $bval) {
213 return 1;
214 }
215 else {
216 return 0;
217 }
218 }
219
220 /**
221 * @param string $xmlString
222 * @param int $clientID
223 * @param int $caseID
224 *
225 * @return mixed
226 */
227 public static function run($xmlString, $clientID, $caseID) {
228 $audit = new CRM_Case_Audit_Audit($xmlString, 'audit.conf.xml');
229 $activities = $audit->getActivities(TRUE);
230
231 $template = CRM_Core_Smarty::singleton();
232 $template->assign_by_ref('activities', $activities);
233
234 $reportDate = CRM_Utils_Date::customFormat(date('Y-m-d H:i'));
235 $template->assign('reportDate', $reportDate);
236 $contents = $template->fetch('CRM/Case/Audit/Report.tpl');
237
238 return $contents;
239 }
240
241 }