Merge pull request #19906 from MikeyMJCO/patch-8
[civicrm-core.git] / CRM / Extension / ClassLoader.php
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 * Class CRM_Extension_ClassLoader
14 */
15 class CRM_Extension_ClassLoader {
16
17 /**
18 * List of class-loader features that are valid in this version of Civi.
19 *
20 * This may be useful for some extensions which enable/disable polyfills based on environment.
21 */
22 const FEATURES = ',psr0,psr4,';
23
24 /**
25 * @var CRM_Extension_Mapper
26 */
27 protected $mapper;
28
29 /**
30 * @var CRM_Extension_Container_Interface
31 */
32 protected $container;
33
34 /**
35 * @var CRM_Extension_Manager
36 */
37 protected $manager;
38
39 /**
40 * @var \Composer\Autoload\ClassLoader
41 */
42 protected $loader;
43
44 /**
45 * CRM_Extension_ClassLoader constructor.
46 * @param \CRM_Extension_Mapper $mapper
47 * @param \CRM_Extension_Container_Interface $container
48 * @param \CRM_Extension_Manager $manager
49 */
50 public function __construct(\CRM_Extension_Mapper $mapper, \CRM_Extension_Container_Interface $container, \CRM_Extension_Manager $manager) {
51 $this->mapper = $mapper;
52 $this->container = $container;
53 $this->manager = $manager;
54 }
55
56 public function __destruct() {
57 $this->unregister();
58 }
59
60 /**
61 * Registers this instance as an autoloader.
62 * @return CRM_Extension_ClassLoader
63 */
64 public function register() {
65 // In pre-installation environments, don't bother with caching.
66 if (!defined('CIVICRM_DSN') || defined('CIVICRM_TEST') || \CRM_Utils_System::isInUpgradeMode()) {
67 return $this->buildClassLoader()->register();
68 }
69
70 $file = $this->getCacheFile();
71 if (file_exists($file)) {
72 $loader = require $file;
73 }
74 else {
75 $loader = $this->buildClassLoader();
76 $ser = serialize($loader);
77 file_put_contents($file,
78 sprintf("<?php\nreturn unserialize(%s);", var_export($ser, 1))
79 );
80 }
81 return $loader->register();
82 }
83
84 /**
85 * @return \Composer\Autoload\ClassLoader
86 * @throws \CRM_Extension_Exception
87 * @throws \Exception
88 */
89 public function buildClassLoader() {
90 $loader = new \Composer\Autoload\ClassLoader();
91
92 $statuses = $this->manager->getStatuses();
93 foreach ($statuses as $key => $status) {
94 if ($status !== CRM_Extension_Manager::STATUS_INSTALLED) {
95 continue;
96 }
97 $path = $this->mapper->keyToBasePath($key);
98 $info = $this->mapper->keyToInfo($key);
99 if (!empty($info->classloader)) {
100 foreach ($info->classloader as $mapping) {
101 switch ($mapping['type']) {
102 case 'psr0':
103 $loader->add($mapping['prefix'], CRM_Utils_File::addTrailingSlash($path . '/' . $mapping['path']));
104 break;
105
106 case 'psr4':
107 $loader->addPsr4($mapping['prefix'], $path . '/' . $mapping['path']);
108 break;
109 }
110 $result[] = $mapping;
111 }
112 }
113 }
114
115 return $loader;
116 }
117
118 public function unregister() {
119 if ($this->loader) {
120 $this->loader->unregister();
121 $this->loader = NULL;
122 }
123 }
124
125 public function refresh() {
126 $this->unregister();
127 $file = $this->getCacheFile();
128 if (file_exists($file)) {
129 unlink($file);
130 }
131 $this->register();
132 }
133
134 /**
135 * @return string
136 */
137 protected function getCacheFile() {
138 $envId = \CRM_Core_Config_Runtime::getId();
139 $file = \Civi::paths()->getPath("[civicrm.compile]/CachedExtLoader.{$envId}.php");
140 return $file;
141 }
142
143 }