Skip to content

Commit 9e82301

Browse files
committed
feature #50291 [AssetMapper] Adding "excluded_patterns" option (weaverryan)
This PR was squashed before being merged into the 6.3 branch. Discussion ---------- [AssetMapper] Adding "excluded_patterns" option | Q | A | ------------- | --- | Branch? | 6.3 | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | None | License | MIT | Doc PR | Still TODO Hi! Invariably, some people will use AssetMapper with certain files that will need to be "built". Examples might be: A) An `assets/app.css` that uses Tailwind, and the user builds this manually to `assets/build/app.css` and includes *that* file in their pipeline. The source `assets/app.css` should not be published to `public/assets`. B) Similar with SCSS - e.g. all `*.scss` might be ignored because you are building them yourself. The new `excluded_patterns` is a glob, for simplicity, and must match the entire file path - hence examples like `*/assets/*.scss` Cheers! Commits ------- 1c5a1e0 [AssetMapper] Adding "excluded_patterns" option
2 parents 46db9fb + 1c5a1e0 commit 9e82301

File tree

9 files changed

+78
-3
lines changed

9 files changed

+78
-3
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,7 @@ private function addAssetMapperSection(ArrayNodeDefinition $rootNode, callable $
821821
->info('Asset Mapper configuration')
822822
->{$enableIfStandalone('symfony/asset-mapper', AssetMapper::class)}()
823823
->fixXmlConfig('path')
824+
->fixXmlConfig('excluded_pattern')
824825
->fixXmlConfig('extension')
825826
->fixXmlConfig('importmap_script_attribute')
826827
->children()
@@ -856,6 +857,11 @@ private function addAssetMapperSection(ArrayNodeDefinition $rootNode, callable $
856857
->end()
857858
->prototype('scalar')->end()
858859
->end()
860+
->arrayNode('excluded_patterns')
861+
->info('Array of glob patterns of asset file paths that should not be in the asset mapper')
862+
->prototype('scalar')->end()
863+
->example(['*/assets/build/*', '*/*_.scss'])
864+
->end()
859865
->booleanNode('server')
860866
->info('If true, a "dev server" will return the assets from the public directory (true in "debug" mode only by default)')
861867
->defaultValue($this->debug)

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
7373
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
7474
use Symfony\Component\Finder\Finder;
75+
use Symfony\Component\Finder\Glob;
7576
use Symfony\Component\Form\ChoiceList\Factory\CachingFactoryDecorator;
7677
use Symfony\Component\Form\Extension\HtmlSanitizer\Type\TextTypeHtmlSanitizerExtension;
7778
use Symfony\Component\Form\Form;
@@ -1277,8 +1278,14 @@ private function registerAssetMapperConfiguration(array $config, ContainerBuilde
12771278
$paths[$dir] = sprintf('bundles/%s', preg_replace('/bundle$/', '', strtolower($name)));
12781279
}
12791280
}
1281+
$excludedPathPatterns = [];
1282+
foreach ($config['excluded_patterns'] as $path) {
1283+
$excludedPathPatterns[] = Glob::toRegex($path, true, false);
1284+
}
1285+
12801286
$container->getDefinition('asset_mapper.repository')
1281-
->setArgument(0, $paths);
1287+
->setArgument(0, $paths)
1288+
->setArgument(2, $excludedPathPatterns);
12821289

12831290
$publicDirName = $this->getPublicDirectoryName($container);
12841291
$container->getDefinition('asset_mapper.public_assets_path_resolver')

src/Symfony/Bundle/FrameworkBundle/Resources/config/asset_mapper.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
->args([
4646
abstract_arg('array of asset mapper paths'),
4747
param('kernel.project_dir'),
48+
abstract_arg('array of excluded path patterns'),
4849
])
4950

5051
->set('asset_mapper.public_assets_path_resolver', PublicAssetsPathResolver::class)

src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@
190190
<xsd:complexType name="asset_mapper">
191191
<xsd:sequence>
192192
<xsd:element name="path" type="asset_mapper_path" minOccurs="0" maxOccurs="unbounded" />
193+
<xsd:element name="excluded-pattern" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
193194
<xsd:element name="server" type="xsd:boolean" minOccurs="0" />
194195
<xsd:element name="public_prefix" type="xsd:string" minOccurs="0" />
195196
<xsd:element name="strict-mode" type="xsd:boolean" minOccurs="0" />

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ public function testAssetMapperCanBeEnabled()
104104
$defaultConfig = [
105105
'enabled' => true,
106106
'paths' => [],
107+
'excluded_patterns' => [],
107108
'server' => true,
108109
'public_prefix' => '/assets/',
109110
'strict_mode' => true,
@@ -615,6 +616,7 @@ protected static function getBundleDefaultConfig()
615616
'asset_mapper' => [
616617
'enabled' => !class_exists(FullStack::class),
617618
'paths' => [],
619+
'excluded_patterns' => [],
618620
'server' => true,
619621
'public_prefix' => '/assets/',
620622
'strict_mode' => true,

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/asset_mapper.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
<framework:asset-mapper>
1111
<framework:path>assets/</framework:path>
1212
<framework:path namespace="my_namespace">assets2/</framework:path>
13+
<framework:excluded-pattern>*/*.scss</framework:excluded-pattern>
1314
<framework:server>true</framework:server>
1415
<framework:public_prefix>/assets_path/</framework:public_prefix>
1516
<framework:strict-mode>true</framework:strict-mode>

src/Symfony/Component/AssetMapper/AssetMapperRepository.php

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ class AssetMapperRepository
3333
*/
3434
public function __construct(
3535
private readonly array $paths,
36-
private readonly string $projectRootDir
36+
private readonly string $projectRootDir,
37+
private readonly array $excludedPathPatterns = [],
3738
) {
3839
}
3940

@@ -54,7 +55,7 @@ public function find(string $logicalPath): ?string
5455
}
5556

5657
$file = rtrim($path, '/').'/'.$localLogicalPath;
57-
if (is_file($file)) {
58+
if (is_file($file) && !$this->isExcluded($file)) {
5859
return realpath($file);
5960
}
6061
}
@@ -70,6 +71,10 @@ public function findLogicalPath(string $filesystemPath): ?string
7071

7172
$filesystemPath = realpath($filesystemPath);
7273

74+
if ($this->isExcluded($filesystemPath)) {
75+
return null;
76+
}
77+
7378
foreach ($this->getDirectories() as $path => $namespace) {
7479
if (!str_starts_with($filesystemPath, $path)) {
7580
continue;
@@ -104,6 +109,10 @@ public function all(): array
104109
continue;
105110
}
106111

112+
if ($this->isExcluded($file->getPathname())) {
113+
continue;
114+
}
115+
107116
/** @var RecursiveDirectoryIterator $innerIterator */
108117
$innerIterator = $iterator->getInnerIterator();
109118
$logicalPath = ($namespace ? rtrim($namespace, '/').'/' : '').$innerIterator->getSubPathName();
@@ -160,4 +169,18 @@ private function normalizeLogicalPath(string $logicalPath): string
160169
{
161170
return ltrim(str_replace('\\', '/', $logicalPath), '/\\');
162171
}
172+
173+
private function isExcluded(string $filesystemPath): bool
174+
{
175+
// normalize Windows slashes and remove trailing slashes
176+
$filesystemPath = rtrim(str_replace('\\', '/', $filesystemPath), '/');
177+
178+
foreach ($this->excludedPathPatterns as $pattern) {
179+
if (preg_match($pattern, $filesystemPath)) {
180+
return true;
181+
}
182+
}
183+
184+
return false;
185+
}
163186
}

src/Symfony/Component/AssetMapper/Tests/AssetMapperRepositoryTest.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\AssetMapper\AssetMapperRepository;
16+
use Symfony\Component\Finder\Glob;
1617

1718
class AssetMapperRepositoryTest extends TestCase
1819
{
@@ -128,4 +129,36 @@ public function testAllWithNamespaces()
128129

129130
$this->assertEquals($normalizedExpectedAllAssets, $normalizedActualAssets);
130131
}
132+
133+
public function testExcludedPaths()
134+
{
135+
$excludedPatterns = [
136+
'*/subdir/*',
137+
'*/*3.css',
138+
'*/*.digested.*',
139+
];
140+
$excludedGlobs = array_map(function ($pattern) {
141+
// globbed equally in FrameworkExtension
142+
return Glob::toRegex($pattern, true, false);
143+
}, $excludedPatterns);
144+
$repository = new AssetMapperRepository([
145+
'dir1' => '',
146+
'dir2' => '',
147+
'dir3' => '',
148+
], __DIR__.'/fixtures', $excludedGlobs);
149+
150+
$expectedAssets = [
151+
'file1.css',
152+
'file2.js',
153+
'file4.js',
154+
'test.gif.foo',
155+
];
156+
157+
$actualAssets = array_keys($repository->all());
158+
sort($actualAssets);
159+
$this->assertEquals($expectedAssets, $actualAssets);
160+
161+
$this->assertNull($repository->find('file3.css'));
162+
$this->assertNull($repository->findLogicalPath(__DIR__.'/fixtures/dir2/file3.css'));
163+
}
131164
}

src/Symfony/Component/AssetMapper/composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"symfony/asset": "^5.4|^6.0",
2525
"symfony/browser-kit": "^5.4|^6.0",
2626
"symfony/console": "^5.4|^6.0",
27+
"symfony/finder": "^5.4|^6.0",
2728
"symfony/framework-bundle": "^6.3",
2829
"symfony/http-foundation": "^5.4|^6.0",
2930
"symfony/http-kernel": "^5.4|^6.0"

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy