function AutoloadGenerator::dump
Return value
Throws
\Seld\JsonLint\ParsingException
\RuntimeException
File
-
vendor/
composer/ composer/ src/ Composer/ Autoload/ AutoloadGenerator.php, line 177
Class
- AutoloadGenerator
- @author Igor Wiedler <igor@wiedler.ch> @author Jordi Boggiano <j.boggiano@seld.be>
Namespace
Composer\AutoloadCode
public function dump(Config $config, InstalledRepositoryInterface $localRepo, RootPackageInterface $rootPackage, InstallationManager $installationManager, string $targetDir, bool $scanPsrPackages = false, ?string $suffix = null, ?Locker $locker = null, bool $strictAmbiguous = false) {
if ($this->classMapAuthoritative) {
// Force scanPsrPackages when classmap is authoritative
$scanPsrPackages = true;
}
// auto-set devMode based on whether dev dependencies are installed or not
if (null === $this->devMode) {
// we assume no-dev mode if no vendor dir is present or it is too old to contain dev information
$this->devMode = false;
$installedJson = new JsonFile($config->get('vendor-dir') . '/composer/installed.json');
if ($installedJson->exists()) {
$installedJson = $installedJson->read();
if (isset($installedJson['dev'])) {
$this->devMode = $installedJson['dev'];
}
}
}
if ($this->runScripts) {
// set COMPOSER_DEV_MODE in case not set yet so it is available in the dump-autoload event listeners
if (!isset($_SERVER['COMPOSER_DEV_MODE'])) {
Platform::putEnv('COMPOSER_DEV_MODE', $this->devMode ? '1' : '0');
}
$this->eventDispatcher
->dispatchScript(ScriptEvents::PRE_AUTOLOAD_DUMP, $this->devMode, [], [
'optimize' => $scanPsrPackages,
]);
}
$classMapGenerator = new ClassMapGenerator([
'php',
'inc',
'hh',
]);
$classMapGenerator->avoidDuplicateScans();
$filesystem = new Filesystem();
$filesystem->ensureDirectoryExists($config->get('vendor-dir'));
// Do not remove double realpath() calls.
// Fixes failing Windows realpath() implementation.
// See https://bugs.php.net/bug.php?id=72738
$basePath = $filesystem->normalizePath(realpath(realpath(Platform::getCwd())));
$vendorPath = $filesystem->normalizePath(realpath(realpath($config->get('vendor-dir'))));
$useGlobalIncludePath = $config->get('use-include-path');
$prependAutoloader = $config->get('prepend-autoloader') === false ? 'false' : 'true';
$targetDir = $vendorPath . '/' . $targetDir;
$filesystem->ensureDirectoryExists($targetDir);
$vendorPathCode = $filesystem->findShortestPathCode(realpath($targetDir), $vendorPath, true);
$vendorPathToTargetDirCode = $filesystem->findShortestPathCode($vendorPath, realpath($targetDir), true);
$appBaseDirCode = $filesystem->findShortestPathCode($vendorPath, $basePath, true);
$appBaseDirCode = str_replace('__DIR__', '$vendorDir', $appBaseDirCode);
$namespacesFile = <<<EOF
<?php
// autoload_namespaces.php @generated by Composer
\$vendorDir = {<span class="php-variable">$vendorPathCode</span>};
\$baseDir = {<span class="php-variable">$appBaseDirCode</span>};
return array(
EOF;
$psr4File = <<<EOF
<?php
// autoload_psr4.php @generated by Composer
\$vendorDir = {<span class="php-variable">$vendorPathCode</span>};
\$baseDir = {<span class="php-variable">$appBaseDirCode</span>};
return array(
EOF;
// Collect information from all packages.
$devPackageNames = $localRepo->getDevPackageNames();
$packageMap = $this->buildPackageMap($installationManager, $rootPackage, $localRepo->getCanonicalPackages());
if ($this->devMode) {
// if dev mode is enabled, then we do not filter any dev packages out so disable this entirely
$filteredDevPackages = false;
}
else {
// if the list of dev package names is available we use that straight, otherwise pass true which means use legacy algo to figure them out
$filteredDevPackages = $devPackageNames ?: true;
}
$autoloads = $this->parseAutoloads($packageMap, $rootPackage, $filteredDevPackages);
// Process the 'psr-0' base directories.
foreach ($autoloads['psr-0'] as $namespace => $paths) {
$exportedPaths = [];
foreach ($paths as $path) {
$exportedPaths[] = $this->getPathCode($filesystem, $basePath, $vendorPath, $path);
}
$exportedPrefix = var_export($namespace, true);
$namespacesFile .= " {$exportedPrefix} => ";
$namespacesFile .= "array(" . implode(', ', $exportedPaths) . "),\n";
}
$namespacesFile .= ");\n";
// Process the 'psr-4' base directories.
foreach ($autoloads['psr-4'] as $namespace => $paths) {
$exportedPaths = [];
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";
// add custom psr-0 autoloading if the root package has a target dir
$targetDirLoader = null;
$mainAutoload = $rootPackage->getAutoload();
if ($rootPackage->getTargetDir() && !empty($mainAutoload['psr-0'])) {
$levels = substr_count($filesystem->normalizePath($rootPackage->getTargetDir()), '/') + 1;
$prefixes = implode(', ', array_map(static function ($prefix) : string {
return var_export($prefix, true);
}, array_keys($mainAutoload['psr-0'])));
$baseDirFromTargetDirCode = $filesystem->findShortestPathCode($targetDir, $basePath, true);
$targetDirLoader = <<<EOF
public static function autoload(\$class)
{
\$dir = {<span class="php-variable">$baseDirFromTargetDirCode</span>} . '/';
\$prefixes = array({<span class="php-variable">$prefixes</span>});
foreach (\$prefixes as \$prefix) {
if (0 !== strpos(\$class, \$prefix)) {
continue;
}
\$path = \$dir . implode('/', array_slice(explode('\\\\', \$class), {<span class="php-variable">$levels</span>})).'.php';
if (!\$path = stream_resolve_include_path(\$path)) {
return false;
}
require \$path;
return true;
}
}
EOF;
}
$excluded = [];
if (!empty($autoloads['exclude-from-classmap'])) {
$excluded = $autoloads['exclude-from-classmap'];
}
foreach ($autoloads['classmap'] as $dir) {
$classMapGenerator->scanPaths($dir, $this->buildExclusionRegex($dir, $excluded));
}
if ($scanPsrPackages) {
$namespacesToScan = [];
// Scan the PSR-0/4 directories for class files, and add them to the class map
foreach ([
'psr-4',
'psr-0',
] as $psrType) {
foreach ($autoloads[$psrType] as $namespace => $paths) {
$namespacesToScan[$namespace][] = [
'paths' => $paths,
'type' => $psrType,
];
}
}
krsort($namespacesToScan);
foreach ($namespacesToScan as $namespace => $groups) {
foreach ($groups as $group) {
foreach ($group['paths'] as $dir) {
$dir = $filesystem->normalizePath($filesystem->isAbsolutePath($dir) ? $dir : $basePath . '/' . $dir);
if (!is_dir($dir)) {
continue;
}
// if the vendor dir is contained within a psr-0/psr-4 dir being scanned we exclude it
if (str_contains($vendorPath, $dir . '/')) {
$exclusionRegex = $this->buildExclusionRegex($dir, array_merge($excluded, [
$vendorPath . '/',
]));
}
else {
$exclusionRegex = $this->buildExclusionRegex($dir, $excluded);
}
$classMapGenerator->scanPaths($dir, $exclusionRegex, $group['type'], $namespace);
}
}
}
}
$classMap = $classMapGenerator->getClassMap();
if ($strictAmbiguous) {
$ambiguousClasses = $classMap->getAmbiguousClasses(false);
}
else {
$ambiguousClasses = $classMap->getAmbiguousClasses();
}
foreach ($ambiguousClasses as $className => $ambiguousPaths) {
if (count($ambiguousPaths) > 1) {
$this->io
->writeError('<warning>Warning: Ambiguous class resolution, "' . $className . '"' . ' was found ' . (count($ambiguousPaths) + 1) . 'x: in "' . $classMap->getClassPath($className) . '" and "' . implode('", "', $ambiguousPaths) . '", the first will be used.</warning>');
}
else {
$this->io
->writeError('<warning>Warning: Ambiguous class resolution, "' . $className . '"' . ' was found in both "' . $classMap->getClassPath($className) . '" and "' . implode('", "', $ambiguousPaths) . '", the first will be used.</warning>');
}
}
if (\count($ambiguousClasses) > 0) {
$this->io
->writeError('<info>To resolve ambiguity in classes not under your control you can ignore them by path using <href=' . OutputFormatter::escape('https://getcomposer.org/doc/04-schema.md#exclude-files-from-classmaps') . '>exclude-files-from-classmap</>');
}
// output PSR violations which are not coming from the vendor dir
$classMap->clearPsrViolationsByPath($vendorPath);
foreach ($classMap->getPsrViolations() as $msg) {
$this->io
->writeError("<warning>{$msg}</warning>");
}
$classMap->addClass('Composer\\InstalledVersions', $vendorPath . '/composer/InstalledVersions.php');
$classMap->sort();
$classmapFile = <<<EOF
<?php
// autoload_classmap.php @generated by Composer
\$vendorDir = {<span class="php-variable">$vendorPathCode</span>};
\$baseDir = {<span class="php-variable">$appBaseDirCode</span>};
return array(
EOF;
foreach ($classMap->getMap() as $className => $path) {
$pathCode = $this->getPathCode($filesystem, $basePath, $vendorPath, $path) . ",\n";
$classmapFile .= ' ' . var_export($className, true) . ' => ' . $pathCode;
}
$classmapFile .= ");\n";
if ('' === $suffix) {
$suffix = null;
}
if (null === $suffix) {
$suffix = $config->get('autoloader-suffix');
// carry over existing autoload.php's suffix if possible and none is configured
if (null === $suffix && Filesystem::isReadable($vendorPath . '/autoload.php')) {
$content = (string) file_get_contents($vendorPath . '/autoload.php');
if (Preg::isMatch('{ComposerAutoloaderInit([^:\\s]+)::}', $content, $match)) {
$suffix = $match[1];
}
}
if (null === $suffix) {
$suffix = $locker !== null && $locker->isLocked() ? $locker->getLockData()['content-hash'] : bin2hex(random_bytes(16));
}
}
if ($this->dryRun) {
return $classMap;
}
$filesystem->filePutContentsIfModified($targetDir . '/autoload_namespaces.php', $namespacesFile);
$filesystem->filePutContentsIfModified($targetDir . '/autoload_psr4.php', $psr4File);
$filesystem->filePutContentsIfModified($targetDir . '/autoload_classmap.php', $classmapFile);
$includePathFilePath = $targetDir . '/include_paths.php';
if ($includePathFileContents = $this->getIncludePathsFile($packageMap, $filesystem, $basePath, $vendorPath, $vendorPathCode, $appBaseDirCode)) {
$filesystem->filePutContentsIfModified($includePathFilePath, $includePathFileContents);
}
elseif (file_exists($includePathFilePath)) {
unlink($includePathFilePath);
}
$includeFilesFilePath = $targetDir . '/autoload_files.php';
if ($includeFilesFileContents = $this->getIncludeFilesFile($autoloads['files'], $filesystem, $basePath, $vendorPath, $vendorPathCode, $appBaseDirCode)) {
$filesystem->filePutContentsIfModified($includeFilesFilePath, $includeFilesFileContents);
}
elseif (file_exists($includeFilesFilePath)) {
unlink($includeFilesFilePath);
}
$filesystem->filePutContentsIfModified($targetDir . '/autoload_static.php', $this->getStaticFile($suffix, $targetDir, $vendorPath, $basePath));
$checkPlatform = $config->get('platform-check') !== false && !$this->platformRequirementFilter instanceof IgnoreAllPlatformRequirementFilter;
$platformCheckContent = null;
if ($checkPlatform) {
$platformCheckContent = $this->getPlatformCheck($packageMap, $config->get('platform-check'), $devPackageNames);
if (null === $platformCheckContent) {
$checkPlatform = false;
}
}
if ($checkPlatform) {
$filesystem->filePutContentsIfModified($targetDir . '/platform_check.php', $platformCheckContent);
}
elseif (file_exists($targetDir . '/platform_check.php')) {
unlink($targetDir . '/platform_check.php');
}
$filesystem->filePutContentsIfModified($vendorPath . '/autoload.php', $this->getAutoloadFile($vendorPathToTargetDirCode, $suffix));
$filesystem->filePutContentsIfModified($targetDir . '/autoload_real.php', $this->getAutoloadRealFile(true, (bool) $includePathFileContents, $targetDirLoader, (bool) $includeFilesFileContents, $vendorPathCode, $appBaseDirCode, $suffix, $useGlobalIncludePath, $prependAutoloader, $checkPlatform));
$filesystem->safeCopy(__DIR__ . '/ClassLoader.php', $targetDir . '/ClassLoader.php');
$filesystem->safeCopy(__DIR__ . '/../../../LICENSE', $targetDir . '/LICENSE');
if ($this->runScripts) {
$this->eventDispatcher
->dispatchScript(ScriptEvents::POST_AUTOLOAD_DUMP, $this->devMode, [], [
'optimize' => $scanPsrPackages,
]);
}
return $classMap;
}