Skip to content

Commit 495f75f

Browse files
authored
fix(serializer): json non-resource intermitent class (#5937)
fixes #5926
1 parent 0f01521 commit 495f75f

File tree

8 files changed

+182
-4
lines changed

8 files changed

+182
-4
lines changed

features/issues/5926.feature

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Feature: Issue 5926
2+
In order to reproduce the issue at https://github.com/api-platform/core/issues/5926
3+
As a client software developer
4+
I need to be able to use every operation on a resource with non-resources embed objects
5+
6+
@!mongodb
7+
Scenario: Create and retrieve a WriteResource
8+
When I add "Accept" header equal to "application/json"
9+
And I send a "GET" request to "/test_issue5926s/1"
10+
Then the response status code should be 200
11+
And the response should be in JSON
12+
And the header "Content-Type" should be equal to "application/json; charset=utf-8"

src/JsonLd/Serializer/ItemNormalizer.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ public function normalize(mixed $object, string $format = null, array $context =
8181
// TODO: we should not remove the resource_class in the normalizeRawCollection as we would find out anyway that it's not the same as the requested one
8282
$previousResourceClass = $context['resource_class'] ?? null;
8383
$metadata = [];
84-
if ($isResourceClass = $this->resourceClassResolver->isResourceClass($resourceClass)) {
85-
$resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null);
84+
if ($isResourceClass = $this->resourceClassResolver->isResourceClass($resourceClass) && (null === $previousResourceClass || $this->resourceClassResolver->isResourceClass($previousResourceClass))) {
85+
$resourceClass = $this->resourceClassResolver->getResourceClass($object, $previousResourceClass);
8686
$context = $this->initContext($resourceClass, $context);
8787
$metadata = $this->addJsonLdContext($this->contextBuilder, $resourceClass, $context);
8888
} elseif ($this->contextBuilder instanceof AnonymousContextBuilderInterface) {

src/Serializer/AbstractItemNormalizer.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -710,8 +710,8 @@ protected function getAttributeValue(object $object, string $attribute, string $
710710
);
711711

712712
// Anonymous resources
713-
if ($type->getClassName()) {
714-
$childContext = $this->createChildContext($this->createOperationContext($context, null), $attribute, $format);
713+
if ($className) {
714+
$childContext = $this->createChildContext($this->createOperationContext($context, $className), $attribute, $format);
715715
$childContext['output']['gen_id'] = $propertyMetadata->getGenId() ?? true;
716716

717717
$attributeValue = $this->propertyAccessor->getValue($object, $attribute);
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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\Tests\Fixtures\TestBundle\Entity\Issue5926;
15+
16+
class ContentItemCollection implements \IteratorAggregate
17+
{
18+
private array $items;
19+
20+
public function __construct(ContentItemInterface ...$items)
21+
{
22+
$this->items = $items;
23+
}
24+
25+
public function getIterator(): \Traversable
26+
{
27+
return new \ArrayIterator($this->items);
28+
}
29+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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\Tests\Fixtures\TestBundle\Entity\Issue5926;
15+
16+
interface ContentItemInterface
17+
{
18+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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\Tests\Fixtures\TestBundle\Entity\Issue5926;
15+
16+
use ApiPlatform\Metadata\ApiResource;
17+
18+
#[ApiResource]
19+
class Media
20+
{
21+
public function __construct(
22+
private readonly string $id,
23+
private readonly string $title,
24+
) {
25+
}
26+
27+
public function getId(): string
28+
{
29+
return $this->id;
30+
}
31+
32+
public function getTitle(): string
33+
{
34+
return $this->title;
35+
}
36+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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\Tests\Fixtures\TestBundle\Entity\Issue5926;
15+
16+
class MediaContentItem implements ContentItemInterface
17+
{
18+
public function __construct(
19+
private readonly Media $media,
20+
) {
21+
}
22+
23+
public function getMedia(): Media
24+
{
25+
return $this->media;
26+
}
27+
}
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\Tests\Fixtures\TestBundle\Entity\Issue5926;
15+
16+
use ApiPlatform\Metadata\ApiResource;
17+
use ApiPlatform\Metadata\Get;
18+
use ApiPlatform\Metadata\Operation;
19+
20+
#[ApiResource(
21+
operations: [
22+
new Get(
23+
provider: [TestIssue5926::class, 'provide']
24+
),
25+
]
26+
)]
27+
class TestIssue5926
28+
{
29+
public function __construct(
30+
private readonly string $id,
31+
private readonly ?ContentItemCollection $content,
32+
) {
33+
}
34+
35+
public function getId(): string
36+
{
37+
return $this->id;
38+
}
39+
40+
public function getContent(): ?ContentItemCollection
41+
{
42+
return $this->content;
43+
}
44+
45+
public static function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
46+
{
47+
$media = new Media('1', 'My media');
48+
$contentItem1 = new MediaContentItem($media);
49+
$media = new Media('2', 'My media 2');
50+
$contentItem2 = new MediaContentItem($media);
51+
52+
$collection = new ContentItemCollection($contentItem1, $contentItem2);
53+
54+
return new self('1', $collection);
55+
}
56+
}

0 commit comments

Comments
 (0)