Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. AutoloadGenerator.php

function AutoloadGenerator::dump

Return value

ClassMap

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\Autoload

Code

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;
}

API Navigation

  • Drupal Core 11.1.x
  • Topics
  • Classes
  • Functions
  • Constants
  • Globals
  • Files
  • Namespaces
  • Deprecated
  • Services
RSS feed
Powered by Drupal