Merge pull request #4851 from totten/master-createtest-bao
[civicrm-core.git] / CRM / Case / BAO / CaseType.php
CommitLineData
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 */
40class 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}