Skip to content

Commit

Permalink
fix(serializer): uriTemplate wrong cache usage in hal format (#6313)
Browse files Browse the repository at this point in the history
* add failing test

* prevent components caching between different subresources

* fix tests for MongoDB
  • Loading branch information
usu committed Apr 17, 2024
1 parent 195ff52 commit a59fbee
Show file tree
Hide file tree
Showing 8 changed files with 232 additions and 6 deletions.
19 changes: 18 additions & 1 deletion features/hal/collection_uri_template.feature
Expand Up @@ -36,16 +36,33 @@ Feature: Exposing a property being a collection of resources
"_links": {
"self": {
"href": "/property_collection_iri_only_relations/1"
},
"children": {
"href": "/property_collection_iri_only_relations/1/children"
}
},
"name": "asb"
"name": "asb1"
},
{
"_links": {
"self": {
"href": "/property_collection_iri_only_relations/2"
},
"children": {
"href": "/property_collection_iri_only_relations/2/children"
}
},
"name": "asb2"
}
],
"iterableIri": [
{
"_links": {
"self": {
"href": "/property_collection_iri_only_relations/9999"
},
"children": {
"href": "/property_collection_iri_only_relations/9999/children"
}
},
"name": "Michel"
Expand Down
4 changes: 4 additions & 0 deletions features/jsonapi/collection_uri_template.feature
Expand Up @@ -33,6 +33,10 @@ Feature: Exposing a property being a collection of resources
{
"type": "PropertyCollectionIriOnlyRelation",
"id": "/property_collection_iri_only_relations/1"
},
{
"type": "PropertyCollectionIriOnlyRelation",
"id": "/property_collection_iri_only_relations/2"
}
]
},
Expand Down
3 changes: 2 additions & 1 deletion src/Hal/Serializer/ItemNormalizer.php
Expand Up @@ -184,6 +184,7 @@ private function getComponents(object $object, ?string $format, array $context):

$relation['iri'] = $this->iriConverter->getIriFromResource($object, UrlGeneratorInterface::ABS_PATH, $operation, $childContext);
$relation['operation'] = $operation;
$cacheKey = null;
}

if ($propertyMetadata->isReadableLink()) {
Expand All @@ -200,7 +201,7 @@ private function getComponents(object $object, ?string $format, array $context):
}
}

if (false !== $context['cache_key']) {
if ($cacheKey && false !== $context['cache_key']) {
$this->componentsCache[$cacheKey] = $components;
}

Expand Down
13 changes: 9 additions & 4 deletions tests/Behat/DoctrineContext.php
Expand Up @@ -1993,18 +1993,23 @@ public function thereAreIriOnlyDummies(int $nb): void
*/
public function thereAreResourcesWithPropertyUriTemplates(): void
{
$propertyCollectionIriOnlyRelation = $this->isOrm() ? new PropertyCollectionIriOnlyRelation() : new PropertyCollectionIriOnlyRelationDocument();
$propertyCollectionIriOnlyRelation->name = 'asb';
$propertyCollectionIriOnlyRelation1 = $this->isOrm() ? new PropertyCollectionIriOnlyRelation() : new PropertyCollectionIriOnlyRelationDocument();
$propertyCollectionIriOnlyRelation1->name = 'asb1';

$propertyCollectionIriOnlyRelation2 = $this->isOrm() ? new PropertyCollectionIriOnlyRelation() : new PropertyCollectionIriOnlyRelationDocument();
$propertyCollectionIriOnlyRelation2->name = 'asb2';

$propertyToOneRelation = $this->isOrm() ? new PropertyUriTemplateOneToOneRelation() : new PropertyUriTemplateOneToOneRelationDocument();
$propertyToOneRelation->name = 'xarguš';

$propertyCollectionIriOnly = $this->isOrm() ? new PropertyCollectionIriOnly() : new PropertyCollectionIriOnlyDocument();
$propertyCollectionIriOnly->addPropertyCollectionIriOnlyRelation($propertyCollectionIriOnlyRelation);
$propertyCollectionIriOnly->addPropertyCollectionIriOnlyRelation($propertyCollectionIriOnlyRelation1);
$propertyCollectionIriOnly->addPropertyCollectionIriOnlyRelation($propertyCollectionIriOnlyRelation2);
$propertyCollectionIriOnly->setToOneRelation($propertyToOneRelation);

$this->manager->persist($propertyCollectionIriOnly);
$this->manager->persist($propertyCollectionIriOnlyRelation);
$this->manager->persist($propertyCollectionIriOnlyRelation1);
$this->manager->persist($propertyCollectionIriOnlyRelation2);
$this->manager->persist($propertyToOneRelation);
$this->manager->flush();
}
Expand Down
Expand Up @@ -13,9 +13,12 @@

namespace ApiPlatform\Tests\Fixtures\TestBundle\Document;

use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Link;
use ApiPlatform\Metadata\Post;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Symfony\Component\Serializer\Annotation\Groups;

Expand All @@ -42,6 +45,16 @@ class PropertyCollectionIriOnlyRelation
#[ODM\ReferenceOne(targetDocument: PropertyCollectionIriOnly::class)]
private ?PropertyCollectionIriOnly $propertyCollectionIriOnly = null;

#[ODM\ReferenceMany(targetDocument: PropertyCollectionIriOnlyRelationSecondLevel::class)]
#[ApiProperty(uriTemplate: '/property_collection_iri_only_relations/{parentId}/children')]
#[Groups('read')]
private Collection $children;

public function __construct()
{
$this->children = new ArrayCollection();
}

public function getId(): ?int
{
return $this->id ?? 9999;
Expand All @@ -56,4 +69,34 @@ public function setPropertyCollectionIriOnly(?PropertyCollectionIriOnly $propert
{
$this->propertyCollectionIriOnly = $propertyCollectionIriOnly;
}

/**
* @return Collection<int, PropertyCollectionIriOnlyRelationSecondLevel>
*/
public function getChildren(): Collection
{
return $this->children;
}

public function addChild(PropertyCollectionIriOnlyRelationSecondLevel $child): self
{
if (!$this->children->contains($child)) {
$this->children->add($child);
$child->setParent($this);
}

return $this;
}

public function removeChild(PropertyCollectionIriOnlyRelationSecondLevel $child): self
{
if ($this->children->removeElement($child)) {
// set the owning side to null (unless already changed)
if ($child->getParent() === $this) {
$child->setParent(null);
}
}

return $this;
}
}
@@ -0,0 +1,54 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Tests\Fixtures\TestBundle\Document;

use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Link;
use ApiPlatform\Metadata\Post;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;

#[
Post,
GetCollection(uriTemplate: '/property-collection-relation-second-levels'),
GetCollection(
uriTemplate: '/property_collection_iri_only_relations/{parentId}/children',
uriVariables: [
'parentId' => new Link(toProperty: 'parent', fromClass: PropertyCollectionIriOnlyRelation::class),
]
)
]
#[ODM\Document]
class PropertyCollectionIriOnlyRelationSecondLevel
{
#[ODM\Id(strategy: 'INCREMENT', type: 'int')]
private ?int $id = null;

#[ODM\ReferenceOne(targetDocument: PropertyCollectionIriOnlyRelation::class)]
private ?PropertyCollectionIriOnlyRelation $parent = null;

public function getId(): ?int
{
return $this->id ?? 9999;
}

public function getParent(): ?PropertyCollectionIriOnlyRelation
{
return $this->parent;
}

public function setParent(?PropertyCollectionIriOnlyRelation $parent): void
{
$this->parent = $parent;
}
}
Expand Up @@ -13,9 +13,12 @@

namespace ApiPlatform\Tests\Fixtures\TestBundle\Entity;

use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Link;
use ApiPlatform\Metadata\Post;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints\NotBlank;
Expand Down Expand Up @@ -49,6 +52,16 @@ class PropertyCollectionIriOnlyRelation
#[ORM\ManyToOne(inversedBy: 'propertyCollectionIriOnlyRelation')]
private ?PropertyCollectionIriOnly $propertyCollectionIriOnly = null;

#[ORM\OneToMany(mappedBy: 'parent', targetEntity: PropertyCollectionIriOnlyRelationSecondLevel::class)]
#[ApiProperty(uriTemplate: '/property_collection_iri_only_relations/{parentId}/children')]
#[Groups('read')]
private Collection $children;

public function __construct()
{
$this->children = new ArrayCollection();
}

public function getId(): ?int
{
return $this->id ?? 9999;
Expand All @@ -63,4 +76,34 @@ public function setPropertyCollectionIriOnly(?PropertyCollectionIriOnly $propert
{
$this->propertyCollectionIriOnly = $propertyCollectionIriOnly;
}

/**
* @return Collection<int, PropertyCollectionIriOnlyRelationSecondLevel>
*/
public function getChildren(): Collection
{
return $this->children;
}

public function addChild(PropertyCollectionIriOnlyRelationSecondLevel $child): self
{
if (!$this->children->contains($child)) {
$this->children->add($child);
$child->setParent($this);
}

return $this;
}

public function removeChild(PropertyCollectionIriOnlyRelationSecondLevel $child): self
{
if ($this->children->removeElement($child)) {
// set the owning side to null (unless already changed)
if ($child->getParent() === $this) {
$child->setParent(null);
}
}

return $this;
}
}
@@ -0,0 +1,59 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Tests\Fixtures\TestBundle\Entity;

use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Link;
use ApiPlatform\Metadata\Post;
use Doctrine\ORM\Mapping as ORM;

#[
Post,
GetCollection(uriTemplate: '/property-collection-relation-second-levels'),
GetCollection(
uriTemplate: '/property_collection_iri_only_relations/{parentId}/children',
uriVariables: [
'parentId' => new Link(toProperty: 'parent', fromClass: PropertyCollectionIriOnlyRelation::class),
]
)
]
#[ORM\Entity]
class PropertyCollectionIriOnlyRelationSecondLevel
{
/**
* The entity ID.
*/
#[ORM\Id]
#[ORM\Column(type: 'integer')]
#[ORM\GeneratedValue]
private ?int $id = null;

#[ORM\ManyToOne(inversedBy: 'children')]
private ?PropertyCollectionIriOnlyRelation $parent = null;

public function getId(): ?int
{
return $this->id ?? 9999;
}

public function getParent(): ?PropertyCollectionIriOnlyRelation
{
return $this->parent;
}

public function setParent(?PropertyCollectionIriOnlyRelation $parent): void
{
$this->parent = $parent;
}
}

0 comments on commit a59fbee

Please sign in to comment.