diff --git a/src/Composer/Autoload/AutoloadGenerator.php b/src/Composer/Autoload/AutoloadGenerator.php index da4f252b8..6ff089bb1 100644 --- a/src/Composer/Autoload/AutoloadGenerator.php +++ b/src/Composer/Autoload/AutoloadGenerator.php @@ -57,6 +57,11 @@ class AutoloadGenerator */ private $apcu = false; + /** + * @var string|null + */ + private $apcuPrefix; + /** * @var bool */ @@ -92,11 +97,13 @@ class AutoloadGenerator /** * Whether or not generated autoloader considers APCu caching. * - * @param bool $apcu + * @param bool $apcu + * @param string|null $apcuPrefix */ - public function setApcu($apcu) + public function setApcu($apcu, $apcuPrefix = null) { $this->apcu = (bool) $apcu; + $this->apcuPrefix = $apcuPrefix !== null ? (string) $apcuPrefix : $apcuPrefix; } /** @@ -858,9 +865,9 @@ CLASSMAPAUTHORITATIVE; } if ($this->apcu) { - $apcuPrefix = substr(base64_encode(md5(uniqid('', true), true)), 0, -3); + $apcuPrefix = var_export(($this->apcuPrefix !== null ? $this->apcuPrefix : substr(base64_encode(md5(uniqid('', true), true)), 0, -3)), true); $file .= <<setApcuPrefix('$apcuPrefix'); + \$loader->setApcuPrefix($apcuPrefix); APCU; } diff --git a/src/Composer/Command/DumpAutoloadCommand.php b/src/Composer/Command/DumpAutoloadCommand.php index 7449d197c..0b2413925 100644 --- a/src/Composer/Command/DumpAutoloadCommand.php +++ b/src/Composer/Command/DumpAutoloadCommand.php @@ -34,6 +34,7 @@ class DumpAutoloadCommand extends BaseCommand new InputOption('optimize', 'o', InputOption::VALUE_NONE, 'Optimizes PSR0 and PSR4 packages to be loaded with classmaps too, good for production.'), new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize`.'), new InputOption('apcu', null, InputOption::VALUE_NONE, 'Use APCu to cache found/not-found classes.'), + new InputOption('apcu-prefix', null, InputOption::VALUE_REQUIRED, 'Use a custom prefix for the APCu autoloader cache. Implicitly enables --apcu'), new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables autoload-dev rules.'), new InputOption('ignore-platform-req', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore a specific platform requirement (php & ext- packages).'), new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore all platform requirements (php & ext- packages).'), @@ -62,7 +63,8 @@ EOT $optimize = $input->getOption('optimize') || $config->get('optimize-autoloader'); $authoritative = $input->getOption('classmap-authoritative') || $config->get('classmap-authoritative'); - $apcu = $input->getOption('apcu') || $config->get('apcu-autoloader'); + $apcuPrefix = $input->getOption('apcu-prefix'); + $apcu = $apcuPrefix !== null || $input->getOption('apcu') || $config->get('apcu-autoloader'); if ($authoritative) { $this->getIO()->write('Generating optimized autoload files (authoritative)'); @@ -77,7 +79,7 @@ EOT $generator = $composer->getAutoloadGenerator(); $generator->setDevMode(!$input->getOption('no-dev')); $generator->setClassMapAuthoritative($authoritative); - $generator->setApcu($apcu); + $generator->setApcu($apcu, $apcuPrefix); $generator->setRunScripts(!$input->getOption('no-scripts')); $generator->setIgnorePlatformRequirements($ignorePlatformReqs); $numberOfClasses = $generator->dump($config, $localRepo, $package, $installationManager, 'composer', $optimize); diff --git a/src/Composer/Command/InstallCommand.php b/src/Composer/Command/InstallCommand.php index f8294c47b..d3f450c50 100644 --- a/src/Composer/Command/InstallCommand.php +++ b/src/Composer/Command/InstallCommand.php @@ -49,6 +49,7 @@ class InstallCommand extends BaseCommand new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump'), new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize-autoloader`.'), new InputOption('apcu-autoloader', null, InputOption::VALUE_NONE, 'Use APCu to cache found/not-found classes.'), + new InputOption('apcu-autoloader-prefix', null, InputOption::VALUE_REQUIRED, 'Use a custom prefix for the APCu autoloader cache. Implicitly enables --apcu-autoloader'), new InputOption('ignore-platform-req', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore a specific platform requirement (php & ext- packages).'), new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore all platform requirements (php & ext- packages).'), new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Should not be provided, use composer require instead to add a given package to composer.json.'), @@ -102,7 +103,8 @@ EOT $optimize = $input->getOption('optimize-autoloader') || $config->get('optimize-autoloader'); $authoritative = $input->getOption('classmap-authoritative') || $config->get('classmap-authoritative'); - $apcu = $input->getOption('apcu-autoloader') || $config->get('apcu-autoloader'); + $apcuPrefix = $input->getOption('apcu-autoloader-prefix'); + $apcu = $apcuPrefix !== null || $input->getOption('apcu-autoloader') || $config->get('apcu-autoloader'); $ignorePlatformReqs = $input->getOption('ignore-platform-reqs') ?: ($input->getOption('ignore-platform-req') ?: false); @@ -118,7 +120,7 @@ EOT ->setRunScripts(!$input->getOption('no-scripts')) ->setOptimizeAutoloader($optimize) ->setClassMapAuthoritative($authoritative) - ->setApcuAutoloader($apcu) + ->setApcuAutoloader($apcu, $apcuPrefix) ->setIgnorePlatformRequirements($ignorePlatformReqs) ; diff --git a/src/Composer/Command/RemoveCommand.php b/src/Composer/Command/RemoveCommand.php index 4a7942e55..936cf0f13 100644 --- a/src/Composer/Command/RemoveCommand.php +++ b/src/Composer/Command/RemoveCommand.php @@ -55,6 +55,7 @@ class RemoveCommand extends BaseCommand new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump'), new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize-autoloader`.'), new InputOption('apcu-autoloader', null, InputOption::VALUE_NONE, 'Use APCu to cache found/not-found classes.'), + new InputOption('apcu-autoloader-prefix', null, InputOption::VALUE_REQUIRED, 'Use a custom prefix for the APCu autoloader cache. Implicitly enables --apcu-autoloader'), )) ->setHelp( <<getOption('update-no-dev'); $optimize = $input->getOption('optimize-autoloader') || $composer->getConfig()->get('optimize-autoloader'); $authoritative = $input->getOption('classmap-authoritative') || $composer->getConfig()->get('classmap-authoritative'); - $apcu = $input->getOption('apcu-autoloader') || $composer->getConfig()->get('apcu-autoloader'); + $apcuPrefix = $input->getOption('apcu-autoloader-prefix'); + $apcu = $apcuPrefix !== null || $input->getOption('apcu-autoloader') || $composer->getConfig()->get('apcu-autoloader'); $updateAllowTransitiveDependencies = Request::UPDATE_LISTED_WITH_TRANSITIVE_DEPS_NO_ROOT_REQUIRE; $flags = ''; @@ -248,7 +250,7 @@ EOT ->setDevMode($updateDevMode) ->setOptimizeAutoloader($optimize) ->setClassMapAuthoritative($authoritative) - ->setApcuAutoloader($apcu) + ->setApcuAutoloader($apcu, $apcuPrefix) ->setUpdate(true) ->setInstall(!$input->getOption('no-install')) ->setUpdateAllowList($packages) diff --git a/src/Composer/Command/RequireCommand.php b/src/Composer/Command/RequireCommand.php index 2d49a7901..03ac10240 100644 --- a/src/Composer/Command/RequireCommand.php +++ b/src/Composer/Command/RequireCommand.php @@ -77,6 +77,7 @@ class RequireCommand extends InitCommand new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump'), new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize-autoloader`.'), new InputOption('apcu-autoloader', null, InputOption::VALUE_NONE, 'Use APCu to cache found/not-found classes.'), + new InputOption('apcu-autoloader-prefix', null, InputOption::VALUE_REQUIRED, 'Use a custom prefix for the APCu autoloader cache. Implicitly enables --apcu-autoloader'), )) ->setHelp( <<getOption('update-no-dev'); $optimize = $input->getOption('optimize-autoloader') || $composer->getConfig()->get('optimize-autoloader'); $authoritative = $input->getOption('classmap-authoritative') || $composer->getConfig()->get('classmap-authoritative'); - $apcu = $input->getOption('apcu-autoloader') || $composer->getConfig()->get('apcu-autoloader'); + $apcuPrefix = $input->getOption('apcu-autoloader-prefix'); + $apcu = $apcuPrefix !== null || $input->getOption('apcu-autoloader') || $composer->getConfig()->get('apcu-autoloader'); $updateAllowTransitiveDependencies = Request::UPDATE_ONLY_LISTED; $flags = ''; @@ -301,7 +303,7 @@ EOT ->setRunScripts(!$input->getOption('no-scripts')) ->setOptimizeAutoloader($optimize) ->setClassMapAuthoritative($authoritative) - ->setApcuAutoloader($apcu) + ->setApcuAutoloader($apcu, $apcuPrefix) ->setUpdate(true) ->setInstall(!$input->getOption('no-install')) ->setUpdateAllowTransitiveDependencies($updateAllowTransitiveDependencies) diff --git a/src/Composer/Command/UpdateCommand.php b/src/Composer/Command/UpdateCommand.php index dad0a6df1..f0557aa97 100644 --- a/src/Composer/Command/UpdateCommand.php +++ b/src/Composer/Command/UpdateCommand.php @@ -60,6 +60,7 @@ class UpdateCommand extends BaseCommand new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump.'), new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize-autoloader`.'), new InputOption('apcu-autoloader', null, InputOption::VALUE_NONE, 'Use APCu to cache found/not-found classes.'), + new InputOption('apcu-autoloader-prefix', null, InputOption::VALUE_REQUIRED, 'Use a custom prefix for the APCu autoloader cache. Implicitly enables --apcu-autoloader'), new InputOption('ignore-platform-req', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore a specific platform requirement (php & ext- packages).'), new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore all platform requirements (php & ext- packages).'), new InputOption('prefer-stable', null, InputOption::VALUE_NONE, 'Prefer stable versions of dependencies.'), @@ -189,7 +190,8 @@ EOT $optimize = $input->getOption('optimize-autoloader') || $config->get('optimize-autoloader'); $authoritative = $input->getOption('classmap-authoritative') || $config->get('classmap-authoritative'); - $apcu = $input->getOption('apcu-autoloader') || $config->get('apcu-autoloader'); + $apcuPrefix = $input->getOption('apcu-autoloader-prefix'); + $apcu = $apcuPrefix !== null || $input->getOption('apcu-autoloader') || $config->get('apcu-autoloader'); $updateAllowTransitiveDependencies = Request::UPDATE_ONLY_LISTED; if ($input->getOption('with-all-dependencies')) { @@ -210,7 +212,7 @@ EOT ->setRunScripts(!$input->getOption('no-scripts')) ->setOptimizeAutoloader($optimize) ->setClassMapAuthoritative($authoritative) - ->setApcuAutoloader($apcu) + ->setApcuAutoloader($apcu, $apcuPrefix) ->setUpdate(true) ->setInstall(!$input->getOption('no-install')) ->setUpdateMirrors($updateMirrors) diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index 535ad8e4c..50ada1981 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -126,6 +126,7 @@ class Installer protected $optimizeAutoloader = false; protected $classMapAuthoritative = false; protected $apcuAutoloader = false; + protected $apcuAutoloaderPrefix; protected $devMode = false; protected $dryRun = false; protected $verbose = false; @@ -307,7 +308,7 @@ class Installer $this->autoloadGenerator->setDevMode($this->devMode); $this->autoloadGenerator->setClassMapAuthoritative($this->classMapAuthoritative); - $this->autoloadGenerator->setApcu($this->apcuAutoloader); + $this->autoloadGenerator->setApcu($this->apcuAutoloader, $this->apcuAutoloaderPrefix); $this->autoloadGenerator->setRunScripts($this->runScripts); $this->autoloadGenerator->setIgnorePlatformRequirements($this->ignorePlatformReqs); $this->autoloadGenerator->dump($this->config, $localRepo, $this->package, $this->installationManager, 'composer', $this->optimizeAutoloader); @@ -1023,12 +1024,14 @@ class Installer /** * Whether or not generated autoloader considers APCu caching. * - * @param bool $apcuAutoloader + * @param bool $apcuAutoloader + * @param string|null $apcuAutoloaderPrefix * @return Installer */ - public function setApcuAutoloader($apcuAutoloader = false) + public function setApcuAutoloader($apcuAutoloader = false, $apcuAutoloaderPrefix = null) { - $this->apcuAutoloader = (bool) $apcuAutoloader; + $this->apcuAutoloader = $apcuAutoloader; + $this->apcuAutoloaderPrefix = $apcuAutoloaderPrefix; return $this; } diff --git a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php index 585d38b59..4a6dd95f3 100644 --- a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php +++ b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php @@ -823,6 +823,55 @@ EOF; $this->assertStringContainsString('$loader->setApcuPrefix(', file_get_contents($this->vendorDir.'/composer/autoload_real.php')); } + public function testClassMapAutoloadingAuthoritativeAndApcuPrefix() + { + $package = new Package('a', '1.0', '1.0'); + $package->setRequires(array( + new Link('a', 'a/a', new MatchAllConstraint()), + new Link('a', 'b/b', new MatchAllConstraint()), + new Link('a', 'c/c', new MatchAllConstraint()), + )); + + $packages = array(); + $packages[] = $a = new Package('a/a', '1.0', '1.0'); + $packages[] = $b = new Package('b/b', '1.0', '1.0'); + $packages[] = $c = new Package('c/c', '1.0', '1.0'); + $a->setAutoload(array('psr-4' => array('' => 'src/'))); + $b->setAutoload(array('psr-4' => array('' => './'))); + $c->setAutoload(array('psr-4' => array('' => 'foo/'))); + + $this->repository->expects($this->once()) + ->method('getCanonicalPackages') + ->will($this->returnValue($packages)); + + $this->fs->ensureDirectoryExists($this->vendorDir.'/composer'); + $this->fs->ensureDirectoryExists($this->vendorDir.'/a/a/src'); + $this->fs->ensureDirectoryExists($this->vendorDir.'/b/b'); + $this->fs->ensureDirectoryExists($this->vendorDir.'/c/c/foo'); + file_put_contents($this->vendorDir.'/a/a/src/ClassMapFoo.php', 'vendorDir.'/b/b/ClassMapBar.php', 'vendorDir.'/c/c/foo/ClassMapBaz.php', 'generator->setClassMapAuthoritative(true); + $this->generator->setApcu(true, 'custom\'Prefix'); + $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', false, '_7'); + + $this->assertFileExists($this->vendorDir.'/composer/autoload_classmap.php', "ClassMap file needs to be generated."); + $this->assertEquals( + array( + 'ClassMapBar' => $this->vendorDir.'/b/b/ClassMapBar.php', + 'ClassMapBaz' => $this->vendorDir.'/c/c/foo/ClassMapBaz.php', + 'ClassMapFoo' => $this->vendorDir.'/a/a/src/ClassMapFoo.php', + 'Composer\\InstalledVersions' => $this->vendorDir.'/composer/InstalledVersions.php', + ), + include $this->vendorDir.'/composer/autoload_classmap.php' + ); + $this->assertAutoloadFiles('classmap8', $this->vendorDir.'/composer', 'classmap'); + + $this->assertStringContainsString('$loader->setClassMapAuthoritative(true);', file_get_contents($this->vendorDir.'/composer/autoload_real.php')); + $this->assertStringContainsString('$loader->setApcuPrefix(\'custom\\\'Prefix\');', file_get_contents($this->vendorDir.'/composer/autoload_real.php')); + } + public function testFilesAutoloadGeneration() { $package = new Package('a', '1.0', '1.0');