---
description: 
globs: *.php
alwaysApply: false
---
```
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