State management in Api Platform
Fetch data and mutate state for custom api resources when using the Api Platform framework.
Define an api resource⌗
The following defines an api resource for a product. Note the provider classes set for the operations annotation.
<?php
declare(strict_types=1);
namespace App\ApiResource;
use App\Entity\Product;
use ApiPlatform\Metadata\Get;
use App\State\ProductProvider;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\GetCollection;
#[ApiResource(
shortName: 'Product',
operations: [
new Get(provider: ProductProvider::class),
new GetCollection(provider: ProductProvider::class)
]
)]
final class ProductResource
{
public string $id;
public string $name;
public int $price;
public static function fromEntity(Product $entity): self
{
$productResource = new self();
$productResource->id = (string) $entity->id();
$productResource->name = $entity->name();
$productResource->price = $entity->price();
return $productResource;
}
}
State Providers⌗
The following defines a state provider for the above resource.
<?php
declare(strict_types=1);
namespace App\State;
use ApiPlatform\Metadata\Operation;
use App\ApiResource\ProductResource;
use App\Repository\ProductRepository;
use ApiPlatform\State\ProviderInterface;
use ApiPlatform\Metadata\CollectionOperationInterface;
use Symfony\Component\Uid\Ulid;
final class ProductProvider implements ProviderInterface
{
public function __construct(private readonly ProductRepository $productRepository)
{
}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
{
if ($operation instanceof CollectionOperationInterface) {
$products = [];
foreach ($this->productRepository->findAll() as $product) {
$products[] = ProductResource::fromEntity($product);
}
return $products;
}
return ProductResource::fromEntity($this->productRepository->find(Ulid::fromString($uriVariables['id'])));
}
}
State Processors⌗
Continuing with the above resource, in order to mutate its state a new operation should be configured. E.g to enable post request to create new product:
#[ApiResource(
shortName: 'Product',
operations: [
new Get(provider: ProductProvider::class),
new GetCollection(provider: ProductProvider::class),
new Post(processor: ProductProcessor::class), // new operation defining processor
]
)]
final class ProductResource
And the corresponding processor:
// App\State\ProductProcessor.php
final class ProductProcessor implements ProcessorInterface
{
public function process($data, Operation $operation, array $uriVariables = [], array $context = [])
{
// mutate and persist data as you like here, e.g:
$this->productRepository->add(ProductResource::toEntity($data));
return $data;
}
}
Read the documentation for more info on state providers and state processors.
Read other posts