TYPO3 CMS  TYPO3_7-6
ClassLoadingInformationGenerator.php
Go to the documentation of this file.
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 
21 
28 {
33 
37  protected $classLoader;
38 
42  protected $installationRoot;
43 
47  protected $isDevMode;
48 
55  public function __construct(ClassLoader $classLoader, array $activeExtensionPackages, $installationRoot, $isDevMode = false)
56  {
57  $this->classLoader = $classLoader;
58  $this->activeExtensionPackages = $activeExtensionPackages;
59  $this->installationRoot = $installationRoot;
60  $this->isDevMode = $isDevMode;
61  }
62 
70  public function buildClassLoadingInformationForPackage(PackageInterface $package, $useRelativePaths = false)
71  {
72  $classMap = [];
73  $psr4 = [];
74  $packagePath = $package->getPackagePath();
75  $manifest = $package->getValueFromComposerManifest();
76 
77  if (empty($manifest->autoload)) {
78  // Legacy mode: Scan the complete extension directory for class files
79  $classMap = $this->createClassMap($packagePath, $useRelativePaths, !$this->isDevMode);
80  } else {
81  $autoloadPsr4 = $this->getAutoloadSectionFromManifest($manifest, 'psr-4');
82  if (!empty($autoloadPsr4)) {
83  $classLoaderPrefixesPsr4 = $this->classLoader->getPrefixesPsr4();
84  foreach ($autoloadPsr4 as $namespacePrefix => $paths) {
85  foreach ((array)$paths as $path) {
86  $namespacePath = $packagePath . $path;
87  if ($useRelativePaths) {
88  $psr4[$namespacePrefix][] = $this->makePathRelative($namespacePath, realpath($namespacePath));
89  } else {
90  $psr4[$namespacePrefix][] = $namespacePath;
91  }
92  if (!empty($classLoaderPrefixesPsr4[$namespacePrefix])) {
93  // The namespace prefix has been registered already, which means there also might be
94  // a class map which we need to override
95  $classMap = array_merge($classMap, $this->createClassMap($namespacePath, $useRelativePaths, false, $namespacePrefix));
96  }
97  }
98  }
99  }
100  $autoloadClassmap = $this->getAutoloadSectionFromManifest($manifest, 'classmap');
101  if (!empty($autoloadClassmap)) {
102  foreach ($autoloadClassmap as $path) {
103  $classMap = array_merge($classMap, $this->createClassMap($packagePath . $path, $useRelativePaths));
104  }
105  }
106  }
107 
108  return ['classMap' => $classMap, 'psr-4' => $psr4];
109  }
110 
119  protected function getAutoloadSectionFromManifest($manifest, $section)
120  {
121  $finalAutoloadSection = [];
122  $autoloadDefinition = json_decode(json_encode($manifest->autoload), true);
123  if (!empty($autoloadDefinition[$section]) && is_array($autoloadDefinition[$section])) {
124  $finalAutoloadSection = $autoloadDefinition[$section];
125  }
126  if ($this->isDevMode) {
127  if (isset($manifest->{'autoload-dev'})) {
128  $autoloadDefinitionDev = json_decode(json_encode($manifest->{'autoload-dev'}), true);
129  if (!empty($autoloadDefinitionDev[$section]) && is_array($autoloadDefinitionDev[$section])) {
130  $finalAutoloadSection = array_merge($finalAutoloadSection, $autoloadDefinitionDev[$section]);
131  }
132  }
133  }
134 
135  return $finalAutoloadSection;
136  }
137 
147  protected function createClassMap($classesPath, $useRelativePaths = false, $ignorePotentialTestClasses = false, $namespace = null)
148  {
149  $classMap = [];
150  $blacklistExpression = null;
151  if ($ignorePotentialTestClasses) {
152  $blacklistPathPrefix = realpath($classesPath);
153  $blacklistPathPrefix = strtr($blacklistPathPrefix, '\\', '/');
154  $blacklistExpression = "{($blacklistPathPrefix/tests/|$blacklistPathPrefix/Tests/|$blacklistPathPrefix/Resources/|$blacklistPathPrefix/res/|$blacklistPathPrefix/class.ext_update.php)}";
155  }
156  foreach (ClassMapGenerator::createMap($classesPath, $blacklistExpression, null, $namespace) as $class => $path) {
157  if ($useRelativePaths) {
158  $classMap[$class] = $this->makePathRelative($classesPath, $path);
159  } else {
160  $classMap[$class] = $path;
161  }
162  }
163  return $classMap;
164  }
165 
174  {
175  $aliasToClassNameMapping = [];
176  $classNameToAliasMapping = [];
177  $possibleClassAliasFiles = [];
178  $manifest = $package->getValueFromComposerManifest();
179  if (!empty($manifest->extra->{'typo3/class-alias-loader'}->{'class-alias-maps'})) {
180  $possibleClassAliasFiles = $manifest->extra->{'typo3/class-alias-loader'}->{'class-alias-maps'};
181  if (!is_array($possibleClassAliasFiles)) {
182  throw new \TYPO3\CMS\Core\Error\Exception('"typo3/class-alias-loader"/"class-alias-maps" must return an array!', 1444142481);
183  }
184  } else {
185  $possibleClassAliasFiles[] = 'Migrations/Code/ClassAliasMap.php';
186  }
187  $packagePath = $package->getPackagePath();
188  foreach ($possibleClassAliasFiles as $possibleClassAliasFile) {
189  $possiblePathToClassAliasFile = $packagePath . $possibleClassAliasFile;
190  if (file_exists($possiblePathToClassAliasFile)) {
191  $packageAliasMap = require $possiblePathToClassAliasFile;
192  if (!is_array($packageAliasMap)) {
193  throw new \TYPO3\CMS\Core\Error\Exception('"class alias maps" must return an array', 1422625075);
194  }
195  foreach ($packageAliasMap as $aliasClassName => $className) {
196  $lowerCasedAliasClassName = strtolower($aliasClassName);
197  $aliasToClassNameMapping[$lowerCasedAliasClassName] = $className;
198  $classNameToAliasMapping[$className][$lowerCasedAliasClassName] = $lowerCasedAliasClassName;
199  }
200  }
201  }
202 
203  return ['aliasToClassNameMapping' => $aliasToClassNameMapping, 'classNameToAliasMapping' => $classNameToAliasMapping];
204  }
205 
212  {
213  $psr4File = $classMapFile = <<<EOF
214 <?php
215 
216 // autoload_classmap.php @generated by TYPO3
217 
218 \$typo3InstallDir = PATH_site;
219 
220 return array(
221 
222 EOF;
223  $classMap = [];
224  $psr4 = [];
225  foreach ($this->activeExtensionPackages as $package) {
226  $classLoadingInformation = $this->buildClassLoadingInformationForPackage($package, true);
227  $classMap = array_merge($classMap, $classLoadingInformation['classMap']);
228  $psr4 = array_merge($psr4, $classLoadingInformation['psr-4']);
229  }
230 
231  ksort($classMap);
232  ksort($psr4);
233  foreach ($classMap as $class => $relativePath) {
234  $classMapFile .= sprintf(' %s => %s,', var_export($class, true), $this->getPathCode($relativePath)) . LF;
235  }
236  $classMapFile .= ");\n";
237 
238  foreach ($psr4 as $prefix => $relativePaths) {
239  $psr4File .= sprintf(' %s => array(%s),', var_export($prefix, true), implode(',', array_map([$this, 'getPathCode'], $relativePaths))) . LF;
240  }
241  $psr4File .= ");\n";
242 
243  return ['classMapFile' => $classMapFile, 'psr-4File' => $psr4File];
244  }
245 
254  protected function makePathRelative($packagePath, $realPathOfClassFile, $relativeToRoot = true)
255  {
256  $realPathOfClassFile = GeneralUtility::fixWindowsFilePath($realPathOfClassFile);
257  $packageRealPath = GeneralUtility::fixWindowsFilePath(realpath($packagePath));
258  $relativePackagePath = rtrim(substr($packagePath, strlen($this->installationRoot)), '/');
259  if ($relativeToRoot) {
260  if ($realPathOfClassFile === $packageRealPath) {
261  $relativePathToClassFile = $relativePackagePath;
262  } else {
263  $relativePathToClassFile = $relativePackagePath . '/' . ltrim(substr($realPathOfClassFile, strlen($packageRealPath)), '/');
264  }
265  } else {
266  $relativePathToClassFile = ltrim(substr($realPathOfClassFile, strlen($packageRealPath)), '/');
267  }
268 
269  return $relativePathToClassFile;
270  }
271 
278  protected function getPathCode($relativePathToClassFile)
279  {
280  return '$typo3InstallDir . ' . var_export($relativePathToClassFile, true);
281  }
282 
290  public function buildClassAliasMapFile()
291  {
292  $aliasToClassNameMapping = [];
293  $classNameToAliasMapping = [];
294  foreach ($this->activeExtensionPackages as $package) {
295  $aliasMappingForPackage = $this->buildClassAliasMapForPackage($package);
296  $aliasToClassNameMapping = array_merge($aliasToClassNameMapping, $aliasMappingForPackage['aliasToClassNameMapping']);
297  $classNameToAliasMapping = array_merge($classNameToAliasMapping, $aliasMappingForPackage['classNameToAliasMapping']);
298  }
299  $exportArray = [
300  'aliasToClassNameMapping' => $aliasToClassNameMapping,
301  'classNameToAliasMapping' => $classNameToAliasMapping
302  ];
303  $fileContent = '<?php' . chr(10) . 'return ';
304  $fileContent .= var_export($exportArray, true);
305  $fileContent .= ";\n";
306  return $fileContent;
307  }
308 }
buildClassLoadingInformationForPackage(PackageInterface $package, $useRelativePaths=false)
createClassMap($classesPath, $useRelativePaths=false, $ignorePotentialTestClasses=false, $namespace=null)
static createMap($path, $blacklist=null, IOInterface $io=null, $namespace=null)
__construct(ClassLoader $classLoader, array $activeExtensionPackages, $installationRoot, $isDevMode=false)
makePathRelative($packagePath, $realPathOfClassFile, $relativeToRoot=true)