commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules-old / civicrm / CRM / Case / BAO / CaseType.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.6 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2015 |
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-2015
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 /**
43 * Static field for all the case information that we can potentially export.
44 *
45 * @var array
46 */
47 static $_exportableFields = NULL;
48
49 /**
50 * Takes an associative array and creates a Case Type object.
51 *
52 * the function extract all the params it needs to initialize the create a
53 * case type object. the params array could contain additional unused name/value
54 * pairs
55 *
56 * @param array $params
57 * (reference ) an assoc array of name/value pairs.
58 *
59 * @throws CRM_Core_Exception
60 *
61 * @return CRM_Case_BAO_CaseType
62 */
63 public static function add(&$params) {
64 $caseTypeDAO = new CRM_Case_DAO_CaseType();
65
66 // form the name only if missing: CRM-627
67 $nameParam = CRM_Utils_Array::value('name', $params, NULL);
68 if (!$nameParam && empty($params['id'])) {
69 $params['name'] = CRM_Utils_String::titleToVar($params['title']);
70 }
71
72 // Old case-types (pre-4.5) may keep their ucky names, but new case-types must satisfy isValidName()
73 if (empty($params['id']) && !empty($params['name']) && !CRM_Case_BAO_CaseType::isValidName($params['name'])) {
74 throw new CRM_Core_Exception("Cannot create new case-type with malformed name [{$params['name']}]");
75 }
76
77 $caseTypeName = (isset($params['name'])) ? $params['name'] : CRM_Core_DAO::getFieldValue('CRM_Case_DAO_CaseType', $params['id'], 'name', 'id', TRUE);
78
79 // function to format definition column
80 if (isset($params['definition']) && is_array($params['definition'])) {
81 $params['definition'] = self::convertDefinitionToXML($caseTypeName, $params['definition']);
82 CRM_Core_ManagedEntities::scheduleReconciliation();
83 }
84
85 $caseTypeDAO->copyValues($params);
86 return $caseTypeDAO->save();
87 }
88
89 /**
90 * Generate and assign an arbitrary value to a field of a test object.
91 *
92 * @param string $fieldName
93 * @param array $fieldDef
94 * @param int $counter
95 * The globally-unique ID of the test object.
96 */
97 protected function assignTestValue($fieldName, &$fieldDef, $counter) {
98 if ($fieldName == 'definition') {
99 $this->{$fieldName} = "<CaseType><name>TestCaseType{$counter}</name></CaseType>";
100 }
101 else {
102 parent::assignTestValue($fieldName, $fieldDef, $counter);
103 }
104 }
105
106
107 /**
108 * Format / convert submitted array to xml for case type definition
109 *
110 * @param string $name
111 * @param array $definition
112 * The case-type defintion expressed as an array-tree.
113 * @return string
114 * XML
115 */
116 public static function convertDefinitionToXML($name, $definition) {
117 $xmlFile = '<?xml version="1.0" encoding="utf-8" ?>' . "\n\n<CaseType>\n";
118 $xmlFile .= "<name>" . self::encodeXmlString($name) . "</name>\n";
119
120 if (array_key_exists('forkable', $definition)) {
121 $xmlFile .= "<forkable>" . ((int) $definition['forkable']) . "</forkable>\n";
122 }
123
124 if (isset($definition['activityTypes'])) {
125 $xmlFile .= "<ActivityTypes>\n";
126 foreach ($definition['activityTypes'] as $values) {
127 $xmlFile .= "<ActivityType>\n";
128 foreach ($values as $key => $value) {
129 $xmlFile .= "<{$key}>" . self::encodeXmlString($value) . "</{$key}>\n";
130 }
131 $xmlFile .= "</ActivityType>\n";
132 }
133 $xmlFile .= "</ActivityTypes>\n";
134 }
135
136 if (isset($definition['activitySets'])) {
137 $xmlFile .= "<ActivitySets>\n";
138 foreach ($definition['activitySets'] as $k => $val) {
139 $xmlFile .= "<ActivitySet>\n";
140 foreach ($val as $index => $setVal) {
141 switch ($index) {
142 case 'activityTypes':
143 if (!empty($setVal)) {
144 $xmlFile .= "<ActivityTypes>\n";
145 foreach ($setVal as $values) {
146 $xmlFile .= "<ActivityType>\n";
147 foreach ($values as $key => $value) {
148 $xmlFile .= "<{$key}>" . self::encodeXmlString($value) . "</{$key}>\n";
149 }
150 $xmlFile .= "</ActivityType>\n";
151 }
152 $xmlFile .= "</ActivityTypes>\n";
153 }
154 break;
155
156 case 'sequence': // passthrough
157 case 'timeline':
158 if ($setVal) {
159 $xmlFile .= "<{$index}>true</{$index}>\n";
160 }
161 break;
162
163 default:
164 $xmlFile .= "<{$index}>" . self::encodeXmlString($setVal) . "</{$index}>\n";
165 }
166 }
167
168 $xmlFile .= "</ActivitySet>\n";
169 }
170
171 $xmlFile .= "</ActivitySets>\n";
172 }
173
174 if (isset($definition['caseRoles'])) {
175 $xmlFile .= "<CaseRoles>\n";
176 foreach ($definition['caseRoles'] as $values) {
177 $xmlFile .= "<RelationshipType>\n";
178 foreach ($values as $key => $value) {
179 $xmlFile .= "<{$key}>" . self::encodeXmlString($value) . "</{$key}>\n";
180 }
181 $xmlFile .= "</RelationshipType>\n";
182 }
183 $xmlFile .= "</CaseRoles>\n";
184 }
185
186 $xmlFile .= '</CaseType>';
187 return $xmlFile;
188 }
189
190 /**
191 * Ugh. This shouldn't exist. Use a real XML-encoder.
192 *
193 * Escape a string for use in XML.
194 *
195 * @param string $str
196 * A string which should outputted to XML.
197 * @return string
198 * @deprecated
199 */
200 protected static function encodeXmlString($str) {
201 // PHP 5.4: return htmlspecialchars($str, ENT_XML1, 'UTF-8')
202 return htmlspecialchars($str);
203 }
204
205 /**
206 * Get the case definition either from db or read from xml file.
207 *
208 * @param SimpleXmlElement $xml
209 * A single case-type record.
210 *
211 * @return array
212 * the definition of the case-type, expressed as PHP array-tree
213 */
214 public static function convertXmlToDefinition($xml) {
215 // build PHP array based on definition
216 $definition = array();
217
218 if (isset($xml->forkable)) {
219 $definition['forkable'] = (int) $xml->forkable;
220 }
221
222 // set activity types
223 if (isset($xml->ActivityTypes)) {
224 $definition['activityTypes'] = array();
225 foreach ($xml->ActivityTypes->ActivityType as $activityTypeXML) {
226 $definition['activityTypes'][] = json_decode(json_encode($activityTypeXML), TRUE);
227 }
228 }
229
230 // set activity sets
231 if (isset($xml->ActivitySets)) {
232 $definition['activitySets'] = array();
233 foreach ($xml->ActivitySets->ActivitySet as $activitySetXML) {
234 // parse basic properties
235 $activitySet = array();
236 $activitySet['name'] = (string) $activitySetXML->name;
237 $activitySet['label'] = (string) $activitySetXML->label;
238 if ('true' == (string) $activitySetXML->timeline) {
239 $activitySet['timeline'] = 1;
240 }
241 if ('true' == (string) $activitySetXML->sequence) {
242 $activitySet['sequence'] = 1;
243 }
244
245 if (isset($activitySetXML->ActivityTypes)) {
246 $activitySet['activityTypes'] = array();
247 foreach ($activitySetXML->ActivityTypes->ActivityType as $activityTypeXML) {
248 $activitySet['activityTypes'][] = json_decode(json_encode($activityTypeXML), TRUE);
249 }
250 }
251 $definition['activitySets'][] = $activitySet;
252 }
253 }
254
255 // set case roles
256 if (isset($xml->CaseRoles)) {
257 $definition['caseRoles'] = array();
258 foreach ($xml->CaseRoles->RelationshipType as $caseRoleXml) {
259 $definition['caseRoles'][] = json_decode(json_encode($caseRoleXml), TRUE);
260 }
261 }
262
263 return $definition;
264 }
265
266 /**
267 * Given the list of params in the params array, fetch the object
268 * and store the values in the values array
269 *
270 * @param array $params
271 * Input parameters to find object.
272 * @param array $values
273 * Output values of the object.
274 *
275 * @return CRM_Case_BAO_CaseType|null the found object or null
276 */
277 public static function &getValues(&$params, &$values) {
278 $caseType = new CRM_Case_BAO_CaseType();
279
280 $caseType->copyValues($params);
281
282 if ($caseType->find(TRUE)) {
283 CRM_Core_DAO::storeValues($caseType, $values);
284 return $caseType;
285 }
286 return NULL;
287 }
288
289 /**
290 * Takes an associative array and creates a case type object.
291 *
292 * @param array $params
293 * (reference ) an assoc array of name/value pairs.
294 *
295 * @return CRM_Case_BAO_CaseType
296 */
297 public static function &create(&$params) {
298 $transaction = new CRM_Core_Transaction();
299
300 if (!empty($params['id'])) {
301 CRM_Utils_Hook::pre('edit', 'CaseType', $params['id'], $params);
302 }
303 else {
304 CRM_Utils_Hook::pre('create', 'CaseType', NULL, $params);
305 }
306
307 $caseType = self::add($params);
308
309 if (is_a($caseType, 'CRM_Core_Error')) {
310 $transaction->rollback();
311 return $caseType;
312 }
313
314 if (!empty($params['id'])) {
315 CRM_Utils_Hook::post('edit', 'CaseType', $caseType->id, $case);
316 }
317 else {
318 CRM_Utils_Hook::post('create', 'CaseType', $caseType->id, $case);
319 }
320 $transaction->commit();
321 CRM_Case_XMLRepository::singleton(TRUE);
322
323 return $caseType;
324 }
325
326 /**
327 * Retrieve DB object based on input parameters.
328 *
329 * It also stores all the retrieved values in the default array.
330 *
331 * @param array $params
332 * (reference ) an assoc array of name/value pairs.
333 * @param array $defaults
334 * (reference ) an assoc array to hold the name / value pairs.
335 * in a hierarchical manner
336 *
337 * @return CRM_Case_BAO_CaseType
338 */
339 public static function retrieve(&$params, &$defaults) {
340 $caseType = CRM_Case_BAO_CaseType::getValues($params, $defaults);
341 return $caseType;
342 }
343
344 /**
345 * @param int $caseTypeId
346 *
347 * @throws CRM_Core_Exception
348 * @return mixed
349 */
350 public static function del($caseTypeId) {
351 $caseType = new CRM_Case_DAO_CaseType();
352 $caseType->id = $caseTypeId;
353 $refCounts = $caseType->getReferenceCounts();
354 $total = array_sum(CRM_Utils_Array::collect('count', $refCounts));
355 if ($total) {
356 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)));
357 }
358 $result = $caseType->delete();
359 CRM_Case_XMLRepository::singleton(TRUE);
360 return $result;
361 }
362
363 /**
364 * Determine if a case-type name is well-formed
365 *
366 * @param string $caseType
367 * @return bool
368 */
369 public static function isValidName($caseType) {
370 return preg_match('/^[a-zA-Z0-9_]+$/', $caseType);
371 }
372
373 /**
374 * Determine if the case-type has *both* DB and file-based definitions.
375 *
376 * @param int $caseTypeId
377 * @return bool|null
378 * TRUE if there are *both* DB and file-based definitions
379 */
380 public static function isForked($caseTypeId) {
381 $caseTypeName = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_CaseType', $caseTypeId, 'name', 'id', TRUE);
382 if ($caseTypeName) {
383 $dbDefinition = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_CaseType', $caseTypeId, 'definition', 'id', TRUE);
384 $fileDefinition = CRM_Case_XMLRepository::singleton()->retrieveFile($caseTypeName);
385 return $fileDefinition && $dbDefinition;
386 }
387 return NULL;
388 }
389
390 /**
391 * Determine if modifications are allowed on the case-type
392 *
393 * @param int $caseTypeId
394 * @return bool
395 * TRUE if the definition can be modified
396 */
397 public static function isForkable($caseTypeId) {
398 $caseTypeName = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_CaseType', $caseTypeId, 'name', 'id', TRUE);
399 if ($caseTypeName) {
400 // if file-based definition explicitly disables "forkable" option, then don't allow changes to definition
401 $fileDefinition = CRM_Case_XMLRepository::singleton()->retrieveFile($caseTypeName);
402 if ($fileDefinition && isset($fileDefinition->forkable)) {
403 return CRM_Utils_String::strtobool((string) $fileDefinition->forkable);
404 }
405 }
406 return TRUE;
407 }
408
409 }