1
0
Fork 0

AutoloadGenerator to support PSR-4. Tests included.

pull/2459/head
Andreas Hennings 2013-11-26 02:53:44 +01:00
parent 2c98813431
commit bbf6278905
9 changed files with 155 additions and 6 deletions

View File

@ -69,9 +69,23 @@ return array(
EOF; EOF;
$psr4File = <<<EOF
<?php
// autoload_psr4.php @generated by Composer
\$vendorDir = $vendorPathCode52;
\$baseDir = $appBaseDirCode;
return array(
EOF;
// Collect information from all packages.
$packageMap = $this->buildPackageMap($installationManager, $mainPackage, $localRepo->getCanonicalPackages()); $packageMap = $this->buildPackageMap($installationManager, $mainPackage, $localRepo->getCanonicalPackages());
$autoloads = $this->parseAutoloads($packageMap, $mainPackage); $autoloads = $this->parseAutoloads($packageMap, $mainPackage);
// Process the 'psr-0' base directories.
foreach ($autoloads['psr-0'] as $namespace => $paths) { foreach ($autoloads['psr-0'] as $namespace => $paths) {
$exportedPaths = array(); $exportedPaths = array();
foreach ($paths as $path) { foreach ($paths as $path) {
@ -83,6 +97,21 @@ EOF;
} }
$namespacesFile .= ");\n"; $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 = <<<EOF $classmapFile = <<<EOF
<?php <?php
@ -131,6 +160,8 @@ EOF;
// flatten array // flatten array
$classMap = array(); $classMap = array();
if ($scanPsr0Packages) { if ($scanPsr0Packages) {
// Scan the PSR-0 directories for class files, and add them to the
// class map.
foreach ($autoloads['psr-0'] as $namespace => $paths) { foreach ($autoloads['psr-0'] as $namespace => $paths) {
foreach ($paths as $dir) { foreach ($paths as $dir) {
$dir = $filesystem->normalizePath($filesystem->isAbsolutePath($dir) ? $dir : $basePath.'/'.$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.+(?<!(?<!/)Test\.php)$}',
preg_quote($dir),
strpos($namespace, '_') === false ? preg_quote(strtr($namespace, '\\', '/')) : ''
);
foreach (ClassMapGenerator::createMap($dir, $whitelist) as $class => $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'])); $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_namespaces.php', $namespacesFile);
file_put_contents($targetDir.'/autoload_psr4.php', $psr4File);
file_put_contents($targetDir.'/autoload_classmap.php', $classmapFile); file_put_contents($targetDir.'/autoload_classmap.php', $classmapFile);
if ($includePathFile = $this->getIncludePathsFile($packageMap, $filesystem, $basePath, $vendorPath, $vendorPathCode52, $appBaseDirCode)) { if ($includePathFile = $this->getIncludePathsFile($packageMap, $filesystem, $basePath, $vendorPath, $vendorPathCode52, $appBaseDirCode)) {
file_put_contents($targetDir.'/include_paths.php', $includePathFile); file_put_contents($targetDir.'/include_paths.php', $includePathFile);
@ -181,7 +236,7 @@ EOF;
file_put_contents($targetDir.'/autoload_files.php', $includeFilesFile); file_put_contents($targetDir.'/autoload_files.php', $includeFilesFile);
} }
file_put_contents($vendorPath.'/autoload.php', $this->getAutoloadFile($vendorPathToTargetDirCode, $suffix)); 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 // use stream_copy_to_stream instead of copy
// to work around https://bugs.php.net/bug.php?id=64634 // to work around https://bugs.php.net/bug.php?id=64634
@ -229,12 +284,14 @@ EOF;
array_unshift($packageMap, $mainPackageMap); array_unshift($packageMap, $mainPackageMap);
$psr0 = $this->parseAutoloadsType($packageMap, 'psr-0', $mainPackage); $psr0 = $this->parseAutoloadsType($packageMap, 'psr-0', $mainPackage);
$psr4 = $this->parseAutoloadsType($packageMap, 'psr-4', $mainPackage);
$classmap = $this->parseAutoloadsType($sortedPackageMap, 'classmap', $mainPackage); $classmap = $this->parseAutoloadsType($sortedPackageMap, 'classmap', $mainPackage);
$files = $this->parseAutoloadsType($sortedPackageMap, 'files', $mainPackage); $files = $this->parseAutoloadsType($sortedPackageMap, 'files', $mainPackage);
krsort($psr0); 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; 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 // TODO the class ComposerAutoloaderInit should be revert to a closure
// when APC has been fixed: // when APC has been fixed:
@ -417,8 +474,7 @@ HEADER;
INCLUDE_PATH; INCLUDE_PATH;
} }
if ($usePSR0) { $file .= <<<'PSR0'
$file .= <<<'PSR0'
$map = require __DIR__ . '/autoload_namespaces.php'; $map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) { foreach ($map as $namespace => $path) {
$loader->set($namespace, $path); $loader->set($namespace, $path);
@ -426,8 +482,16 @@ INCLUDE_PATH;
PSR0; PSR0;
$file .= <<<'PSR4'
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
} }
PSR4;
if ($useClassMap) { if ($useClassMap) {
$file .= <<<'CLASSMAP' $file .= <<<'CLASSMAP'
$classMap = require __DIR__ . '/autoload_classmap.php'; $classMap = require __DIR__ . '/autoload_classmap.php';

View File

@ -95,7 +95,14 @@ class AutoloadGeneratorTest extends TestCase
{ {
$package = new Package('a', '1.0', '1.0'); $package = new Package('a', '1.0', '1.0');
$package->setAutoload(array( $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/'), 'classmap' => array('composersrc/'),
)); ));
@ -107,11 +114,22 @@ class AutoloadGeneratorTest extends TestCase
$this->fs->ensureDirectoryExists($this->workingDir.'/src'); $this->fs->ensureDirectoryExists($this->workingDir.'/src');
$this->fs->ensureDirectoryExists($this->workingDir.'/lib'); $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'); $this->fs->ensureDirectoryExists($this->workingDir.'/composersrc');
file_put_contents($this->workingDir.'/composersrc/foo.php', '<?php class ClassMapFoo {}'); file_put_contents($this->workingDir.'/composersrc/foo.php', '<?php class ClassMapFoo {}');
$this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', false, '_1'); $this->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'); $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'); $this->assertAutoloadFiles('classmap', $this->vendorDir.'/composer', 'classmap');
} }
@ -122,6 +140,10 @@ class AutoloadGeneratorTest extends TestCase
$package = new Package('a', '1.0', '1.0'); $package = new Package('a', '1.0', '1.0');
$package->setAutoload(array( $package->setAutoload(array(
'psr-0' => array('Main' => 'src/', 'Lala' => 'src/'), 'psr-0' => array('Main' => 'src/', 'Lala' => 'src/'),
'psr-4' => array(
'Acme\Fruit\\' => 'src-fruit/',
'Acme\Cake\\' => array('src-cake/', 'lib-cake/'),
),
'classmap' => array('composersrc/'), '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->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', true, '_2');
$this->assertAutoloadFiles('main3', $this->vendorDir.'/composer'); $this->assertAutoloadFiles('main3', $this->vendorDir.'/composer');
$this->assertAutoloadFiles('psr4_3', $this->vendorDir.'/composer', 'psr4');
$this->assertAutoloadFiles('classmap3', $this->vendorDir.'/composer', 'classmap'); $this->assertAutoloadFiles('classmap3', $this->vendorDir.'/composer', 'classmap');
} }
@ -146,6 +169,10 @@ class AutoloadGeneratorTest extends TestCase
$package = new Package('a', '1.0', '1.0'); $package = new Package('a', '1.0', '1.0');
$package->setAutoload(array( $package->setAutoload(array(
'psr-0' => array('Main' => 'src/', 'Lala' => 'src/'), 'psr-0' => array('Main' => 'src/', 'Lala' => 'src/'),
'psr-4' => array(
'Acme\Fruit\\' => 'src-fruit/',
'Acme\Cake\\' => array('src-cake/', 'lib-cake/'),
),
'classmap' => array('composersrc/'), 'classmap' => array('composersrc/'),
)); ));
@ -162,6 +189,7 @@ class AutoloadGeneratorTest extends TestCase
file_put_contents($this->workingDir.'/composersrc/foo.php', '<?php class ClassMapFoo {}'); file_put_contents($this->workingDir.'/composersrc/foo.php', '<?php class ClassMapFoo {}');
$this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', false, '_3'); $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', false, '_3');
$this->assertAutoloadFiles('main2', $this->vendorDir.'/composer'); $this->assertAutoloadFiles('main2', $this->vendorDir.'/composer');
$this->assertAutoloadFiles('psr4_2', $this->vendorDir.'/composer', 'psr4');
$this->assertAutoloadFiles('classmap2', $this->vendorDir.'/composer', 'classmap'); $this->assertAutoloadFiles('classmap2', $this->vendorDir.'/composer', 'classmap');
} }
@ -170,6 +198,10 @@ class AutoloadGeneratorTest extends TestCase
$package = new Package('a', '1.0', '1.0'); $package = new Package('a', '1.0', '1.0');
$package->setAutoload(array( $package->setAutoload(array(
'psr-0' => array('Main\\Foo' => '', 'Main\\Bar' => ''), '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'), 'classmap' => array('Main/Foo/src', 'lib'),
'files' => array('foo.php', 'Main/Foo/bar.php'), 'files' => array('foo.php', 'Main/Foo/bar.php'),
)); ));

View File

@ -0,0 +1,11 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Acme\\Fruit\\' => array($baseDir . '/src-fruit'),
'Acme\\Cake\\' => array($baseDir . '/src-cake', $baseDir . '/lib-cake'),
);

View File

@ -0,0 +1,11 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname(dirname($vendorDir));
return array(
'Acme\\Fruit\\' => array($baseDir . '/src-fruit'),
'Acme\\Cake\\' => array($baseDir . '/src-cake', $baseDir . '/lib-cake'),
);

View File

@ -0,0 +1,11 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = $vendorDir;
return array(
'Acme\\Fruit\\' => array($vendorDir . '/src-fruit'),
'Acme\\Cake\\' => array($vendorDir . '/src-cake', $vendorDir . '/lib-cake'),
);

View File

@ -31,6 +31,11 @@ class ComposerAutoloaderInitFilesAutoloadOrder
$loader->set($namespace, $path); $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'; $classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) { if ($classMap) {
$loader->addClassMap($classMap); $loader->addClassMap($classMap);

View File

@ -31,6 +31,11 @@ class ComposerAutoloaderInitFilesAutoload
$loader->set($namespace, $path); $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'; $classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) { if ($classMap) {
$loader->addClassMap($classMap); $loader->addClassMap($classMap);

View File

@ -31,6 +31,11 @@ class ComposerAutoloaderInitIncludePath
$loader->set($namespace, $path); $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'; $classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) { if ($classMap) {
$loader->addClassMap($classMap); $loader->addClassMap($classMap);

View File

@ -31,6 +31,11 @@ class ComposerAutoloaderInitTargetDir
$loader->set($namespace, $path); $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'; $classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) { if ($classMap) {
$loader->addClassMap($classMap); $loader->addClassMap($classMap);