8000 Merge branch '6.4' into 7.0 · symfony/symfony@adcadd1 · GitHub
[go: up one dir, main page]

Skip to content

Commit adcadd1

Browse files
committed
Merge branch '6.4' into 7.0
* 6.4: relax assertions for ICU 72.1 [Validator] Fix regression with class metadatada on parent classes [Intl] Fixed directory traversal in emoji compression tool [VarExporter] Fix exporting classes with __serialize() but not __unserialize() [HttpFoundation][HttpKernel] Fix deprecations when `Content-Type` is `null`
2 parents ab06dca + b15e258 commit adcadd1

File tree

18 files changed

+137
-43
lines changed

18 files changed

+137
-43
lines changed

.github/workflows/intl-data-tests.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,11 @@ jobs:
8484
run: |
8585
[ -f src/Symfony/Component/Intl/Resources/data/locales/en.php ]
8686
[ ! -f src/Symfony/Component/Intl/Resources/data/locales/en.php.gz ]
87+
[ -f src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-en.php ]
88+
[ ! -f src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-en.php.gz ]
8789
src/Symfony/Component/Intl/Resources/bin/compress
8890
[ ! -f src/Symfony/Component/Intl/Resources/data/locales/en.php ]
8991
[ -f src/Symfony/Component/Intl/Resources/data/locales/en.php.gz ]
92+
[ ! -f src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-en.php ]
93+
[ -f src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-en.php.gz ]
9094
./phpunit src/Symfony/Component/Intl

src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ public function loadClassMetadata(ClassMetadata $metadata): bool
105105
if (isset($mapping['originalClass']) && !str_contains($mapping['declaredField'], '.')) {
106106
$metadata->addPropertyConstraint($mapping['declaredField'], new Valid());
107107
$loaded = true;
108-
} elseif (property_exists($className, $mapping['fieldName'])) {
108+
} elseif (property_exists($className, $mapping['fieldName']) && (!$doctrineMetadata->isMappedSuperclass || $metadata->getReflectionClass()->getProperty($mapping['fieldName'])->isPrivate())) {
109109
$metadata->addPropertyConstraint($mapping['fieldName'], new Length(['max' => $mapping['length']]));
110110
$loaded = true;
111111
}

src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ public function testTransformToDifferentLocale()
124124

125125
$transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC');
126126

127-
$this->assertEquals('Feb 3, 2010, 4:05 AM', $transformer->transform($this->dateTime));
127+
$this->assertMatchesRegularExpression('/^Feb 3, 2010, 4:05\s+AM$/u', $transformer->transform($this->dateTime));
128128
}
129129

130130
public function testTransformEmpty()

src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ public function testSingleTextWidgetWithCustomNonHtml5Format()
537537
]);
538538
$view = $form->createView();
539539

540-
$this->assertSame('2/13/19, 7:12:13 PM', $view->vars['value']);
540+
$this->assertMatchesRegularExpression('#^2/13/19, 7:12:13\s+PM$#u', $view->vars['value']);
541541
}
542542

543543
public function testDateTypeChoiceErrorsBubbleUp()

src/Symfony/Component/HttpFoundation/Response.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ public function prepare(Request $request): static
286286
$charset = $this->charset ?: 'UTF-8';
287287
if (!$headers->has('Content-Type')) {
288288
$headers->set('Content-Type', 'text/html; charset='.$charset);
289-
} elseif (0 === stripos($headers->get('Content-Type'), 'text/') && false === stripos($headers->get('Content-Type'), 'charset')) {
289+
} elseif (0 === stripos($headers->get('Content-Type') ?? '', 'text/') && false === stripos($headers->get('Content-Type') ?? '', 'charset')) {
290290
// add the charset
291291
$headers->set('Content-Type', $headers->get('Content-Type').'; charset='.$charset);
292292
}

src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,16 @@ public function testContentTypeCharset()
548548
$this->assertEquals('text/css; charset=UTF-8', $response->headers->get('Content-Type'));
549549
}
550550

551+
public function testContentTypeIsNull()
552+
{
553+
$response = new Response('foo');
554+
$response->headers->set('Content-Type', null);
555+
556+
$response->prepare(new Request());
557+
558+
$this->expectNotToPerformAssertions();
559+
}
560+
551561
public function testPrepareDoesNothingIfContentTypeIsSet()
552562
{
553563
$response = new Response('foo');

src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,11 @@ public function collect(Request $request, Response $response, \Throwable $except
113113
if (!$this->requestStack
114114
|| !$response->headers->has('X-Debug-Token')
115115
|| $response->isRedirection()
116-
|| ($response->headers->has('Content-Type') && !str_contains($response->headers->get('Content-Type'), 'html'))
116+
|| ($response->headers->has('Content-Type') && !str_contains($response->headers->get('Content-Type') ?? '', 'html'))
117117
|| 'html' !== $request->getRequestFormat()
118118
|| false === strripos($response->getContent(), '</body>')
119119
) {
120-
if ($response->headers->has('Content-Type') && str_contains($response->headers->get('Content-Type'), 'html')) {
120+
if ($response->headers->has('Content-Type') && str_contains($response->headers->get('Content-Type') ?? '', 'html')) {
121121
$dumper = new HtmlDumper('php://output', $this->charset);
122122
$dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
123123
} else {

src/Symfony/Component/HttpKernel/Tests/DataCollector/DumpDataCollectorTest.php

Lines changed: 19 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\HttpFoundation\Request;
16+
use Symfony\Component\HttpFoundation\RequestStack;
1617
use Symfony\Component\HttpFoundation\Response;
1718
use Symfony\Component\HttpKernel\DataCollector\DumpDataCollector;
1819
use Symfony\Component\HttpKernel\Debug\FileLinkFormatter;
@@ -158,4 +159,22 @@ public function testFlushNothingWhenDataDumperIsProvided()
158159
$collector->__destruct();
159160
$this->assertEmpty(ob_get_clean());
160161
}
162+
163+
public function testNullContentTypeWithNoDebugEnv()
164+
{
165+
$request = new Request();
166+
$requestStack = new RequestStack();
167+
$requestStack->push($request);
168+
169+
$response = new Response('<html><head></head><body></body></html>');
170+
$response->headers->set('Content-Type', null);
171+
$response->headers->set('X-Debug-Token', 'xxxxxxxx');
172+
173+
$collector = new DumpDataCollector(null, null, null, $requestStack);
174+
$collector->collect($request, $response);
175+
176+
ob_start();
177+
$collector->__destruct();
178+
$this->assertEmpty(ob_get_clean());
179+
}
161180
}

src/Symfony/Component/Intl/Resources/bin/compress

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,15 @@ if (!extension_loaded('zlib')) {
1717
throw new Exception('This script requires the zlib extension.');
1818
}
1919

20-
foreach (glob(dirname(__DIR__).'/data/*/*.php') as $file) {
21-
if ('meta.php' === basename($file)) {
20+
$iterator = new RecursiveIteratorIterator(
21+
new RecursiveDirectoryIterator(
22+
dirname(__DIR__).'/data',
23+
FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::SKIP_DOTS
24+
)
25+
);
26+
27+
foreach ($iterator as $file) {
28+
if ('php' !== $file->getExtension() || 'meta.php' === $file->getFilename()) {
2229
continue;
2330
}
2431

src/Symfony/Component/Validator/Mapping/Clas 10000 sMetadata.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -346,11 +346,11 @@ public function mergeConstraints(self $source): void
346346

347347
if ($member instanceof MemberMetadata && !$member->isPrivate($this->name)) {
348348
$property = $member->getPropertyName();
349-
$this->members[$property] = [$member];
349+
$this->members[$property][] = $member;
350350

351-
if ($member instanceof PropertyMetadata) {
351+
if ($member instanceof PropertyMetadata && !isset($this->properties[$property])) {
352352
$this->properties[$property] = $member;
353-
} elseif ($member instanceof GetterMetadata) {
353+
} elseif ($member instanceof GetterMetadata && !isset($this->getters[$property])) {
354354
$this->getters[$property] = $member;
355355
}
356356
} else {

src/Symfony/Component/Validator/Tests/Fixtures/Annotation/Entity.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ class Entity extends EntityParent implements EntityInterfaceB
5555
private $internal;
5656
public $data = 'Overridden data';
5757
public $initialized = false;
58+
/**
59+
* @Assert\Type("integer")
60+
*/
61+
protected $other;
5862

5963
public function __construct($internal = null)
6064
{

src/Symfony/Component/Validator/Tests/Fixtures/Attribute/Entity.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ class Entity extends EntityParent implements EntityInterfaceB
5757
private $internal;
5858
public $data = 'Overridden data';
5959
public $initialized = false;
60+
#[Assert\Type('integer')]
61+
protected $other;
6062

6163
public function __construct($internal = null)
6264
{

src/Symfony/Component/Validator/Tests/Fixtures/NestedAttribute/Entity.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ class Entity extends EntityParent implements EntityInterfaceB
7878
private $internal;
7979
public $data = 'Overridden data';
8080
public $initialized = false;
81+
#[Assert\Type('integer')]
82+
protected $other;
8183

8284
public function __construct($internal = null)
8385
{

src/Symfony/Component/Validator/Tests/Mapping/ClassMetadataTest.php

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,8 @@ public function testMergeConstraintsMergesMemberConstraints()
163163
$parent->addPropertyConstraint('firstName', new ConstraintA());
164164
$parent->addPropertyConstraint('firstName', new ConstraintB(['groups' => 'foo']));
165165

166-
$this->metadata->mergeConstraints($parent);
167166
$this->metadata->addPropertyConstraint('firstName', new ConstraintA());
167+
$this->metadata->mergeConstraints($parent);
168168

169169
$constraintA1 = new ConstraintA(['groups' => [
170170
'Default',
@@ -179,35 +179,29 @@ public function testMergeConstraintsMergesMemberConstraints()
179179
'groups' => ['foo'],
180180
]);
181181

182-
$constraints = [
183-
$constraintA1,
184-
$constraintB,
185-
$constraintA2,
186-
];
182+
$members = $this->metadata->getPropertyMetadata('firstName');
187183

188-
$constraintsByGroup = [
189-
'Default' => [
190-
$constraintA1,
191-
$constraintA2,
192-
],
193-
'EntityParent' => [
194-
$constraintA1,
195-
],
196-
'Entity' => [
197-
$constraintA1,
198-
$constraintA2,
184+
$this->assertCount(2, $members);
185+
$this->assertEquals(self::CLASSNAME, $members[0]->getClassName());
186+
$this->assertEquals([$constraintA2], $members[0]->getConstraints());
187+
$this->assertEquals(
188+
[
189+
'Default' => [$constraintA2],
190+
'Entity' => [$constraintA2],
199191
],
200-
'foo' => [
201-
$constraintB,
192+
$members[0]->constraintsByGroup
193+
);
194+
$this->assertEquals(self::PARENTCLASS, $members[1]->getClassName());
195+
$this->assertEquals([$constraintA1, $constraintB], $members[1]->getConstraints());
196+
$this->assertEquals(
197+
[
198+
'Default' => [$constraintA1],
199+
'Entity' => [$constraintA1],
200+
'EntityParent' => [$constraintA1],
201+
'foo' => [$constraintB],
202202
],
203-
];
204-
205-
$members = $this->metadata->getPropertyMetadata('firstName');
206-
207-
$this->assertCount(1, $members);
208-
$this->assertEquals(self::PARENTCLASS, $members[0]->getClassName());
209-
$this->assertEquals($constraints, $members[0]->getConstraints());
210-
$this->assertEquals($constraintsByGroup, $members[0]->constraintsByGroup);
203+
$members[1]->constraintsByGroup
204+
);
211205
}
212206

213207
public function testMemberMetadatas()

src/Symfony/Component/Validator/Tests/Mapping/Loader/AnnotationLoaderTest.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
use Symfony\Component\Validator\Constraints\Range;
2828
use Symfony\Component\Validator\Constraints\Required;
2929
use Symfony\Component\Validator\Constraints\Sequentially;
30+
use Symfony\Component\Validator\Constraints\Type;
3031
use Symfony\Component\Validator\Constraints\Valid;
3132
use Symfony\Component\Validator\Mapping\ClassMetadata;
3233
use Symfony\Component\Validator\Mapping\Loader\AnnotationLoader;
@@ -98,6 +99,7 @@ public function testLoadClassMetadata(string $namespace)
9899
$expected->addGetterConstraint('lastName', new NotNull());
99100
$expected->addGetterMethodConstraint('valid', 'isValid', new IsTrue());
100101
$expected->addGetterConstraint('permissions', new IsTrue());
102+
$expected->addPropertyConstraint('other', new Type('integer'));
101103

102104
// load reflection class so that the comparison passes
103105
$expected->getReflectionClass();
@@ -139,18 +141,16 @@ public function testLoadClassMetadataAndMerge(string $namespace)
139141
$loader->loadClassMetadata($parent_metadata);
140142

141143
$metadata = new ClassMetadata($namespace.'\Entity');
144+
$loader->loadClassMetadata($metadata);
142145

143146
// Merge parent metaData.
144147
$metadata->mergeConstraints($parent_metadata);
145148

146-
$loader->loadClassMetadata($metadata);
147-
148149
$expected_parent = new ClassMetadata($namespace.'\EntityParent');
149150
$expected_parent->addPropertyConstraint('other', new NotNull());
150151
$expected_parent->getReflectionClass();
151152

152153
$expected = new ClassMetadata($namespace.'\Entity');
153-
$expected->mergeConstraints($expected_parent);
154154

155155
$expected->setGroupSequence(['Foo', 'Entity']);
156156
$expected->addConstraint(new ConstraintA());
@@ -187,11 +187,18 @@ public function testLoadClassMetadataAndMerge(string $namespace)
187187
$expected->addGetterConstraint('lastName', new NotNull());
188188
$expected->addGetterMethodConstraint('valid', 'isValid', new IsTrue());
189189
$expected->addGetterConstraint('permissions', new IsTrue());
190+
$expected->addPropertyConstraint('other', new Type('integer'));
190191

191192
// load reflection class so that the comparison passes
192193
$expected->getReflectionClass();
194+
$expected->mergeConstraints($expected_parent);
193195

194196
$this->assertEquals($expected, $metadata);
197+
198+
$otherMetadata = $metadata->getPropertyMetadata('other');
199+
$this->assertCount(2, $otherMetadata);
200+
$this->assertInstanceOf(Type::class, $otherMetadata[0]->getConstraints()[0]);
201+
$this->assertInstanceOf(NotNull::class, $otherMetadata[1]->getConstraints()[0]);
195202
}
196203

197204
/**

src/Symfony/Component/VarExporter/Internal/Exporter.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,20 +75,29 @@ public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount
7575

7676
$class = $value::class;
7777
$reflector = Registry::$reflectors[$class] ??= Registry::getClassReflector($class);
78+
$properties = [];
7879

7980
if ($reflector->hasMethod('__serialize')) {
8081
if (!$reflector->getMethod('__serialize')->isPublic()) {
8182
throw new \Error(sprintf('Call to %s method "%s::__serialize()".', $reflector->getMethod('__serialize')->isProtected() ? 'protected' : 'private', $class));
8283
}
8384

84-
if (!\is_array($properties = $value->__serialize())) {
85+
if (!\is_array($serializeProperties = $value->__serialize())) {
8586
throw new \TypeError($class.'::__serialize() must return an array');
8687
}
8788

89+
if ($reflector->hasMethod('__unserialize')) {
90+
$properties = $serializeProperties;
91+
} else {
92+
foreach ($serializeProperties as $n => $v) {
93+
$c = \PHP_VERSION_ID >= 80100 && $reflector->hasProperty($n) && ($p = $reflector->getProperty($n))->isReadOnly() ? $p->class : 'stdClass';
94+
$properties[$c][$n] = $v;
95+
}
96+
}
97+
8898
goto prepare_value;
8999
}
90100

91-
$properties = [];
92101
$sleep = null;
93102
$proto = Registry::$prototypes[$class];
94103

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate(
4+
$o = [
5+
clone (\Symfony\Component\VarExporter\Internal\Registry::$prototypes['Symfony\\Component\\VarExporter\\Tests\\__SerializeButNo__Unserialize'] ?? \Symfony\Component\VarExporter\Internal\Registry::p('Symfony\\Component\\VarExporter\\Tests\\__SerializeButNo__Unserialize')),
6+
],
7+
null,
8+
[
9+
'stdClass' => [
10+
'foo' => [
11+
'ccc',
12+
],
13+
],
14+
],
15+
$o[0],
16+
[]
17+
);

src/Symfony/Component/VarExporter/Tests/VarExporterTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,8 @@ public static function provideExport()
231231

232232
yield ['__unserialize-but-no-__serialize', new __UnserializeButNo__Serialize()];
233233

234+
yield ['__serialize-but-no-__unserialize', new __SerializeButNo__Unserialize()];
235+
234236
yield ['unit-enum', [FooUnitEnum::Bar], true];
235237
yield ['readonly', new FooReadonly('k', 'v')];
236238
}
@@ -450,3 +452,20 @@ public function __unserialize(array $data): void
450452
$this->foo = $data['foo'];
451453
}
452454
}
455+
456+
class __SerializeButNo__Unserialize
457+
{
458+
public $foo;
459+
460+
public function __construct()
461+
{
462+
$this->foo = 'ccc';
463+
}
464+
465+
public function __serialize(): array
466+
{
467+
return [
468+
'foo' => $this->foo,
469+
];
470+
}
471+
}

0 commit comments

Comments
 (0)
0