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 
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 = array();
73  $psr4 = array();
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 => $path) {
85  $namespacePath = $packagePath . $path;
86  if ($useRelativePaths) {
87  $psr4[$namespacePrefix] = $this->makePathRelative($namespacePath, realpath($namespacePath));
88  } else {
89  $psr4[$namespacePrefix] = $namespacePath;
90  }
91  if (!empty($classLoaderPrefixesPsr4[$namespacePrefix])) {
92  // The namespace prefix has been registered already, which means there also might be
93  // a class map which we need to override
94  $classMap = array_merge($classMap, $this->createClassMap($namespacePath, $useRelativePaths, false, $namespacePrefix));
95  }
96  }
97  }
98  $autoloadClassmap = $this->getAutoloadSectionFromManifest($manifest, 'classmap');
99  if (!empty($autoloadClassmap)) {
100  foreach ($autoloadClassmap as $path) {
101  $classMap = array_merge($classMap, $this->createClassMap($packagePath . $path, $useRelativePaths));
102  }
103  }
104  }
105 
106  return array('classMap' => $classMap, 'psr-4' => $psr4);
107  }
108 
117  protected function getAutoloadSectionFromManifest($manifest, $section)
118  {
119  $finalAutoloadSection = [];
120  $autoloadDefinition = json_decode(json_encode($manifest->autoload), true);
121  if (!empty($autoloadDefinition[$section]) && is_array($autoloadDefinition[$section])) {
122  $finalAutoloadSection = $autoloadDefinition[$section];
123  }
124  if ($this->isDevMode) {
125  $autoloadDefinitionDev = json_decode(json_encode($manifest->{'autoload-dev'}), true);
126  if (!empty($autoloadDefinitionDev[$section]) && is_array($autoloadDefinitionDev[$section])) {
127  $finalAutoloadSection = array_merge($finalAutoloadSection, $autoloadDefinitionDev[$section]);
128  }
129  }
130 
131  return $finalAutoloadSection;
132  }
133 
143  protected function createClassMap($classesPath, $useRelativePaths = false, $ignorePotentialTestClasses = false, $namespace = null)
144  {
145  $classMap = array();
146  foreach (ClassMapGenerator::createMap($classesPath, null, null, $namespace) as $class => $path) {
147  if ($ignorePotentialTestClasses) {
148  if ($this->isIgnoredPath($classesPath, $path)) {
149  continue;
150  }
151  if ($this->isIgnoredClassName($class)) {
152  continue;
153  }
154  }
155  if ($useRelativePaths) {
156  $classMap[$class] = $this->makePathRelative($classesPath, $path);
157  } else {
158  $classMap[$class] = $path;
159  }
160  }
161  return $classMap;
162  }
163 
172  protected function isIgnoredPath($packagePath, $path)
173  {
174  if (stripos($this->makePathRelative($packagePath, $path, false), 'tests') !== false) {
175  return true;
176  }
177 
178  return false;
179  }
180 
188  protected function isIgnoredClassName($className)
189  {
190  foreach (array('Test', 'Fixture') as $suffix) {
191  if (preg_match('/(^|[a-z])' . $suffix . '$/', $className)) {
192  return true;
193  }
194  }
195  return false;
196  }
197 
205  public function buildClassAliasMapForPackage(PackageInterface $package)
206  {
207  $aliasToClassNameMapping = [];
208  $classNameToAliasMapping = [];
209  $possibleClassAliasFiles = [];
210  $manifest = $package->getValueFromComposerManifest();
211  if (!empty($manifest->extra->{'typo3/class-alias-loader'}->{'class-alias-maps'})) {
212  $possibleClassAliasFiles = $manifest->extra->{'typo3/class-alias-loader'}->{'class-alias-maps'};
213  if (!is_array($possibleClassAliasFiles)) {
214  throw new \TYPO3\CMS\Core\Error\Exception('"typo3/class-alias-loader"/"class-alias-maps" must return an array!', 1444142481);
215  }
216  } else {
217  $possibleClassAliasFiles[] = 'Migrations/Code/ClassAliasMap.php';
218  }
219  $packagePath = $package->getPackagePath();
220  foreach ($possibleClassAliasFiles as $possibleClassAliasFile) {
221  $possiblePathToClassAliasFile = $packagePath . $possibleClassAliasFile;
222  if (file_exists($possiblePathToClassAliasFile)) {
223  $packageAliasMap = require $possiblePathToClassAliasFile;
224  if (!is_array($packageAliasMap)) {
225  throw new \TYPO3\CMS\Core\Error\Exception('"class alias maps" must return an array', 1422625075);
226  }
227  foreach ($packageAliasMap as $aliasClassName => $className) {
228  $lowerCasedAliasClassName = strtolower($aliasClassName);
229  $aliasToClassNameMapping[$lowerCasedAliasClassName] = $className;
230  $classNameToAliasMapping[$className][$lowerCasedAliasClassName] = $lowerCasedAliasClassName;
231  }
232  }
233  }
234 
235  return array('aliasToClassNameMapping' => $aliasToClassNameMapping, 'classNameToAliasMapping' => $classNameToAliasMapping);
236  }
237 
243  public function buildAutoloadInformationFiles()
244  {
245  $psr4File = $classMapFile = <<<EOF
246 <?php
247 
248 // autoload_classmap.php @generated by TYPO3
249 
250 \$typo3InstallDir = PATH_site;
251 
252 return array(
253 
254 EOF;
255  $classMap = array();
256  $psr4 = array();
257  foreach ($this->activeExtensionPackages as $package) {
258  $classLoadingInformation = $this->buildClassLoadingInformationForPackage($package, true);
259  $classMap = array_merge($classMap, $classLoadingInformation['classMap']);
260  $psr4 = array_merge($psr4, $classLoadingInformation['psr-4']);
261  }
262 
263  ksort($classMap);
264  ksort($psr4);
265  foreach ($classMap as $class => $relativePath) {
266  $classMapFile .= sprintf(' %s => %s,', var_export($class, true), $this->getPathCode($relativePath)) . LF;
267  }
268  $classMapFile .= ");\n";
269 
270  foreach ($psr4 as $prefix => $relativePath) {
271  $psr4File .= sprintf(' %s => array(%s),', var_export($prefix, true), $this->getPathCode($relativePath)) . LF;
272  }
273  $psr4File .= ");\n";
274 
275  return array('classMapFile' => $classMapFile, 'psr-4File' => $psr4File);
276  }
277 
286  protected function makePathRelative($packagePath, $realPathOfClassFile, $relativeToRoot = true)
287  {
288  $realPathOfClassFile = GeneralUtility::fixWindowsFilePath($realPathOfClassFile);
289  $packageRealPath = GeneralUtility::fixWindowsFilePath(realpath($packagePath));
290  $relativePackagePath = rtrim(substr($packagePath, strlen($this->installationRoot)), '/');
291  if ($relativeToRoot) {
292  if ($realPathOfClassFile === $packageRealPath) {
293  $relativePathToClassFile = $relativePackagePath;
294  } else {
295  $relativePathToClassFile = $relativePackagePath . '/' . ltrim(substr($realPathOfClassFile, strlen($packageRealPath)), '/');
296  }
297  } else {
298  $relativePathToClassFile = ltrim(substr($realPathOfClassFile, strlen($packageRealPath)), '/');
299  }
300 
301  return $relativePathToClassFile;
302  }
303 
310  protected function getPathCode($relativePathToClassFile)
311  {
312  return '$typo3InstallDir . ' . var_export($relativePathToClassFile, true);
313  }
314 
322  public function buildClassAliasMapFile()
323  {
324  $aliasToClassNameMapping = array();
325  $classNameToAliasMapping = array();
326  foreach ($this->activeExtensionPackages as $package) {
327  $aliasMappingForPackage = $this->buildClassAliasMapForPackage($package);
328  $aliasToClassNameMapping = array_merge($aliasToClassNameMapping, $aliasMappingForPackage['aliasToClassNameMapping']);
329  $classNameToAliasMapping = array_merge($classNameToAliasMapping, $aliasMappingForPackage['classNameToAliasMapping']);
330  }
331  $exportArray = array(
332  'aliasToClassNameMapping' => $aliasToClassNameMapping,
333  'classNameToAliasMapping' => $classNameToAliasMapping
334  );
335  $fileContent = '<?php' . chr(10) . 'return ';
336  $fileContent .= var_export($exportArray, true);
337  $fileContent .= ";\n";
338  return $fileContent;
339  }
340 }