diff --git a/src/Symfony/Component/AssetMapper/Factory/CachedMappedAssetFactory.php b/src/Symfony/Component/AssetMapper/Factory/CachedMappedAssetFactory.php index c4245d686858d..e666999dbab24 100644 --- a/src/Symfony/Component/AssetMapper/Factory/CachedMappedAssetFactory.php +++ b/src/Symfony/Component/AssetMapper/Factory/CachedMappedAssetFactory.php @@ -59,7 +59,8 @@ private function getCacheFilePath(string $logicalPath, string $sourcePath): stri */ private function collectResourcesFromAsset(MappedAsset $mappedAsset): array { - $resources = [new FileResource($mappedAsset->getSourcePath())]; + $resources = array_map(fn (string $path) => new FileResource($path), $mappedAsset->getFileDependencies()); + $resources[] = new FileResource($mappedAsset->getSourcePath()); foreach ($mappedAsset->getDependencies() as $dependency) { if (!$dependency->isContentDependency) { diff --git a/src/Symfony/Component/AssetMapper/MappedAsset.php b/src/Symfony/Component/AssetMapper/MappedAsset.php index ef9e0ef3d216e..d1c690343301e 100644 --- a/src/Symfony/Component/AssetMapper/MappedAsset.php +++ b/src/Symfony/Component/AssetMapper/MappedAsset.php @@ -31,6 +31,8 @@ final class MappedAsset private bool $isPredigested; /** @var AssetDependency[] */ private array $dependencies = []; + /** @var string[] */ + private array $fileDependencies = []; public function __construct(private readonly string $logicalPath) { @@ -79,6 +81,14 @@ public function getDependencies(): array return $this->dependencies; } + /** + * @return string[] + */ + public function getFileDependencies(): array + { + return $this->fileDependencies; + } + public function setPublicPath(string $publicPath): void { if (isset($this->publicPath)) { @@ -130,6 +140,16 @@ public function addDependency(AssetDependency $assetDependency): void $this->dependencies[] = $assetDependency; } + /** + * Any filesystem files whose contents are used to create this asset. + * + * This is used to invalidate the cache when any of these files change. + */ + public function addFileDependency(string $sourcePath): void + { + $this->fileDependencies[] = $sourcePath; + } + public function getPublicPathWithoutDigest(): string { return $this->publicPathWithoutDigest; diff --git a/src/Symfony/Component/AssetMapper/Tests/Factory/CachedMappedAssetFactoryTest.php b/src/Symfony/Component/AssetMapper/Tests/Factory/CachedMappedAssetFactoryTest.php index fe72b94a3a975..690aa52df3b63 100644 --- a/src/Symfony/Component/AssetMapper/Tests/Factory/CachedMappedAssetFactoryTest.php +++ b/src/Symfony/Component/AssetMapper/Tests/Factory/CachedMappedAssetFactoryTest.php @@ -106,6 +106,9 @@ public function testAssetConfigCacheResourceContainsDependencies() $notDependentOnContentAsset->setSourcePath(__DIR__.'/../fixtures/dir2/already-abcdefVWXYZ0123456789.digested.css'); $mappedAsset->addDependency(new AssetDependency($notDependentOnContentAsset, isContentDependency: false)); + // just adding any file as an example + $mappedAsset->addFileDependency(__DIR__.'/../fixtures/importmap.php'); + $factory = $this->createMock(MappedAssetFactoryInterface::class); $factory->expects($this->once()) ->method('createMappedAsset') @@ -119,12 +122,13 @@ public function testAssetConfigCacheResourceContainsDependencies() $cachedFactory->createMappedAsset('file1.css', $sourcePath); $configCacheMetadata = $this->loadConfigCacheMetadataFor($mappedAsset); - $this->assertCount(3, $configCacheMetadata); + $this->assertCount(4, $configCacheMetadata); $this->assertInstanceOf(FileResource::class, $configCacheMetadata[0]); $this->assertInstanceOf(FileResource::class, $configCacheMetadata[1]); - $this->assertSame($mappedAsset->getSourcePath(), $configCacheMetadata[0]->getResource()); - $this->assertSame($dependentOnContentAsset->getSourcePath(), $configCacheMetadata[1]->getResource()); - $this->assertSame($deeplyNestedAsset->getSourcePath(), $configCacheMetadata[2]->getResource()); + $this->assertSame(realpath(__DIR__.'/../fixtures/importmap.php'), $configCacheMetadata[0]->getResource()); + $this->assertSame($mappedAsset->getSourcePath(), $configCacheMetadata[1]->getResource()); + $this->assertSame($dependentOnContentAsset->getSourcePath(), $configCacheMetadata[2]->getResource()); + $this->assertSame($deeplyNestedAsset->getSourcePath(), $configCacheMetadata[3]->getResource()); } private function loadConfigCacheMetadataFor(MappedAsset $mappedAsset): array diff --git a/src/Symfony/Component/AssetMapper/Tests/MappedAssetTest.php b/src/Symfony/Component/AssetMapper/Tests/MappedAssetTest.php index 2cd0bc733ba1c..5a84082f9231c 100644 --- a/src/Symfony/Component/AssetMapper/Tests/MappedAssetTest.php +++ b/src/Symfony/Component/AssetMapper/Tests/MappedAssetTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\AssetMapper\Tests; use PHPUnit\Framework\TestCase; +use Symfony\Component\AssetMapper\AssetDependency; use Symfony\Component\AssetMapper\MappedAsset; class MappedAssetTest extends TestCase @@ -78,4 +79,17 @@ public function testGetContent() $asset->setContent('body { color: red; }'); $this->assertSame('body { color: red; }', $asset->getContent()); } + + public function testAddDependencies() + { + $mainAsset = new MappedAsset('file.js'); + + $assetFoo = new MappedAsset('foo.js'); + $dependency = new AssetDependency($assetFoo, false, false); + $mainAsset->addDependency($dependency); + $mainAsset->addFileDependency('/path/to/foo.js'); + + $this->assertSame([$dependency], $mainAsset->getDependencies()); + $this->assertSame(['/path/to/foo.js'], $mainAsset->getFileDependencies()); + } }