[TASK] Update to latest class alias loader version
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Core / ClassLoadingInformation.php
1 <?php
2 namespace TYPO3\CMS\Core\Core;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use Composer\Autoload\ClassLoader as ComposerClassLoader;
18 use Helhum\ClassAliasLoader\ClassAliasMap;
19 use TYPO3\CMS\Core\Package\PackageInterface;
20 use TYPO3\CMS\Core\Utility\GeneralUtility;
21
22 /**
23 * Get and manipulate class loading information, only necessary/in use
24 * when TYPO3 is not purely set up by composer but when e.g. extensions are installed via the extension manager
25 * by utilizing the composer class loader and adding more information built by the ClassLoadingInformationGenerator
26 * class.
27 *
28 * @internal
29 */
30 class ClassLoadingInformation {
31
32 /**
33 * Base directory storing all autoload information
34 */
35 const AUTOLOAD_INFO_DIR = 'typo3temp/autoload/';
36
37 /**
38 * Base directory storing all autoload information in testing context
39 */
40 const AUTOLOAD_INFO_DIR_TESTS = 'typo3temp/autoload-tests/';
41
42 /**
43 * Name of file that contains all classes-filename mappings
44 */
45 const AUTOLOAD_CLASSMAP_FILENAME = 'autoload_classmap.php';
46
47 /**
48 * Name of file that contains all PSR4 mappings, fetched from the composer.json files of extensions
49 */
50 const AUTOLOAD_PSR4_FILENAME = 'autoload_psr4.php';
51
52 /**
53 * Name of file that contains all class alias mappings
54 */
55 const AUTOLOAD_CLASSALIASMAP_FILENAME = 'autoload_classaliasmap.php';
56
57 /**
58 * Checks if the autoload_classmap.php exists. Used to see if the ClassLoadingInformationGenerator
59 * should be called.
60 *
61 * @return bool
62 */
63 static public function classLoadingInformationExists() {
64 return file_exists(self::getClassLoadingInformationDirectory() . self::AUTOLOAD_CLASSMAP_FILENAME);
65 }
66
67 /**
68 * Puts all information compiled by the ClassLoadingInformationGenerator to files
69 */
70 static public function dumpClassLoadingInformation() {
71 self::ensureAutoloadInfoDirExists();
72 /** @var ClassLoadingInformationGenerator $generator */
73 $generator = GeneralUtility::makeInstance(ClassLoadingInformationGenerator::class);
74 $classInfoFiles = $generator->buildAutoloadInformationFiles();
75 GeneralUtility::writeFile(self::getClassLoadingInformationDirectory() . self::AUTOLOAD_CLASSMAP_FILENAME, $classInfoFiles['classMapFile']);
76 GeneralUtility::writeFile(self::getClassLoadingInformationDirectory() . self::AUTOLOAD_PSR4_FILENAME, $classInfoFiles['psr-4File']);
77
78 $classAliasMapFile = $generator->buildClassAliasMapFile();
79 GeneralUtility::writeFile(self::getClassLoadingInformationDirectory() . self::AUTOLOAD_CLASSALIASMAP_FILENAME, $classAliasMapFile);
80 }
81
82 /**
83 * Registers the class aliases, the class maps and the PSR4 prefixes previously identified by
84 * the ClassLoadingInformationGenerator during runtime.
85 */
86 static public function registerClassLoadingInformation() {
87 $composerClassLoader = static::getClassLoader();
88
89 $dynamicClassAliasMapFile = self::getClassLoadingInformationDirectory() . self::AUTOLOAD_CLASSALIASMAP_FILENAME;
90 if (file_exists($dynamicClassAliasMapFile)) {
91 $classAliasMap = require $dynamicClassAliasMapFile;
92 if (is_array($classAliasMap) && !empty($classAliasMap['aliasToClassNameMapping']) && !empty($classAliasMap['classNameToAliasMapping'])) {
93 ClassAliasMap::addAliasMap($classAliasMap);
94 }
95 }
96
97 $dynamicClassMapFile = self::getClassLoadingInformationDirectory() . self::AUTOLOAD_CLASSMAP_FILENAME;
98 if (file_exists($dynamicClassMapFile)) {
99 $classMap = require $dynamicClassMapFile;
100 if (is_array($classMap)) {
101 $composerClassLoader->addClassMap($classMap);
102 }
103 }
104
105 $dynamicPsr4File = self::getClassLoadingInformationDirectory() . self::AUTOLOAD_PSR4_FILENAME;
106 if (file_exists($dynamicPsr4File)) {
107 $psr4 = require $dynamicPsr4File;
108 if (is_array($psr4)) {
109 foreach ($psr4 as $prefix => $paths) {
110 $composerClassLoader->setPsr4($prefix, $paths);
111 }
112 }
113 }
114 }
115
116 /**
117 * Sets class loading information for a package for the current web request
118 *
119 * @param PackageInterface $package
120 * @throws \TYPO3\CMS\Core\Error\Exception
121 */
122 static public function registerTransientClassLoadingInformationForPackage(PackageInterface $package) {
123 $composerClassLoader = static::getClassLoader();
124
125 /** @var ClassLoadingInformationGenerator $generator */
126 $generator = GeneralUtility::makeInstance(ClassLoadingInformationGenerator::class);
127
128 $classInformation = $generator->buildClassLoadingInformationForPackage($package);
129 $composerClassLoader->addClassMap($classInformation['classMap']);
130 foreach ($classInformation['psr-4'] as $prefix => $paths) {
131 $composerClassLoader->setPsr4($prefix, $paths);
132 }
133 $classAliasMap = $generator->buildClassAliasMapForPackage($package);
134 if (is_array($classAliasMap) && !empty($classAliasMap['aliasToClassNameMapping']) && !empty($classAliasMap['classNameToAliasMapping'])) {
135 ClassAliasMap::addAliasMap($classAliasMap);
136 }
137 }
138
139 /**
140 * @return string
141 */
142 static protected function getClassLoadingInformationDirectory() {
143 if (Bootstrap::getInstance()->getApplicationContext()->isTesting()) {
144 return PATH_site . self::AUTOLOAD_INFO_DIR_TESTS;
145 } else {
146 return PATH_site . self::AUTOLOAD_INFO_DIR;
147 }
148 }
149
150 /**
151 * Get class name for alias
152 *
153 * @param string $alias
154 * @return mixed
155 */
156 static public function getClassNameForAlias($alias) {
157 return ClassAliasMap::getClassNameForAlias($alias);
158 }
159
160 /**
161 * Ensures the defined path for class information files exists
162 * And clears it in case we're in testing context
163 */
164 static protected function ensureAutoloadInfoDirExists() {
165 $autoloadInfoDir = self::getClassLoadingInformationDirectory();
166 if (!file_exists($autoloadInfoDir)) {
167 GeneralUtility::mkdir_deep($autoloadInfoDir);
168 } elseif (Bootstrap::getInstance()->getApplicationContext()->isTesting()) {
169 GeneralUtility::flushDirectory($autoloadInfoDir, TRUE);
170 }
171 }
172
173 /**
174 * Internal method calling the bootstrap to fetch the composer class loader
175 *
176 * @return ComposerClassLoader
177 * @throws \TYPO3\CMS\Core\Exception
178 */
179 static protected function getClassLoader() {
180 return Bootstrap::getInstance()->getEarlyInstance(ComposerClassLoader::class);
181 }
182
183 }