* Jordi Boggiano * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Composer\Autoload; use Composer\Installer\InstallationManager; use Composer\Json\JsonFile; use Composer\Package\AliasPackage; use Composer\Package\Loader\JsonLoader; use Composer\Package\PackageInterface; use Composer\Repository\RepositoryInterface; use Composer\Util\Filesystem; /** * @author Igor Wiedler * @author Jordi Boggiano */ class AutoloadGenerator { public function dump(RepositoryInterface $localRepo, PackageInterface $mainPackage, InstallationManager $installationManager, $targetDir, $bcLinks = false) { $filesystem = new Filesystem(); $filesystem->ensureDirectoryExists($installationManager->getVendorPath()); $filesystem->ensureDirectoryExists($targetDir); $vendorPath = strtr(realpath($installationManager->getVendorPath()), '\\', '/'); $relVendorPath = $filesystem->findShortestPath(getcwd(), $vendorPath, true); $vendorPathCode = $filesystem->findShortestPathCode(realpath($targetDir), $vendorPath, true); $vendorPathToTargetDirCode = $filesystem->findShortestPathCode($vendorPath, realpath($targetDir), true); $appBaseDirCode = $filesystem->findShortestPathCode($vendorPath, getcwd(), true); $appBaseDirCode = str_replace('__DIR__', '$vendorDir', $appBaseDirCode); $namespacesFile = <<buildPackageMap($installationManager, $mainPackage, $localRepo->getPackages()); $autoloads = $this->parseAutoloads($packageMap); foreach ($autoloads['psr-0'] as $namespace => $paths) { $exportedPaths = array(); foreach ($paths as $path) { $exportedPaths[] = $this->getPathCode($filesystem, $relVendorPath, $vendorPath, $path); } $exportedPrefix = var_export($namespace, true); $namespacesFile .= " $exportedPrefix => "; if (count($exportedPaths) > 1) { $namespacesFile .= "array(".implode(', ', $exportedPaths)."),\n"; } else { $namespacesFile .= $exportedPaths[0].",\n"; } } $namespacesFile .= ");\n"; $classmapFile = <<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']))); $baseDirFromVendorDirCode = $filesystem->findShortestPathCode($vendorPath, getcwd(), true); $targetDirLoader = << $path) { $path = '/'.$filesystem->findShortestPath(getcwd(), $path, true); $classmapFile .= ' '.var_export($class, true).' => $baseDir . '.var_export($path, true).",\n"; } } $classmapFile .= ");\n"; file_put_contents($targetDir.'/autoload_namespaces.php', $namespacesFile); file_put_contents($targetDir.'/autoload_classmap.php', $classmapFile); if ($includePathFile = $this->getIncludePathsFile($packageMap, $filesystem, $relVendorPath, $vendorPath, $vendorPathCode, $appBaseDirCode)) { file_put_contents($targetDir.'/include_paths.php', $includePathFile); } file_put_contents($vendorPath.'/autoload.php', $this->getAutoloadFile($vendorPathToTargetDirCode, true, true, (Boolean) $includePathFile, $targetDirLoader)); copy(__DIR__.'/ClassLoader.php', $targetDir.'/ClassLoader.php'); // TODO BC feature, remove after June 15th if ($bcLinks) { $filesystem->ensureDirectoryExists($vendorPath.'/.composer'); $deprecated = "// Deprecated file, use the one in root of vendor dir\n". "trigger_error(__FILE__.' is deprecated, please use vendor/autoload.php or vendor/composer/autoload_* instead'.PHP_EOL.'See https://groups.google.com/forum/#!msg/composer-dev/fWIs3KocwoA/nU3aLko9LhQJ for details', E_USER_DEPRECATED);\n"; file_put_contents($vendorPath.'/.composer/autoload_namespaces.php', " install path map $packageMap = array(); // add main package $packageMap[] = array($mainPackage, ''); foreach ($packages as $package) { if ($package instanceof AliasPackage) { continue; } $packageMap[] = array( $package, $installationManager->getInstallPath($package) ); } return $packageMap; } /** * Compiles an ordered list of namespace => path mappings * * @param array $packageMap array of array(package, installDir-relative-to-composer.json) * @return array array('psr-0' => array('Ns\\Foo' => array('installDir'))) */ public function parseAutoloads(array $packageMap) { $autoloads = array('classmap' => array(), 'psr-0' => array()); foreach ($packageMap as $item) { list($package, $installPath) = $item; if (null !== $package->getTargetDir()) { $installPath = substr($installPath, 0, -strlen('/'.$package->getTargetDir())); } foreach ($package->getAutoload() as $type => $mapping) { // skip misconfigured packages if (!is_array($mapping)) { continue; } foreach ($mapping as $namespace => $paths) { foreach ((array) $paths as $path) { $autoloads[$type][$namespace][] = empty($installPath) ? $path : $installPath.'/'.$path; } } } } foreach ($autoloads as $type => $maps) { krsort($autoloads[$type]); } return $autoloads; } /** * Registers an autoloader based on an autoload map returned by parseAutoloads * * @param array $autoloads see parseAutoloads return value * @return ClassLoader */ public function createLoader(array $autoloads) { $loader = new ClassLoader(); if (isset($autoloads['psr-0'])) { foreach ($autoloads['psr-0'] as $namespace => $path) { $loader->add($namespace, $path); } } return $loader; } protected function getIncludePathsFile(array $packageMap, Filesystem $filesystem, $relVendorPath, $vendorPath, $vendorPathCode, $appBaseDirCode) { $includePaths = array(); foreach ($packageMap as $item) { list($package, $installPath) = $item; if (null !== $package->getTargetDir()) { $installPath = substr($installPath, 0, -strlen('/'.$package->getTargetDir())); } foreach ($package->getIncludePaths() as $includePath) { $includePath = trim($includePath, '/'); $includePaths[] = empty($installPath) ? $includePath : $installPath.'/'.$includePath; } } if (!$includePaths) { return; } $includePathsFile = <<getPathCode($filesystem, $relVendorPath, $vendorPath, $path) . ",\n"; } return $includePathsFile . ");\n"; } protected function getPathCode(Filesystem $filesystem, $relVendorPath, $vendorPath, $path) { $path = strtr($path, '\\', '/'); $baseDir = ''; if (!$filesystem->isAbsolutePath($path)) { if (strpos($path, $relVendorPath) === 0) { // path starts with vendor dir $path = substr($path, strlen($relVendorPath)); $baseDir = '$vendorDir . '; } else { $path = '/'.$path; $baseDir = '$baseDir . '; } } elseif (strpos($path, $vendorPath) === 0) { $path = substr($path, strlen($vendorPath)); $baseDir = '$vendorDir . '; } return $baseDir.var_export($path, true); } protected function getAutoloadFile($vendorPathToTargetDirCode, $usePSR0, $useClassMap, $useIncludePath, $targetDirLoader) { $file = <<
$path) { $loader->add($namespace, $path); } PSR0; } if ($useClassMap) { $file .= <<<'CLASSMAP' $classMap = require $composerDir . '/autoload_classmap.php'; if ($classMap) { $loader->addClassMap($classMap); } CLASSMAP; } $file .= $targetDirLoader; return $file . <<<'FOOTER' $loader->register(); return $loader; }); FOOTER; } }