Merge pull request #18378 from colemanw/noMoreStupidHTMLTypes
[civicrm-core.git] / CRM / Case / XMLRepository.php
CommitLineData
fa1c763d
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
bc77d7c0 4 | Copyright CiviCRM LLC. All rights reserved. |
fa1c763d 5 | |
bc77d7c0
TO
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
fa1c763d 9 +--------------------------------------------------------------------+
d25dd0ee 10 */
fa1c763d
TO
11
12/**
13 *
14 * @package CRM
ca5cec67 15 * @copyright CiviCRM LLC https://civicrm.org/licensing
fa1c763d 16 * The XMLRepository is responsible for loading XML for case-types.
7458ddd3
TO
17 * It includes any bulk operations that apply across the list of all XML
18 * documents of all case-types.
fa1c763d
TO
19 */
20class CRM_Case_XMLRepository {
21 private static $singleton;
22
23 /**
51dda21e
SL
24 * @var array
25 * <String,SimpleXMLElement>
fa1c763d 26 */
be2fb01f 27 protected $xml = [];
fa1c763d
TO
28
29 /**
cc101011 30 * @var array|null
fa1c763d
TO
31 */
32 protected $hookCache = NULL;
33
34 /**
cc101011 35 * Symbolic names of case-types.
36 *
37 * @var array|null
fa1c763d
TO
38 */
39 protected $allCaseTypes = NULL;
40
41 /**
42 * @param bool $fresh
e19323c9 43 * @return CRM_Case_XMLRepository
fa1c763d
TO
44 */
45 public static function singleton($fresh = FALSE) {
46 if (!self::$singleton || $fresh) {
47 self::$singleton = new static();
48 }
49 return self::$singleton;
50 }
51
e492e278 52 public function flush() {
be2fb01f 53 $this->xml = [];
e492e278
TO
54 $this->hookCache = NULL;
55 $this->allCaseTypes = NULL;
be2fb01f 56 CRM_Core_DAO::$_dbColumnValueCache = [];
e492e278
TO
57 }
58
fa1c763d 59 /**
54957108 60 * Class constructor.
61 *
62 * @param array $allCaseTypes
63 * @param array $xml
fa1c763d 64 */
be2fb01f 65 public function __construct($allCaseTypes = NULL, $xml = []) {
e19323c9 66 $this->allCaseTypes = $allCaseTypes;
fa1c763d
TO
67 $this->xml = $xml;
68 }
69
70 /**
54957108 71 * Retrieve case.
72 *
fa1c763d 73 * @param string $caseType
54957108 74 *
75 * @return FALSE|\SimpleXMLElement
76 * @throws \CRM_Core_Exception
fa1c763d
TO
77 */
78 public function retrieve($caseType) {
ff7838ab 79 // check if xml definition is defined in db
80 $definition = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_CaseType', $caseType, 'definition', 'name');
81
82 if (!empty($definition)) {
edcc7f99
TO
83 list ($xml, $error) = CRM_Utils_XML::parseString($definition);
84 if (!$xml) {
85 throw new CRM_Core_Exception("Failed to parse CaseType XML: $error");
86 }
87 return $xml;
ff7838ab 88 }
89
46ec593d
TO
90 // TODO In 4.6 or 5.0, remove support for weird machine-names
91 //if (!CRM_Case_BAO_CaseType::isValidName($caseType)) {
92 // // perhaps caller provider a the label instead of the name?
93 // throw new CRM_Core_Exception("Cannot load caseType with malformed name [$caseType]");
94 //}
fa1c763d 95
f3acfdd9 96 if (empty($this->xml[$caseType])) {
32f1c917
TO
97 $fileXml = $this->retrieveFile($caseType);
98 if ($fileXml) {
99 $this->xml[$caseType] = $fileXml;
0db6c3e1
TO
100 }
101 else {
32f1c917 102 return FALSE;
46ec593d 103 }
32f1c917
TO
104 }
105 return $this->xml[$caseType];
106 }
bb68492c 107
32f1c917 108 /**
54957108 109 * Retrieve file.
110 *
32f1c917
TO
111 * @param string $caseType
112 * @return SimpleXMLElement|FALSE
113 */
114 public function retrieveFile($caseType) {
115 $fileName = NULL;
116 $fileXml = NULL;
fa1c763d 117
32f1c917
TO
118 if (CRM_Case_BAO_CaseType::isValidName($caseType)) {
119 // Search for a file based directly on the $caseType name
120 $fileName = $this->findXmlFile($caseType);
121 }
fa1c763d 122
32f1c917
TO
123 // For backward compatibility, also search for double-munged file names
124 // TODO In 4.6 or 5.0, remove support for loading double-munged file names
125 if (!$fileName || !file_exists($fileName)) {
126 $fileName = $this->findXmlFile(CRM_Case_XMLProcessor::mungeCaseType($caseType));
127 }
128
129 if ($fileName && file_exists($fileName)) {
fa1c763d
TO
130 // read xml file
131 $dom = new DomDocument();
f9857c59
JP
132 $xmlString = file_get_contents($fileName);
133 $dom->loadXML($xmlString);
134 $dom->documentURI = $fileName;
fa1c763d 135 $dom->xinclude();
32f1c917 136 $fileXml = simplexml_import_dom($dom);
fa1c763d 137 }
32f1c917
TO
138
139 return $fileXml;
fa1c763d
TO
140 }
141
a8354614 142 /**
54957108 143 * Find xml file.
144 *
a8354614 145 * @param string $caseType
72b3a70c
CW
146 * @return null|string
147 * file path
a8354614 148 */
e547f744
TO
149 public function findXmlFile($caseType) {
150 // first check custom templates directory
a8354614
TO
151 $fileName = NULL;
152
153 if (!$fileName || !file_exists($fileName)) {
154 $caseTypesViaHook = $this->getCaseTypesViaHook();
155 if (isset($caseTypesViaHook[$caseType], $caseTypesViaHook[$caseType]['file'])) {
156 $fileName = $caseTypesViaHook[$caseType]['file'];
157 }
158 }
159
160 if (!$fileName || !file_exists($fileName)) {
161 $config = CRM_Core_Config::singleton();
162 if (isset($config->customTemplateDir) && $config->customTemplateDir) {
163 // check if the file exists in the custom templates directory
164 $fileName = implode(DIRECTORY_SEPARATOR,
be2fb01f 165 [
a8354614
TO
166 $config->customTemplateDir,
167 'CRM',
168 'Case',
169 'xml',
170 'configuration',
171 "$caseType.xml",
be2fb01f 172 ]
a8354614
TO
173 );
174 }
175 }
176
177 if (!$fileName || !file_exists($fileName)) {
178 if (!file_exists($fileName)) {
179 // check if file exists locally
180 $fileName = implode(DIRECTORY_SEPARATOR,
be2fb01f 181 [
a8354614
TO
182 dirname(__FILE__),
183 'xml',
184 'configuration',
185 "$caseType.xml",
be2fb01f 186 ]
a8354614
TO
187 );
188 }
189
190 if (!file_exists($fileName)) {
191 // check if file exists locally
192 $fileName = implode(DIRECTORY_SEPARATOR,
be2fb01f 193 [
a8354614
TO
194 dirname(__FILE__),
195 'xml',
196 'configuration.sample',
197 "$caseType.xml",
be2fb01f 198 ]
a8354614
TO
199 );
200 }
201 }
202 return file_exists($fileName) ? $fileName : NULL;
203 }
204
fa1c763d
TO
205 /**
206 * @return array
207 * @see CRM_Utils_Hook::caseTypes
208 */
209 public function getCaseTypesViaHook() {
210 if ($this->hookCache === NULL) {
be2fb01f 211 $this->hookCache = [];
fa1c763d
TO
212 CRM_Utils_Hook::caseTypes($this->hookCache);
213 }
214 return $this->hookCache;
215 }
e19323c9
TO
216
217 /**
bb68492c 218 * @return array<string> symbolic names of case-types
e19323c9
TO
219 */
220 public function getAllCaseTypes() {
221 if ($this->allCaseTypes === NULL) {
222 $this->allCaseTypes = CRM_Case_PseudoConstant::caseType("name");
223 }
224 return $this->allCaseTypes;
225 }
226
7458ddd3
TO
227 /**
228 * @return array<string> symbolic-names of activity-types
229 */
230 public function getAllDeclaredActivityTypes() {
be2fb01f 231 $result = [];
7458ddd3
TO
232
233 $p = new CRM_Case_XMLProcessor_Process();
234 foreach ($this->getAllCaseTypes() as $caseTypeName) {
235 $caseTypeXML = $this->retrieve($caseTypeName);
236 $result = array_merge($result, $p->getDeclaredActivityTypes($caseTypeXML));
237 }
238
239 $result = array_unique($result);
240 sort($result);
241 return $result;
242 }
243
244 /**
d0a94888
AF
245 * Relationships are straight from XML, described from perspective of non-client
246 *
7458ddd3
TO
247 * @return array<string> symbolic-names of relationship-types
248 */
249 public function getAllDeclaredRelationshipTypes() {
be2fb01f 250 $result = [];
7458ddd3
TO
251
252 $p = new CRM_Case_XMLProcessor_Process();
253 foreach ($this->getAllCaseTypes() as $caseTypeName) {
254 $caseTypeXML = $this->retrieve($caseTypeName);
255 $result = array_merge($result, $p->getDeclaredRelationshipTypes($caseTypeXML));
256 }
257
258 $result = array_unique($result);
259 sort($result);
260 return $result;
261 }
262
e19323c9
TO
263 /**
264 * Determine the number of times a particular activity-type is
265 * referenced in CiviCase XML.
266 *
64bd5a0e
TO
267 * @param string $activityType
268 * Symbolic-name of an activity type.
e19323c9
TO
269 * @return int
270 */
00be9182 271 public function getActivityReferenceCount($activityType) {
e19323c9
TO
272 $p = new CRM_Case_XMLProcessor_Process();
273 $count = 0;
274 foreach ($this->getAllCaseTypes() as $caseTypeName) {
275 $caseTypeXML = $this->retrieve($caseTypeName);
276 if (in_array($activityType, $p->getDeclaredActivityTypes($caseTypeXML))) {
277 $count++;
278 }
279 }
280 return $count;
281 }
282
283 /**
284 * Determine the number of times a particular activity-type is
285 * referenced in CiviCase XML.
286 *
64bd5a0e
TO
287 * @param string $relationshipTypeName
288 * Symbolic-name of a relationship-type.
e19323c9
TO
289 * @return int
290 */
00be9182 291 public function getRelationshipReferenceCount($relationshipTypeName) {
e19323c9
TO
292 $p = new CRM_Case_XMLProcessor_Process();
293 $count = 0;
294 foreach ($this->getAllCaseTypes() as $caseTypeName) {
295 $caseTypeXML = $this->retrieve($caseTypeName);
296 if (in_array($relationshipTypeName, $p->getDeclaredRelationshipTypes($caseTypeXML))) {
297 $count++;
298 }
299 }
300 return $count;
301 }
302
fa1c763d 303}