2011-10-16 18:04:29 +00:00
< ? php
/*
* This file is part of Composer .
*
* ( c ) Nils Adermann < naderman @ naderman . de >
* Jordi Boggiano < j . boggiano @ seld . be >
*
* 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 ;
2012-05-14 12:01:37 +00:00
use Composer\Package\AliasPackage ;
2011-10-16 18:04:29 +00:00
use Composer\Package\PackageInterface ;
use Composer\Repository\RepositoryInterface ;
2012-02-09 17:45:28 +00:00
use Composer\Util\Filesystem ;
2011-10-16 18:04:29 +00:00
/**
* @ author Igor Wiedler < igor @ wiedler . ch >
2011-10-23 19:23:37 +00:00
* @ author Jordi Boggiano < j . boggiano @ seld . be >
2011-10-16 18:04:29 +00:00
*/
class AutoloadGenerator
{
2012-04-19 19:55:35 +00:00
public function dump ( RepositoryInterface $localRepo , PackageInterface $mainPackage , InstallationManager $installationManager , $targetDir , $bcLinks = false )
2011-10-16 18:04:29 +00:00
{
2011-12-03 22:20:36 +00:00
$filesystem = new Filesystem ();
2012-04-15 15:48:30 +00:00
$filesystem -> ensureDirectoryExists ( $installationManager -> getVendorPath ());
$filesystem -> ensureDirectoryExists ( $targetDir );
2011-12-03 22:20:36 +00:00
$vendorPath = strtr ( realpath ( $installationManager -> getVendorPath ()), '\\' , '/' );
2012-03-22 09:11:48 +00:00
$relVendorPath = $filesystem -> findShortestPath ( getcwd (), $vendorPath , true );
2012-04-22 20:11:03 +00:00
$vendorPathCode = $filesystem -> findShortestPathCode ( realpath ( $targetDir ), $vendorPath , true );
$vendorPathToTargetDirCode = $filesystem -> findShortestPathCode ( $vendorPath , realpath ( $targetDir ), true );
2011-12-03 22:20:36 +00:00
2012-04-19 08:51:57 +00:00
$appBaseDirCode = $filesystem -> findShortestPathCode ( $vendorPath , getcwd (), true );
$appBaseDirCode = str_replace ( '__DIR__' , '$vendorDir' , $appBaseDirCode );
2012-03-10 00:59:59 +00:00
2011-12-03 22:20:36 +00:00
$namespacesFile = <<< EOF
2011-10-30 19:29:06 +00:00
< ? php
2011-10-29 05:24:30 +00:00
2011-10-30 19:29:06 +00:00
// autoload_namespace.php generated by Composer
2011-10-16 18:04:29 +00:00
2012-04-22 20:11:03 +00:00
\ $vendorDir = $vendorPathCode ;
2012-04-19 08:51:57 +00:00
\ $baseDir = $appBaseDirCode ;
2011-11-20 21:02:22 +00:00
2011-10-30 19:29:06 +00:00
return array (
2011-10-16 18:04:29 +00:00
EOF ;
2012-02-07 10:12:03 +00:00
$packageMap = $this -> buildPackageMap ( $installationManager , $mainPackage , $localRepo -> getPackages ());
2011-11-03 21:22:12 +00:00
$autoloads = $this -> parseAutoloads ( $packageMap );
2011-10-30 19:29:06 +00:00
2012-03-10 00:59:59 +00:00
foreach ( $autoloads [ 'psr-0' ] as $namespace => $paths ) {
$exportedPaths = array ();
foreach ( $paths as $path ) {
2012-04-19 08:51:57 +00:00
$exportedPaths [] = $this -> getPathCode ( $filesystem , $relVendorPath , $vendorPath , $path );
2012-03-10 00:59:59 +00:00
}
$exportedPrefix = var_export ( $namespace , true );
$namespacesFile .= " $exportedPrefix => " ;
if ( count ( $exportedPaths ) > 1 ) {
$namespacesFile .= " array( " . implode ( ', ' , $exportedPaths ) . " ), \n " ;
} else {
$namespacesFile .= $exportedPaths [ 0 ] . " , \n " ;
2011-10-16 18:04:29 +00:00
}
}
2011-10-30 19:29:06 +00:00
$namespacesFile .= " ); \n " ;
2011-10-16 18:04:29 +00:00
2012-03-10 00:59:59 +00:00
$classmapFile = <<< EOF
< ? php
// autoload_classmap.php generated by Composer
2012-04-22 20:11:03 +00:00
\ $vendorDir = $vendorPathCode ;
2012-04-19 08:51:57 +00:00
\ $baseDir = $appBaseDirCode ;
2012-03-10 00:59:59 +00:00
return array (
EOF ;
2012-03-05 12:26:46 +00:00
2012-04-19 19:26:01 +00:00
// 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 (), '\\' , '/' ), '/' )));
2012-04-19 20:04:49 +00:00
$prefixes = implode ( ', ' , array_map ( function ( $prefix ) {
2012-04-19 19:26:01 +00:00
return var_export ( $prefix , true );
}, array_keys ( $mainAutoload [ 'psr-0' ])));
2012-04-23 08:56:46 +00:00
$baseDirFromVendorDirCode = $filesystem -> findShortestPathCode ( $vendorPath , getcwd (), true );
2012-04-19 19:26:01 +00:00
$targetDirLoader = <<< EOF
spl_autoload_register ( function ( \ $class ) {
2012-04-23 08:56:46 +00:00
\ $dir = $baseDirFromVendorDirCode . '/' ;
\ $prefixes = array ( $prefixes );
2012-04-19 19:26:01 +00:00
foreach ( \ $prefixes as \ $prefix ) {
if ( 0 !== strpos ( \ $class , \ $prefix )) {
continue ;
}
2012-04-22 20:11:03 +00:00
\ $path = \ $dir . implode ( '/' , array_slice ( explode ( '\\\\' , \ $class ), $levels )) . '.php' ;
2012-06-11 12:15:08 +00:00
if ( ! \ $path = stream_resolve_include_path ( \ $path )) {
2012-04-19 19:26:01 +00:00
return false ;
}
2012-06-11 12:15:08 +00:00
require \ $path ;
2012-05-22 10:07:08 +00:00
2012-04-19 19:26:01 +00:00
return true ;
}
});
EOF ;
}
2012-03-10 00:59:59 +00:00
// flatten array
$autoloads [ 'classmap' ] = new \RecursiveIteratorIterator ( new \RecursiveArrayIterator ( $autoloads [ 'classmap' ]));
foreach ( $autoloads [ 'classmap' ] as $dir ) {
foreach ( ClassMapGenerator :: createMap ( $dir ) as $class => $path ) {
2012-03-22 09:11:48 +00:00
$path = '/' . $filesystem -> findShortestPath ( getcwd (), $path , true );
2012-03-10 00:59:59 +00:00
$classmapFile .= ' ' . var_export ( $class , true ) . ' => $baseDir . ' . var_export ( $path , true ) . " , \n " ;
}
}
$classmapFile .= " ); \n " ;
2012-03-05 13:10:01 +00:00
2012-06-11 12:15:08 +00:00
$filesCode = " " ;
2012-06-02 16:18:33 +00:00
$autoloads [ 'files' ] = new \RecursiveIteratorIterator ( new \RecursiveArrayIterator ( $autoloads [ 'files' ]));
foreach ( $autoloads [ 'files' ] as $functionFile ) {
2012-06-11 12:15:08 +00:00
$filesCode .= 'require __DIR__ . ' . var_export ( '/' . $filesystem -> findShortestPath ( $vendorPath , $functionFile ), true ) . " ; \n " ;
2012-06-02 16:18:33 +00:00
}
2011-10-30 19:29:06 +00:00
file_put_contents ( $targetDir . '/autoload_namespaces.php' , $namespacesFile );
2012-03-10 00:59:59 +00:00
file_put_contents ( $targetDir . '/autoload_classmap.php' , $classmapFile );
2012-04-22 20:11:03 +00:00
if ( $includePathFile = $this -> getIncludePathsFile ( $packageMap , $filesystem , $relVendorPath , $vendorPath , $vendorPathCode , $appBaseDirCode )) {
2012-04-08 15:42:57 +00:00
file_put_contents ( $targetDir . '/include_paths.php' , $includePathFile );
}
2012-06-02 16:18:33 +00:00
file_put_contents ( $vendorPath . '/autoload.php' , $this -> getAutoloadFile ( $vendorPathToTargetDirCode , true , true , ( Boolean ) $includePathFile , $targetDirLoader , $filesCode ));
2012-01-22 21:39:54 +00:00
copy ( __DIR__ . '/ClassLoader.php' , $targetDir . '/ClassLoader.php' );
2012-04-19 19:55:35 +00:00
2012-05-13 09:35:50 +00:00
// TODO BC feature, remove after June 15th
2012-04-19 19:55:35 +00:00
if ( $bcLinks ) {
2012-04-22 20:11:03 +00:00
$filesystem -> ensureDirectoryExists ( $vendorPath . '/.composer' );
2012-05-13 09:35:50 +00:00
$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' , " <?php \n { $deprecated } \n return include dirname(__DIR__).'/composer/autoload_namespaces.php'; \n " );
file_put_contents ( $vendorPath . '/.composer/autoload_classmap.php' , " <?php \n { $deprecated } \n return include dirname(__DIR__).'/composer/autoload_classmap.php'; \n " );
file_put_contents ( $vendorPath . '/.composer/autoload.php' , " <?php \n { $deprecated } \n return include dirname(__DIR__).'/autoload.php'; \n " );
file_put_contents ( $vendorPath . '/.composer/ClassLoader.php' , " <?php \n { $deprecated } \n return include dirname(__DIR__).'/composer/ClassLoader.php'; \n " );
2012-04-19 19:55:35 +00:00
if ( $includePathFile ) {
2012-05-13 09:35:50 +00:00
file_put_contents ( $vendorPath . '/.composer/include_paths.php' , " <?php \n { $deprecated } \n return include dirname(__DIR__).'/composer/include_paths.php'; \n " );
2012-04-19 19:55:35 +00:00
}
}
2011-10-16 18:04:29 +00:00
}
2012-02-07 10:12:03 +00:00
public function buildPackageMap ( InstallationManager $installationManager , PackageInterface $mainPackage , array $packages )
{
// build package => install path map
$packageMap = array ();
// add main package
$packageMap [] = array ( $mainPackage , '' );
foreach ( $packages as $package ) {
2012-05-14 12:01:37 +00:00
if ( $package instanceof AliasPackage ) {
continue ;
}
2012-02-07 10:12:03 +00:00
$packageMap [] = array (
$package ,
$installationManager -> getInstallPath ( $package )
);
}
return $packageMap ;
}
2011-11-03 21:22:12 +00:00
/**
* Compiles an ordered list of namespace => path mappings
*
2012-05-22 10:07:08 +00:00
* @ param array $packageMap array of array ( package , installDir - relative - to - composer . json )
2012-01-13 03:14:30 +00:00
* @ return array array ( 'psr-0' => array ( 'Ns\\Foo' => array ( 'installDir' )))
2011-11-03 21:22:12 +00:00
*/
public function parseAutoloads ( array $packageMap )
2011-10-16 18:04:29 +00:00
{
2012-06-02 16:18:33 +00:00
$autoloads = array ( 'classmap' => array (), 'psr-0' => array (), 'files' => array ());
2011-11-03 21:22:12 +00:00
foreach ( $packageMap as $item ) {
2011-10-16 18:04:29 +00:00
list ( $package , $installPath ) = $item ;
if ( null !== $package -> getTargetDir ()) {
$installPath = substr ( $installPath , 0 , - strlen ( '/' . $package -> getTargetDir ()));
}
foreach ( $package -> getAutoload () as $type => $mapping ) {
2012-04-17 12:01:24 +00:00
// skip misconfigured packages
if ( ! is_array ( $mapping )) {
continue ;
}
2012-03-28 15:09:07 +00:00
foreach ( $mapping as $namespace => $paths ) {
foreach (( array ) $paths as $path ) {
$autoloads [ $type ][ $namespace ][] = empty ( $installPath ) ? $path : $installPath . '/' . $path ;
}
2011-11-03 20:05:01 +00:00
}
2011-10-16 18:04:29 +00:00
}
}
2011-11-03 20:05:01 +00:00
foreach ( $autoloads as $type => $maps ) {
2012-01-13 03:14:30 +00:00
krsort ( $autoloads [ $type ]);
2011-11-03 20:05:01 +00:00
}
2011-10-16 18:04:29 +00:00
return $autoloads ;
}
2011-11-03 21:22:12 +00:00
/**
* Registers an autoloader based on an autoload map returned by parseAutoloads
*
2012-05-22 10:07:08 +00:00
* @ param array $autoloads see parseAutoloads return value
2011-11-03 21:22:12 +00:00
* @ return ClassLoader
*/
public function createLoader ( array $autoloads )
{
$loader = new ClassLoader ();
if ( isset ( $autoloads [ 'psr-0' ])) {
2012-01-13 03:14:30 +00:00
foreach ( $autoloads [ 'psr-0' ] as $namespace => $path ) {
$loader -> add ( $namespace , $path );
2011-11-03 21:22:12 +00:00
}
}
return $loader ;
}
2012-04-04 07:46:31 +00:00
2012-04-22 20:11:03 +00:00
protected function getIncludePathsFile ( array $packageMap , Filesystem $filesystem , $relVendorPath , $vendorPath , $vendorPathCode , $appBaseDirCode )
2012-04-04 07:46:31 +00:00
{
$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 ) {
2012-04-19 08:51:57 +00:00
$includePath = trim ( $includePath , '/' );
2012-04-04 07:46:31 +00:00
$includePaths [] = empty ( $installPath ) ? $includePath : $installPath . '/' . $includePath ;
}
}
2012-04-08 15:42:57 +00:00
if ( ! $includePaths ) {
return ;
}
2012-04-19 08:51:57 +00:00
$includePathsFile = <<< EOF
< ? php
// include_paths.php generated by Composer
2012-04-22 20:11:03 +00:00
\ $vendorDir = $vendorPathCode ;
2012-04-19 08:51:57 +00:00
\ $baseDir = $appBaseDirCode ;
return array (
EOF ;
foreach ( $includePaths as $path ) {
$includePathsFile .= " " . $this -> 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 . ' ;
}
2012-05-22 10:07:08 +00:00
2012-04-19 08:51:57 +00:00
return $baseDir . var_export ( $path , true );
2012-04-04 07:46:31 +00:00
}
2012-04-08 15:42:57 +00:00
2012-06-02 16:18:33 +00:00
protected function getAutoloadFile ( $vendorPathToTargetDirCode , $usePSR0 , $useClassMap , $useIncludePath , $targetDirLoader , $filesCode )
2012-04-08 15:42:57 +00:00
{
2012-06-11 12:15:08 +00:00
if ( $filesCode ) {
$filesCode = " \n " . $filesCode ;
}
2012-04-22 20:11:03 +00:00
$file = <<< HEADER
2012-04-08 15:42:57 +00:00
< ? php
// autoload.php generated by Composer
2012-04-22 20:11:03 +00:00
if ( ! class_exists ( 'Composer\\\\Autoload\\\\ClassLoader' , false )) {
require $vendorPathToTargetDirCode . '/ClassLoader.php' ;
2012-04-08 15:42:57 +00:00
}
2012-06-02 16:18:33 +00:00
$filesCode
2012-04-08 15:42:57 +00:00
return call_user_func ( function () {
2012-04-22 20:11:03 +00:00
\ $loader = new \\Composer\\Autoload\\ClassLoader ();
\ $composerDir = $vendorPathToTargetDirCode ;
2012-04-08 15:42:57 +00:00
HEADER ;
if ( $useIncludePath ) {
$file .= <<< 'INCLUDE_PATH'
2012-04-22 20:11:03 +00:00
$includePaths = require $composerDir . '/include_paths.php' ;
2012-04-08 15:42:57 +00:00
array_unshift ( $includePaths , get_include_path ());
set_include_path ( join ( PATH_SEPARATOR , $includePaths ));
INCLUDE_PATH ;
}
if ( $usePSR0 ) {
$file .= <<< 'PSR0'
2012-04-22 20:11:03 +00:00
$map = require $composerDir . '/autoload_namespaces.php' ;
2012-04-08 15:42:57 +00:00
foreach ( $map as $namespace => $path ) {
$loader -> add ( $namespace , $path );
}
PSR0 ;
}
if ( $useClassMap ) {
$file .= <<< 'CLASSMAP'
2012-04-22 20:11:03 +00:00
$classMap = require $composerDir . '/autoload_classmap.php' ;
2012-04-08 15:42:57 +00:00
if ( $classMap ) {
$loader -> addClassMap ( $classMap );
}
CLASSMAP ;
}
2012-04-19 19:26:01 +00:00
$file .= $targetDirLoader ;
2012-04-08 15:42:57 +00:00
return $file . <<< 'FOOTER'
$loader -> register ();
return $loader ;
});
FOOTER ;
}
2011-10-16 18:04:29 +00:00
}