Skip to content

Commit d15ed2e

Browse files
committed
Merge branch '8.0' into 8.1
* 8.0: bump required PropertyInfo component patch version [VarDumper] Fix dumper selection for Accept: */* requests [Messenger] fix test file/class name src/Symfony/Component/JsonPath - fix [PropertyInfo] Fix calling same-named method with required args instead of reading public property [Messenger] The component v8.0 is backed by Cadoles, thanks to them! [Serializer] Do not skip nested `null` values when denormalizing
2 parents e880e53 + ea62ddc commit d15ed2e

File tree

10 files changed

+86
-17
lines changed

10 files changed

+86
-17
lines changed

src/Symfony/Component/JsonPath/JsonCrawler.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1097,7 +1097,7 @@ private function isArrayOrObject(mixed $value): bool
10971097
private function normalizeStorage(\stdClass|array $data): array
10981098
{
10991099
return array_map(function ($value) {
1100-
return $value instanceof \stdClass || $value && \is_array($value) ? self::normalizeStorage($value) : $value;
1100+
return $value instanceof \stdClass || $value && \is_array($value) ? $this->normalizeStorage($value) : $value;
11011101
}, (array) $data);
11021102
}
11031103

src/Symfony/Component/Messenger/README.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@ other applications or via message queues.
77
Sponsor
88
-------
99

10-
Help Symfony by [sponsoring][1] its development!
10+
The Messenger component for Symfony 8.0 is [backed][1] by [Cadoles][2].
11+
12+
Cadoles is a French Cooperative and Participative Company (SCOP) providing IT
13+
services based in Dijon. This company is a key player in free software and open
14+
formats, and uses Symfony in its development services for businesses and
15+
institutions.
16+
17+
Help Symfony by [sponsoring][3] its development!
1118

1219
Resources
1320
---------
@@ -18,4 +25,6 @@ Resources
1825
[send Pull Requests](https://github.com/symfony/symfony/pulls)
1926
in the [main Symfony repository](https://github.com/symfony/symfony)
2027

21-
[1]: https://symfony.com/sponsor
28+
[1]: https://symfony.com/backers
29+
[2]: https://www.cadoles.com
30+
[3]: https://symfony.com/sponsor

src/Symfony/Component/Messenger/Tests/Handler/HandleDescriptorTest.php renamed to src/Symfony/Component/Messenger/Tests/Handler/HandlerDescriptorTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
use Symfony\Component\Messenger\Handler\HandlerDescriptor;
1717
use Symfony\Component\Messenger\Tests\Fixtures\DummyCommandHandler;
1818

19-
class HandleDescriptorTest extends TestCase
19+
class HandlerDescriptorTest extends TestCase
2020
{
2121
#[DataProvider('provideHandlers')]
2222
public function testDescriptorNames(callable $handler, ?string $expectedHandlerString)
@@ -42,7 +42,7 @@ public static function provideHandlers(): iterable
4242
public function __invoke()
4343
{
4444
}
45-
}, 'class@anonymous%sHandleDescriptorTest.php%s::__invoke'];
45+
}, 'class@anonymous%sHandlerDescriptorTest.php%s::__invoke'];
4646
}
4747

4848
public function testGetOptions()

src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,21 @@ protected function setUp(): void
5252
$this->propertyAccessor = new PropertyAccessor();
5353
}
5454

55+
public function testPrefersPropertyOverMethodWithSameNameAndRequiredArgs()
56+
{
57+
$obj = new class {
58+
public bool $loaded = true;
59+
60+
// Same name as property, but requires an argument: must NOT be called for reading
61+
public function loaded(string $arg): bool
62+
{
63+
throw new \RuntimeException('Method should not be invoked during property read');
64+
}
65+
};
66+
67+
$this->assertTrue($this->propertyAccessor->getValue($obj, 'loaded'));
68+
}
69+
5570
public static function getPathsWithMissingProperty()
5671
{
5772
return [

src/Symfony/Component/PropertyAccess/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
],
1818
"require": {
1919
"php": ">=8.4",
20-
"symfony/property-info": "^7.4|^8.0"
20+
"symfony/property-info": "^7.4.2|^8.0.3"
2121
},
2222
"require-dev": {
2323
"symfony/cache": "^7.4|^8.0",

src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,10 @@ public function getReadInfo(string $class, string $property, array $context = []
328328

329329
if ($allowGetterSetter && $reflClass->hasMethod($getsetter) && ($reflClass->getMethod($getsetter)->getModifiers() & $this->methodReflectionFlags)) {
330330
$method = $reflClass->getMethod($getsetter);
331-
332-
return new PropertyReadInfo(PropertyReadInfo::TYPE_METHOD, $getsetter, $this->getReadVisibilityForMethod($method), $method->isStatic(), false);
331+
// Only consider jQuery-style accessors when they don't require parameters
332+
if (!$method->getNumberOfRequiredParameters()) {
333+
return new PropertyReadInfo(PropertyReadInfo::TYPE_METHOD, $getsetter, $this->getReadVisibilityForMethod($method), $method->isStatic(), false);
334+
}
333335
}
334336

335337
if ($allowMagicGet && $reflClass->hasMethod('__get') && (($r = $reflClass->getMethod('__get'))->getModifiers() & $this->methodReflectionFlags)) {

src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php

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

1414
use Symfony\Component\PropertyAccess\Exception\InvalidArgumentException as PropertyAccessInvalidArgumentException;
1515
use Symfony\Component\PropertyAccess\Exception\InvalidTypeException;
16+
use Symfony\Component\PropertyAccess\Exception\NoSuchIndexException;
1617
use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException;
1718
use Symfony\Component\PropertyAccess\Exception\UninitializedPropertyException;
1819
use Symfony\Component\PropertyAccess\PropertyAccess;
@@ -322,15 +323,16 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
322323

323324
$nestedAttributes = $this->getNestedAttributes($mappedClass);
324325
$nestedData = $originalNestedData = [];
325-
$propertyAccessor = PropertyAccess::createPropertyAccessor();
326+
$propertyAccessor = PropertyAccess::createPropertyAccessorBuilder()->enableExceptionOnInvalidIndex()->getPropertyAccessor();
326327
foreach ($nestedAttributes as $property => $serializedPath) {
327-
if (null === $value = $propertyAccessor->getValue($normalizedData, $serializedPath)) {
328-
continue;
328+
try {
329+
$value = $propertyAccessor->getValue($normalizedData, $serializedPath);
330+
$convertedProperty = $this->nameConverter ? $this->nameConverter->normalize($property, $mappedClass, $format, $context) : $property;
331+
$nestedData[$convertedProperty] = $value;
332+
$originalNestedData[$property] = $value;
333+
$normalizedData = $this->removeNestedValue($serializedPath->getElements(), $normalizedData);
334+
} catch (NoSuchIndexException) {
329335
}
330-
$convertedProperty = $this->nameConverter ? $this->nameConverter->normalize($property, $mappedClass, $format, $context) : $property;
331-
$nestedData[$convertedProperty] = $value;
332-
$originalNestedData[$property] = $value;
333-
$normalizedData = $this->removeNestedValue($serializedPath->getElements(), $normalizedData);
334336
}
335337

336338
$normalizedData = $nestedData + $normalizedData;

src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,29 @@ public function testDenormalizeWithCorrectOrderOfAttributeAndProperty()
958958
$this->assertSame('nested-id', $test->id);
959959
}
960960

961+
public function testDenormalizeMissingAndNullNestedValues()
962+
{
963+
$normalizer = new AbstractObjectNormalizerWithMetadata();
964+
965+
$data = [
966+
'data' => [
967+
'foo' => null,
968+
],
969+
];
970+
971+
$obj = new class {
972+
#[SerializedPath('[data][foo]')]
973+
public ?string $foo;
974+
975+
#[SerializedPath('[data][bar]')]
976+
public ?string $bar;
977+
};
978+
979+
$test = $normalizer->denormalize($data, $obj::class);
980+
$this->assertNull($test->foo);
981+
$this->assertFalse((new \ReflectionProperty($obj, 'bar'))->isInitialized($obj));
982+
}
983+
961984
public function testNormalizeBasedOnAllowedAttributes()
962985
{
963986
$normalizer = new class extends AbstractObjectNormalizer {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
Test dump() with "Accept: */*" uses HTML dumper
3+
--FILE--
4+
<?php
5+
putenv('NO_COLOR=1');
6+
7+
$vendor = __DIR__;
8+
while (!file_exists($vendor.'/vendor')) {
9+
$vendor = \dirname($vendor);
10+
}
11+
require $vendor.'/vendor/autoload.php';
12+
13+
$_SERVER['HTTP_ACCEPT'] = '*/*';
14+
dump('Test with wildcard');
15+
--EXPECTF--
16+
%a>Test with wildcard</%a

src/Symfony/Component/VarDumper/VarDumper.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,13 @@ private static function register(): void
7676
case 'server' === $format:
7777
case $format && 'tcp' === parse_url($format, \PHP_URL_SCHEME):
7878
$host = 'server' === $format ? $_SERVER['VAR_DUMPER_SERVER'] ?? '127.0.0.1:9912' : $format;
79-
$dumper = str_contains($_SERVER['HTTP_ACCEPT'] ?? (\in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true) ? 'txt' : 'html'), 'html') ? new HtmlDumper() : new CliDumper();
79+
$accept = $_SERVER['HTTP_ACCEPT'] ?? (\in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true) ? 'txt' : 'html');
80+
$dumper = str_contains($accept, 'html') || str_contains($accept, '*/*') ? new HtmlDumper() : new CliDumper();
8081
$dumper = new ServerDumper($host, $dumper, self::getDefaultContextProviders());
8182
break;
8283
default:
83-
$dumper = str_contains($_SERVER['HTTP_ACCEPT'] ?? (\in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true) ? 'txt' : 'html'), 'html') ? new HtmlDumper() : new CliDumper();
84+
$accept = $_SERVER['HTTP_ACCEPT'] ?? (\in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true) ? 'txt' : 'html');
85+
$dumper = str_contains($accept, 'html') || str_contains($accept, '*/*') ? new HtmlDumper() : new CliDumper();
8486
}
8587

8688
if (!$dumper instanceof ServerDumper) {

0 commit comments

Comments
 (0)