4 * When deploying on systems that lack mixin support, fake it.
6 * @mixinFile polyfill.php
8 * This polyfill does some (persnickity) deduplication, but it doesn't allow upgrades or shipping replacements in core.
10 * Note: The polyfill.php is designed to be copied into extensions for interoperability. Consequently, this file is
11 * not used 'live' by `civicrm-core`. However, the file does need a canonical home, and it's convenient to keep it
12 * adjacent to the actual mixin files.
14 * @param string $longName
15 * @param string $shortName
16 * @param string $basePath
18 return function ($longName, $shortName, $basePath) {
19 // Construct imitations of the mixin services. These cannot work as well (e.g. with respect to
20 // number of file-reads, deduping, upgrading)... but they should be OK for a few months while
21 // the mixin services become available.
23 // List of active mixins; deduped by version
25 foreach ((array) glob($basePath . '/mixin/*.mixin.php') as $f) {
26 [$name, $ver] = explode('@', substr(basename($f), 0, -10));
27 if (!isset($mixinVers[$name]) ||
version_compare($ver, $mixinVers[$name], '>')) {
28 $mixinVers[$name] = $ver;
32 foreach ($mixinVers as $name => $ver) {
33 $mixins[] = "$name@$ver";
36 // Imitate CRM_Extension_MixInfo.
37 $mixInfo = new class() {
51 public function getPath($file = NULL) {
52 return $this->_basePath
. ($file === NULL ?
'' : (DIRECTORY_SEPARATOR
. $file));
55 public function isActive() {
56 return \CRM_Extension_System
::singleton()->getMapper()->isActiveModule($this->shortName
);
60 $mixInfo->longName
= $longName;
61 $mixInfo->shortName
= $shortName;
62 $mixInfo->_basePath
= $basePath;
64 // Imitate CRM_Extension_BootCache.
65 $bootCache = new class() {
67 public function define($name, $callback) {
68 $envId = \CRM_Core_Config_Runtime
::getId();
69 $oldExtCachePath = \Civi
::paths()->getPath("[civicrm.compile]/CachedExtLoader.{$envId}.php");
70 $stat = stat($oldExtCachePath);
71 $file = Civi
::paths()->getPath('[civicrm.compile]/CachedMixin.' . md5($name . ($stat['mtime'] ??
0)) . '.php');
72 if (file_exists($file)) {
77 file_put_contents($file, '<' . "?php\nreturn " . var_export($data, 1) . ';');
84 // Imitate CRM_Extension_MixinLoader::run()
85 // Parse all live mixins before trying to scan any classes.
86 global $_CIVIX_MIXIN_POLYFILL;
87 foreach ($mixins as $mixin) {
88 // If the exact same mixin is defined by multiple exts, just use the first one.
89 if (!isset($_CIVIX_MIXIN_POLYFILL[$mixin])) {
90 $_CIVIX_MIXIN_POLYFILL[$mixin] = include_once $basePath . '/mixin/' . $mixin . '.mixin.php';
93 foreach ($mixins as $mixin) {
94 // If there's trickery about installs/uninstalls/resets, then we may need to register a second time.
95 if (!isset(\Civi
::$statics[__FUNCTION__
][$mixin])) {
96 \Civi
::$statics[__FUNCTION__
][$mixin] = 1;
97 $func = $_CIVIX_MIXIN_POLYFILL[$mixin];
98 $func($mixInfo, $bootCache);