dev/core#3828 Fix required fields check to account 0
[civicrm-core.git] / CRM / Extension / MixinLoader.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 * The MixinLoader gets a list of extensions and mixins - then loads them.
14 */
15 class CRM_Extension_MixinLoader {
16
17 /**
18 * List extension-mixins that have been loaded already.
19 *
20 * @var array
21 */
22 protected $done = [];
23
24 public function run($force = FALSE) {
25 $system = CRM_Extension_System::singleton();
26 $cache = $system->getCache();
27
28 $cachedScan = $force ? NULL : $cache->get('mixinScan');
29 $cachedBootData = $force ? NULL : $cache->get('mixinBoot');
30
31 [$funcFiles, $mixInfos] = $cachedScan ?: (new CRM_Extension_MixinScanner($system->getMapper(), $system->getManager(), TRUE))->build();
32 $bootData = $cachedBootData ?: new CRM_Extension_BootCache();
33
34 $this->loadMixins($bootData, $funcFiles, $mixInfos);
35
36 if ($cachedScan === NULL) {
37 $cache->set('mixinScan', [$funcFiles, $mixInfos], 24 * 60 * 60);
38 }
39 if ($cachedBootData === NULL) {
40 $bootData->lock();
41 $cache->set('mixinBoot', $bootData, 24 * 60 * 60);
42 }
43 }
44
45 /**
46 * Load all extensions and call their respective function-files.
47 *
48 * @throws \CRM_Core_Exception
49 */
50 protected function loadMixins(CRM_Extension_BootCache $bootCache, array $liveFuncFiles, array $mixInfos): void {
51 // Read each live func-file once, even if there's some kind of Civi::reset(). This avoids hard-crash where the func-file registers a PHP class/function/interface.
52 // Granted, PHP symbols require care to avoid conflicts between `mymixin@1.0` and `mymixin@2.0` -- but you can deal with that. For minor-versions, you're
53 // safe because we deduplicate.
54 static $funcsByFile = [];
55 foreach ($liveFuncFiles as $verExpr => $file) {
56 if (!isset($funcsByFile[$file])) {
57 $func = include_once $file;
58 if (is_callable($func)) {
59 $funcsByFile[$file] = $func;
60 }
61 else {
62 error_log(sprintf('MixinLoader: Received invalid callback from \"%s\"', $file));
63 }
64 }
65 }
66
67 foreach ($mixInfos as $ext) {
68 /** @var \CRM_Extension_MixInfo $ext */
69 foreach ($ext->mixins as $verExpr) {
70 $doneId = $ext->longName . '::' . $verExpr;
71 if (isset($this->done[$doneId])) {
72 continue;
73 }
74 if (isset($funcsByFile[$liveFuncFiles[$verExpr]])) {
75 call_user_func($funcsByFile[$liveFuncFiles[$verExpr]], $ext, $bootCache);
76 $this->done[$doneId] = 1;
77 }
78 else {
79 error_log(sprintf('MixinLoader: Failed to load "%s" for extension "%s"', $verExpr, $ext->longName));
80 }
81 }
82 }
83 }
84
85 }