Skip to content

Commit 5a3a7dc

Browse files
authored
fix(state): prioritize input class over output in ObjectMapperProvider (#7879)
Closes #7745
1 parent aefeca5 commit 5a3a7dc

2 files changed

Lines changed: 48 additions & 1 deletion

File tree

src/State/Provider/ObjectMapperProvider.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public function __construct(
4141
public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
4242
{
4343
$data = $this->decorated->provide($operation, $uriVariables, $context);
44-
$class = $operation->getOutput()['class'] ?? $operation->getClass();
44+
$class = $operation->getInput()['class'] ?? $operation->getOutput()['class'] ?? $operation->getClass();
4545

4646
if (!$this->objectMapper || !$operation->canMap()) {
4747
return $data;

tests/State/Provider/ObjectMapperProviderTest.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
namespace ApiPlatform\Tests\State\Provider;
1515

1616
use ApiPlatform\Metadata\Get;
17+
use ApiPlatform\Metadata\Patch;
1718
use ApiPlatform\State\Pagination\ArrayPaginator;
1819
use ApiPlatform\State\Pagination\MappedObjectPaginator;
1920
use ApiPlatform\State\Provider\ObjectMapperProvider;
@@ -168,6 +169,42 @@ public function testProvideMapsPaginator(): void
168169
$this->assertSame($targetResource2, $items[1]);
169170
}
170171

172+
public function testProvideMapsToInputClassWhenInputIsSet(): void
173+
{
174+
$sourceEntity = new SourceEntity();
175+
$inputResource = new InputResource();
176+
$operation = new Patch(class: TargetResource::class, input: ['class' => InputResource::class], output: ['class' => OutputResource::class], map: true);
177+
$objectMapper = $this->createMock(ObjectMapperInterface::class);
178+
$objectMapper->expects($this->once())
179+
->method('map')
180+
->with($sourceEntity, InputResource::class)
181+
->willReturn($inputResource);
182+
$decorated = $this->createStub(ProviderInterface::class);
183+
$decorated->method('provide')->willReturn($sourceEntity);
184+
$provider = new ObjectMapperProvider($objectMapper, $decorated);
185+
186+
$result = $provider->provide($operation);
187+
$this->assertSame($inputResource, $result);
188+
}
189+
190+
public function testProvideMapsToOutputClassWhenNoInput(): void
191+
{
192+
$sourceEntity = new SourceEntity();
193+
$outputResource = new OutputResource();
194+
$operation = new Get(class: TargetResource::class, output: ['class' => OutputResource::class], map: true);
195+
$objectMapper = $this->createMock(ObjectMapperInterface::class);
196+
$objectMapper->expects($this->once())
197+
->method('map')
198+
->with($sourceEntity, OutputResource::class)
199+
->willReturn($outputResource);
200+
$decorated = $this->createStub(ProviderInterface::class);
201+
$decorated->method('provide')->willReturn($sourceEntity);
202+
$provider = new ObjectMapperProvider($objectMapper, $decorated);
203+
204+
$result = $provider->provide($operation);
205+
$this->assertSame($outputResource, $result);
206+
}
207+
171208
public function testProvideMapsEmptyArray(): void
172209
{
173210
$operation = new Get(class: TargetResource::class, map: true);
@@ -207,3 +244,13 @@ class TargetResource
207244
{
208245
public string $name = 'target';
209246
}
247+
248+
class InputResource
249+
{
250+
public string $name = 'input';
251+
}
252+
253+
class OutputResource
254+
{
255+
public string $name = 'output';
256+
}

0 commit comments

Comments
 (0)