Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit af01e99

Browse files
Merge branch '7.3' into 7.4
* 7.3: [HttpClient] Fix ever growing $maxHostConnections Fix typo [DependencyInjection] Fix referencing build-time array parameters cs fix [FrameworkBundle] Fix cache:pool:prune exit code on failure [Form] Always normalize CRLF and CR to LF in `TextareaType` [Cache] Fix stampede protection when forcing item recomputation [Console] Fix EofShortcut instruction when using a modern terminal on Windows [Console] Do not call non-static method via class-name [Console] Fix choice autocomplete issue when string has spaces Update SameOriginCsrfTokenManager.php [Serializer] Fix inconsistent field naming from accessors when using groups [Finder] Fix converting unanchored glob patterns to regex
2 parents c302114 + e6769b1 commit af01e99

4 files changed

Lines changed: 86 additions & 15 deletions

File tree

Mapping/Loader/AttributeLoader.php

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -138,14 +138,30 @@ private function doLoadClassMetadata(\ReflectionClass $reflectionClass, ClassMet
138138
if ($method->getDeclaringClass()->name !== $className) {
139139
continue;
140140
}
141+
$name = $method->name;
141142

142-
if (0 === stripos($method->name, 'get') && $method->getNumberOfRequiredParameters()) {
143+
if (0 === stripos($name, 'get') && $method->getNumberOfRequiredParameters()) {
143144
continue; /* matches the BC behavior in `Symfony\Component\Serializer\Normalizer\ObjectNormalizer::extractAttributes` */
144145
}
145146

146-
$accessorOrMutator = preg_match('/^(get|is|has|set|can)(.+)$/i', $method->name, $matches);
147-
if ($accessorOrMutator && !ctype_lower($matches[2][0])) {
148-
$attributeName = lcfirst($matches[2]);
147+
$accessorOrMutator = match ($name[0]) {
148+
's' => str_starts_with($name, 'set') && isset($name[$i = 3]),
149+
'g' => str_starts_with($name, 'get') && isset($name[$i = 3]),
150+
'h' => str_starts_with($name, 'has') && isset($name[$i = 3]),
151+
'c' => str_starts_with($name, 'can') && isset($name[$i = 3]),
152+
'i' => str_starts_with($name, 'is') && isset($name[$i = 2]),
153+
default => false,
154+
};
155+
if ($accessorOrMutator && !ctype_lower($name[$i])) {
156+
if ($this->hasProperty($method->getDeclaringClass(), $name)) {
157+
$attributeName = $name;
158+
} else {
159+
$attributeName = substr($name, $i);
160+
161+
if (!$reflectionClass->hasProperty($attributeName)) {
162+
$attributeName = lcfirst($attributeName);
163+
}
164+
}
149165

150166
if (isset($attributesMetadata[$attributeName])) {
151167
$attributeMetadata = $attributesMetadata[$attributeName];
@@ -158,27 +174,27 @@ private function doLoadClassMetadata(\ReflectionClass $reflectionClass, ClassMet
158174
foreach ($this->loadAttributes($method) as $attribute) {
159175
if ($attribute instanceof Groups) {
160176
if (!$accessorOrMutator) {
161-
throw new MappingException(\sprintf('Groups on "%s::%s()" cannot be added. Groups can only be added on methods beginning with "get", "is", "has" or "set".', $className, $method->name));
177+
throw new MappingException(\sprintf('Groups on "%s::%s()" cannot be added. Groups can only be added on methods beginning with "get", "is", "has", "can" or "set".', $className, $method->name));
162178
}
163179

164180
foreach ($attribute->groups as $group) {
165181
$attributeMetadata->addGroup($group);
166182
}
167183
} elseif ($attribute instanceof MaxDepth) {
168184
if (!$accessorOrMutator) {
169-
throw new MappingException(\sprintf('MaxDepth on "%s::%s()" cannot be added. MaxDepth can only be added on methods beginning with "get", "is", "has" or "set".', $className, $method->name));
185+
throw new MappingException(\sprintf('MaxDepth on "%s::%s()" cannot be added. MaxDepth can only be added on methods beginning with "get", "is", "has", "can" or "set".', $className, $method->name));
170186
}
171187

172188
$attributeMetadata->setMaxDepth($attribute->maxDepth);
173189
} elseif ($attribute instanceof SerializedName) {
174190
if (!$accessorOrMutator) {
175-
throw new MappingException(\sprintf('SerializedName on "%s::%s()" cannot be added. SerializedName can only be added on methods beginning with "get", "is", "has" or "set".', $className, $method->name));
191+
throw new MappingException(\sprintf('SerializedName on "%s::%s()" cannot be added. SerializedName can only be added on methods beginning with "get", "is", "has", "can" or "set".', $className, $method->name));
176192
}
177193

178194
$attributeMetadata->setSerializedName($attribute->serializedName);
179195
} elseif ($attribute instanceof SerializedPath) {
180196
if (!$accessorOrMutator) {
181-
throw new MappingException(\sprintf('SerializedPath on "%s::%s()" cannot be added. SerializedPath can only be added on methods beginning with "get", "is", "has" or "set".', $className, $method->name));
197+
throw new MappingException(\sprintf('SerializedPath on "%s::%s()" cannot be added. SerializedPath can only be added on methods beginning with "get", "is", "has", "can" or "set".', $className, $method->name));
182198
}
183199

184200
$attributeMetadata->setSerializedPath($attribute->serializedPath);
@@ -188,7 +204,7 @@ private function doLoadClassMetadata(\ReflectionClass $reflectionClass, ClassMet
188204
}
189205
} elseif ($attribute instanceof Context) {
190206
if (!$accessorOrMutator) {
191-
throw new MappingException(\sprintf('Context on "%s::%s()" cannot be added. Context can only be added on methods beginning with "get", "is", "has" or "set".', $className, $method->name));
207+
throw new MappingException(\sprintf('Context on "%s::%s()" cannot be added. Context can only be added on methods beginning with "get", "is", "has", "can" or "set".', $className, $method->name));
192208
}
193209

194210
$this->setAttributeContextsForGroups($attribute, $attributeMetadata);
@@ -250,4 +266,15 @@ private function isKnownAttribute(string $attributeName): bool
250266

251267
return false;
252268
}
269+
270+
private function hasProperty(\ReflectionClass $class, string $propName): bool
271+
{
272+
do {
273+
if ($class->hasProperty($propName)) {
274+
return true;
275+
}
276+
} while ($class = $class->getParentClass());
277+
278+
return false;
279+
}
253280
}

Normalizer/ObjectNormalizer.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ protected function extractAttributes(object $object, ?string $format = null, arr
9595
'i' => str_starts_with($name, 'is') && isset($name[$i = 2]),
9696
default => false,
9797
} && !ctype_lower($name[$i])) {
98-
if ($this->hasProperty($reflMethod, $name)) {
98+
if ($this->hasProperty($reflMethod->getDeclaringClass(), $name)) {
9999
$attributeName = $name;
100100
} else {
101101
$attributeName = substr($name, $i);
@@ -127,10 +127,8 @@ protected function extractAttributes(object $object, ?string $format = null, arr
127127
return array_keys($attributes);
128128
}
129129

130-
private function hasProperty(\ReflectionMethod $method, string $propName): bool
130+
private function hasProperty(\ReflectionClass $class, string $propName): bool
131131
{
132-
$class = $method->getDeclaringClass();
133-
134132
do {
135133
if ($class->hasProperty($propName)) {
136134
return true;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Serializer\Tests\Fixtures\Attributes;
13+
14+
use Symfony\Component\Serializer\Attribute\Groups;
15+
16+
class GroupDummyWithIsPrefixedProperty
17+
{
18+
private bool $isSomething = false;
19+
20+
#[Groups(['test'])]
21+
public function isSomething(): bool
22+
{
23+
return $this->isSomething;
24+
}
25+
26+
public function setIsSomething(bool $isSomething): void
27+
{
28+
$this->isSomething = $isSomething;
29+
}
30+
}

Tests/Normalizer/ObjectNormalizerTest.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
use Symfony\Component\Serializer\Serializer;
4141
use Symfony\Component\Serializer\SerializerInterface;
4242
use Symfony\Component\Serializer\Tests\Fixtures\Attributes\GroupDummy;
43+
use Symfony\Component\Serializer\Tests\Fixtures\Attributes\GroupDummyWithIsPrefixedProperty;
4344
use Symfony\Component\Serializer\Tests\Fixtures\CircularReferenceDummy;
4445
use Symfony\Component\Serializer\Tests\Fixtures\DummyPrivatePropertyWithoutGetter;
4546
use Symfony\Component\Serializer\Tests\Fixtures\DummyWithUnion;
@@ -1139,8 +1140,7 @@ public function testNormalizeChildWithPropertySameAsParentMethod()
11391140

11401141
$this->assertSame([
11411142
'foo' => 'foo',
1142-
],
1143-
$normalized);
1143+
], $normalized);
11441144
}
11451145

11461146
/**
@@ -1196,6 +1196,22 @@ public function testDiscriminatorWithAllowExtraAttributesFalse()
11961196

11971197
$this->assertInstanceOf(DiscriminatorDummyTypeA::class, $obj);
11981198
}
1199+
1200+
public function testNormalizeObjectWithGroupsAndIsPrefixedProperty()
1201+
{
1202+
$classMetadataFactory = new ClassMetadataFactory(new AttributeLoader());
1203+
$normalizer = new ObjectNormalizer($classMetadataFactory);
1204+
$serializer = new Serializer([$normalizer]);
1205+
$normalizer->setSerializer($serializer);
1206+
1207+
$object = new GroupDummyWithIsPrefixedProperty();
1208+
1209+
$normalizedWithoutGroups = $normalizer->normalize($object);
1210+
$this->assertArrayHasKey('isSomething', $normalizedWithoutGroups);
1211+
1212+
$normalizedWithGroups = $normalizer->normalize($object, null, [AbstractNormalizer::GROUPS => ['test']]);
1213+
$this->assertArrayHasKey('isSomething', $normalizedWithGroups);
1214+
}
11991215
}
12001216

12011217
class ProxyObjectDummy extends ObjectDummy

0 commit comments

Comments
 (0)