core
core copied to clipboard
Doctrine ODM Documents return inconsistent data for GET Collection and Item Operations in Symfony production environment
API Platform version(s) affected: 3.3.5
Description
The GET Collection and Item operations do not always return the latest data for document resources after updating a resource via the PATCH or PUT operations; sometimes the old data is returned.
Important: This happens only in the production environment docker compose -f compose.yaml -f compose.prod.yaml up --build. I don't know if this is related to the production setup.
How to reproduce
<?php
declare(strict_types=1);
namespace App\Document;
use ApiPlatform\Metadata\ApiResource;
use App\Repository\ProductRepository;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Doctrine\ODM\MongoDB\Types\Type;
#[ApiResource]
#[ODM\Document(collection: 'products', repositoryClass: ProductRepository::class)]
class Product
{
#[ODM\Id(type: Type::INT, strategy: 'INCREMENT')]
private ?int $id = null;
#[ODM\Field(type: Type::STRING, nullable: true)]
private ?string $name = null;
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(?string $name): static
{
$this->name = $name;
return $this;
}
}
- Create a new Product via the
POSTAPI. - Update the Product data via the
PATCHorPUTAPI. - Hit the
GETCollection of Products or theGETSingle Product APIs multiple times, and you'll see that sometimes the latest data is not returned.
Use this repo for testing the above.
Possible Solution
I had to create custom state provider for the GET item operation and call the refresh method after retrieving the object from the built-in state provider.
Custom state provider:
<?php
declare(strict_types=1);
namespace App\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\Document\Product;
use App\Repository\ProductRepository;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
final readonly class ProductProvider implements ProviderInterface
{
public function __construct(
#[Autowire(service: 'api_platform.doctrine_mongodb.odm.state.item_provider')]
private ProviderInterface $itemProvider,
private ProductRepository $productRepository
) {
}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): ?Product
{
/** @var Product|null $product */
$product = $this->itemProvider->provide($operation, $uriVariables, $context);
if (!$product) {
return null;
}
$this->productRepository->getDocumentManager()->refresh($product);
return $product;
}
}
Updated document:
<?php
declare(strict_types=1);
namespace App\Document;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Put;
use App\Repository\ProductRepository;
use App\State\ProductProvider;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Doctrine\ODM\MongoDB\Types\Type;
#[ApiResource(
operations: [
new GetCollection(),
new Post(),
new Get(provider: ProductProvider::class),
new Patch(),
new Put(),
new Delete(),
],
)]
#[ODM\Document(collection: 'products', repositoryClass: ProductRepository::class)]
class Product
{
#[ODM\Id(type: Type::INT, strategy: 'INCREMENT')]
private ?int $id = null;
#[ODM\Field(type: Type::STRING, nullable: true)]
private ?string $name = null;
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(?string $name): static
{
$this->name = $name;
return $this;
}
}
I haven't found a solution for the Get Collection operation yet.
Additional Context
Recording: https://www.awesomescreenshot.com/video/28637492?key=483e51522dd7bd03d915244bf090e6ff
would you be able to patch this please?
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.