Merge pull request #15956 from colemanw/removeFn
[civicrm-core.git] / CRM / Core / Component.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
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 |
9 +--------------------------------------------------------------------+
10 */
11
12 /**
13 * Component stores all the static and dynamic information of the various
14 * CiviCRM components
15 *
16 * @package CRM
17 * @copyright CiviCRM LLC https://civicrm.org/licensing
18 * $Id$
19 *
20 */
21 class CRM_Core_Component {
22
23 /**
24 * End part (filename) of the component information class'es name
25 * that needs to be present in components main directory.
26 */
27 const COMPONENT_INFO_CLASS = 'Info';
28
29 /**
30 * @var array
31 */
32 public static $_contactSubTypes = NULL;
33
34 /**
35 * @param bool $force
36 *
37 * @return CRM_Core_Component_Info[]
38 */
39 private static function &_info($force = FALSE) {
40 if (!isset(Civi::$statics[__CLASS__]['info'])|| $force) {
41 Civi::$statics[__CLASS__]['info'] = [];
42 $c = [];
43
44 $config = CRM_Core_Config::singleton();
45 $c = self::getComponents();
46
47 foreach ($c as $name => $comp) {
48 if (in_array($name, $config->enableComponents)) {
49 Civi::$statics[__CLASS__]['info'][$name] = $comp;
50 }
51 }
52 }
53
54 return Civi::$statics[__CLASS__]['info'];
55 }
56
57 /**
58 * @param string $name
59 * @param null $attribute
60 *
61 * @return mixed
62 */
63 public static function get($name, $attribute = NULL) {
64 $comp = CRM_Utils_Array::value($name, self::_info());
65 if ($attribute) {
66 return CRM_Utils_Array::value($attribute, $comp->info);
67 }
68 return $comp;
69 }
70
71 /**
72 * @param bool $force
73 *
74 * @return CRM_Core_Component_Info[]
75 * @throws Exception
76 */
77 public static function &getComponents($force = FALSE) {
78 if (!isset(Civi::$statics[__CLASS__]['all']) || $force) {
79 Civi::$statics[__CLASS__]['all'] = [];
80
81 $cr = new CRM_Core_DAO_Component();
82 $cr->find(FALSE);
83 while ($cr->fetch()) {
84 $infoClass = $cr->namespace . '_' . self::COMPONENT_INFO_CLASS;
85 $infoClassFile = str_replace('_', DIRECTORY_SEPARATOR, $infoClass) . '.php';
86 if (!CRM_Utils_File::isIncludable($infoClassFile)) {
87 continue;
88 }
89 require_once $infoClassFile;
90 $infoObject = new $infoClass($cr->name, $cr->namespace, $cr->id);
91 if ($infoObject->info['name'] !== $cr->name) {
92 CRM_Core_Error::fatal("There is a discrepancy between name in component registry and in info file ({$cr->name}).");
93 }
94 Civi::$statics[__CLASS__]['all'][$cr->name] = $infoObject;
95 unset($infoObject);
96 }
97 }
98
99 return Civi::$statics[__CLASS__]['all'];
100 }
101
102 /**
103 * @return array
104 * Array(string $name => int $id).
105 */
106 public static function &getComponentIDs() {
107 $componentIDs = [];
108
109 $cr = new CRM_Core_DAO_Component();
110 $cr->find(FALSE);
111 while ($cr->fetch()) {
112 $componentIDs[$cr->name] = $cr->id;
113 }
114
115 return $componentIDs;
116 }
117
118 /**
119 * @param bool $force
120 *
121 * @return CRM_Core_Component_Info[]
122 */
123 public static function &getEnabledComponents($force = FALSE) {
124 return self::_info($force);
125 }
126
127 public static function flushEnabledComponents() {
128 unset(Civi::$statics[__CLASS__]);
129 CRM_Core_BAO_Navigation::resetNavigation();
130 }
131
132 /**
133 * @param bool $translated
134 *
135 * @return array
136 */
137 public static function &getNames($translated = FALSE) {
138 $allComponents = self::getComponents();
139
140 $names = [];
141 foreach ($allComponents as $name => $comp) {
142 if ($translated) {
143 $names[$comp->componentID] = $comp->info['translatedName'];
144 }
145 else {
146 $names[$comp->componentID] = $name;
147 }
148 }
149 return $names;
150 }
151
152 /**
153 * @param $args
154 * @param $type
155 *
156 * @return bool
157 */
158 public static function invoke(&$args, $type) {
159 $info = self::_info();
160 $config = CRM_Core_Config::singleton();
161
162 $firstArg = CRM_Utils_Array::value(1, $args, '');
163 $secondArg = CRM_Utils_Array::value(2, $args, '');
164 foreach ($info as $name => $comp) {
165 if (in_array($name, $config->enableComponents) &&
166 (($comp->info['url'] === $firstArg && $type == 'main') ||
167 ($comp->info['url'] === $secondArg && $type == 'admin')
168 )
169 ) {
170 if ($type == 'main') {
171 // also set the smarty variables to the current component
172 $template = CRM_Core_Smarty::singleton();
173 $template->assign('activeComponent', $name);
174 if (!empty($comp->info[$name]['formTpl'])) {
175 $template->assign('formTpl', $comp->info[$name]['formTpl']);
176 }
177 if (!empty($comp->info[$name]['css'])) {
178 $styleSheets = '<style type="text/css">@import url(' . "{$config->resourceBase}css/{$comp->info[$name]['css']});</style>";
179 CRM_Utils_System::addHTMLHead($styleSheet);
180 }
181 }
182 $inv = $comp->getInvokeObject();
183 $inv->$type($args);
184 return TRUE;
185 }
186 }
187 return FALSE;
188 }
189
190 /**
191 * @return array
192 */
193 public static function xmlMenu() {
194
195 // lets build the menu for all components
196 $info = self::getComponents(TRUE);
197
198 $files = [];
199 foreach ($info as $name => $comp) {
200 $files = array_merge($files,
201 $comp->menuFiles()
202 );
203 }
204
205 return $files;
206 }
207
208 /**
209 * @return array
210 */
211 public static function &menu() {
212 $info = self::_info();
213 $items = [];
214 foreach ($info as $name => $comp) {
215 $mnu = $comp->getMenuObject();
216
217 $ret = $mnu->permissioned();
218 $items = array_merge($items, $ret);
219
220 $ret = $mnu->main($task);
221 $items = array_merge($items, $ret);
222 }
223 return $items;
224 }
225
226 /**
227 * @param string $componentName
228 *
229 * @return mixed
230 */
231 public static function getComponentID($componentName) {
232 $info = self::_info();
233 if (!empty($info[$componentName])) {
234 return $info[$componentName]->componentID;
235 }
236 else {
237 return;
238 }
239 }
240
241 /**
242 * @param int $componentID
243 *
244 * @return int|null|string
245 */
246 public static function getComponentName($componentID) {
247 $info = self::_info();
248
249 $componentName = NULL;
250 foreach ($info as $compName => $component) {
251 if ($component->componentID == $componentID) {
252 $componentName = $compName;
253 break;
254 }
255 }
256
257 return $componentName;
258 }
259
260 /**
261 * @return array
262 */
263 public static function &getQueryFields($checkPermission = TRUE) {
264 $info = self::_info();
265 $fields = [];
266 foreach ($info as $name => $comp) {
267 if ($comp->usesSearch()) {
268 $bqr = $comp->getBAOQueryObject();
269 $flds = $bqr->getFields($checkPermission);
270 $fields = array_merge($fields, $flds);
271 }
272 }
273 return $fields;
274 }
275
276 /**
277 * @param $query
278 * @param string $fnName
279 */
280 public static function alterQuery(&$query, $fnName) {
281 $info = self::_info();
282
283 foreach ($info as $name => $comp) {
284 if ($comp->usesSearch()) {
285 $bqr = $comp->getBAOQueryObject();
286 $bqr->$fnName($query);
287 }
288 }
289 }
290
291 /**
292 * @param string $fieldName
293 * @param $mode
294 * @param $side
295 *
296 * @return null
297 */
298 public static function from($fieldName, $mode, $side) {
299 $info = self::_info();
300
301 $from = NULL;
302 foreach ($info as $name => $comp) {
303 if ($comp->usesSearch()) {
304 $bqr = $comp->getBAOQueryObject();
305 $from = $bqr->from($fieldName, $mode, $side);
306 if ($from) {
307 return $from;
308 }
309 }
310 }
311 return $from;
312 }
313
314 /**
315 * @param $mode
316 * @param bool $includeCustomFields
317 *
318 * @return null
319 */
320 public static function &defaultReturnProperties(
321 $mode,
322 $includeCustomFields = TRUE
323 ) {
324 $info = self::_info();
325
326 $properties = NULL;
327 foreach ($info as $name => $comp) {
328 if ($comp->usesSearch()) {
329 $bqr = $comp->getBAOQueryObject();
330 $properties = $bqr->defaultReturnProperties($mode, $includeCustomFields);
331 if ($properties) {
332 return $properties;
333 }
334 }
335 }
336 return $properties;
337 }
338
339 /**
340 * @param CRM_Core_Form $form
341 */
342 public static function &buildSearchForm(&$form) {
343 $info = self::_info();
344
345 foreach ($info as $name => $comp) {
346 if ($comp->usesSearch()) {
347 $bqr = $comp->getBAOQueryObject();
348 $bqr->buildSearchForm($form);
349 }
350 }
351 }
352
353 /**
354 * @param $row
355 * @param int $id
356 */
357 public static function searchAction(&$row, $id) {
358 $info = self::_info();
359
360 foreach ($info as $name => $comp) {
361 if ($comp->usesSearch()) {
362 $bqr = $comp->getBAOQueryObject();
363 $bqr->searchAction($row, $id);
364 }
365 }
366 }
367
368 /**
369 * @return array|null
370 */
371 public static function &contactSubTypes() {
372 if (self::$_contactSubTypes == NULL) {
373 self::$_contactSubTypes = [];
374 }
375 return self::$_contactSubTypes;
376 }
377
378 /**
379 * @param $subType
380 * @param $op
381 *
382 * @return null
383 */
384 public static function &contactSubTypeProperties($subType, $op) {
385 $properties = self::contactSubTypes();
386 if (array_key_exists($subType, $properties) &&
387 array_key_exists($op, $properties[$subType])
388 ) {
389 return $properties[$subType][$op];
390 }
391 return CRM_Core_DAO::$_nullObject;
392 }
393
394 /**
395 * Handle table dependencies of components.
396 *
397 * @param array $tables
398 * Array of tables.
399 *
400 */
401 public static function tableNames(&$tables) {
402 $info = self::_info();
403
404 foreach ($info as $name => $comp) {
405 if ($comp->usesSearch()) {
406 $bqr = $comp->getBAOQueryObject();
407 $bqr->tableNames($tables);
408 }
409 }
410 }
411
412 /**
413 * Get components info from info file.
414 *
415 * @param string $crmFolderDir
416 *
417 * @return array
418 */
419 public static function getComponentsFromFile($crmFolderDir) {
420 $components = [];
421 //traverse CRM folder and check for Info file
422 if (is_dir($crmFolderDir) && $dir = opendir($crmFolderDir)) {
423 while ($subDir = readdir($dir)) {
424 // skip the extensions diretory since it has an Info.php file also
425 if ($subDir == 'Extension') {
426 continue;
427 }
428
429 $infoFile = $crmFolderDir . "/{$subDir}/" . self::COMPONENT_INFO_CLASS . '.php';
430 if (file_exists($infoFile)) {
431 $infoClass = 'CRM_' . $subDir . '_' . self::COMPONENT_INFO_CLASS;
432 require_once str_replace('_', DIRECTORY_SEPARATOR, $infoClass) . '.php';
433 $infoObject = new $infoClass(NULL, NULL, NULL);
434 $components[$infoObject->info['name']] = $infoObject;
435 unset($infoObject);
436 }
437 }
438 }
439
440 return $components;
441 }
442
443 }