Commit | Line | Data |
---|---|---|
92ee7b19 TO |
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 | /** | |
1521e0f8 | 13 | * The MixinLoader gets a list of extensions and mixins - then loads them. |
92ee7b19 TO |
14 | */ |
15 | class CRM_Extension_MixinLoader { | |
16 | ||
1521e0f8 TO |
17 | public function run($force = FALSE) { |
18 | $system = CRM_Extension_System::singleton(); | |
19 | $cache = $system->getCache(); | |
20 | ||
21 | $cachedScan = $force ? NULL : $cache->get('mixinScan'); | |
22 | $cachedBootData = $force ? NULL : $cache->get('mixinBoot'); | |
23 | ||
24 | [$funcFiles, $mixInfos] = $cachedScan ?: (new CRM_Extension_MixinScanner($system->getMapper(), $system->getManager(), TRUE))->build(); | |
25 | $bootData = $cachedBootData ?: new CRM_Extension_BootCache(); | |
26 | ||
27 | $this->loadMixins($bootData, $funcFiles, $mixInfos); | |
28 | ||
29 | if ($cachedScan === NULL) { | |
30 | $cache->set('mixinScan', [$funcFiles, $mixInfos], 24 * 60 * 60); | |
31 | } | |
32 | if ($cachedBootData === NULL) { | |
33 | $bootData->lock(); | |
34 | $cache->set('mixinBoot', $bootData, 24 * 60 * 60); | |
35 | } | |
36 | } | |
37 | ||
92ee7b19 TO |
38 | /** |
39 | * Load all extensions and call their respective function-files. | |
40 | * | |
92ee7b19 TO |
41 | * @throws \CRM_Core_Exception |
42 | */ | |
1521e0f8 | 43 | protected function loadMixins(CRM_Extension_BootCache $bootCache, array $liveFuncFiles, array $mixInfos): void { |
92ee7b19 TO |
44 | // == WIP == |
45 | // | |
46 | //Do mixins run strictly once (during boot)? Or could they run twice? Or incrementally? Some edge-cases: | |
47 | // - Mixins should make changes via dispatcher() and container(). If there's a Civi::reset(), then these things go away. We'll need to | |
48 | // re-register. (Example scenario: unit-testing) | |
49 | // - Mixins register for every active module. If a new module is enabled, then we haven't had a chance to run on the new extension. | |
50 | // - Mixins register for every active module. If an old module is disabled, then there may be old listeners/services lingering. | |
51 | if (!isset(\Civi::$statics[__CLASS__]['done'])) { | |
52 | \Civi::$statics[__CLASS__]['done'] = []; | |
53 | } | |
54 | $done = &\Civi::$statics[__CLASS__]['done']; | |
55 | ||
56 | // 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. | |
57 | // 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 | |
58 | // safe because we deduplicate. | |
59 | static $funcsByFile = []; | |
1795aaf5 | 60 | foreach ($liveFuncFiles as $verExpr => $file) { |
92ee7b19 TO |
61 | if (!isset($funcsByFile[$file])) { |
62 | $func = include_once $file; | |
63 | if (is_callable($func)) { | |
64 | $funcsByFile[$file] = $func; | |
65 | } | |
66 | else { | |
67 | error_log(sprintf('MixinLoader: Received invalid callback from \"%s\"', $file)); | |
68 | } | |
69 | } | |
70 | } | |
71 | ||
1795aaf5 | 72 | foreach ($mixInfos as $ext) { |
92ee7b19 TO |
73 | /** @var \CRM_Extension_MixInfo $ext */ |
74 | foreach ($ext->mixins as $verExpr) { | |
75 | $doneId = $ext->longName . '::' . $verExpr; | |
76 | if (isset($done[$doneId])) { | |
77 | continue; | |
78 | } | |
1795aaf5 TO |
79 | if (isset($funcsByFile[$liveFuncFiles[$verExpr]])) { |
80 | call_user_func($funcsByFile[$liveFuncFiles[$verExpr]], $ext, $bootCache); | |
92ee7b19 TO |
81 | $done[$doneId] = 1; |
82 | } | |
83 | else { | |
84 | error_log(sprintf('MixinLoader: Failed to load "%s" for extension "%s"', $verExpr, $ext->longName)); | |
85 | } | |
86 | } | |
87 | } | |
92ee7b19 TO |
88 | } |
89 | ||
90 | } |