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