Skip to content
Snippets Groups Projects
polyfill.php 3.22 KiB
Newer Older
  • Learn to ignore specific revisions
  • Kevin Cristiano's avatar
    Kevin Cristiano committed
    <?php
    
    /**
     * When deploying on systems that lack mixin support, fake it.
     *
     * @mixinFile polyfill.php
     *
     * This polyfill does some (persnickity) deduplication, but it doesn't allow upgrades or shipping replacements in core.
     *
     * Note: The polyfill.php is designed to be copied into extensions for interoperability. Consequently, this file is
     * not used 'live' by `civicrm-core`. However, the file does need a canonical home, and it's convenient to keep it
     * adjacent to the actual mixin files.
     *
     * @param string $longName
     * @param string $shortName
     * @param string $basePath
     */
    return function ($longName, $shortName, $basePath) {
      // Construct imitations of the mixin services. These cannot work as well (e.g. with respect to
      // number of file-reads, deduping, upgrading)... but they should be OK for a few months while
      // the mixin services become available.
    
      // List of active mixins; deduped by version
      $mixinVers = [];
      foreach ((array) glob($basePath . '/mixin/*.mixin.php') as $f) {
        [$name, $ver] = explode('@', substr(basename($f), 0, -10));
        if (!isset($mixinVers[$name]) || version_compare($ver, $mixinVers[$name], '>')) {
          $mixinVers[$name] = $ver;
        }
      }
      $mixins = [];
      foreach ($mixinVers as $name => $ver) {
        $mixins[] = "$name@$ver";
      }
    
      // Imitate CRM_Extension_MixInfo.
      $mixInfo = new class() {
    
        /**
         * @var string
         */
        public $longName;
    
        /**
         * @var string
         */
        public $shortName;
    
        public $_basePath;
    
        public function getPath($file = NULL) {
          return $this->_basePath . ($file === NULL ? '' : (DIRECTORY_SEPARATOR . $file));
        }
    
        public function isActive() {
          return \CRM_Extension_System::singleton()->getMapper()->isActiveModule($this->shortName);
        }
    
      };
      $mixInfo->longName = $longName;
      $mixInfo->shortName = $shortName;
      $mixInfo->_basePath = $basePath;
    
      // Imitate CRM_Extension_BootCache.
      $bootCache = new class() {
    
        public function define($name, $callback) {
          $envId = \CRM_Core_Config_Runtime::getId();
          $oldExtCachePath = \Civi::paths()->getPath("[civicrm.compile]/CachedExtLoader.{$envId}.php");
          $stat = stat($oldExtCachePath);
          $file = Civi::paths()->getPath('[civicrm.compile]/CachedMixin.' . md5($name . ($stat['mtime'] ?? 0)) . '.php');
          if (file_exists($file)) {
            return include $file;
          }
          else {
            $data = $callback();
            file_put_contents($file, '<' . "?php\nreturn " . var_export($data, TRUE) . ';');
            return $data;
          }
        }
    
      };
    
      // Imitate CRM_Extension_MixinLoader::run()
      // Parse all live mixins before trying to scan any classes.
      global $_CIVIX_MIXIN_POLYFILL;
      foreach ($mixins as $mixin) {
        // If the exact same mixin is defined by multiple exts, just use the first one.
        if (!isset($_CIVIX_MIXIN_POLYFILL[$mixin])) {
          $_CIVIX_MIXIN_POLYFILL[$mixin] = include_once $basePath . '/mixin/' . $mixin . '.mixin.php';
        }
      }
      foreach ($mixins as $mixin) {
        // If there's trickery about installs/uninstalls/resets, then we may need to register a second time.
        if (!isset(\Civi::$statics[$longName][$mixin])) {
          \Civi::$statics[$longName][$mixin] = 1;
          $func = $_CIVIX_MIXIN_POLYFILL[$mixin];
          $func($mixInfo, $bootCache);
        }
      }
    };