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