8000 Merge branch '6.4' into 7.1 · priyadi/symfony@39b5b8f · GitHub
[go: up one dir, main page]

Skip to content

Commit 39b5b8f

Browse files
committed
Merge branch '6.4' into 7.1
* 6.4: [FrameworkBundle] Add missing `not-compromised-password` entry in XSD [AssetMapper] Fix CssCompiler matches url in comments Add support for doctrine/persistence 4 Ensure TransportExceptionInterface populates stream debug data Fix typo in validators.sk.xlf [Mime] Fix body validity check in `Email` when using `Message::setBody()` Review Arabic translations for the validator Fixed mistakes in proper hebrew writing in the previous translation and confirmed the rest to be correct and in the same style. Review translation [Cache] Don't clear system caches on cache:clear [FrameworkBundle] Fix patching refs to the tmp warmup dir in files generated by optional cache warmers Mark Czech Validator translation as reviewed [PropertyInfo] Fix `TypeTest` duplicated assert [HtmlSanitizer] Avoid accessing non existent array key when checking for hosts validity Update validators.ar.xlf [DomCrawler] Make `ChoiceFormField::isDisabled` return `true` for unchecked disabled checkboxes
2 parents 29e1ee8 + c5704e9 commit 39b5b8f

File tree

26 files changed

+230
-88
lines changed

26 files changed

+230
-88
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
"composer/semver": "^3.0",
3939
"ext-xml": "*",
4040
"doctrine/event-manager": "^2",
41-
"doctrine/persistence": "^3.1",
41+
"doctrine/persistence": "^3.1|^4",
4242
"twig/twig": "^3.10",
4343
"psr/cache": "^2.0|^3.0",
4444
"psr/clock": "^1.0",

src/Symfony/Bridge/Doctrine/Tests/ArgumentResolver/EntityValueResolverTest.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -487,9 +487,13 @@ private function createRegistry(?ObjectManager $manager = null): ManagerRegistry
487487
->method('getManagerForClass')
488488
->willReturn($manager);
489489

490-
$registry->expects($this->any())
491-
->method('getManager')
492-
->willReturn($manager);
490+
if (null === $manager) {
491+
$registry->method('getManager')
492+
->willThrowException(new \InvalidArgumentException());
493+
} else {
494+
$registry->method('getManager')->willReturn($manager);
495+
}
496+
493497

494498
return $registry;
495499
}

src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,16 @@ protected function setUp(): void
8484
protected function createRegistryMock($em = null)
8585
{
8686
$registry = $this->createMock(ManagerRegistry::class);
87-
$registry->expects($this->any())
88-
->method('getManager')
89-
->with($this->equalTo(self::EM_NAME))
90-
->willReturn($em);
87+
88+
if (null === $em) {
89+
$registry->method('getManager')
90+
->with($this->equalTo(self::EM_NAME))
91+
->willThrowException(new \InvalidArgumentException());
92+
} else {
93+
$registry->method('getManager')
94+
->with($this->equalTo(self::EM_NAME))
95+
->willReturn($em);
96+
}
9197

9298
return $registry;
9399
}

src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,10 @@ public function validate(mixed $value, Constraint $constraint): void
6969
$entityClass = $constraint->entityClass ?? $value::class;
7070

7171
if ($constraint->em) {
72-
$em = $this->registry->getManager($constraint->em);
73-
74-
if (!$em) {
75-
throw new ConstraintDefinitionException(sprintf('Object manager "%s" does not exist.', $constraint->em));
72+
try {
73+
$em = $this->registry->getManager($constraint->em);
74+
} catch (\InvalidArgumentException $e) {
75+
throw new ConstraintDefinitionException(sprintf('Object manager "%s" does not exist.', $constraint->em), 0, $e);
7676
}
7777
} else {
7878
$em = $this->registry->getManagerForClass($entityClass);

src/Symfony/Bridge/Doctrine/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"require": {
1919
"php": ">=8.2",
2020
"doctrine/event-manager": "^2",
21-
"doctrine/persistence": "^3.1",
21+
"doctrine/persistence": "^3.1|^4",
2222
"symfony/deprecation-contracts": "^2.5|^3",
2323
"symfony/polyfill-ctype": "~1.8",
2424
"symfony/polyfill-mbstring": "~1.0",

src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,16 @@ protected function execute(InputInterface $input, OutputInterface $output): int
146146
}
147147
$this->warmupOptionals($useBuildDir ? $realCacheDir : $warmupDir, $warmupDir, $io);
148148
}
149+
150+
// fix references to cached files with the real cache directory name
151+
$search = [$warmupDir, str_replace('/', '\\/', $warmupDir), str_replace('\\', '\\\\', $warmupDir)];
152+
$replace = str_replace('\\', '/', $realBuildDir);
153+
foreach (Finder::create()->files()->in($warmupDir) as $file) {
154+
$content = str_replace($search, $replace, $this->filesystem->readFile($file), $count);
155+
if ($count) {
156+
file_put_contents($file, $content);
157+
}
158+
}
149159
}
150160

151161
if (!$fs->exists($warmupDir.'/'.$containerDir)) {
@@ -227,16 +237,6 @@ private function warmup(string $warmupDir, string $realBuildDir): void
227237
throw new \LogicException('Calling "cache:clear" with a kernel that does not implement "Symfony\Component\HttpKernel\RebootableInterface" is not supported.');
228238
}
229239
$kernel->reboot($warmupDir);
230-
231-
// fix references to cached files with the real cache directory name
232-
$search = [$warmupDir, str_replace('\\', '\\\\', $warmupDir)];
233-
$replace = str_replace('\\', '/', $realBuildDir);
234-
foreach (Finder::create()->files()->in($warmupDir) as $file) {
235-
$content = str_replace($search, $replace, $this->filesystem->readFile($file), $count);
236-
if ($count) {
237-
file_put_contents($file, $content);
238-
}
239-
}
240240
}
241241

242242
private function warmupOptionals(string $cacheDir, string $warmupDir, SymfonyStyle $io): void

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@
265265
<xsd:element name="static-method" type="xsd:string" />
266266
<xsd:element name="mapping" type="file_mapping" />
267267
<xsd:element name="auto-mapping" type="auto_mapping" />
268+
<xsd:element name="not-compromised-password" type="not-compromised-password" />
268269
</xsd:choice>
269270

270271
<xsd:attribute name="enabled" type="xsd:boolean" />
@@ -297,6 +298,11 @@
297298
</xsd:restriction>
298299
</xsd:simpleType>
299300

301+
<xsd:complexType name="not-compromised-password">
302+
<xsd:attribute name="enabled" type="xsd:boolean" />
303+
<xsd:attribute name="endpoint" type="xsd:string" />
304+
</xsd:complexType>
305+
300306
<xsd:complexType name="annotations">
301307
<xsd:attribute name="cache" type="xsd:string" />
302308
<xsd:attribute name="debug" type="xsd:string" />

src/Symfony/Bundle/FrameworkBundle/Tests/Functional/CachePoolsTest.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,6 @@ private function doTestCachePools($options, $adapterClass)
8888
$pool2 = $container->get('cache.pool2');
8989
$pool2->save($item);
9090

91-
$container->get('cache_clearer.alias')->clear($container->getParameter('kernel.cache_dir'));
92-
$item = $pool1->getItem($key);
93-
$this->assertFalse($item->isHit());
94-
9591
$item = $pool2->getItem($key);
9692
$this->assertTrue($item->isHit());
9793

src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -139,14 +139,18 @@ public function testTagsPartialSearch()
139139
$tester->setInputs(['0']);
140140
$tester->run(['command' => 'debug:container', '--tag' => 'kernel.'], ['decorated' => false]);
141141

142-
$this->assertStringContainsString('Select one of the following tags to display its information', $tester->getDisplay());
143-
$this->assertStringContainsString('[0] kernel.cache_clearer', $tester->getDisplay());
144-
$this->assertStringContainsString('[1] kernel.cache_warmer', $tester->getDisplay());
145-
$this->assertStringContainsString('[2] kernel.event_subscriber', $tester->getDisplay());
146-
$this->assertStringContainsString('[3] kernel.fragment_renderer', $tester->getDisplay());
147-
$this->assertStringContainsString('[4] kernel.locale_aware', $tester->getDisplay());
148-
$this->assertStringContainsString('[5] kernel.reset', $tester->getDisplay());
149-
$this->assertStringContainsString('Symfony Container Services Tagged with "kernel.cache_clearer" Tag', $tester->getDisplay());
142+
$this->assertStringMatchesFormat(<<<EOTXT
143+
144+
Select one of the following tags to display its information:
145+
%A
146+
[%d] kernel.reset
147+
%A
148+
149+
Symfony Container Services Tagged with "kernel.%a" Tag
150+
%A
151+
EOTXT,
152+
$tester->getDisplay()
153+
);
150154
}
151155

152156
public function testDescribeEnvVars()
Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,2 @@
11
imports:
22
- { resource: ../config/default.yml }
3-
4-
services:
5-
cache_clearer.alias:
6-
alias: cache_clearer
7-
public: true

src/Symfony/Component/AssetMapper/Compiler/CssAssetUrlCompiler.php

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,32 @@ public function __construct(
3535

3636
public function compile(string $content, MappedAsset $asset, AssetMapperInterface $assetMapper): string
3737
{
38-
return preg_replace_callback(self::ASSET_URL_PATTERN, function ($matches) use ($asset, $assetMapper) {
38+
preg_match_all('/\/\*|\*\//', $content, $commentMatches, \PREG_OFFSET_CAPTURE);
39+
40+
$start = null;
41+
$commentBlocks = [];
42+
foreach ($commentMatches[0] as $match) {
43+
if ('/*' === $match[0]) {
44+
$start = $match[1];
45+
} elseif ($start) {
46+
$commentBlocks[] = [$start, $match[1]];
47+
$start = null;
48+
}
49+
}
50+
51+
return preg_replace_callback(self::ASSET_URL_PATTERN, function ($matches) use ($asset, $assetMapper, $commentBlocks) {
52+
$matchPos = $matches[0][1];
53+
54+
// Ignore matchs inside comments
55+
foreach ($commentBlocks as $block) {
56+
if ($matchPos > $block[0]) {
57+
if ($matchPos < $block[1]) {
58+
return $matches[0][0];
59+
}
60+
break;
61+
}
62+
}
63+
3964
try {
4065
$resolvedSourcePath = Path::join(\dirname($asset->sourcePath), $matches[1]);
4166
} catch (RuntimeException $e) {

src/Symfony/Component/AssetMapper/Tests/Compiler/CssAssetUrlCompilerTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,36 @@ public static function provideCompileTests(): iterable
114114
'expectedOutput' => 'body { background: url("https://cdn.io/images/bar.png"); }',
115115
'expectedDependencies' => [],
116116
];
117+
118+
yield 'ignore_comments' => [
119+
'input' => 'body { background: url("images/foo.png"); /* background: url("images/bar.png"); */ }',
120+
'expectedOutput' => 'body { background: url("images/foo.123456.png"); /* background: url("images/bar.png"); */ }',
121+
'expectedDependencies' => ['images/foo.png'],
122+
];
123+
124+
yield 'ignore_comment_after_rule' => [
125+
'input' => 'body { background: url("images/foo.png"); } /* url("images/need-ignore.png") */',
126+
'expectedOutput' => 'body { background: url("images/foo.123456.png"); } /* url("images/need-ignore.png") */',
127+
'expectedDependencies' => ['images/foo.png'],
128+
];
129+
130+
yield 'ignore_comment_within_rule' => [
131+
'input' => 'body { background: url("images/foo.png") /* url("images/need-ignore.png") */; }',
132+
'expectedOutput' => 'body { background: url("images/foo.123456.png") /* url("images/need-ignore.png") */; }',
133+
'expectedDependencies' => ['images/foo.png'],
134+
];
135+
136+
yield 'ignore_multiline_comment_after_rule' => [
137+
'input' => 'body {
138+
background: url("images/foo.png"); /*
139+
url("images/need-ignore.png") */
140+
}',
141+
'expectedOutput' => 'body {
142+
background: url("images/foo.123456.png"); /*
143+
url("images/need-ignore.png") */
144+
}',
145+
'expectedDependencies' => ['images/foo.png'],
146+
];
117147
}
118148

119149
public function testCompileFindsRelativeFilesViaSourcePath()

src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -194,10 +194,6 @@ public function process(ContainerBuilder $container): void
194194
$clearer->setArgument(0, $pools);
195195
}
196196
$clearer->addTag('cache.pool.clearer');
197-
198-
if ('cache.system_clearer' === $id) {
199-
$clearer->addTag('kernel.cache_clearer');
200-
}
201197
}
202198

203199
$allPoolsKeys = array_keys($allPools);

src/Symfony/Component/DomCrawler/Field/ChoiceFormField.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ public function hasValue(): bool
4545
*/
4646
public function isDisabled(): bool
4747
{
48+
if ('checkbox' === $this->type) {
49+
return parent::isDisabled();
50+
}
51+
4852
if (parent::isDisabled() && 'select' === $this->type) {
4953
return true;
5054
}

src/Symfony/Component/DomCrawler/Tests/Field/ChoiceFormFieldTest.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,17 @@ public function testCheckboxWithEmptyBooleanAttribute()
272272
$this->assertEquals('foo', $field->getValue());
273273
}
274274

275+
public function testCheckboxIsDisabled()
276+
{
277+
$node = $this->createNode('input', '', ['type' => 'checkbox', 'name' => 'name', 'disabled' => '']);
278+
$field = new ChoiceFormField($node);
279+
280+
$this->assertTrue($field->isDisabled(), '->isDisabled() returns true when the checkbox is disabled, even if it is not checked');
281+
282+
$field->tick();
283+
$this->assertTrue($field->isDisabled(), '->isDisabled() returns true when the checkbox is disabled, even if it is checked');
284+
}
285+
275286
public function testTick()
276287
{
277288
$node = $this->createSelectNode(['foo' => false, 'bar' => false]);

src/Symfony/Component/HtmlSanitizer/Tests/TextSanitizer/UrlSanitizerTest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,15 @@ public static function provideSanitize(): iterable
274274
'expected' => null,
275275
];
276276

277+
yield [
278+
'input' => 'https://trusted.com/link.php',
279+
'allowedSchemes' => ['http', 'https'],
280+
'allowedHosts' => ['subdomain.trusted.com', 'trusted.com'],
281+
'forceHttps' => false,
282+
'allowRelative' => false,
283+
'expected' => 'https://trusted.com/link.php',
284+
];
285+
277286
// Allow relative
278287
yield [
279288
'input' => '/link.php',

src/Symfony/Component/HtmlSanitizer/TextSanitizer/UrlSanitizer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ private static function matchAllowedHostParts(array $uriParts, array $trustedPar
132132
{
133133
// Check each chunk of the domain is valid
134134
foreach ($trustedParts as $key => $trustedPart) {
135-
if ($uriParts[$key] !== $trustedPart) {
135+
if (!array_key_exists($key, $uriParts) || $uriParts[$key] !== $trustedPart) {
136136
return false;
137137
}
138138
}

src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,11 +205,11 @@ protected function doSend(SentMessage $message): void
205205
$this->ping();
206206
}
207207

208-
if (!$this->started) {
209-
$this->start();
210-
}
211-
212208
try {
209+
if (!$this->started) {
210+
$this->start();
211+
}
212+
213213
$envelope = $message->getEnvelope();
214214
$this->doMailFromCommand($envelope->getSender()->getEncodedAddress());
215215
foreach ($envelope->getRecipients() as $recipient) {

src/Symfony/Component/Mime/Email.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ public function ensureValidity(): void
401401

402402
private function ensureBodyValid(): void
403403
{
404-
if (null === $this->text && null === $this->html && !$this->attachments) {
404+
if (null === $this->text && null === $this->html && !$this->attachments && null === parent::getBody()) {
405405
throw new LogicException('A message must have a text or an HTML part or attachments.');
406406
}
407407
}
Original file line numberDiff line numberDiff line change
@@ -695,4 +695,60 @@ public function testEmailsWithAttachmentsWhichAreAFileInstanceCanBeUnserialized(
695695
$this->assertCount(1, $attachments);
696696
$this->assertStringContainsString('foo_bar_xyz_123', $attachments[0]->getBody());
697697
}
698+
699+
public function testInvalidBodyWithEmptyEmail()
700+
{
701+
$this->expectException(\LogicException::class);
702+
$this->expectExceptionMessage('A message must have a text or an HTML part or attachments.');
703+
704+
(new Email())->ensureValidity();
705+
}
706+
707+
public function testBodyWithTextIsValid()
708+
{
709+
$email = new Email();
710+
$email->to('test@example.com')
711+
->from('test@example.com')
712+
->text('foo');
713+
714+
$email->ensureValidity();
715+
716+
$this->expectNotToPerformAssertions();
717+
}
718+
719+
public function testBodyWithHtmlIsValid()
720+
{
721+
$email = new Email();
722+
$email->to('test@example.com')
723+
->from('test@example.com')
724+
->html('foo');
725+
726+
$email->ensureValidity();
727+
728+
$this->expectNotToPerformAssertions();
729+
}
730+
731+
public function testEmptyBodyWithAttachmentsIsValid()
732+
{
733+
$email = new Email();
734+
$email->to('test@example.com')
735+
->from('test@example.com')
736+
->addPart(new DataPart('foo'));
737+
738+
$email->ensureValidity();
739+
740+
$this->expectNotToPerformAssertions();
741+
}
742+
743+
public function testSetBodyIsValid()
744+
{
745+
$email = new Email();
746+
$email->to('test@example.com')
747+
->from('test@example.com')
748+
->setBody(new TextPart('foo'));
749+
750+
$email->ensureValidity();
751+
752+
$this->expectNotToPerformAssertions();
753+
}
698754
}
0