[BUGIFX] Allow overriding system extensions 22/43522/7
authorHelmut Hummel <helmut.hummel@typo3.org>
Thu, 24 Sep 2015 13:11:29 +0000 (15:11 +0200)
committerAnja Leichsenring <aleichsenring@ab-softlab.de>
Fri, 25 Sep 2015 14:08:40 +0000 (16:08 +0200)
When making a copy of a system extension and place the copy
in typo3conf/ext, the package manager is capable of loading the copy
instead of the original extension. However the path of the classes would
still be wrong.

To support this feature properly, we need to create class maps of the
new location to override the already registered maps.

For this to work the package type needs to be changed
from "typo3-cms-framework" to "typo3-cms-extension" in composer.json of
the copied system extension.

Resolves: #70077
Releases: master
Change-Id: I77168b8957e7b5658ce710f13dedf258474b040b
Reviewed-on: http://review.typo3.org/43522
Reviewed-by: Nicole Cordes <typo3@cordes.co>
Tested-by: Nicole Cordes <typo3@cordes.co>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Andreas Fernandez <typo3@scripting-base.de>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
typo3/sysext/core/Classes/Core/ClassLoadingInformation.php
typo3/sysext/core/Classes/Core/ClassLoadingInformationGenerator.php

index 231407e..e3704e3 100644 (file)
@@ -97,7 +97,7 @@ class ClassLoadingInformation {
                $dynamicClassMapFile = self::getClassLoadingInformationDirectory() . self::AUTOLOAD_CLASSMAP_FILENAME;
                if (file_exists($dynamicClassMapFile)) {
                        $classMap = require $dynamicClassMapFile;
-                       if (is_array($classMap)) {
+                       if (!empty($classMap) && is_array($classMap)) {
                                $composerClassLoader->addClassMap($classMap);
                        }
                }
index b6b5720..1ce3c3b 100644 (file)
@@ -15,7 +15,7 @@ namespace TYPO3\CMS\Core\Core;
  */
 
 use Composer\Autoload\ClassMapGenerator;
-use TYPO3\CMS\Core\Package\Exception\MissingPackageManifestException;
+use Composer\Autoload\ClassLoader as ComposerClassLoader;
 use TYPO3\CMS\Core\Package\PackageInterface;
 use TYPO3\CMS\Core\Package\PackageManager;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -55,25 +55,47 @@ class ClassLoadingInformationGenerator {
                                        } else {
                                                $psr4[$namespacePrefix] = $namespacePath;
                                        }
+                                       if (!empty($this->getClassLoader()->getPrefixesPsr4()[$namespacePrefix])) {
+                                               // The namespace prefix has been registered already, which means there also might be
+                                               // a class map which we need to override
+                                               $classMap = array_merge($classMap, $this->createClassMap($namespacePath, $useRelativePaths, FALSE, $namespacePrefix));
+                                       }
                                }
                        }
                } else {
-                       foreach (ClassMapGenerator::createMap($packagePath) as $class => $path) {
-                               if ($this->isIgnoredPath($packagePath, $path)) {
+                       $classMap = $this->createClassMap($packagePath, $useRelativePaths, TRUE);
+               }
+
+               return array('classMap' => $classMap, 'psr-4' => $psr4);
+       }
+
+       /**
+        * Creates a class map for a given (absolute) path
+        *
+        * @param string $classesPath
+        * @param bool $useRelativePaths
+        * @param bool $ignorePotentialTestClasses
+        * @param string $namespace
+        * @return array
+        */
+       protected function createClassMap($classesPath, $useRelativePaths = FALSE, $ignorePotentialTestClasses = FALSE, $namespace = NULL) {
+               $classMap = array();
+               foreach (ClassMapGenerator::createMap($classesPath, NULL, NULL, $namespace) as $class => $path) {
+                       if ($ignorePotentialTestClasses) {
+                               if ($this->isIgnoredPath($classesPath, $path)) {
                                        continue;
                                }
                                if ($this->isIgnoredClassName($class)) {
                                        continue;
                                }
-                               if ($useRelativePaths) {
-                                       $classMap[$class] = $this->makePathRelative($packagePath, $path);
-                               } else {
-                                       $classMap[$class] = $path;
-                               }
+                       }
+                       if ($useRelativePaths) {
+                               $classMap[$class] = $this->makePathRelative($classesPath, $path);
+                       } else {
+                               $classMap[$class] = $path;
                        }
                }
-
-               return array('classMap' => $classMap, 'psr-4' => $psr4);
+               return $classMap;
        }
 
        /**
@@ -267,4 +289,13 @@ EOF;
                return Bootstrap::getInstance()->getEarlyInstance(PackageManager::class);
        }
 
+       /**
+        * Internal method calling the bootstrap to fetch the composer class loader
+        *
+        * @return ComposerClassLoader
+        * @throws \TYPO3\CMS\Core\Exception
+        */
+       protected function getClassLoader() {
+               return Bootstrap::getInstance()->getEarlyInstance(ComposerClassLoader::class);
+       }
 }