Commit | Line | Data |
---|---|---|
8ffdec17 ARW |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
39de6fd5 | 4 | | CiviCRM version 4.6 | |
8ffdec17 ARW |
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 | ||
36 | /** | |
37 | * This class contains the functions for Case Type management | |
38 | * | |
39 | */ | |
40 | class CRM_Case_BAO_CaseType extends CRM_Case_DAO_CaseType { | |
41 | ||
42 | /** | |
100fef9d | 43 | * Static field for all the case information that we can potentially export |
8ffdec17 ARW |
44 | * |
45 | * @var array | |
46 | * @static | |
47 | */ | |
48 | static $_exportableFields = NULL; | |
49 | ||
50 | /** | |
c490a46a | 51 | * Takes an associative array and creates a Case Type object |
8ffdec17 ARW |
52 | * |
53 | * the function extract all the params it needs to initialize the create a | |
54 | * case type object. the params array could contain additional unused name/value | |
55 | * pairs | |
56 | * | |
64bd5a0e TO |
57 | * @param array $params |
58 | * (reference ) an assoc array of name/value pairs. | |
77b97be7 | 59 | * |
c490a46a | 60 | * @throws CRM_Core_Exception |
8ffdec17 | 61 | * |
c490a46a | 62 | * @return CRM_Case_BAO_CaseType object |
8ffdec17 ARW |
63 | * @static |
64 | */ | |
00be9182 | 65 | public static function add(&$params) { |
8ffdec17 | 66 | $caseTypeDAO = new CRM_Case_DAO_CaseType(); |
20173e0e | 67 | |
c7bccb5f | 68 | // form the name only if missing: CRM-627 |
69 | $nameParam = CRM_Utils_Array::value('name', $params, NULL); | |
70 | if (!$nameParam && empty($params['id'])) { | |
71 | $params['name'] = CRM_Utils_String::titleToVar($params['title']); | |
72 | } | |
46ec593d TO |
73 | |
74 | // Old case-types (pre-4.5) may keep their ucky names, but new case-types must satisfy isValidName() | |
75 | if (empty($params['id']) && !empty($params['name']) && !CRM_Case_BAO_CaseType::isValidName($params['name'])) { | |
76 | throw new CRM_Core_Exception("Cannot create new case-type with malformed name [{$params['name']}]"); | |
076f81b6 | 77 | } |
c7bccb5f | 78 | |
32f1c917 TO |
79 | $caseTypeName = (isset($params['name'])) ? $params['name'] : CRM_Core_DAO::getFieldValue('CRM_Case_DAO_CaseType', $params['id'], 'name', 'id', TRUE); |
80 | ||
20173e0e | 81 | // function to format definition column |
c2f2bbe6 | 82 | if (isset($params['definition']) && is_array($params['definition'])) { |
32f1c917 | 83 | $params['definition'] = self::convertDefinitionToXML($caseTypeName, $params['definition']); |
ba3228d1 | 84 | CRM_Core_ManagedEntities::scheduleReconciliation(); |
c2f2bbe6 | 85 | } |
20173e0e | 86 | |
88396939 | 87 | $caseTypeDAO->copyValues($params); |
8ffdec17 ARW |
88 | return $caseTypeDAO->save(); |
89 | } | |
90 | ||
1753bd71 | 91 | protected function assignTestValue($fieldName, &$fieldDef, $counter) { |
e547f744 | 92 | if ($fieldName == 'definition') { |
1753bd71 | 93 | $this->{$fieldName} = "<CaseType><name>TestCaseType{$counter}</name></CaseType>"; |
0db6c3e1 TO |
94 | } |
95 | else { | |
1753bd71 TO |
96 | parent::assignTestValue($fieldName, $fieldDef, $counter); |
97 | } | |
98 | } | |
99 | ||
100 | ||
20173e0e | 101 | /** |
100fef9d | 102 | * Format / convert submitted array to xml for case type definition |
20173e0e | 103 | * |
10b0bbee | 104 | * @param string $name |
64bd5a0e TO |
105 | * @param array $definition |
106 | * The case-type defintion expressed as an array-tree. | |
10b0bbee | 107 | * @return string XML |
20173e0e | 108 | * @static |
20173e0e | 109 | */ |
00be9182 | 110 | public static function convertDefinitionToXML($name, $definition) { |
c9c175f9 | 111 | $xmlFile = '<?xml version="1.0" encoding="utf-8" ?>' . "\n\n<CaseType>\n"; |
10b0bbee | 112 | $xmlFile .= "<name>{$name}</name>\n"; |
20173e0e | 113 | |
466fba66 TO |
114 | if (array_key_exists('forkable', $definition)) { |
115 | $xmlFile .= "<forkable>" . ((int) $definition['forkable']) . "</forkable>\n"; | |
116 | } | |
117 | ||
728b5029 | 118 | if (isset($definition['activityTypes'])) { |
20173e0e | 119 | $xmlFile .= "<ActivityTypes>\n"; |
10b0bbee | 120 | foreach ($definition['activityTypes'] as $values) { |
20173e0e | 121 | $xmlFile .= "<ActivityType>\n"; |
122 | foreach ($values as $key => $value) { | |
123 | $xmlFile .= "<{$key}>{$value}</{$key}>\n"; | |
124 | } | |
125 | $xmlFile .= "</ActivityType>\n"; | |
126 | } | |
127 | $xmlFile .= "</ActivityTypes>\n"; | |
128 | } | |
129 | ||
728b5029 | 130 | if (isset($definition['activitySets'])) { |
20173e0e | 131 | $xmlFile .= "<ActivitySets>\n"; |
10b0bbee | 132 | foreach ($definition['activitySets'] as $k => $val) { |
834bc8e2 | 133 | $xmlFile .= "<ActivitySet>\n"; |
134 | foreach ($val as $index => $setVal) { | |
2f58fb09 TO |
135 | switch ($index) { |
136 | case 'activityTypes': | |
137 | if (!empty($setVal)) { | |
138 | $xmlFile .= "<ActivityTypes>\n"; | |
139 | foreach ($setVal as $values) { | |
140 | $xmlFile .= "<ActivityType>\n"; | |
141 | foreach ($values as $key => $value) { | |
142 | $xmlFile .= "<{$key}>{$value}</{$key}>\n"; | |
143 | } | |
144 | $xmlFile .= "</ActivityType>\n"; | |
834bc8e2 | 145 | } |
2f58fb09 | 146 | $xmlFile .= "</ActivityTypes>\n"; |
20173e0e | 147 | } |
2f58fb09 | 148 | break; |
e547f744 | 149 | |
2f58fb09 TO |
150 | case 'sequence': // passthrough |
151 | case 'timeline': | |
152 | if ($setVal) { | |
153 | $xmlFile .= "<{$index}>true</{$index}>\n"; | |
154 | } | |
155 | break; | |
e547f744 | 156 | |
2f58fb09 TO |
157 | default: |
158 | $xmlFile .= "<{$index}>{$setVal}</{$index}>\n"; | |
20173e0e | 159 | } |
160 | } | |
834bc8e2 | 161 | |
162 | $xmlFile .= "</ActivitySet>\n"; | |
20173e0e | 163 | } |
164 | ||
20173e0e | 165 | $xmlFile .= "</ActivitySets>\n"; |
166 | } | |
167 | ||
728b5029 | 168 | if (isset($definition['caseRoles'])) { |
20173e0e | 169 | $xmlFile .= "<CaseRoles>\n"; |
10b0bbee | 170 | foreach ($definition['caseRoles'] as $values) { |
20173e0e | 171 | $xmlFile .= "<RelationshipType>\n"; |
172 | foreach ($values as $key => $value) { | |
173 | $xmlFile .= "<{$key}>{$value}</{$key}>\n"; | |
174 | } | |
175 | $xmlFile .= "</RelationshipType>\n"; | |
176 | } | |
177 | $xmlFile .= "</CaseRoles>\n"; | |
178 | } | |
179 | ||
180 | $xmlFile .= '</CaseType>'; | |
10b0bbee | 181 | return $xmlFile; |
20173e0e | 182 | } |
183 | ||
184 | /** | |
100fef9d | 185 | * Get the case definition either from db or read from xml file |
20173e0e | 186 | * |
64bd5a0e TO |
187 | * @param SimpleXmlElement $xml |
188 | * A single case-type record. | |
20173e0e | 189 | * |
93d47462 | 190 | * @return array the definition of the case-type, expressed as PHP array-tree |
20173e0e | 191 | * @static |
192 | */ | |
00be9182 | 193 | public static function convertXmlToDefinition($xml) { |
93d47462 TO |
194 | // build PHP array based on definition |
195 | $definition = array(); | |
20173e0e | 196 | |
466fba66 TO |
197 | if (isset($xml->forkable)) { |
198 | $definition['forkable'] = (int) $xml->forkable; | |
199 | } | |
200 | ||
20173e0e | 201 | // set activity types |
728b5029 TO |
202 | if (isset($xml->ActivityTypes)) { |
203 | $definition['activityTypes'] = array(); | |
204 | foreach ($xml->ActivityTypes->ActivityType as $activityTypeXML) { | |
205 | $definition['activityTypes'][] = json_decode(json_encode($activityTypeXML), TRUE); | |
206 | } | |
ae195e71 | 207 | } |
208 | ||
728b5029 TO |
209 | // set activity sets |
210 | if (isset($xml->ActivitySets)) { | |
211 | $definition['activitySets'] = array(); | |
212 | foreach ($xml->ActivitySets->ActivitySet as $activitySetXML) { | |
213 | // parse basic properties | |
2f58fb09 TO |
214 | $activitySet = array(); |
215 | $activitySet['name'] = (string) $activitySetXML->name; | |
216 | $activitySet['label'] = (string) $activitySetXML->label; | |
217 | if ('true' == (string) $activitySetXML->timeline) { | |
218 | $activitySet['timeline'] = 1; | |
219 | } | |
220 | if ('true' == (string) $activitySetXML->sequence) { | |
221 | $activitySet['sequence'] = 1; | |
222 | } | |
728b5029 | 223 | |
728b5029 TO |
224 | if (isset($activitySetXML->ActivityTypes)) { |
225 | $activitySet['activityTypes'] = array(); | |
226 | foreach ($activitySetXML->ActivityTypes->ActivityType as $activityTypeXML) { | |
227 | $activitySet['activityTypes'][] = json_decode(json_encode($activityTypeXML), TRUE); | |
228 | } | |
ae195e71 | 229 | } |
728b5029 | 230 | $definition['activitySets'][] = $activitySet; |
ae195e71 | 231 | } |
b6e48667 | 232 | } |
20173e0e | 233 | |
234 | // set case roles | |
728b5029 TO |
235 | if (isset($xml->CaseRoles)) { |
236 | $definition['caseRoles'] = array(); | |
237 | foreach ($xml->CaseRoles->RelationshipType as $caseRoleXml) { | |
238 | $definition['caseRoles'][] = json_decode(json_encode($caseRoleXml), TRUE); | |
239 | } | |
240 | } | |
20173e0e | 241 | |
93d47462 | 242 | return $definition; |
20173e0e | 243 | } |
244 | ||
8ffdec17 ARW |
245 | /** |
246 | * Given the list of params in the params array, fetch the object | |
247 | * and store the values in the values array | |
248 | * | |
64bd5a0e TO |
249 | * @param array $params |
250 | * Input parameters to find object. | |
251 | * @param array $values | |
252 | * Output values of the object. | |
77b97be7 | 253 | * |
8ffdec17 | 254 | * @return CRM_Case_BAO_CaseType|null the found object or null |
8ffdec17 ARW |
255 | * @static |
256 | */ | |
00be9182 | 257 | public static function &getValues(&$params, &$values) { |
8ffdec17 ARW |
258 | $caseType = new CRM_Case_BAO_CaseType(); |
259 | ||
260 | $caseType->copyValues($params); | |
261 | ||
262 | if ($caseType->find(TRUE)) { | |
263 | CRM_Core_DAO::storeValues($caseType, $values); | |
264 | return $caseType; | |
265 | } | |
266 | return NULL; | |
267 | } | |
268 | ||
269 | /** | |
100fef9d | 270 | * Takes an associative array and creates a case type object |
8ffdec17 | 271 | * |
64bd5a0e TO |
272 | * @param array $params |
273 | * (reference ) an assoc array of name/value pairs. | |
77b97be7 | 274 | * |
c490a46a | 275 | * @return CRM_Case_BAO_CaseType object |
8ffdec17 ARW |
276 | * @static |
277 | */ | |
00be9182 | 278 | public static function &create(&$params) { |
8ffdec17 ARW |
279 | $transaction = new CRM_Core_Transaction(); |
280 | ||
281 | if (!empty($params['id'])) { | |
282 | CRM_Utils_Hook::pre('edit', 'CaseType', $params['id'], $params); | |
283 | } | |
284 | else { | |
285 | CRM_Utils_Hook::pre('create', 'CaseType', NULL, $params); | |
286 | } | |
287 | ||
288 | $caseType = self::add($params); | |
289 | ||
290 | if (is_a($caseType, 'CRM_Core_Error')) { | |
291 | $transaction->rollback(); | |
292 | return $caseType; | |
293 | } | |
294 | ||
295 | if (!empty($params['id'])) { | |
296 | CRM_Utils_Hook::post('edit', 'CaseType', $caseType->id, $case); | |
297 | } | |
298 | else { | |
299 | CRM_Utils_Hook::post('create', 'CaseType', $caseType->id, $case); | |
300 | } | |
301 | $transaction->commit(); | |
10ffff26 | 302 | CRM_Case_XMLRepository::singleton(TRUE); |
8ffdec17 ARW |
303 | |
304 | return $caseType; | |
305 | } | |
306 | ||
307 | /** | |
308 | * Takes a bunch of params that are needed to match certain criteria and | |
309 | * retrieves the relevant objects. We'll tweak this function to be more | |
310 | * full featured over a period of time. This is the inverse function of | |
311 | * create. It also stores all the retrieved values in the default array | |
312 | * | |
64bd5a0e TO |
313 | * @param array $params |
314 | * (reference ) an assoc array of name/value pairs. | |
315 | * @param array $defaults | |
316 | * (reference ) an assoc array to hold the name / value pairs. | |
8ffdec17 | 317 | * in a hierarchical manner |
da6b46f4 | 318 | * |
c490a46a | 319 | * @return CRM_Case_BAO_CaseType object |
8ffdec17 ARW |
320 | * @static |
321 | */ | |
00be9182 | 322 | public static function retrieve(&$params, &$defaults) { |
8ffdec17 ARW |
323 | $caseType = CRM_Case_BAO_CaseType::getValues($params, $defaults); |
324 | return $caseType; | |
325 | } | |
326 | ||
4c6ce474 | 327 | /** |
100fef9d | 328 | * @param int $caseTypeId |
4c6ce474 | 329 | * |
c490a46a | 330 | * @throws CRM_Core_Exception |
4c6ce474 EM |
331 | * @return mixed |
332 | */ | |
00be9182 | 333 | public static function del($caseTypeId) { |
8ffdec17 ARW |
334 | $caseType = new CRM_Case_DAO_CaseType(); |
335 | $caseType->id = $caseTypeId; | |
10ffff26 TO |
336 | $refCounts = $caseType->getReferenceCounts(); |
337 | $total = array_sum(CRM_Utils_Array::collect('count', $refCounts)); | |
338 | if ($total) { | |
84dfe0f2 | 339 | throw new CRM_Core_Exception(ts("You can not delete this case type -- it is assigned to %1 existing case record(s). If you do not want this case type to be used going forward, consider disabling it instead.", array(1 => $total))); |
10ffff26 TO |
340 | } |
341 | $result = $caseType->delete(); | |
342 | CRM_Case_XMLRepository::singleton(TRUE); | |
343 | return $result; | |
8ffdec17 | 344 | } |
076f81b6 | 345 | |
346 | /** | |
347 | * Determine if a case-type name is well-formed | |
348 | * | |
349 | * @param string $caseType | |
350 | * @return bool | |
351 | */ | |
00be9182 | 352 | public static function isValidName($caseType) { |
e547f744 | 353 | return preg_match('/^[a-zA-Z0-9_]+$/', $caseType); |
076f81b6 | 354 | } |
32f1c917 TO |
355 | |
356 | /** | |
357 | * Determine if the case-type has *both* DB and file-based definitions. | |
358 | * | |
359 | * @param int $caseTypeId | |
360 | * @return bool|null TRUE if there are *both* DB and file-based definitions | |
361 | */ | |
00be9182 | 362 | public static function isForked($caseTypeId) { |
32f1c917 TO |
363 | $caseTypeName = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_CaseType', $caseTypeId, 'name', 'id', TRUE); |
364 | if ($caseTypeName) { | |
365 | $dbDefinition = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_CaseType', $caseTypeId, 'definition', 'id', TRUE); | |
366 | $fileDefinition = CRM_Case_XMLRepository::singleton()->retrieveFile($caseTypeName); | |
367 | return $fileDefinition && $dbDefinition; | |
368 | } | |
369 | return NULL; | |
370 | } | |
371 | ||
372 | /** | |
373 | * Determine if modifications are allowed on the case-type | |
374 | * | |
375 | * @param int $caseTypeId | |
376 | * @return bool TRUE if the definition can be modified | |
377 | */ | |
00be9182 | 378 | public static function isForkable($caseTypeId) { |
32f1c917 TO |
379 | $caseTypeName = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_CaseType', $caseTypeId, 'name', 'id', TRUE); |
380 | if ($caseTypeName) { | |
381 | // if file-based definition explicitly disables "forkable" option, then don't allow changes to definition | |
382 | $fileDefinition = CRM_Case_XMLRepository::singleton()->retrieveFile($caseTypeName); | |
2210eab6 | 383 | if ($fileDefinition && isset($fileDefinition->forkable)) { |
e547f744 | 384 | return CRM_Utils_String::strtobool((string) $fileDefinition->forkable); |
32f1c917 TO |
385 | } |
386 | } | |
387 | return TRUE; | |
388 | } | |
8ffdec17 | 389 | } |