Skip to content

Commit 0a80506

Browse files
committed
Merge branch '6.2' into 6.3
* 6.2: Remove 6.0 and 6.1 from the PR template [Validator] Make ConstraintValidatorTestCase compatible with PHPUnit 10 [WebProfilerBundle] Fix some minor HTML issues [WebProfilerBundle] Disable Turbo for debug toolbar links [WebProfilerBundle] Fix an accessibility issue in the search form of the header [Mailer][MailPace] Fix undefined key in error response [Form] Fix PasswordHasherListener to work with empty data [PropertyInfo] Add meaningful message when `phpstan/phpdoc-parser` is not installed when using `PhpStanExtractor`
2 parents 53816fa + d3766c3 commit 0a80506

File tree

12 files changed

+117
-50
lines changed

12 files changed

+117
-50
lines changed

Diff for: .github/PULL_REQUEST_TEMPLATE.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
| Q | A
22
| ------------- | ---
3-
| Branch? | 6.3 for features / 5.4, 6.0, 6.1, or 6.2 for bug fixes <!-- see below -->
3+
| Branch? | 6.3 for features / 5.4 or 6.2 for bug fixes <!-- see below -->
44
| Bug fix? | yes/no
55
| New feature? | yes/no <!-- please update src/**/CHANGELOG.md files -->
66
| Deprecations? | yes/no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->

Diff for: src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/logger.html.twig

+5-3
Original file line numberDiff line numberDiff line change
@@ -341,8 +341,10 @@
341341
</colgroup>
342342

343343
<thead>
344-
<th>Time</th>
345-
<th>Message</th>
344+
<tr>
345+
<th>Time</th>
346+
<th>Message</th>
347+
</tr>
346348
</thead>
347349

348350
<tbody>
@@ -391,7 +393,7 @@
391393
<details class="container-compilation-logs">
392394
<summary>
393395
<h4>Container Compilation Logs <span class="text-muted">({{ compilerLogTotal }})</span></h4>
394-
<p class="text-muted">Log messages generated during the compilation of the service container.</p>
396+
<span class="text-muted">Log messages generated during the compilation of the service container.</span>
395397
</summary>
396398

397399
{% if collector.compilerLogs is empty %}

Diff for: src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/header.html.twig

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
<div class="search">
55
<form method="get" action="https://symfony.com/search" target="_blank">
66
<div class="form-row">
7-
<input name="q" id="search-id" type="search" placeholder="search on symfony.com">
7+
<input name="q" id="search-id" type="search" placeholder="search on symfony.com" aria-label="Search on symfony.com">
8+
<button type="submit" class="visually-hidden">Search</button>
89
</div>
910
</form>
1011
</div>

Diff for: src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.html.twig

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!-- START of Symfony Web Debug Toolbar -->
2-
<div id="sfMiniToolbar-{{ token }}" class="sf-minitoolbar" data-no-turbolink>
2+
<div id="sfMiniToolbar-{{ token }}" class="sf-minitoolbar" data-no-turbolink data-turbo="false">
33
<button type="button" title="Show Symfony toolbar" id="sfToolbarMiniToggler-{{ token }}" accesskey="D" aria-expanded="false" aria-controls="sfToolbarMainContent-{{ token }}">
44
{{ source('@WebProfiler/Icon/symfony.svg') }}
55
</button>

Diff for: src/Symfony/Component/ErrorHandler/Resources/views/error.html.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!DOCTYPE html>
2-
<html>
2+
<html lang="en">
33
<head>
44
<meta charset="<?= $this->charset; ?>" />
55
<meta name="robots" content="noindex,nofollow,noarchive" />

Diff for: src/Symfony/Component/Form/Extension/PasswordHasher/EventListener/PasswordHasherListener.php

+38-20
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@
1414
use Symfony\Component\Form\Exception\InvalidConfigurationException;
1515
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
1616
use Symfony\Component\Form\FormEvent;
17+
use Symfony\Component\Form\FormInterface;
1718
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
1819
use Symfony\Component\PropertyAccess\PropertyAccess;
1920
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
2021
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
2122

2223
/**
2324
* @author Sébastien Alfaiate <[email protected]>
25+
* @author Gábor Egyed <[email protected]>
2426
*/
2527
class PasswordHasherListener
2628
{
@@ -35,26 +37,11 @@ public function __construct(
3537

3638
public function registerPassword(FormEvent $event)
3739
{
38-
$form = $event->getForm();
39-
$parentForm = $form->getParent();
40-
$mapped = $form->getConfig()->getMapped();
41-
42-
if ($parentForm && $parentForm->getConfig()->getType()->getInnerType() instanceof RepeatedType) {
43-
$mapped = $parentForm->getConfig()->getMapped();
44-
$parentForm = $parentForm->getParent();
45-
}
46-
47-
if ($mapped) {
48-
throw new InvalidConfigurationException('The "hash_property_path" option cannot be used on mapped field.');
49-
}
50-
51-
if (!($user = $parentForm?->getData()) || !$user instanceof PasswordAuthenticatedUserInterface) {
52-
throw new InvalidConfigurationException(sprintf('The "hash_property_path" option only supports "%s" objects, "%s" given.', PasswordAuthenticatedUserInterface::class, get_debug_type($user)));
53-
}
40+
$this->assertNotMapped($event->getForm());
5441

5542
$this->passwords[] = [
56-
'user' => $user,
57-
'property_path' => $form->getConfig()->getOption('hash_property_path'),
43+
'form' => $event->getForm(),
44+
'property_path' => $event->getForm()->getConfig()->getOption('hash_property_path'),
5845
'password' => $event->getData(),
5946
];
6047
}
@@ -69,14 +56,45 @@ public function hashPasswords(FormEvent $event)
6956

7057
if ($form->isValid()) {
7158
foreach ($this->passwords as $password) {
59+
$user = $this->getUser($password['form']);
60+
7261
$this->propertyAccessor->setValue(
73-
$password['user'],
62+
$user,
7463
$password['property_path'],
75-
$this->passwordHasher->hashPassword($password['user'], $password['password'])
64+
$this->passwordHasher->hashPassword($user, $password['password'])
7665
);
7766
}
7867
}
7968

8069
$this->passwords = [];
8170
}
71+
72+
private function getTargetForm(FormInterface $form): FormInterface
73+
{
74+
$parent = $form->getParent();
75+
76+
if ($parent && $parent->getConfig()->getType()->getInnerType() instanceof RepeatedType) {
77+
return $parent;
78+
}
79+
80+
return $form;
81+
}
82+
83+
private function getUser(FormInterface $form): PasswordAuthenticatedUserInterface
84+
{
85+
$parent = $this->getTargetForm($form)->getParent();
86+
87+
if (!($user = $parent?->getData()) || !$user instanceof PasswordAuthenticatedUserInterface) {
88+
throw new InvalidConfigurationException(sprintf('The "hash_property_path" option only supports "%s" objects, "%s" given.', PasswordAuthenticatedUserInterface::class, get_debug_type($user)));
89+
}
90+
91+
return $user;
92+
}
93+
94+
private function assertNotMapped(FormInterface $form): void
95+
{
96+
if ($this->getTargetForm($form)->getConfig()->getMapped()) {
97+
throw new InvalidConfigurationException('The "hash_property_path" option cannot be used on mapped field.');
98+
}
99+
}
82100
}

Diff for: src/Symfony/Component/Form/Tests/Extension/PasswordHasher/Type/PasswordTypePasswordHasherExtensionTest.php

+36
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,42 @@ public function testPasswordHashSuccess()
7777
$this->assertSame($user->getPassword(), $hashedPassword);
7878
}
7979

80+
public function testPasswordHashSuccessWitnEmptyData()
81+
{
82+
$user = new User();
83+
84+
$plainPassword = 'PlainPassword';
85+
$hashedPassword = 'HashedPassword';
86+
87+
$this->passwordHasher
88+
->expects($this->once())
89+
->method('hashPassword')
90+
->with($user, $plainPassword)
91+
->willReturn($hashedPassword)
92+
;
93+
94+
$this->assertNull($user->getPassword());
95+
96+
$form = $this->factory
97+
->createBuilder('Symfony\Component\Form\Extension\Core\Type\FormType', null, [
98+
'data_class' => User::class,
99+
'empty_data' => function () use ($user) {
100+
return $user;
101+
},
102+
])
103+
->add('plainPassword', 'Symfony\Component\Form\Extension\Core\Type\PasswordType', [
104+
'hash_property_path' => 'password',
105+
'mapped' => false,
106+
])
107+
->getForm()
108+
;
109+
110+
$form->submit(['plainPassword' => $plainPassword]);
111+
112+
$this->assertTrue($form->isValid());
113+
$this->assertSame($user->getPassword(), $hashedPassword);
114+
}
115+
80116
public function testPasswordHashOnInvalidForm()
81117
{
82118
$user = new User();

Diff for: src/Symfony/Component/Mailer/Bridge/MailPace/Tests/Transport/MailPaceApiTransportTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ public function testSend()
9999

100100
public function testSendThrowsForErrorResponse()
101101
{
102-
$client = new MockHttpClient(static fn (string $method, string $url, array $options): ResponseInterface => new MockResponse(json_encode(['Message' => 'i\'m a teapot', 'ErrorCode' => 418]), [
102+
$client = new MockHttpClient(static fn (string $method, string $url, array $options): ResponseInterface => new MockResponse(json_encode(['error' => 'i\'m a teapot']), [
103103
'http_code' => 418,
104104
'response_headers' => [
105105
'content-type' => 'application/json',

Diff for: src/Symfony/Component/Mailer/Bridge/MailPace/Transport/MailPaceApiTransport.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ protected function doSendApi(SentMessage $sentMessage, Email $email, Envelope $e
6767
}
6868

6969
if (200 !== $statusCode) {
70-
throw new HttpTransportException('Unable to send an email: '.$result['Message'].sprintf(' (code %d).', $result['ErrorCode']), $response);
70+
throw new HttpTransportException('Unable to send an email: '.$result['error'].sprintf(' (code %d).', $statusCode), $response);
7171
}
7272

7373
$sentMessage->setMessageId($result['id']);

Diff for: src/Symfony/Component/PropertyInfo/Extractor/PhpStanExtractor.php

+4
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ public function __construct(array $mutatorPrefixes = null, array $accessorPrefix
6464
throw new \LogicException(sprintf('Unable to use the "%s" class as the "phpdocumentor/type-resolver" package is not installed. Try running composer require "phpdocumentor/type-resolver".', __CLASS__));
6565
}
6666

67+
if (!class_exists(PhpDocParser::class)) {
68+
throw new \LogicException(sprintf('Unable to use the "%s" class as the "phpstan/phpdoc-parser" package is not installed. Try running composer require "phpstan/phpdoc-parser".', __CLASS__));
69+
}
70+
6771
$this->phpStanTypeHelper = new PhpStanTypeHelper();
6872
$this->mutatorPrefixes = $mutatorPrefixes ?? ReflectionExtractor::$defaultMutatorPrefixes;
6973
$this->accessorPrefixes = $accessorPrefixes ?? ReflectionExtractor::$defaultAccessorPrefixes;

Diff for: src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php

+11-11
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public function testParamTagTypeIsOmitted()
5151
$this->assertNull($this->extractor->getTypes(OmittedParamTagTypeDocBlock::class, 'omittedType'));
5252
}
5353

54-
public function invalidTypesProvider()
54+
public static function invalidTypesProvider()
5555
{
5656
return [
5757
'pub' => ['pub', null, null],
@@ -81,7 +81,7 @@ public function testExtractTypesWithNoPrefixes($property, array $type = null)
8181
$this->assertEquals($type, $noPrefixExtractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property));
8282
}
8383

84-
public function typesProvider()
84+
public static function typesProvider()
8585
{
8686
return [
8787
['foo', null, 'Short description.', 'Long description.'],
@@ -139,7 +139,7 @@ public function testExtractCollection($property, array $type = null, $shortDescr
139139
$this->testExtract($property, $type, $shortDescription, $longDescription);
140140
}
141141

142-
public function provideCollectionTypes()
142+
public static function provideCollectionTypes()
143143
{
144144
return [
145145
['iteratorCollection', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Iterator', true, null, new Type(Type::BUILTIN_TYPE_STRING))], null, null],
@@ -203,7 +203,7 @@ public function testExtractTypesWithCustomPrefixes($property, array $type = null
203203
$this->assertEquals($type, $customExtractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property));
204204
}
205205

206-
public function typesWithCustomPrefixesProvider()
206+
public static function typesWithCustomPrefixesProvider()
207207
{
208208
return [
209209
['foo', null, 'Short description.', 'Long description.'],
@@ -244,7 +244,7 @@ public function typesWithCustomPrefixesProvider()
244244
];
245245
}
246246

247-
public function typesWithNoPrefixesProvider()
247+
public static function typesWithNoPrefixesProvider()
248248
{
249249
return [
250250
['foo', null, 'Short description.', 'Long description.'],
@@ -290,7 +290,7 @@ public function testReturnNullOnEmptyDocBlock()
290290
$this->assertNull($this->extractor->getShortDescription(EmptyDocBlock::class, 'foo'));
291291
}
292292

293-
public function dockBlockFallbackTypesProvider()
293+
public static function dockBlockFallbackTypesProvider()
294294
{
295295
return [
296296
'pub' => [
@@ -321,7 +321,7 @@ public function testPropertiesDefinedByTraits(string $property, Type $type)
321321
$this->assertEquals([$type], $this->extractor->getTypes(DummyUsingTrait::class, $property));
322322
}
323323

324-
public function propertiesDefinedByTraitsProvider(): array
324+
public static function propertiesDefinedByTraitsProvider(): array
325325
{
326326
return [
327327
['propertyInTraitPrimitiveType', new Type(Type::BUILTIN_TYPE_STRING)],
@@ -341,7 +341,7 @@ public function testMethodsDefinedByTraits(string $property, Type $type)
341341
$this->assertEquals([$type], $this->extractor->getTypes(DummyUsingTrait::class, $property));
342342
}
343343

344-
public function methodsDefinedByTraitsProvider(): array
344+
public static function methodsDefinedByTraitsProvider(): array
345345
{
346346
return [
347347
['methodInTraitPrimitiveType', new Type(Type::BUILTIN_TYPE_STRING)],
@@ -361,7 +361,7 @@ public function testPropertiesStaticType(string $class, string $property, Type $
361361
$this->assertEquals([$type], $this->extractor->getTypes($class, $property));
362362
}
363363

364-
public function propertiesStaticTypeProvider(): array
364+
public static function propertiesStaticTypeProvider(): array
365365
{
366366
return [
367367
[ParentDummy::class, 'propertyTypeStatic', new Type(Type::BUILTIN_TYPE_OBJECT, false, ParentDummy::class)],
@@ -377,7 +377,7 @@ public function testPropertiesParentType(string $class, string $property, ?array
377377
$this->assertEquals($types, $this->extractor->getTypes($class, $property));
378378
}
379379

380-
public function propertiesParentTypeProvider(): array
380+
public static function propertiesParentTypeProvider(): array
381381
{
382382
return [
383383
[ParentDummy::class, 'parentAnnotationNoParent', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'parent')]],
@@ -398,7 +398,7 @@ public function testExtractConstructorTypes($property, array $type = null)
398398
$this->assertEquals($type, $this->extractor->getTypesFromConstructor('Symfony\Component\PropertyInfo\Tests\Fixtures\ConstructorDummy', $property));
399399
}
400400

401-
public function constructorTypesProvider()
401+
public static function constructorTypesProvider()
402402
{
403403
return [
404404
['date', [new Type(Type::BUILTIN_TYPE_INT)]],

Diff for: src/Symfony/Component/Validator/Test/ConstraintValidatorTestCase.php

+16-10
Original file line numberDiff line numberDiff line change
@@ -131,16 +131,22 @@ protected function createContext()
131131
$context->setNode($this->value, $this->object, $this->metadata, $this->propertyPath);
132132
$context->setConstraint($this->constraint);
133133

134-
$contextualValidator = $this->getMockBuilder(AssertingContextualValidator::class)
135-
->setConstructorArgs([$context])
136-
->setMethods([
137-
'atPath',
138-
'validate',
139-
'validateProperty',
140-
'validatePropertyValue',
141-
'getViolations',
142-
])
143-
->getMock();
134+
$contextualValidatorMockBuilder = $this->getMockBuilder(AssertingContextualValidator::class)
135+
->setConstructorArgs([$context]);
136+
$contextualValidatorMethods = [
137+
'atPath',
138+
'validate',
139+
'validateProperty',
140+
'validatePropertyValue',
141+
'getViolations',
142+
];
143+
// PHPUnit 10 removed MockBuilder::setMethods()
144+
if (method_exists($contextualValidatorMockBuilder, 'onlyMethods')) {
145+
$contextualValidatorMockBuilder->onlyMethods($contextualValidatorMethods);
146+
} else {
147+
$contextualValidatorMockBuilder->setMethods($contextualValidatorMethods);
148+
}
149+
$contextualValidator = $contextualValidatorMockBuilder->getMock();
144150
$contextualValidator->expects($this->any())
145151
->method('atPath')
146152
->willReturnCallback(fn ($path) => $contextualValidator->doAtPath($path));

0 commit comments

Comments
 (0)