8000 Option to make asset manifests strict on missing item · symfony/symfony@e84046e · GitHub
[go: up one dir, main page]

Skip to content

Commit e84046e

Browse files
committed
Option to make asset manifests strict on missing item
1 parent 4537f85 commit e84046e

File tree

14 files changed

+186
-18
lines changed

14 files changed

+186
-18
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,10 @@ private function addAssetsSection(ArrayNodeDefinition $rootNode)
675675
->{!class_exists(FullStack::class) && class_exists(Package::class) ? 'canBeDisabled' : 'canBeEnabled'}()
676676
->fixXmlConfig('base_url')
677677
->children()
678+
->booleanNode('strict_mode')
679+
->info('Throw an exception if an entry is missing from the manifest.json')
680+
->defaultFalse()
681+
->end()
678682
->scalarNode('version_strategy')->defaultNull()->end()
679683
->scalarNode('version')->defaultNull()->end()
680684
->scalarNode('version_format')->defaultValue('%%s?%%s')->end()
@@ -712,6 +716,10 @@ private function addAssetsSection(ArrayNodeDefinition $rootNode)
712716
->prototype('array')
713717
->fixXmlConfig('base_url')
714718
->children()
719+
->booleanNode('strict_mode')
720+
->info('Throw an exception if an entry is missing from the manifest.json')
721+
->defaultFalse()
722+
->end()
715723
->scalarNode('version_strategy')->defaultNull()->end()
716724
->scalarNode('version')
717725
->beforeNormalization()

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,7 +1073,7 @@ private function registerAssetsConfiguration(array $config, ContainerBuilder $co
10731073
if ($config['version_strategy']) {
10741074
$defaultVersion = new Reference($config['version_strategy']);
10751075
} else {
1076-
$defaultVersion = $this->createVersion($container, $config['version'], $config['version_format'], $config['json_manifest_path'], '_default');
1076+
$defaultVersion = $this->createVersion($container, $config['version'], $config['version_format'], $config['json_manifest_path'], '_default', $config['strict_mode']);
10771077
}
10781078

10791079
$defaultPackage = $this->createPackageDefinition($config['base_path'], $config['base_urls'], $defaultVersion);
@@ -1090,7 +1090,7 @@ private function registerAssetsConfiguration(array $config, ContainerBuilder $co
10901090
// let format fallback to main version_format
10911091
$format = $package['version_format'] ?: $config['version_format'];
10921092
$version = $package['version'] ?? null;
1093-
$version = $this->createVersion($container, $version, $format, $package['json_manifest_path'], $name);
1093+
$version = $this->createVersion($container, $version, $format, $package['json_manifest_path'], $name, $package['strict_mode']);
10941094
}
10951095

10961096
$container->setDefinition('assets._package_'.$name, $this->createPackageDefinition($package['base_path'], $package['base_urls'], $version));
@@ -1123,7 +1123,7 @@ private function createPackageDefinition(?string $basePath, array $baseUrls, Ref
11231123
return $package;
11241124
}
11251125

1126-
private function createVersion(ContainerBuilder $container, ?string $version, ?string $format, ?string $jsonManifestPath, string $name): Reference
1126+
private function createVersion(ContainerBuilder $container, ?string $version, ?string $format, ?string $jsonManifestPath, string $name, bool $strictMode): Reference
11271127
{
11281128
// Configuration prevents $version and $jsonManifestPath from being set
11291129
if (null !== $version) {
@@ -1140,6 +1140,7 @@ private function createVersion(ContainerBuilder $container, ?string $version, ?s
11401140
if (null !== $jsonManifestPath) {
11411141
$def = new ChildDefinition('assets.json_manifest_version_strategy');
11421142
$def->replaceArgument(0, $jsonManifestPath);
1143+
$def->replaceArgument(2, $strictMode);
11431144
$container->setDefinition('assets._version_'.$name, $def);
11441145

11451146
return new Reference('assets._version_'.$name);

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
->args([
7979
abstract_arg('manifest path'),
8080
service('http_client')->nullOnInvalid(),
81+
false,
8182
])
8283

8384
->set('assets.remote_json_manifest_version_strategy', RemoteJsonManifestVersionStrategy::class)

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@
151151
<xsd:attribute name="version" type="xsd:string" />
152152
<xsd:attribute name="version-format" type="xsd:string" />
153153
<xsd:attribute name="json-manifest-path" type="xsd:string" />
154+
<xsd:attribute name="strict-mode" type="xsd:boolean" />
154155
</xsd:complexType>
155156

156157
<xsd:complexType name="package">
@@ -164,6 +165,7 @@
164165
<xsd:attribute name="version" type="xsd:string" />
165166
<xsd:attribute name="version-format" type="xsd:string" />
166167
<xsd:attribute name="json-manifest-path" type="xsd:string" />
168+
<xsd:attribute name="strict-mode" type="xsd:boolean" />
167169
</xsd:complexType>
168170

169171
<xsd:complexType name="translator">

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ public function testAssetsCanBeEnabled()
8383
'base_urls' => [],
8484
'packages' => [],
8585
'json_manifest_path' => null,
86+
'strict_mode' => false,
8687
];
8788

8889
$this->assertEquals($defaultConfig, $config['assets']);
@@ -482,6 +483,7 @@ protected static function getBundleDefaultConfig()
482483
'base_urls' => [],
483484
'packages' => [],
484485
'json_manifest_path' => null,
486+
'strict_mode' => false,
485487
],
486488
'cache' => [
487489
'pools' => [],

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/assets.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
'env_manifest' => [
3737
'json_manifest_path' => '%env(env_manifest)%',
3838
],
39+
'strict_manifest_strategy' => [
40+
'json_manifest_path' => '/path/to/manifest.json',
41+
'strict_mode' => true,
42+
],
3943
],
4044
],
4145
]);

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
<framework:package name="remote_manifest" json-manifest-path="https://cdn.example.com/manifest.json" />
2626
<framework:package name="var_manifest" json-manifest-path="%var_json_manifest_path%" />
2727
<framework:package name="env_manifest" json-manifest-path="%env(env_manifest)%" />
28+
<framework:package name="strict_manifest_strategy" json-manifest-path="/path/to/manifest.json" strict-mode="true" />
2829
</framework:assets>
2930
</framework:config>
3031

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/assets.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ framework:
2525
json_manifest_path: '%var_json_manifest_path%'
2626
env_manifest:
2727
json_manifest_path: '%env(env_manifest)%'
28+
strict_manifest_strategy:
29+
json_manifest_path: '/path/to/manifest.json'
30+
strict_mode: true
2831

2932
parameters:
3033
var_json_manifest_path: 'https://cdn.example.com/manifest.json'

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,7 @@ public function testAssets()
604604

605605
// packages
606606
$packages = $packages->getArgument(1);
607-
$this->assertCount(9, $packages);
607+
$this->assertCount(10, $packages);
608608

609609
$package = $container->getDefinition((string) $packages['images_path']);
610610
$this->assertPathPackage($container, $package, '/foo', 'SomeVersionScheme', '%%s?version=%%s');
@@ -625,6 +625,7 @@ public function testAssets()
625625
$versionStrategy = $container->getDefinition((string) $package->getArgument(1));
626626
$this->assertEquals('assets.json_manifest_version_strategy', $versionStrategy->getParent());
627627
$this->assertEquals('/path/to/manifest.json', $versionStrategy->getArgument(0));
628+
$this->assertFalse($versionStrategy->getArgument(2));
628629

629630
$package = $container->getDefinition($packages['remote_manifest']);
630631
$versionStrategy = $container->getDefinition($package->getArgument(1));
@@ -635,11 +636,19 @@ public function testAssets()
635636
$versionStrategy = $container->getDefinition($package->getArgument(1));
636637
$this->assertSame('assets.json_manifest_version_strategy', $versionStrategy->getParent());
637638
$this->assertSame('https://cdn.example.com/manifest.json', $versionStrategy->getArgument(0));
639+
$this->assertFalse($versionStrategy->getArgument(2));
638640

639641
$package = $container->getDefinition($packages['env_manifest']);
640642
$versionStrategy = $container->getDefinition($package->getArgument(1));
641643
$this->assertSame('assets.json_manifest_version_strategy', $versionStrategy->getParent());
642644
$this->assertStringMatchesFormat('env_%s', $versionStrategy->getArgument(0));
645+
$this->assertFalse($versionStrategy->getArgument(2));
646+
647+
$package = $container->getDefinition((string) $packages['strict_manifest_strategy']);
648+
$versionStrategy = $container->getDefinition((string) $package->getArgument(1));
649+
$this->assertEquals('assets.json_manifest_version_strategy', $versionStrategy->getParent());
650+
$this->assertEquals('/path/to/manifest.json', $versionStrategy->getArgument(0));
651+
$this->assertTrue($versionStrategy->getArgument(2));
643652
}
644653

645654
public function testAssetsDefaultVersionStrategyAsService()
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Asset\Exception;
13+
14+
/**
15+
* Represents an asset not found in a manifest.
16+
*/
17+
class AssetNotFoundException extends RuntimeException
18+
{
19+
private $alternatives;
20+
21+
/**
22+
* @param string $message Exception message to throw
23+
* @param array $alternatives List of similar defined names
24+
* @param int $code Exception code
25+
* @param \Throwable $previous Previous exception used for the exception chaining
26+
*/
27+
public function __construct(string $message, array $alternatives = [], int $code = 0, \Throwable $previous = null)
28+
{
29+
parent::__construct($message, $code, $previous);
30+
31+
$this->alternatives = $alternatives;
32+
}
33+
34+
/**
35+
* @return array A list of similar defined names
36+
*/
37+
public function getAlternatives(): array
38+
{
39+
return $this->alternatives;
40+
}
41+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Asset\Exception;
13+
14+
/**
15+
* Base RuntimeException for the Asset component.
16+
*/
17+
class RuntimeException extends \RuntimeException implements ExceptionInterface
18+
{
19+
}

src/Symfony/Component/Asset/Tests/VersionStrategy/JsonManifestVersionStrategyTest.php

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,51 +12,64 @@
1212
namespace Symfony\Component\Asset\Tests\VersionStrategy;
1313

1414
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Asset\Exception\AssetNotFoundException;
16+
use Symfony\Component\Asset\Exception\RuntimeException;
1517
use Symfony\Component\Asset\VersionStrategy\JsonManifestVersionStrategy;
1618
use Symfony\Component\HttpClient\MockHttpClient;
1719
use Symfony\Component\HttpClient\Response\MockResponse;
1820

1921
class JsonManifestVersionStrategyTest extends TestCase
2022
{
2123
/**
22-
* @dataProvider ProvideValidStrategies
24+
* @dataProvider provideValidStrategies
2325
*/
2426
public function testGetVersion(JsonManifestVersionStrategy $strategy)
2527
{
2628
$this->assertSame('main.123abc.js', $strategy->getVersion('main.js'));
2729
}
2830

2931
/**
30-
* @dataProvider ProvideValidStrategies
32+
* @dataProvider provideValidStrategies
3133
*/
3234
public function testApplyVersion(JsonManifestVersionStrategy $strategy)
3335
{
3436
$this->assertSame('css/styles.555def.css', $strategy->applyVersion('css/styles.css'));
3537
}
3638

3739
/**
38-
* @dataProvider ProvideValidStrategies
40+
* @dataProvider provideValidStrategies
3941
*/
4042
public function testApplyVersionWhenKeyDoesNotExistInManifest(JsonManifestVersionStrategy $strategy)
4143
{
4244
$this->assertSame('css/other.css', $strategy->applyVersion('css/other.css'));
4345
}
4446

4547
/**
46-
* @dataProvider ProvideMissingStrategies
48+
* @dataProvider provideStrictStrategies
49+
*/
50+
public function testStrictExceptionWhenKeyDoesNotExistInManifest(JsonManifestVersionStrategy $strategy, $path, $message)
51+
{
52+
$this->expectException(AssetNotFoundException::class);
53+
$this->expectExceptionMessageMatches($message);
54+
55+
$strategy->getVersion($path);
56+
}
57+
58+
/**
59+
* @dataProvider provideMissingStrategies
4760
*/
4861
public function testMissingManifestFileThrowsException(JsonManifestVersionStrategy $strategy)
4962
{
50-
$this->expectException(\RuntimeException::class);
63+
$this->expectException(RuntimeException::class);
5164
$strategy->getVersion('main.js');
5265
}
5366

5467
/**
55-
* @dataProvider ProvideInvalidStrategies
68+
* @dataProvider provideInvalidStrategies
5669
*/
5770
public function testManifestFileWithBadJSONThrowsException(JsonManifestVersionStrategy $strategy)
5871
{
59-
$this->expectException(\RuntimeException::class);
72+
$this->expectException(RuntimeException::class);
6073
$this->expectExceptionMessage('Error parsing JSON');
6174
$strategy->getVersion('main.js');
6275
}
@@ -100,4 +113,21 @@ public function provideStrategies(string $manifestPath)
100113

101114
yield [new JsonManifestVersionStrategy(__DIR__.'/../fixtures/'.$manifestPath)];
102115
}
116+
117+
public function provideStrictStrategies()
118+
{
119+
$strategy = new JsonManifestVersionStrategy(__DIR__.'/../fixtures/manifest-valid.json', null, true);
120+
121+
yield [
122+
$strategy,
123+
'css/styles.555def.css',
124+
'~Asset "css/styles.555def.css" not found in manifest "(.*)/manifest-valid.json"\. Did you mean one of these\? "css/styles.css", "css/style.css".~',
125+
];
126+
127+
yield [
128+
$strategy,
129+
'img/avatar.png',
130+
'~Asset "img/avatar.png" not found in manifest "(.*)/manifest-valid.json"\.~',
131+
];
132+
}
103133
}
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
{
22
"main.js": "main.123abc.js",
3-
"css/styles.css": "css/styles.555def.css"
3+
"css/styles.css": "css/styles.555def.css",
4+
"css/style.css": "css/style.abcdef.css",
5+
"main/home.css": "main/home.css"
46
}

0 commit comments

Comments
 (0)
0