Browse Source

Merge pull request #602 from Seldaek/target_dir_autoload

Target dir autoloading for root packages, fixes #139
Nils Adermann 13 years ago
parent
commit
e74e218bdb

+ 1 - 0
CHANGELOG.md

@@ -7,6 +7,7 @@
   * Added caching of repository metadata (faster startup times & failover if packagist is down)
   * Added include_path support for legacy projects that are full of require_once statements
   * Added installation notifications API to allow better statistics on Composer repositories
+  * Added autoloading support for root packages that use target-dir
   * Improved repository protocol to have large cacheable parts
 
 * 1.0.0-alpha2 (2012-04-03)

+ 34 - 2
src/Composer/Autoload/AutoloadGenerator.php

@@ -79,6 +79,36 @@ return array(
 
 EOF;
 
+        // add custom psr-0 autoloading if the root package has a target dir
+        $targetDirLoader = null;
+        $mainAutoload = $mainPackage->getAutoload();
+        if ($mainPackage->getTargetDir() && $mainAutoload['psr-0']) {
+            $levels = count(explode('/', trim(strtr($mainPackage->getTargetDir(), '\\', '/'), '/')));
+            $prefixes = implode(', ', array_map(function ($prefix) {
+                return var_export($prefix, true);
+            }, array_keys($mainAutoload['psr-0'])));
+            $baseDirFromTargetDirCode = $filesystem->findShortestPathCode(realpath($targetDir), getcwd(), true);
+
+            $targetDirLoader = <<<EOF
+    spl_autoload_register(function(\$class) {
+        \$prefixes = array($prefixes);
+        foreach (\$prefixes as \$prefix) {
+            if (0 !== strpos(\$class, \$prefix)) {
+                continue;
+            }
+            \$path = $baseDirFromTargetDirCode . '/' . implode('/', array_slice(explode('\\\\', \$class), $levels)).'.php';
+            if (!stream_resolve_include_path(\$path)) {
+                return false;
+            }
+            require_once \$path;
+            return true;
+        }
+    });
+
+
+EOF;
+        }
+
         // flatten array
         $autoloads['classmap'] = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($autoloads['classmap']));
         foreach ($autoloads['classmap'] as $dir) {
@@ -94,7 +124,7 @@ EOF;
         if ($includePathFile = $this->getIncludePathsFile($packageMap, $filesystem, $relVendorPath, $vendorPath, $vendorDirCode, $appBaseDirCode)) {
             file_put_contents($targetDir.'/include_paths.php', $includePathFile);
         }
-        file_put_contents($targetDir.'/autoload.php', $this->getAutoloadFile(true, true, (Boolean) $includePathFile));
+        file_put_contents($targetDir.'/autoload.php', $this->getAutoloadFile(true, true, (Boolean) $includePathFile, $targetDirLoader));
         copy(__DIR__.'/ClassLoader.php', $targetDir.'/ClassLoader.php');
 
         // TODO BC feature, add E_DEPRECATED in autoload.php on April 30th, remove after May 30th
@@ -243,7 +273,7 @@ EOF;
         return $baseDir.var_export($path, true);
     }
 
-    protected function getAutoloadFile($usePSR0, $useClassMap, $useIncludePath)
+    protected function getAutoloadFile($usePSR0, $useClassMap, $useIncludePath, $targetDirLoader)
     {
         $file = <<<'HEADER'
 <?php
@@ -291,6 +321,8 @@ PSR0;
 CLASSMAP;
         }
 
+        $file .= $targetDirLoader;
+
         return $file . <<<'FOOTER'
     $loader->register();
 

+ 16 - 0
tests/Composer/Test/Autoload/AutoloadGeneratorTest.php

@@ -141,6 +141,22 @@ class AutoloadGeneratorTest extends TestCase
         $this->assertAutoloadFiles('classmap2', $this->vendorDir.'/.composer', 'classmap');
     }
 
+    public function testMainPackageAutoloadingWithTargetDir()
+    {
+        $package = new MemoryPackage('a', '1.0', '1.0');
+        $package->setAutoload(array(
+            'psr-0' => array('Main\\Foo' => '', 'Main\\Bar' => ''),
+        ));
+        $package->setTargetDir('Main/Foo/');
+
+        $this->repository->expects($this->once())
+            ->method('getPackages')
+            ->will($this->returnValue(array()));
+
+        $this->generator->dump($this->repository, $package, $this->im, $this->vendorDir.'/.composer');
+        $this->assertFileEquals(__DIR__.'/Fixtures/autoload_target_dir.php', $this->vendorDir.'/.composer/autoload.php');
+    }
+
     public function testVendorsAutoloading()
     {
         $package = new MemoryPackage('a', '1.0', '1.0');

+ 39 - 0
tests/Composer/Test/Autoload/Fixtures/autoload_target_dir.php

@@ -0,0 +1,39 @@
+<?php
+
+// autoload.php generated by Composer
+if (!class_exists('Composer\\Autoload\\ClassLoader', false)) {
+    require __DIR__.'/ClassLoader.php';
+}
+
+return call_user_func(function() {
+    $loader = new \Composer\Autoload\ClassLoader();
+
+    $map = require __DIR__.'/autoload_namespaces.php';
+    foreach ($map as $namespace => $path) {
+        $loader->add($namespace, $path);
+    }
+
+    $classMap = require __DIR__.'/autoload_classmap.php';
+    if ($classMap) {
+        $loader->addClassMap($classMap);
+    }
+
+    spl_autoload_register(function($class) {
+        $prefixes = array('Main\\Foo', 'Main\\Bar');
+        foreach ($prefixes as $prefix) {
+            if (0 !== strpos($class, $prefix)) {
+                continue;
+            }
+            $path = dirname(dirname(__DIR__)) . '/' . implode('/', array_slice(explode('\\', $class), 2)).'.php';
+            if (!stream_resolve_include_path($path)) {
+                return false;
+            }
+            require_once $path;
+            return true;
+        }
+    });
+
+    $loader->register();
+
+    return $loader;
+});