224 lines
6.4 KiB
Plaintext
224 lines
6.4 KiB
Plaintext
---
|
|
description:
|
|
globs:
|
|
alwaysApply: true
|
|
---
|
|
```
|
|
Domain/Manga/Infrastructure/ApiPlatform/
|
|
├── Resource/ # Resources API par opération
|
|
│ └── GetMangaResource.php # Resources pour l'opération Get
|
|
│ └── CreateMangaResource.php # Resources pour l'opération Create
|
|
├── State/ # Providers et Processors par opération
|
|
├── Provider/ # State Providers
|
|
│ └── GetMangaStateProvider.php
|
|
└── Processor/ # State Processors
|
|
└── CreateMangaStateProcessor.php
|
|
```
|
|
|
|
## Règles d'Organisation
|
|
|
|
### 1. Resources
|
|
- Localisation : `Infrastructure/ApiPlatform/Resource/`
|
|
- Principes :
|
|
- Une Resource par Operation
|
|
- Validation des données avec les attributs Symfony dans la Resource
|
|
- Documentation exhaustive avec les attributs PHP 8
|
|
- Nommage : `{Operation}Resource`
|
|
- Contient tous les attributs nécessaires en public
|
|
- Doit implémenter les interfaces de validation appropriées
|
|
|
|
### 2. State Providers
|
|
- Localisation : `Infrastructure/ApiPlatform/State/Provider/`
|
|
- Principes :
|
|
- Un Provider par Operation de type Query
|
|
- Utilise les QueryHandler du domaine
|
|
- Convertit la Response du QueryHandler en Resource
|
|
- Renvoie toujours une Resource
|
|
- Nommage : `{Operation}StateProvider`
|
|
|
|
### 3. State Processors
|
|
- Localisation : `Infrastructure/ApiPlatform/State/Processor/`
|
|
- Principes :
|
|
- Un Processor par Operation de type Command
|
|
- Utilise les CommandHandler du domaine
|
|
- Convertit la Resource en Command
|
|
- Renvoie uniquement un code HTTP
|
|
- Nommage : `{Operation}StateProcessor`
|
|
|
|
## Exemples de Code
|
|
|
|
### 1. Resource API
|
|
```php
|
|
namespace App\Domain\Manga\Infrastructure\ApiPlatform\Resource;
|
|
|
|
use ApiPlatform\Metadata\ApiResource;
|
|
use ApiPlatform\Metadata\Get;
|
|
use App\Domain\Manga\Infrastructure\ApiPlatform\State\Provider\GetMangaStateProvider;
|
|
use Symfony\Component\Validator\Constraints as Assert;
|
|
|
|
#[ApiResource(
|
|
shortName: 'Manga',
|
|
operations: [
|
|
new Get(
|
|
uriTemplate: '/mangas/{id}',
|
|
provider: GetMangaStateProvider::class,
|
|
output: GetMangaResource::class,
|
|
description: 'Récupère un manga par son identifiant'
|
|
)
|
|
]
|
|
)]
|
|
class GetMangaResource
|
|
{
|
|
public function __construct(
|
|
#[Assert\NotBlank]
|
|
#[Assert\Uuid]
|
|
public readonly string $id,
|
|
|
|
#[Assert\NotBlank]
|
|
public readonly string $title,
|
|
|
|
public readonly ?string $description = null,
|
|
|
|
#[Assert\NotBlank]
|
|
#[Assert\All([
|
|
new Assert\Type('string')
|
|
])]
|
|
public readonly array $authors = [],
|
|
|
|
#[Assert\Url]
|
|
public readonly ?string $coverUrl = null
|
|
) {}
|
|
}
|
|
```
|
|
|
|
### 2. State Provider
|
|
```php
|
|
namespace App\Domain\Manga\Infrastructure\ApiPlatform\Resource\CreateManga;
|
|
namespace App\Domain\Manga\Infrastructure\ApiPlatform\State\Provider;
|
|
|
|
use ApiPlatform\Metadata\Operation;
|
|
use ApiPlatform\State\ProviderInterface;
|
|
use App\Domain\Manga\Application\Query\GetMangaByIdQuery;
|
|
use App\Domain\Manga\Infrastructure\ApiPlatform\Resource\GetMangaResource;
|
|
use Symfony\Component\Messenger\MessageBusInterface;
|
|
|
|
class GetMangaStateProvider implements ProviderInterface
|
|
{
|
|
public function __construct(
|
|
private readonly MessageBusInterface $queryBus
|
|
) {}
|
|
|
|
public function provide(Operation $operation, array $uriVariables = [], array $context = []): ?GetMangaResource
|
|
{
|
|
$query = new GetMangaByIdQuery($uriVariables['id']);
|
|
$response = $this->queryBus->dispatch($query);
|
|
|
|
if (null === $response) {
|
|
return null;
|
|
}
|
|
|
|
return new GetMangaResource(
|
|
id: $response->id,
|
|
title: $response->title,
|
|
description: $response->description,
|
|
authors: $response->authors,
|
|
coverUrl: $response->coverUrl
|
|
);
|
|
}
|
|
}
|
|
```
|
|
|
|
### 3. Resource CreateManga
|
|
```php
|
|
namespace App\Domain\Manga\Infrastructure\ApiPlatform\Resource;
|
|
|
|
use ApiPlatform\Metadata\ApiResource;
|
|
use ApiPlatform\Metadata\Post;
|
|
use App\Domain\Manga\Infrastructure\ApiPlatform\State\Processor\CreateMangaStateProcessor;
|
|
use Symfony\Component\Validator\Constraints as Assert;
|
|
|
|
#[ApiResource(
|
|
shortName: 'Manga',
|
|
operations: [
|
|
new Post(
|
|
uriTemplate: '/mangas',
|
|
processor: CreateMangaStateProcessor::class,
|
|
input: CreateMangaResource::class,
|
|
status: 201,
|
|
description: 'Crée un nouveau manga'
|
|
)
|
|
]
|
|
)]
|
|
class CreateMangaResource
|
|
{
|
|
public function __construct(
|
|
#[Assert\NotBlank(message: 'Le titre est obligatoire')]
|
|
#[Assert\Length(min: 1, max: 255)]
|
|
public readonly string $title,
|
|
|
|
#[Assert\Length(max: 1000)]
|
|
public readonly ?string $description = null,
|
|
|
|
#[Assert\NotNull]
|
|
#[Assert\Count(min: 1, max: 10)]
|
|
#[Assert\All([
|
|
new Assert\Type('string'),
|
|
new Assert\Length(min: 1, max: 100)
|
|
])]
|
|
public readonly array $authors = [],
|
|
|
|
#[Assert\Url]
|
|
#[Assert\Length(max: 255)]
|
|
public readonly ?string $coverUrl = null
|
|
) {}
|
|
}
|
|
```
|
|
|
|
### 4. State Processor
|
|
```php
|
|
namespace App\Domain\Manga\Infrastructure\ApiPlatform\State\Processor;
|
|
|
|
use ApiPlatform\Metadata\Operation;
|
|
use ApiPlatform\State\ProcessorInterface;
|
|
use App\Domain\Manga\Application\Command\CreateMangaCommand;
|
|
use App\Domain\Manga\Infrastructure\ApiPlatform\Resource\CreateMangaResource;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
use Symfony\Component\Messenger\MessageBusInterface;
|
|
|
|
class CreateMangaStateProcessor implements ProcessorInterface
|
|
{
|
|
public function __construct(
|
|
private readonly MessageBusInterface $commandBus
|
|
) {}
|
|
|
|
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): int
|
|
{
|
|
assert($data instanceof CreateMangaResource);
|
|
|
|
$command = new CreateMangaCommand(
|
|
title: $data->title,
|
|
description: $data->description,
|
|
authors: $data->authors,
|
|
coverUrl: $data->coverUrl
|
|
);
|
|
|
|
$this->commandBus->dispatch($command);
|
|
|
|
return Response::HTTP_CREATED;
|
|
}
|
|
}
|
|
```
|
|
|
|
## Bonnes Pratiques
|
|
|
|
### 1. Documentation
|
|
- Documentation exhaustive des endpoints
|
|
- Description claire des paramètres
|
|
- Exemples de requêtes/réponses
|
|
- Documentation des codes d'erreur
|
|
|
|
### 2. Validation
|
|
- Validation dans les Resources uniquement
|
|
- Groupes de validation par contexte
|
|
- Messages d'erreur explicites
|
|
- Validation des types et formats |