Commit | Line | Data |
---|---|---|
6a488035 TO |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
bc77d7c0 | 4 | | Copyright CiviCRM LLC. All rights reserved. | |
6a488035 | 5 | | | |
bc77d7c0 TO |
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 | | |
6a488035 | 9 | +--------------------------------------------------------------------+ |
d25dd0ee | 10 | */ |
6a488035 TO |
11 | |
12 | /** | |
13 | * | |
14 | * | |
15 | * @package CRM | |
ca5cec67 | 16 | * @copyright CiviCRM LLC https://civicrm.org/licensing |
6a488035 TO |
17 | */ |
18 | class CRM_Core_ClassLoader { | |
19 | ||
20 | /** | |
21 | * We only need one instance of this object. So we use the singleton | |
22 | * pattern and cache the instance in this variable | |
23 | * @var object | |
6a488035 TO |
24 | */ |
25 | private static $_singleton = NULL; | |
26 | ||
649d6dd0 TO |
27 | /** |
28 | * The classes in CiviTest have ucky, non-standard naming. | |
29 | * | |
30 | * @var array | |
31 | * Array(string $className => string $filePath). | |
32 | */ | |
33 | private $civiTestClasses; | |
34 | ||
a0ee3941 EM |
35 | /** |
36 | * @param bool $force | |
37 | * | |
38 | * @return object | |
39 | */ | |
00be9182 | 40 | public static function &singleton($force = FALSE) { |
6a488035 TO |
41 | if ($force || self::$_singleton === NULL) { |
42 | self::$_singleton = new CRM_Core_ClassLoader(); | |
43 | } | |
44 | return self::$_singleton; | |
45 | } | |
46 | ||
47 | /** | |
e97c66ff | 48 | * Has this been registered already. |
49 | * | |
50 | * @var bool | |
6a488035 TO |
51 | */ |
52 | protected $_registered; | |
53 | ||
a0ee3941 | 54 | /** |
e97c66ff | 55 | * Class constructor. |
a0ee3941 | 56 | */ |
6a488035 TO |
57 | protected function __construct() { |
58 | $this->_registered = FALSE; | |
be2fb01f | 59 | $this->civiTestClasses = [ |
649d6dd0 TO |
60 | 'CiviCaseTestCase', |
61 | 'CiviDBAssert', | |
62 | 'CiviMailUtils', | |
63 | 'CiviReportTestCase', | |
64 | 'CiviSeleniumTestCase', | |
649d6dd0 TO |
65 | 'CiviTestSuite', |
66 | 'CiviUnitTestCase', | |
9e80c052 | 67 | 'CiviEndToEndTestCase', |
649d6dd0 TO |
68 | 'Contact', |
69 | 'ContributionPage', | |
70 | 'Custom', | |
71 | 'Event', | |
72 | 'Membership', | |
73 | 'Participant', | |
74 | 'PaypalPro', | |
be2fb01f | 75 | ]; |
6a488035 TO |
76 | } |
77 | ||
45b293a2 DS |
78 | /** |
79 | * Requires the autoload.php generated by composer | |
80 | * | |
81 | * @return void | |
82 | */ | |
83 | protected function requireComposerAutoload() { | |
d1f60655 DS |
84 | // We are trying to locate 'vendor/autoload.php'. When installing CiviCRM |
85 | // manually from the built tarball, that will be two directories up in the | |
86 | // civicrm-core directory. However, if civicrm-core was installed via | |
87 | // composer as a library, that'll be 5 directories up where composer was | |
88 | // run (ex. the Drupal root on a Drupal 8 site). | |
9f1588f9 DS |
89 | $civicrm_base_path = dirname(dirname(__DIR__)); |
90 | $top_path = dirname(dirname(dirname(dirname(dirname(__DIR__))))); | |
45b293a2 DS |
91 | |
92 | if (file_exists($civicrm_base_path . '/vendor/autoload.php')) { | |
93 | require_once $civicrm_base_path . '/vendor/autoload.php'; | |
94 | } | |
95 | elseif (file_exists($top_path . '/vendor/autoload.php')) { | |
96 | require_once $top_path . '/vendor/autoload.php'; | |
97 | } | |
98 | } | |
99 | ||
6a488035 TO |
100 | /** |
101 | * Registers this instance as an autoloader. | |
102 | * | |
6a0b768e TO |
103 | * @param bool $prepend |
104 | * Whether to prepend the autoloader or not. | |
6a488035 TO |
105 | * |
106 | * @api | |
107 | */ | |
00be9182 | 108 | public function register($prepend = FALSE) { |
6a488035 TO |
109 | if ($this->_registered) { |
110 | return; | |
111 | } | |
fa184193 TO |
112 | $civicrm_base_path = dirname(dirname(__DIR__)); |
113 | ||
45b293a2 | 114 | $this->requireComposerAutoload(); |
6a488035 TO |
115 | |
116 | // we do this to prevent a autoloader errors with joomla / 3rd party packages | |
117 | // use absolute path since we dont know the content of include_path as yet | |
118 | // CRM-11304 | |
fa184193 TO |
119 | // TODO Remove this autoloader. For civicrm-core and civicrm-packages, the composer autoloader works fine. |
120 | // Extensions rely on include_path-based autoloading | |
be2fb01f | 121 | spl_autoload_register([$this, 'loadClass'], TRUE, $prepend); |
6a488035 TO |
122 | |
123 | $this->_registered = TRUE; | |
3b8898e8 TO |
124 | // The ClassLoader runs before the classes are available. Approximate Civi::paths()->get('[civicrm.packages]'). |
125 | if (isset($GLOBALS['civicrm_paths']['civicrm.packages']['path'])) { | |
126 | $packages_path = rtrim($GLOBALS['civicrm_paths']['civicrm.packages']['path'], DIRECTORY_SEPARATOR); | |
127 | } | |
128 | else { | |
129 | $packages_path = implode(DIRECTORY_SEPARATOR, [$civicrm_base_path, 'packages']); | |
130 | } | |
be2fb01f | 131 | $include_paths = [ |
fa184193 TO |
132 | '.', |
133 | $civicrm_base_path, | |
21dfd5f5 | 134 | $packages_path, |
be2fb01f | 135 | ]; |
fa184193 TO |
136 | $include_paths = implode(PATH_SEPARATOR, $include_paths); |
137 | set_include_path($include_paths . PATH_SEPARATOR . get_include_path()); | |
7991d8ed | 138 | // @todo Why do we need to load this again? |
45b293a2 | 139 | $this->requireComposerAutoload(); |
6a488035 TO |
140 | } |
141 | ||
a0ee3941 EM |
142 | /** |
143 | * @param $class | |
144 | */ | |
00be9182 | 145 | public function loadClass($class) { |
fcb47cfd | 146 | if ($class === 'CiviCRM_API3_Exception' || $class === 'API_Exception') { |
eb1afb93 ON |
147 | //call internal error class api/Exception first |
148 | // allow api/Exception class call external error class | |
149 | // CiviCRM_API3_Exception | |
150 | require_once 'api/Exception.php'; | |
151 | } | |
6a488035 TO |
152 | if ( |
153 | // Only load classes that clearly belong to CiviCRM. | |
8581f9ae | 154 | // Note: api/v3 does not use classes, but api_v3's test-suite does |
dbaa9d7d | 155 | (0 === strncmp($class, 'CRM_', 4) || 0 === strncmp($class, 'CRMTraits', 9) || 0 === strncmp($class, 'api_v3_', 7) || 0 === strncmp($class, 'WebTest_', 8) || 0 === strncmp($class, 'E2E_', 4)) && |
6a488035 TO |
156 | // Do not load PHP 5.3 namespaced classes. |
157 | // (in a future version, maybe) | |
158 | FALSE === strpos($class, '\\') | |
159 | ) { | |
160 | $file = strtr($class, '_', '/') . '.php'; | |
161 | // There is some question about the best way to do this. | |
162 | // "require_once" is nice because it's simple and throws | |
a03a3680 TO |
163 | // intelligible errors. |
164 | if (FALSE != stream_resolve_include_path($file)) { | |
165 | require_once $file; | |
166 | } | |
6a488035 | 167 | } |
649d6dd0 TO |
168 | elseif (in_array($class, $this->civiTestClasses)) { |
169 | $file = "tests/phpunit/CiviTest/{$class}.php"; | |
170 | if (FALSE != stream_resolve_include_path($file)) { | |
171 | require_once $file; | |
172 | } | |
173 | } | |
174 | elseif ($class === 'CiviSeleniumSettings') { | |
175 | if (!empty($GLOBALS['_CV'])) { | |
176 | require_once 'tests/phpunit/CiviTest/CiviSeleniumSettings.auto.php'; | |
177 | } | |
178 | elseif (CRM_Utils_File::isIncludable('tests/phpunit/CiviTest/CiviSeleniumSettings.php')) { | |
179 | require_once 'tests/phpunit/CiviTest/CiviSeleniumSettings.php'; | |
180 | } | |
181 | } | |
6a488035 | 182 | } |
a03a3680 | 183 | |
6a488035 | 184 | } |