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 | ||
27b71274 TO |
17 | /** |
18 | * List extension-mixins that have been loaded already. | |
19 | * | |
20 | * @var array | |
21 | */ | |
22 | protected $done = []; | |
23 | ||
1521e0f8 TO |
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 | ||
92ee7b19 TO |
45 | /** |
46 | * Load all extensions and call their respective function-files. | |
47 | * | |
92ee7b19 TO |
48 | * @throws \CRM_Core_Exception |
49 | */ | |
1521e0f8 | 50 | protected function loadMixins(CRM_Extension_BootCache $bootCache, array $liveFuncFiles, array $mixInfos): void { |
92ee7b19 TO |
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 = []; | |
1795aaf5 | 55 | foreach ($liveFuncFiles as $verExpr => $file) { |
92ee7b19 TO |
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 | ||
1795aaf5 | 67 | foreach ($mixInfos as $ext) { |
92ee7b19 TO |
68 | /** @var \CRM_Extension_MixInfo $ext */ |
69 | foreach ($ext->mixins as $verExpr) { | |
70 | $doneId = $ext->longName . '::' . $verExpr; | |
27b71274 | 71 | if (isset($this->done[$doneId])) { |
92ee7b19 TO |
72 | continue; |
73 | } | |
1795aaf5 TO |
74 | if (isset($funcsByFile[$liveFuncFiles[$verExpr]])) { |
75 | call_user_func($funcsByFile[$liveFuncFiles[$verExpr]], $ext, $bootCache); | |
27b71274 | 76 | $this->done[$doneId] = 1; |
92ee7b19 TO |
77 | } |
78 | else { | |
79 | error_log(sprintf('MixinLoader: Failed to load "%s" for extension "%s"', $verExpr, $ext->longName)); | |
80 | } | |
81 | } | |
82 | } | |
92ee7b19 TO |
83 | } |
84 | ||
85 | } |