From 8142126b16d0f559c43cab37624bae7b36007b7e Mon Sep 17 00:00:00 2001 From: Andreas Hennings Date: Fri, 26 Jul 2013 22:31:06 +0200 Subject: [PATCH 01/16] Add PSR-4 class loader. (tests needed) --- src/Composer/Autoload/ClassLoader.php | 138 +++++++++++++++++++------- 1 file changed, 102 insertions(+), 36 deletions(-) diff --git a/src/Composer/Autoload/ClassLoader.php b/src/Composer/Autoload/ClassLoader.php index 1db8d9a0b..a6d784b9e 100644 --- a/src/Composer/Autoload/ClassLoader.php +++ b/src/Composer/Autoload/ClassLoader.php @@ -42,19 +42,26 @@ namespace Composer\Autoload; */ class ClassLoader { - private $prefixes = array(); - private $fallbackDirs = array(); + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + private $useIncludePath = false; private $classMap = array(); public function getPrefixes() { - return call_user_func_array('array_merge', $this->prefixes); + return call_user_func_array('array_merge', $this->prefixesPsr0); } public function getFallbackDirs() { - return $this->fallbackDirs; + return $this->fallbackDirsPsr0; } public function getClassMap() @@ -85,13 +92,13 @@ class ClassLoader { if (!$prefix) { if ($prepend) { - $this->fallbackDirs = array_merge( + $this->fallbackDirsPsr0 = array_merge( (array) $paths, - $this->fallbackDirs + $this->fallbackDirsPsr0 ); } else { - $this->fallbackDirs = array_merge( - $this->fallbackDirs, + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, (array) $paths ); } @@ -100,19 +107,58 @@ class ClassLoader } $first = $prefix[0]; - if (!isset($this->prefixes[$first][$prefix])) { - $this->prefixes[$first][$prefix] = (array) $paths; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; return; } if ($prepend) { - $this->prefixes[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix] = array_merge( (array) $paths, - $this->prefixes[$first][$prefix] + $this->prefixesPsr0[$first][$prefix] ); } else { - $this->prefixes[$first][$prefix] = array_merge( - $this->prefixes[$first][$prefix], + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + + return; + } + + $prefix = rtrim($prefix, '\\'); + $prefix = $prefix . '\\'; + + if (!isset($this->prefixDirsPsr4[$prefix])) { + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = strlen($prefix); + $this->prefixDirsPsr4[$prefix] = (array) $paths; + return; + } + if ($prepend) { + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], (array) $paths ); } @@ -127,11 +173,11 @@ class ClassLoader public function set($prefix, $paths) { if (!$prefix) { - $this->fallbackDirs = (array) $paths; + $this->fallbackDirsPsr0 = (array) $paths; return; } - $this->prefixes[substr($prefix, 0, 1)][$prefix] = (array) $paths; + $this->prefixesPsr0[substr($prefix, 0, 1)][$prefix] = (array) $paths; } /** @@ -206,38 +252,58 @@ class ClassLoader return $this->classMap[$class]; } - if (false !== $pos = strrpos($class, '\\')) { - // namespaced class name - $classPath = strtr(substr($class, 0, $pos), '\\', DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; - $className = substr($class, $pos + 1); - } else { - // PEAR-like class name - $classPath = null; - $className = $class; - } - - $classPath .= strtr($className, '_', DIRECTORY_SEPARATOR) . '.php'; + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . '.php'; $first = $class[0]; - if (isset($this->prefixes[$first])) { - foreach ($this->prefixes[$first] as $prefix => $dirs) { + if (isset($this->prefixLengthsPsr4[$first])) { + foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) { if (0 === strpos($class, $prefix)) { - foreach ($dirs as $dir) { - if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) { - return $dir . DIRECTORY_SEPARATOR . $classPath; + foreach ($this->prefixDirsPsr4[$prefix] as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { + return $file; } } } } } - foreach ($this->fallbackDirs as $dir) { - if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) { - return $dir . DIRECTORY_SEPARATOR . $classPath; + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; } } - if ($this->useIncludePath && $file = stream_resolve_include_path($classPath)) { + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 + = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR) + ; + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR); + } + + $first = $class[0]; + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { return $file; } From c49a651d815cc1fa39ee9da8370fc8434d7c38f7 Mon Sep 17 00:00:00 2001 From: Andreas Hennings Date: Mon, 29 Jul 2013 13:38:46 +0200 Subject: [PATCH 02/16] PSR-4 class loader: Add getters for PSR-4 prefixes. Rename PSR-0 related attributes by appending *Psr0. Add more comments. --- src/Composer/Autoload/ClassLoader.php | 78 ++++++++++++++++++++------- 1 file changed, 60 insertions(+), 18 deletions(-) diff --git a/src/Composer/Autoload/ClassLoader.php b/src/Composer/Autoload/ClassLoader.php index a6d784b9e..b44aa6013 100644 --- a/src/Composer/Autoload/ClassLoader.php +++ b/src/Composer/Autoload/ClassLoader.php @@ -59,11 +59,21 @@ class ClassLoader return call_user_func_array('array_merge', $this->prefixesPsr0); } + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + public function getFallbackDirs() { return $this->fallbackDirsPsr0; } + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + public function getClassMap() { return $this->classMap; @@ -82,9 +92,10 @@ class ClassLoader } /** - * Registers a set of classes, merging with any others previously set. + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. * - * @param string $prefix The classes prefix + * @param string $prefix The namespace, with trailing '\\'. * @param array|string $paths The location(s) of the classes * @param bool $prepend Prepend the location(s) */ @@ -125,9 +136,17 @@ class ClassLoader } } + /** + * Registers a set of classes, merging with any others previously set. + * + * @param string $prefix The namespace, with trailing '\\'. + * @param array|string $paths The location(s) of the classes + * @param bool $prepend Prepend the location(s) + */ public function addPsr4($prefix, $paths, $prepend = false) { if (!$prefix) { + // Register directories for the root namespace. if ($prepend) { $this->fallbackDirsPsr4 = array_merge( (array) $paths, @@ -139,24 +158,22 @@ class ClassLoader (array) $paths ); } - - return; - } - - $prefix = rtrim($prefix, '\\'); - $prefix = $prefix . '\\'; - - if (!isset($this->prefixDirsPsr4[$prefix])) { - $this->prefixLengthsPsr4[$prefix[0]][$prefix] = strlen($prefix); + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \Exception("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; $this->prefixDirsPsr4[$prefix] = (array) $paths; - return; - } - if ($prepend) { + } elseif ($prepend) { + // Prepend directories for an already registered namespace. $this->prefixDirsPsr4[$prefix] = array_merge( (array) $paths, $this->prefixDirsPsr4[$prefix] ); } else { + // Append directories for an already registered namespace. $this->prefixDirsPsr4[$prefix] = array_merge( $this->prefixDirsPsr4[$prefix], (array) $paths @@ -174,10 +191,29 @@ class ClassLoader { if (!$prefix) { $this->fallbackDirsPsr0 = (array) $paths; - - return; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The namespace, with trailing slash. + * @param array|string $paths The location(s) of the classes + */ + public function setPsr4($prefix, $paths) { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \Exception("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; } - $this->prefixesPsr0[substr($prefix, 0, 1)][$prefix] = (array) $paths; } /** @@ -248,10 +284,12 @@ class ClassLoader $class = substr($class, 1); } + // class map lookup if (isset($this->classMap[$class])) { return $this->classMap[$class]; } + // PSR-4 lookup $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . '.php'; $first = $class[0]; @@ -267,12 +305,14 @@ class ClassLoader } } + // PSR-4 fallback dirs foreach ($this->fallbackDirsPsr4 as $dir) { if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { return $file; } } + // PSR-0 lookup if (false !== $pos = strrpos($class, '\\')) { // namespaced class name $logicalPathPsr0 @@ -284,7 +324,6 @@ class ClassLoader $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR); } - $first = $class[0]; if (isset($this->prefixesPsr0[$first])) { foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { if (0 === strpos($class, $prefix)) { @@ -297,16 +336,19 @@ class ClassLoader } } + // PSR-0 fallback dirs foreach ($this->fallbackDirsPsr0 as $dir) { if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { return $file; } } + // PSR-0 include paths. if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { return $file; } + // Remember that this class does not exist. return $this->classMap[$class] = false; } } From 2e80d148f80fafb6cff708ecb01b6317473fcae8 Mon Sep 17 00:00:00 2001 From: Andreas Hennings Date: Mon, 29 Jul 2013 13:48:32 +0200 Subject: [PATCH 03/16] PSR-4 loader: Fix comments: PSR-0 related methods should have comments refering to PSR-0 and prefixes. PSR-4 related methods should have comments refering to PSR-4 and namespaces. --- src/Composer/Autoload/ClassLoader.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Composer/Autoload/ClassLoader.php b/src/Composer/Autoload/ClassLoader.php index b44aa6013..ef3fc0575 100644 --- a/src/Composer/Autoload/ClassLoader.php +++ b/src/Composer/Autoload/ClassLoader.php @@ -92,10 +92,10 @@ class ClassLoader } /** - * Registers a set of PSR-4 directories for a given namespace, either - * appending or prepending to the ones previously set for this namespace. + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. * - * @param string $prefix The namespace, with trailing '\\'. + * @param string $prefix The prefix. * @param array|string $paths The location(s) of the classes * @param bool $prepend Prepend the location(s) */ @@ -137,7 +137,8 @@ class ClassLoader } /** - * Registers a set of classes, merging with any others previously set. + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. * * @param string $prefix The namespace, with trailing '\\'. * @param array|string $paths The location(s) of the classes @@ -182,7 +183,8 @@ class ClassLoader } /** - * Registers a set of classes, replacing any others previously set. + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. * * @param string $prefix The classes prefix * @param array|string $paths The location(s) of the classes From 5dd3c12d3d80e9fb54f02820744884421ad9786e Mon Sep 17 00:00:00 2001 From: Andreas Hennings Date: Mon, 29 Jul 2013 13:54:44 +0200 Subject: [PATCH 04/16] Further improve comments. --- src/Composer/Autoload/ClassLoader.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Composer/Autoload/ClassLoader.php b/src/Composer/Autoload/ClassLoader.php index ef3fc0575..a784187dd 100644 --- a/src/Composer/Autoload/ClassLoader.php +++ b/src/Composer/Autoload/ClassLoader.php @@ -95,9 +95,9 @@ class ClassLoader * Registers a set of PSR-0 directories for a given prefix, either * appending or prepending to the ones previously set for this prefix. * - * @param string $prefix The prefix. - * @param array|string $paths The location(s) of the classes - * @param bool $prepend Prepend the location(s) + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories */ public function add($prefix, $paths, $prepend = false) { @@ -140,9 +140,9 @@ class ClassLoader * Registers a set of PSR-4 directories for a given namespace, either * appending or prepending to the ones previously set for this namespace. * - * @param string $prefix The namespace, with trailing '\\'. - * @param array|string $paths The location(s) of the classes - * @param bool $prepend Prepend the location(s) + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-0 base directories + * @param bool $prepend Whether to prepend the directories */ public function addPsr4($prefix, $paths, $prepend = false) { @@ -186,8 +186,8 @@ class ClassLoader * Registers a set of PSR-0 directories for a given prefix, * replacing any others previously set for this prefix. * - * @param string $prefix The classes prefix - * @param array|string $paths The location(s) of the classes + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories */ public function set($prefix, $paths) { @@ -202,8 +202,8 @@ class ClassLoader * Registers a set of PSR-4 directories for a given namespace, * replacing any others previously set for this namespace. * - * @param string $prefix The namespace, with trailing slash. - * @param array|string $paths The location(s) of the classes + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories */ public function setPsr4($prefix, $paths) { if (!$prefix) { From b08179e39972519cafdd2670662ed76db242f640 Mon Sep 17 00:00:00 2001 From: Andreas Hennings Date: Tue, 6 Aug 2013 17:58:38 +0200 Subject: [PATCH 05/16] PSR-4 ClassLoader: Bug fix: PEAR-like path needs ".php" appended. --- src/Composer/Autoload/ClassLoader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Autoload/ClassLoader.php b/src/Composer/Autoload/ClassLoader.php index a784187dd..6218afb06 100644 --- a/src/Composer/Autoload/ClassLoader.php +++ b/src/Composer/Autoload/ClassLoader.php @@ -323,7 +323,7 @@ class ClassLoader ; } else { // PEAR-like class name - $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR); + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . '.php'; } if (isset($this->prefixesPsr0[$first])) { From 2c98813431d14cccf2c8d3cd7fbbd8ff2e8a703d Mon Sep 17 00:00:00 2001 From: Andreas Hennings Date: Thu, 26 Sep 2013 23:44:21 +0200 Subject: [PATCH 06/16] Add unit tests for ClassLoader, covering PSR-0 and PSR-4. --- .../Test/Autoload/ClassLoaderTest.php | 65 +++++++++++++++++++ .../Autoload/Fixtures/SubNamespace/Bar.php | 5 ++ .../Autoload/Fixtures/SubNamespace/Foo.php | 5 ++ 3 files changed, 75 insertions(+) create mode 100644 tests/Composer/Test/Autoload/ClassLoaderTest.php create mode 100644 tests/Composer/Test/Autoload/Fixtures/SubNamespace/Bar.php create mode 100644 tests/Composer/Test/Autoload/Fixtures/SubNamespace/Foo.php diff --git a/tests/Composer/Test/Autoload/ClassLoaderTest.php b/tests/Composer/Test/Autoload/ClassLoaderTest.php new file mode 100644 index 000000000..7a8ae253b --- /dev/null +++ b/tests/Composer/Test/Autoload/ClassLoaderTest.php @@ -0,0 +1,65 @@ +loadClass() with a class name with preceding + * namespace separator, as it happens in PHP 5.3.0 - 5.3.2. + * See https://bugs.php.net/50731 + */ + public function testLoadClass($class, $prependSeparator = FALSE) + { + $loader = new ClassLoader(); + $loader->add('Namespaced\\', __DIR__ . '/Fixtures'); + $loader->add('Pearlike_', __DIR__ . '/Fixtures'); + $loader->addPsr4('ShinyVendor\\ShinyPackage\\', __DIR__ . '/Fixtures'); + + if ($prependSeparator) { + $prepend = '\\'; + $message = "->loadClass() loads '$class'."; + } + else { + $prepend = ''; + $message = "->loadClass() loads '\\$class', as required in PHP 5.3.0 - 5.3.2."; + } + + $loader->loadClass($prepend . $class); + $this->assertTrue(class_exists($class, false), $message); + } + + /** + * Provides arguments for ->testLoadClass(). + * + * @return array + * Array of parameter sets to test with. + */ + public function getLoadClassTests() + { + return array( + array('Namespaced\\Foo'), + array('Pearlike_Foo'), + array('ShinyVendor\\ShinyPackage\\SubNamespace\\Foo'), + // "Bar" would not work here, since it is defined in a ".inc" file, + // instead of a ".php" file. So, use "Baz" instead. + array('Namespaced\\Baz', '\\'), + array('Pearlike_Bar', '\\'), + array('ShinyVendor\\ShinyPackage\\SubNamespace\\Bar', '\\'), + ); + } + +} diff --git a/tests/Composer/Test/Autoload/Fixtures/SubNamespace/Bar.php b/tests/Composer/Test/Autoload/Fixtures/SubNamespace/Bar.php new file mode 100644 index 000000000..74cd9d7f3 --- /dev/null +++ b/tests/Composer/Test/Autoload/Fixtures/SubNamespace/Bar.php @@ -0,0 +1,5 @@ + Date: Tue, 26 Nov 2013 02:53:44 +0100 Subject: [PATCH 07/16] AutoloadGenerator to support PSR-4. Tests included. --- src/Composer/Autoload/AutoloadGenerator.php | 74 +++++++++++++++++-- .../Test/Autoload/AutoloadGeneratorTest.php | 34 ++++++++- .../Test/Autoload/Fixtures/autoload_psr4.php | 11 +++ .../Autoload/Fixtures/autoload_psr4_2.php | 11 +++ .../Autoload/Fixtures/autoload_psr4_3.php | 11 +++ .../autoload_real_files_by_dependency.php | 5 ++ .../Fixtures/autoload_real_functions.php | 5 ++ .../Fixtures/autoload_real_include_path.php | 5 ++ .../Fixtures/autoload_real_target_dir.php | 5 ++ 9 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 tests/Composer/Test/Autoload/Fixtures/autoload_psr4.php create mode 100644 tests/Composer/Test/Autoload/Fixtures/autoload_psr4_2.php create mode 100644 tests/Composer/Test/Autoload/Fixtures/autoload_psr4_3.php diff --git a/src/Composer/Autoload/AutoloadGenerator.php b/src/Composer/Autoload/AutoloadGenerator.php index 1252371d6..e3dae3ea8 100644 --- a/src/Composer/Autoload/AutoloadGenerator.php +++ b/src/Composer/Autoload/AutoloadGenerator.php @@ -69,9 +69,23 @@ return array( EOF; + $psr4File = <<buildPackageMap($installationManager, $mainPackage, $localRepo->getCanonicalPackages()); $autoloads = $this->parseAutoloads($packageMap, $mainPackage); + // Process the 'psr-0' base directories. foreach ($autoloads['psr-0'] as $namespace => $paths) { $exportedPaths = array(); foreach ($paths as $path) { @@ -83,6 +97,21 @@ EOF; } $namespacesFile .= ");\n"; + // Process the 'psr-4' base directories. + foreach ($autoloads['psr-4'] as $namespace => $paths) { + if ('\\' !== $namespace[strlen($namespace) - 1]) { + throw new \Exception("PSR-4 namespaces must end with a namespace separator. '$namespace' does not."); + } + $exportedPaths = array(); + foreach ($paths as $path) { + $exportedPaths[] = $this->getPathCode($filesystem, $basePath, $vendorPath, $path); + } + $exportedPrefix = var_export($namespace, true); + $psr4File .= " $exportedPrefix => "; + $psr4File .= "array(".implode(', ', $exportedPaths)."),\n"; + } + $psr4File .= ");\n"; + $classmapFile = << $paths) { foreach ($paths as $dir) { $dir = $filesystem->normalizePath($filesystem->isAbsolutePath($dir) ? $dir : $basePath.'/'.$dir); @@ -152,6 +183,29 @@ EOF; } } } + // Scan the PSR-4 directories for class files, and add them to the + // class map. + foreach ($autoloads['psr-4'] as $namespace => $paths) { + foreach ($paths as $dir) { + $dir = $filesystem->normalizePath($filesystem->isAbsolutePath($dir) ? $dir : $basePath.'/'.$dir); + if (!is_dir($dir)) { + continue; + } + $whitelist = sprintf( + '{%s/%s.+(? $path) { + if ('' === $namespace || 0 === strpos($class, $namespace)) { + if (!isset($classMap[$class])) { + $path = $this->getPathCode($filesystem, $basePath, $vendorPath, $path); + $classMap[$class] = $path.",\n"; + } + } + } + } + } } $autoloads['classmap'] = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($autoloads['classmap'])); @@ -173,6 +227,7 @@ EOF; } file_put_contents($targetDir.'/autoload_namespaces.php', $namespacesFile); + file_put_contents($targetDir.'/autoload_psr4.php', $psr4File); file_put_contents($targetDir.'/autoload_classmap.php', $classmapFile); if ($includePathFile = $this->getIncludePathsFile($packageMap, $filesystem, $basePath, $vendorPath, $vendorPathCode52, $appBaseDirCode)) { file_put_contents($targetDir.'/include_paths.php', $includePathFile); @@ -181,7 +236,7 @@ EOF; file_put_contents($targetDir.'/autoload_files.php', $includeFilesFile); } file_put_contents($vendorPath.'/autoload.php', $this->getAutoloadFile($vendorPathToTargetDirCode, $suffix)); - file_put_contents($targetDir.'/autoload_real.php', $this->getAutoloadRealFile(true, true, (bool) $includePathFile, $targetDirLoader, (bool) $includeFilesFile, $vendorPathCode, $appBaseDirCode, $suffix, $useGlobalIncludePath, $prependAutoloader)); + file_put_contents($targetDir.'/autoload_real.php', $this->getAutoloadRealFile(true, (bool) $includePathFile, $targetDirLoader, (bool) $includeFilesFile, $vendorPathCode, $appBaseDirCode, $suffix, $useGlobalIncludePath, $prependAutoloader)); // use stream_copy_to_stream instead of copy // to work around https://bugs.php.net/bug.php?id=64634 @@ -229,12 +284,14 @@ EOF; array_unshift($packageMap, $mainPackageMap); $psr0 = $this->parseAutoloadsType($packageMap, 'psr-0', $mainPackage); + $psr4 = $this->parseAutoloadsType($packageMap, 'psr-4', $mainPackage); $classmap = $this->parseAutoloadsType($sortedPackageMap, 'classmap', $mainPackage); $files = $this->parseAutoloadsType($sortedPackageMap, 'files', $mainPackage); krsort($psr0); + krsort($psr4); - return array('psr-0' => $psr0, 'classmap' => $classmap, 'files' => $files); + return array('psr-0' => $psr0, 'psr-4' => $psr4, 'classmap' => $classmap, 'files' => $files); } /** @@ -366,7 +423,7 @@ return ComposerAutoloaderInit$suffix::getLoader(); AUTOLOAD; } - protected function getAutoloadRealFile($usePSR0, $useClassMap, $useIncludePath, $targetDirLoader, $useIncludeFiles, $vendorPathCode, $appBaseDirCode, $suffix, $useGlobalIncludePath, $prependAutoloader) + protected function getAutoloadRealFile($useClassMap, $useIncludePath, $targetDirLoader, $useIncludeFiles, $vendorPathCode, $appBaseDirCode, $suffix, $useGlobalIncludePath, $prependAutoloader) { // TODO the class ComposerAutoloaderInit should be revert to a closure // when APC has been fixed: @@ -417,8 +474,7 @@ HEADER; INCLUDE_PATH; } - if ($usePSR0) { - $file .= <<<'PSR0' + $file .= <<<'PSR0' $map = require __DIR__ . '/autoload_namespaces.php'; foreach ($map as $namespace => $path) { $loader->set($namespace, $path); @@ -426,8 +482,16 @@ INCLUDE_PATH; PSR0; + + $file .= <<<'PSR4' + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); } + +PSR4; + if ($useClassMap) { $file .= <<<'CLASSMAP' $classMap = require __DIR__ . '/autoload_classmap.php'; diff --git a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php index 7a1609926..38fb4886e 100644 --- a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php +++ b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php @@ -95,7 +95,14 @@ class AutoloadGeneratorTest extends TestCase { $package = new Package('a', '1.0', '1.0'); $package->setAutoload(array( - 'psr-0' => array('Main' => 'src/', 'Lala' => array('src/', 'lib/')), + 'psr-0' => array( + 'Main' => 'src/', + 'Lala' => array('src/', 'lib/'), + ), + 'psr-4' => array( + 'Acme\Fruit\\' => 'src-fruit/', + 'Acme\Cake\\' => array('src-cake/', 'lib-cake/'), + ), 'classmap' => array('composersrc/'), )); @@ -107,11 +114,22 @@ class AutoloadGeneratorTest extends TestCase $this->fs->ensureDirectoryExists($this->workingDir.'/src'); $this->fs->ensureDirectoryExists($this->workingDir.'/lib'); + $this->fs->ensureDirectoryExists($this->workingDir.'/src-fruit'); + $this->fs->ensureDirectoryExists($this->workingDir.'/src-cake'); + $this->fs->ensureDirectoryExists($this->workingDir.'/lib-cake'); + $this->fs->ensureDirectoryExists($this->workingDir.'/composersrc'); file_put_contents($this->workingDir.'/composersrc/foo.php', 'generator->dump($this->config, $this->repository, $package, $this->im, 'composer', false, '_1'); + + // Assert that autoload_namespaces.php was correctly generated. $this->assertAutoloadFiles('main', $this->vendorDir.'/composer'); + + // Assert that autoload_psr4.php was correctly generated. + $this->assertAutoloadFiles('psr4', $this->vendorDir.'/composer', 'psr4'); + + // Assert that autoload_classmap.php was correctly generated. $this->assertAutoloadFiles('classmap', $this->vendorDir.'/composer', 'classmap'); } @@ -122,6 +140,10 @@ class AutoloadGeneratorTest extends TestCase $package = new Package('a', '1.0', '1.0'); $package->setAutoload(array( 'psr-0' => array('Main' => 'src/', 'Lala' => 'src/'), + 'psr-4' => array( + 'Acme\Fruit\\' => 'src-fruit/', + 'Acme\Cake\\' => array('src-cake/', 'lib-cake/'), + ), 'classmap' => array('composersrc/'), )); @@ -138,6 +160,7 @@ class AutoloadGeneratorTest extends TestCase $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', true, '_2'); $this->assertAutoloadFiles('main3', $this->vendorDir.'/composer'); + $this->assertAutoloadFiles('psr4_3', $this->vendorDir.'/composer', 'psr4'); $this->assertAutoloadFiles('classmap3', $this->vendorDir.'/composer', 'classmap'); } @@ -146,6 +169,10 @@ class AutoloadGeneratorTest extends TestCase $package = new Package('a', '1.0', '1.0'); $package->setAutoload(array( 'psr-0' => array('Main' => 'src/', 'Lala' => 'src/'), + 'psr-4' => array( + 'Acme\Fruit\\' => 'src-fruit/', + 'Acme\Cake\\' => array('src-cake/', 'lib-cake/'), + ), 'classmap' => array('composersrc/'), )); @@ -162,6 +189,7 @@ class AutoloadGeneratorTest extends TestCase file_put_contents($this->workingDir.'/composersrc/foo.php', 'generator->dump($this->config, $this->repository, $package, $this->im, 'composer', false, '_3'); $this->assertAutoloadFiles('main2', $this->vendorDir.'/composer'); + $this->assertAutoloadFiles('psr4_2', $this->vendorDir.'/composer', 'psr4'); $this->assertAutoloadFiles('classmap2', $this->vendorDir.'/composer', 'classmap'); } @@ -170,6 +198,10 @@ class AutoloadGeneratorTest extends TestCase $package = new Package('a', '1.0', '1.0'); $package->setAutoload(array( 'psr-0' => array('Main\\Foo' => '', 'Main\\Bar' => ''), + 'psr-4' => array( + 'Acme\Fruit\\' => 'src-fruit/', + 'Acme\Cake\\' => array('src-cake/', 'lib-cake/'), + ), 'classmap' => array('Main/Foo/src', 'lib'), 'files' => array('foo.php', 'Main/Foo/bar.php'), )); diff --git a/tests/Composer/Test/Autoload/Fixtures/autoload_psr4.php b/tests/Composer/Test/Autoload/Fixtures/autoload_psr4.php new file mode 100644 index 000000000..78b609869 --- /dev/null +++ b/tests/Composer/Test/Autoload/Fixtures/autoload_psr4.php @@ -0,0 +1,11 @@ + array($baseDir . '/src-fruit'), + 'Acme\\Cake\\' => array($baseDir . '/src-cake', $baseDir . '/lib-cake'), +); diff --git a/tests/Composer/Test/Autoload/Fixtures/autoload_psr4_2.php b/tests/Composer/Test/Autoload/Fixtures/autoload_psr4_2.php new file mode 100644 index 000000000..ab9ca2f54 --- /dev/null +++ b/tests/Composer/Test/Autoload/Fixtures/autoload_psr4_2.php @@ -0,0 +1,11 @@ + array($baseDir . '/src-fruit'), + 'Acme\\Cake\\' => array($baseDir . '/src-cake', $baseDir . '/lib-cake'), +); diff --git a/tests/Composer/Test/Autoload/Fixtures/autoload_psr4_3.php b/tests/Composer/Test/Autoload/Fixtures/autoload_psr4_3.php new file mode 100644 index 000000000..a903b17b8 --- /dev/null +++ b/tests/Composer/Test/Autoload/Fixtures/autoload_psr4_3.php @@ -0,0 +1,11 @@ + array($vendorDir . '/src-fruit'), + 'Acme\\Cake\\' => array($vendorDir . '/src-cake', $vendorDir . '/lib-cake'), +); diff --git a/tests/Composer/Test/Autoload/Fixtures/autoload_real_files_by_dependency.php b/tests/Composer/Test/Autoload/Fixtures/autoload_real_files_by_dependency.php index d1f9afd30..e58e8d2fa 100644 --- a/tests/Composer/Test/Autoload/Fixtures/autoload_real_files_by_dependency.php +++ b/tests/Composer/Test/Autoload/Fixtures/autoload_real_files_by_dependency.php @@ -31,6 +31,11 @@ class ComposerAutoloaderInitFilesAutoloadOrder $loader->set($namespace, $path); } + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + $classMap = require __DIR__ . '/autoload_classmap.php'; if ($classMap) { $loader->addClassMap($classMap); diff --git a/tests/Composer/Test/Autoload/Fixtures/autoload_real_functions.php b/tests/Composer/Test/Autoload/Fixtures/autoload_real_functions.php index dc09bc0ee..a92e664cd 100644 --- a/tests/Composer/Test/Autoload/Fixtures/autoload_real_functions.php +++ b/tests/Composer/Test/Autoload/Fixtures/autoload_real_functions.php @@ -31,6 +31,11 @@ class ComposerAutoloaderInitFilesAutoload $loader->set($namespace, $path); } + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + $classMap = require __DIR__ . '/autoload_classmap.php'; if ($classMap) { $loader->addClassMap($classMap); diff --git a/tests/Composer/Test/Autoload/Fixtures/autoload_real_include_path.php b/tests/Composer/Test/Autoload/Fixtures/autoload_real_include_path.php index 3c92a5a2c..e72ea108a 100644 --- a/tests/Composer/Test/Autoload/Fixtures/autoload_real_include_path.php +++ b/tests/Composer/Test/Autoload/Fixtures/autoload_real_include_path.php @@ -31,6 +31,11 @@ class ComposerAutoloaderInitIncludePath $loader->set($namespace, $path); } + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + $classMap = require __DIR__ . '/autoload_classmap.php'; if ($classMap) { $loader->addClassMap($classMap); diff --git a/tests/Composer/Test/Autoload/Fixtures/autoload_real_target_dir.php b/tests/Composer/Test/Autoload/Fixtures/autoload_real_target_dir.php index cae8d5a31..4a6259da2 100644 --- a/tests/Composer/Test/Autoload/Fixtures/autoload_real_target_dir.php +++ b/tests/Composer/Test/Autoload/Fixtures/autoload_real_target_dir.php @@ -31,6 +31,11 @@ class ComposerAutoloaderInitTargetDir $loader->set($namespace, $path); } + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + $classMap = require __DIR__ . '/autoload_classmap.php'; if ($classMap) { $loader->addClassMap($classMap); From a9321f3101cb5e14e2999d1091802526fa9f82cc Mon Sep 17 00:00:00 2001 From: Andreas Hennings Date: Tue, 26 Nov 2013 19:19:02 +0100 Subject: [PATCH 08/16] Travis CI should use bin/composer and not system-wide Composer. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ad72478df..db431b533 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ php: before_script: - sudo apt-get install parallel - echo '' > ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini - - composer install --dev --prefer-source + - bin/composer install --dev --prefer-source - git config --global user.name travis-ci - git config --global user.email travis@example.com From b62fa2bc1c9cf74e0b227118fa583ebde8358151 Mon Sep 17 00:00:00 2001 From: Andreas Hennings Date: Tue, 26 Nov 2013 22:57:40 +0100 Subject: [PATCH 09/16] run system-wide composer install and THEN run bin/composer install --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index db431b533..9d288b023 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ php: before_script: - sudo apt-get install parallel - echo '' > ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini + - composer install --dev --prefer-source - bin/composer install --dev --prefer-source - git config --global user.name travis-ci - git config --global user.email travis@example.com From 39c09d519238618a888a99113c883dc7d0ca2f9e Mon Sep 17 00:00:00 2001 From: Andreas Hennings Date: Sat, 14 Dec 2013 16:28:27 +0100 Subject: [PATCH 10/16] Add psr-4 stuff in a few more places. --- doc/04-schema.md | 4 ++++ res/composer-schema.json | 5 +++++ src/Composer/Autoload/AutoloadGenerator.php | 6 ++++++ src/Composer/Command/ShowCommand.php | 4 ++++ src/Composer/Package/Loader/ValidatingArrayLoader.php | 2 +- 5 files changed, 20 insertions(+), 1 deletion(-) diff --git a/doc/04-schema.md b/doc/04-schema.md index 3a250a418..56044f06f 100644 --- a/doc/04-schema.md +++ b/doc/04-schema.md @@ -438,6 +438,10 @@ use an empty prefix like: } } +#### PSR-4 + +Stub: Similar to PSR-0. + #### Classmap The `classmap` references are all combined, during install/update, into a single diff --git a/res/composer-schema.json b/res/composer-schema.json index 7b52d7733..2f3b97a84 100644 --- a/res/composer-schema.json +++ b/res/composer-schema.json @@ -203,6 +203,11 @@ "description": "This is a hash of namespaces (keys) and the directories they can be found into (values, can be arrays of paths) by the autoloader.", "additionalProperties": true }, + "psr-4": { + "type": "object", + "description": "This is a hash of namespaces (keys) and the PSR-4 directories they can be found into (values, can be arrays of paths) by the autoloader.", + "additionalProperties": true + }, "classmap": { "type": "array", "description": "This is an array of directories that contain classes to be included in the class-map generation process." diff --git a/src/Composer/Autoload/AutoloadGenerator.php b/src/Composer/Autoload/AutoloadGenerator.php index e3dae3ea8..3a0d6c2c2 100644 --- a/src/Composer/Autoload/AutoloadGenerator.php +++ b/src/Composer/Autoload/AutoloadGenerator.php @@ -310,6 +310,12 @@ EOF; } } + if (isset($autoloads['psr-4'])) { + foreach ($autoloads['psr-4'] as $namespace => $path) { + $loader->addPsr4($namespace, $path); + } + } + return $loader; } diff --git a/src/Composer/Command/ShowCommand.php b/src/Composer/Command/ShowCommand.php index 97e315a5b..4b5b6ee9c 100644 --- a/src/Composer/Command/ShowCommand.php +++ b/src/Composer/Command/ShowCommand.php @@ -303,6 +303,10 @@ EOT foreach ($autoloads as $name => $path) { $output->writeln(($name ?: '*') . ' => ' . (is_array($path) ? implode(', ', $path) : ($path ?: '.'))); } + } elseif ($type === 'psr-4') { + foreach ($autoloads as $name => $path) { + $output->writeln(($name ?: '*') . ' => ' . (is_array($path) ? implode(', ', $path) : ($path ?: '.'))); + } } elseif ($type === 'classmap') { $output->writeln(implode(', ', $autoloads)); } diff --git a/src/Composer/Package/Loader/ValidatingArrayLoader.php b/src/Composer/Package/Loader/ValidatingArrayLoader.php index a5b6281a3..6d71a09bd 100644 --- a/src/Composer/Package/Loader/ValidatingArrayLoader.php +++ b/src/Composer/Package/Loader/ValidatingArrayLoader.php @@ -180,7 +180,7 @@ class ValidatingArrayLoader implements LoaderInterface } if ($this->validateArray('autoload') && !empty($this->config['autoload'])) { - $types = array('psr-0', 'classmap', 'files'); + $types = array('psr-0', 'psr-4', 'classmap', 'files'); foreach ($this->config['autoload'] as $type => $typeConfig) { if (!in_array($type, $types)) { $this->errors[] = 'autoload : invalid value ('.$type.'), must be one of '.implode(', ', $types); From c0aad84d8bbb1d4041036e99354ba429552af999 Mon Sep 17 00:00:00 2001 From: Andreas Hennings Date: Sat, 14 Dec 2013 16:33:59 +0100 Subject: [PATCH 11/16] Validation to make the combination of target-dir with psr-4 illegal. --- src/Composer/Autoload/AutoloadGenerator.php | 16 ++++++++++++++++ .../Package/Loader/ValidatingArrayLoader.php | 7 +++++++ 2 files changed, 23 insertions(+) diff --git a/src/Composer/Autoload/AutoloadGenerator.php b/src/Composer/Autoload/AutoloadGenerator.php index 3a0d6c2c2..86a39e47f 100644 --- a/src/Composer/Autoload/AutoloadGenerator.php +++ b/src/Composer/Autoload/AutoloadGenerator.php @@ -259,6 +259,7 @@ EOF; if ($package instanceof AliasPackage) { continue; } + $this->validatePackage($package); $packageMap[] = array( $package, @@ -269,6 +270,21 @@ EOF; return $packageMap; } + /** + * @param PackageInterface $package + * + * @throws \Exception + * Throws an exception, if the package has illegal settings. + */ + protected function validatePackage(PackageInterface $package) { + $autoload = $package->getAutoload(); + if (!empty($autoload['psr-4']) && null !== $package->getTargetDir()) { + $name = $package->getName(); + $package->getTargetDir(); + throw new \Exception("The ['autoload']['psr-4'] setting is incompatible with the ['target-dir'] setting, in package '$name'."); + } + } + /** * Compiles an ordered list of namespace => path mappings * diff --git a/src/Composer/Package/Loader/ValidatingArrayLoader.php b/src/Composer/Package/Loader/ValidatingArrayLoader.php index 6d71a09bd..f93e10bf1 100644 --- a/src/Composer/Package/Loader/ValidatingArrayLoader.php +++ b/src/Composer/Package/Loader/ValidatingArrayLoader.php @@ -189,6 +189,13 @@ class ValidatingArrayLoader implements LoaderInterface } } + if (!empty($this->config['autoload']['psr-4']) && !empty($this->config['target-dir'])) { + $this->errors[] = "The ['autoload']['psr-4'] setting is incompatible with the ['target-dir'] setting."; + // Unset the psr-4 setting, since unsetting target-dir might + // interfere with other settings. + unset($this->config['autoload']['psr-4']); + } + // TODO validate dist // TODO validate source From e4bbd83f1385d2de992ad5fc71a3eda203a10869 Mon Sep 17 00:00:00 2001 From: Andreas Hennings Date: Sun, 22 Dec 2013 19:03:23 +0100 Subject: [PATCH 12/16] expected message in ValidatingArrayLoaderTest should also contain psr-4 as allowed key. --- .../Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php b/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php index 262c24bf6..9b1982b9d 100644 --- a/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php +++ b/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php @@ -253,7 +253,7 @@ class ValidatingArrayLoaderTest extends \PHPUnit_Framework_TestCase ), ), array( - 'autoload : invalid value (psr0), must be one of psr-0, classmap, files' + 'autoload : invalid value (psr0), must be one of psr-0, psr-4, classmap, files' ) ), ); From 8e11a7684fb16201ab4c0a9e056cce8709d5c816 Mon Sep 17 00:00:00 2001 From: Andreas Hennings Date: Sun, 22 Dec 2013 19:24:58 +0100 Subject: [PATCH 13/16] phar compiler should also compile autoload_psr4.php --- src/Composer/Compiler.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Composer/Compiler.php b/src/Composer/Compiler.php index c81e300b6..41c30d6d1 100644 --- a/src/Composer/Compiler.php +++ b/src/Composer/Compiler.php @@ -103,6 +103,7 @@ class Compiler $this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/autoload.php')); $this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/composer/autoload_namespaces.php')); + $this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/composer/autoload_psr4.php')); $this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/composer/autoload_classmap.php')); $this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/composer/autoload_real.php')); if (file_exists(__DIR__.'/../../vendor/composer/include_paths.php')) { From 8966376f40d7d2b6d6e44258aa8ffe8f497a3473 Mon Sep 17 00:00:00 2001 From: Andreas Hennings Date: Sun, 22 Dec 2013 19:38:11 +0100 Subject: [PATCH 14/16] Verify generation of autoload_psr4.php even if empty. --- .../Test/Autoload/AutoloadGeneratorTest.php | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php index 38fb4886e..7d3d8ba9c 100644 --- a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php +++ b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php @@ -518,6 +518,20 @@ return array( 'A' => array(\$vendorDir . '/a/a/src'), ); +EOF; + + // autoload_psr4.php is expected to be empty in this example. + $expectedPsr4 = <<generator->dump($this->config, $this->repository, $package, $this->im, 'composer', true, '_9'); $this->assertEquals($expectedNamespace, file_get_contents($this->vendorDir.'/composer/autoload_namespaces.php')); + $this->assertEquals($expectedPsr4, file_get_contents($this->vendorDir.'/composer/autoload_psr4.php')); $this->assertEquals($expectedClassmap, file_get_contents($this->vendorDir.'/composer/autoload_classmap.php')); } @@ -766,6 +781,20 @@ return array( 'Bar' => array($vendorDir . '/b/b/lib'), ); +EOF; + + // autoload_psr4.php is expected to be empty in this example. + $expectedPsr4 = <<<'EOF' +assertEquals($expectedNamespace, file_get_contents($vendorDir.'/composer/autoload_namespaces.php')); + $this->assertEquals($expectedPsr4, file_get_contents($vendorDir.'/composer/autoload_psr4.php')); $this->assertEquals($expectedClassmap, file_get_contents($vendorDir.'/composer/autoload_classmap.php')); $this->assertContains("\n \$vendorDir . '/b/b/bootstrap.php',\n", file_get_contents($vendorDir.'/composer/autoload_files.php')); $this->assertContains("\n \$baseDir . '/test.php',\n", file_get_contents($vendorDir.'/composer/autoload_files.php')); @@ -828,6 +858,20 @@ return array( 'Foo' => array($baseDir . '/../src'), ); +EOF; + + // autoload_psr4.php is expected to be empty in this example. + $expectedPsr4 = <<<'EOF' +assertEquals($expectedNamespace, file_get_contents($this->vendorDir.'/composer/autoload_namespaces.php')); + $this->assertEquals($expectedPsr4, file_get_contents($this->vendorDir.'/composer/autoload_psr4.php')); $this->assertEquals($expectedClassmap, file_get_contents($this->vendorDir.'/composer/autoload_classmap.php')); $this->assertContains("\n \$baseDir . '/../test.php',\n", file_get_contents($this->vendorDir.'/composer/autoload_files.php')); } @@ -880,6 +925,20 @@ return array( 'Foo' => array($baseDir . '/'), ); +EOF; + + // autoload_psr4.php is expected to be empty in this example. + $expectedPsr4 = <<assertEquals($expectedNamespace, file_get_contents($this->vendorDir.'/composer/autoload_namespaces.php')); + $this->assertEquals($expectedPsr4, file_get_contents($this->vendorDir.'/composer/autoload_psr4.php')); $this->assertEquals($expectedClassmap, file_get_contents($this->vendorDir.'/composer/autoload_classmap.php')); } @@ -926,10 +986,25 @@ return array( 'Foo' => array($baseDir . '/composer-test-autoload-src/src'), ); +EOF; + + // autoload_psr4.php is expected to be empty in this example. + $expectedPsr4 = <<generator->dump($this->config, $this->repository, $package, $this->im, 'composer', false, 'VendorSubstring'); $this->assertEquals($expectedNamespace, file_get_contents($this->vendorDir.'/composer/autoload_namespaces.php')); + $this->assertEquals($expectedPsr4, file_get_contents($this->vendorDir.'/composer/autoload_psr4.php')); } private function assertAutoloadFiles($name, $dir, $type = 'namespaces') From bda2bcac135bc89a96e543a0e950b4bf33f07174 Mon Sep 17 00:00:00 2001 From: Andreas Hennings Date: Sun, 22 Dec 2013 19:39:09 +0100 Subject: [PATCH 15/16] Fix indentation of assignment in AutoloadGeneratorTest --- tests/Composer/Test/Autoload/AutoloadGeneratorTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php index 7d3d8ba9c..6d44721bb 100644 --- a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php +++ b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php @@ -874,7 +874,7 @@ return array( EOF; - $expectedClassmap = <<<'EOF' + $expectedClassmap = <<<'EOF' Date: Sun, 22 Dec 2013 19:58:27 +0100 Subject: [PATCH 16/16] More interesting generator tests for PSR-4. --- .../Test/Autoload/AutoloadGeneratorTest.php | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php index 6d44721bb..331d0225a 100644 --- a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php +++ b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php @@ -725,6 +725,7 @@ EOF; $package = new Package('a', '1.0', '1.0'); $package->setAutoload(array( 'psr-0' => array('Foo' => 'src'), + 'psr-4' => array('Acme\Foo\\' => 'src-psr4'), 'classmap' => array('classmap'), 'files' => array('test.php'), )); @@ -732,6 +733,7 @@ EOF; $vendorPackage = new Package('b/b', '1.0', '1.0'); $vendorPackage->setAutoload(array( 'psr-0' => array('Bar' => 'lib'), + 'psr-4' => array('Acme\Bar\\' => 'lib-psr4'), 'classmap' => array('classmaps'), 'files' => array('bootstrap.php'), )); @@ -783,7 +785,6 @@ return array( EOF; - // autoload_psr4.php is expected to be empty in this example. $expectedPsr4 = <<<'EOF' array($baseDir . '/src-psr4'), + 'Acme\\Bar\\' => array($vendorDir . '/b/b/lib-psr4'), ); EOF; @@ -830,6 +833,7 @@ EOF; $package = new Package('a', '1.0', '1.0'); $package->setAutoload(array( 'psr-0' => array('Foo' => '../path/../src'), + 'psr-4' => array('Acme\Foo\\' => '../path/../src-psr4'), 'classmap' => array('../classmap'), 'files' => array('../test.php'), )); @@ -860,7 +864,6 @@ return array( EOF; - // autoload_psr4.php is expected to be empty in this example. $expectedPsr4 = <<<'EOF' array($baseDir . '/../src-psr4'), ); EOF; @@ -900,6 +904,7 @@ EOF; $package = new Package('a', '1.0', '1.0'); $package->setAutoload(array( 'psr-0' => array('Foo' => ''), + 'psr-4' => array('Acme\Foo\\' => ''), 'classmap' => array(''), )); @@ -927,16 +932,16 @@ return array( EOF; - // autoload_psr4.php is expected to be empty in this example. - $expectedPsr4 = << array($baseDir . '/'), ); EOF; @@ -966,6 +971,7 @@ EOF; $package = new Package('a', '1.0', '1.0'); $package->setAutoload(array( 'psr-0' => array('Foo' => 'composer-test-autoload-src/src'), + 'psr-4' => array('Acme\Foo\\' => 'composer-test-autoload-src/src-psr4'), )); $this->repository->expects($this->once()) @@ -988,16 +994,16 @@ return array( EOF; - // autoload_psr4.php is expected to be empty in this example. - $expectedPsr4 = << array($baseDir . '/composer-test-autoload-src/src-psr4'), ); EOF;