diff --git a/src/Box.php b/src/Box.php index f9e980e26..90bf57b6f 100644 --- a/src/Box.php +++ b/src/Box.php @@ -115,7 +115,7 @@ public function startBuffering(): void } /** - * @param callable(SymbolsRegistry, string): void $dumpAutoload + * @param callable(SymbolsRegistry, string, string[]): void $dumpAutoload */ public function endBuffering(?callable $dumpAutoload): void { diff --git a/src/Composer/AutoloadDumper.php b/src/Composer/AutoloadDumper.php index 6a4133c88..f96b951fc 100644 --- a/src/Composer/AutoloadDumper.php +++ b/src/Composer/AutoloadDumper.php @@ -14,6 +14,7 @@ namespace KevinGH\Box\Composer; +use Humbug\PhpScoper\Autoload\ComposerFileHasher; use Humbug\PhpScoper\Autoload\ScoperAutoloadGenerator; use Humbug\PhpScoper\Symbol\SymbolsRegistry; use KevinGH\Box\NotInstantiable; @@ -23,6 +24,7 @@ use function implode; use function preg_match; use function preg_replace; +use function sprintf; use function str_replace; use const PHP_EOL; @@ -30,15 +32,26 @@ final class AutoloadDumper { use NotInstantiable; + private const PACKAGE_PATH_REGEX = '~^%s/(?[^/]+?/[^/]+?)/(?.+?)$~'; + + /** + * @param string[] $excludedComposerAutoloadFiles + */ public static function generateAutoloadStatements( SymbolsRegistry $symbolsRegistry, - array $excludedComposerAutoloadFileHashes, + string $vendorDir, + array $excludedComposerAutoloadFiles, string $autoloadContents, ): string { if (0 === $symbolsRegistry->count()) { return $autoloadContents; } + $excludedComposerAutoloadFileHashes = self::getExcludedComposerAutoloadFileHashes( + $vendorDir, + $excludedComposerAutoloadFiles, + ); + $autoloadContents = self::extractInlinedAutoloadContents($autoloadContents); $scoperStatements = self::getOriginalScoperAutoloaderContents( $symbolsRegistry, @@ -59,6 +72,25 @@ public static function generateAutoloadStatements( return self::cleanupDuplicateLineReturns($mergedAutoloadContents); } + /** + * @param string[] $excludedComposerAutoloadFiles + */ + private static function getExcludedComposerAutoloadFileHashes( + string $vendorDir, + array $excludedComposerAutoloadFiles, + ): array { + $fileHashGenerator = new ComposerFileHasher( + '', + $excludedComposerAutoloadFiles, + sprintf( + self::PACKAGE_PATH_REGEX, + $vendorDir, + ), + ); + + return $fileHashGenerator->generateHashes(); + } + private static function extractInlinedAutoloadContents(string $autoloadContents): string { $autoloadContents = str_replace('dumpAutoloader(true === $excludeDevFiles); @@ -122,17 +127,22 @@ public function dumpAutoload( return; } - $autoloadFile = $this->getVendorDir().'/autoload.php'; + $vendorDir = $this->getVendorDir(); + $autoloadFile = $vendorDir.'/autoload.php'; $autoloadContents = AutoloadDumper::generateAutoloadStatements( $symbolsRegistry, - $excludedComposerAutoloadFileHashes, + $vendorDir, + $excludedComposerAutoloadFiles, $this->fileSystem->getFileContents($autoloadFile), ); $this->fileSystem->dumpFile($autoloadFile, $autoloadContents); } + /** + * @return string The vendor-dir directory path relative to its composer.json. + */ public function getVendorDir(): string { $vendorDirProcess = $this->processFactory->getVendorDirProcess(); diff --git a/tests/Composer/AutoloadDumperTest.php b/tests/Composer/AutoloadDumperTest.php index 11e100b7a..802ba8b58 100644 --- a/tests/Composer/AutoloadDumperTest.php +++ b/tests/Composer/AutoloadDumperTest.php @@ -19,6 +19,7 @@ use PHPUnit\Framework\Attributes\CoversNothing; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; +use function md5; /** * @internal @@ -29,12 +30,14 @@ final class AutoloadDumperTest extends TestCase #[DataProvider('autoloadProvider')] public function test_it_can_generate_the_autoload( SymbolsRegistry $symbolsRegistry, + string $vendorDir, array $excludedComposerAutoloadFileHashes, string $autoloadContents, string $expected, ): void { $actual = AutoloadDumper::generateAutoloadStatements( $symbolsRegistry, + $vendorDir, $excludedComposerAutoloadFileHashes, $autoloadContents, ); @@ -44,8 +47,16 @@ public function test_it_can_generate_the_autoload( public static function autoloadProvider(): iterable { + $defaultVendorDir = 'vendor'; + + $excludedFile1 = 'vendor/phpstorm/stubs/stub1.php'; + $excludedFile1Hash = md5('phpstorm/stubs:stub1.php'); + $excludedFile2 = 'vendor/phpstorm/stubs/stub2.php'; + $excludedFile2Hash = md5('phpstorm/stubs:stub2.php'); + yield 'no symbols' => [ new SymbolsRegistry(), + $defaultVendorDir, [], <<<'PHP'