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 | /** | |
13 | * The MixinLoader tracks a list of extensions and mixins. | |
14 | */ | |
15 | class CRM_Extension_MixinLoader { | |
16 | ||
92ee7b19 TO |
17 | /** |
18 | * Load all extensions and call their respective function-files. | |
19 | * | |
92ee7b19 TO |
20 | * @throws \CRM_Core_Exception |
21 | */ | |
1795aaf5 | 22 | public function run(CRM_Extension_BootCache $bootCache, array $liveFuncFiles, array $mixInfos): void { |
92ee7b19 TO |
23 | // == WIP == |
24 | // | |
25 | //Do mixins run strictly once (during boot)? Or could they run twice? Or incrementally? Some edge-cases: | |
26 | // - Mixins should make changes via dispatcher() and container(). If there's a Civi::reset(), then these things go away. We'll need to | |
27 | // re-register. (Example scenario: unit-testing) | |
28 | // - 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. | |
29 | // - Mixins register for every active module. If an old module is disabled, then there may be old listeners/services lingering. | |
30 | if (!isset(\Civi::$statics[__CLASS__]['done'])) { | |
31 | \Civi::$statics[__CLASS__]['done'] = []; | |
32 | } | |
33 | $done = &\Civi::$statics[__CLASS__]['done']; | |
34 | ||
35 | // 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. | |
36 | // 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 | |
37 | // safe because we deduplicate. | |
38 | static $funcsByFile = []; | |
1795aaf5 | 39 | foreach ($liveFuncFiles as $verExpr => $file) { |
92ee7b19 TO |
40 | if (!isset($funcsByFile[$file])) { |
41 | $func = include_once $file; | |
42 | if (is_callable($func)) { | |
43 | $funcsByFile[$file] = $func; | |
44 | } | |
45 | else { | |
46 | error_log(sprintf('MixinLoader: Received invalid callback from \"%s\"', $file)); | |
47 | } | |
48 | } | |
49 | } | |
50 | ||
1795aaf5 | 51 | foreach ($mixInfos as $ext) { |
92ee7b19 TO |
52 | /** @var \CRM_Extension_MixInfo $ext */ |
53 | foreach ($ext->mixins as $verExpr) { | |
54 | $doneId = $ext->longName . '::' . $verExpr; | |
55 | if (isset($done[$doneId])) { | |
56 | continue; | |
57 | } | |
1795aaf5 TO |
58 | if (isset($funcsByFile[$liveFuncFiles[$verExpr]])) { |
59 | call_user_func($funcsByFile[$liveFuncFiles[$verExpr]], $ext, $bootCache); | |
92ee7b19 TO |
60 | $done[$doneId] = 1; |
61 | } | |
62 | else { | |
63 | error_log(sprintf('MixinLoader: Failed to load "%s" for extension "%s"', $verExpr, $ext->longName)); | |
64 | } | |
65 | } | |
66 | } | |
92ee7b19 TO |
67 | } |
68 | ||
69 | } |