Skip to content

Commit 391e9df

Browse files
committed
Denormalize Input Class with Different Fields
Fixes the bug where AbstractItemSerializer would use the resource class instead of the input class to determine allowed properties. Enforced `$context['resource_class']` to be set to current denormalized class to resolve issue. Figured this should be the case since AbstractItemNormalizer only works on resources. Signed-off-by: RJ Garcia <[email protected]>
1 parent bcfc1c4 commit 391e9df

File tree

4 files changed

+135
-3
lines changed

4 files changed

+135
-3
lines changed

src/Serializer/AbstractItemNormalizer.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,7 @@ public function supportsDenormalization($data, $type, $format = null)
128128
public function denormalize($data, $class, $format = null, array $context = [])
129129
{
130130
$context['api_denormalize'] = true;
131-
if (!isset($context['resource_class'])) {
132-
$context['resource_class'] = $class;
133-
}
131+
$context['resource_class'] = $class;
134132

135133
return parent::denormalize($data, $class, $format, $context);
136134
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[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+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity;
15+
16+
use ApiPlatform\Core\Annotation\ApiResource;
17+
use Doctrine\ORM\Mapping as ORM;
18+
19+
/**
20+
* @ApiResource
21+
* @ORM\Entity
22+
*/
23+
class DummyForAdditionalFields
24+
{
25+
/**
26+
* @ORM\Id
27+
* @ORM\GeneratedValue
28+
* @ORM\Column(type="integer")
29+
*/
30+
private $id;
31+
/** @ORM\Column */
32+
private $name;
33+
/** @ORM\Column */
34+
private $slug;
35+
36+
public function __construct(string $name, string $slug)
37+
{
38+
$this->name = $name;
39+
$this->slug = $slug;
40+
}
41+
42+
public function getId(): ?int
43+
{
44+
return $this->id;
45+
}
46+
47+
public function getName(): string
48+
{
49+
return $this->name;
50+
}
51+
52+
public function getSlug(): string
53+
{
54+
return $this->slug;
55+
}
56+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[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+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity;
15+
16+
use ApiPlatform\Core\Annotation\ApiResource;
17+
18+
/**
19+
* @ApiResource
20+
*/
21+
final class DummyForAdditionalFieldsInput
22+
{
23+
private $dummyName;
24+
25+
public function __construct(string $dummyName)
26+
{
27+
$this->dummyName = $dummyName;
28+
}
29+
30+
public function getDummyName(): string
31+
{
32+
return $this->dummyName;
33+
}
34+
}

tests/Serializer/AbstractItemNormalizerTest.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
use ApiPlatform\Core\Metadata\Property\PropertyNameCollection;
2424
use ApiPlatform\Core\Serializer\AbstractItemNormalizer;
2525
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy;
26+
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyForAdditionalFields;
27+
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyForAdditionalFieldsInput;
2628
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyTableInheritance;
2729
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyTableInheritanceChild;
2830
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\RelatedDummy;
@@ -290,6 +292,48 @@ public function testDenormalize()
290292
], Dummy::class);
291293
}
292294

295+
public function testCanDenormalizeInputClassWithDifferentFieldsThanResourceClass()
296+
{
297+
$propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
298+
$propertyNameCollectionFactoryProphecy->create(DummyForAdditionalFieldsInput::class, [])->willReturn(
299+
new PropertyNameCollection(['dummyName'])
300+
);
301+
$propertyNameCollectionFactoryProphecy->create(DummyForAdditionalFields::class, [])->willReturn(
302+
new PropertyNameCollection(['id', 'name', 'slug'])
303+
);
304+
305+
$propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
306+
// Create DummyForAdditionalFieldsInput mocks
307+
$propertyMetadataFactoryProphecy->create(DummyForAdditionalFieldsInput::class, 'dummyName', [])->willReturn(
308+
(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), '', true, false))->withInitializable(true)
309+
);
310+
// Create DummyForAdditionalFields mocks
311+
$propertyMetadataFactoryProphecy->create(DummyForAdditionalFields::class, 'id', [])->willReturn(
312+
(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT), '', true, false))->withInitializable(false)
313+
);
314+
$propertyMetadataFactoryProphecy->create(DummyForAdditionalFields::class, 'name', [])->willReturn(
315+
(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), '', true, false))->withInitializable(true)
316+
);
317+
$propertyMetadataFactoryProphecy->create(DummyForAdditionalFields::class, 'slug', [])->willReturn(
318+
(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), '', true, false))->withInitializable(true)
319+
);
320+
321+
$normalizer = new class($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $this->prophesize(IriConverterInterface::class)->reveal(), $this->prophesize(ResourceClassResolverInterface::class)->reveal()) extends AbstractItemNormalizer {
322+
};
323+
324+
/** @var DummyForAdditionalFieldsInput $res */
325+
$res = $normalizer->denormalize([
326+
'dummyName' => 'Dummy Name',
327+
], DummyForAdditionalFieldsInput::class, 'json', [
328+
'resource_class' => DummyForAdditionalFields::class,
329+
'input_class' => DummyForAdditionalFieldsInput::class,
330+
'output_class' => DummyForAdditionalFields::class,
331+
]);
332+
333+
$this->assertInstanceOf(DummyForAdditionalFieldsInput::class, $res);
334+
$this->assertEquals('Dummy Name', $res->getDummyName());
335+
}
336+
293337
public function testDenormalizeWritableLinks()
294338
{
295339
$relatedDummy1 = new RelatedDummy();

0 commit comments

Comments
 (0)