From api-platform
Génère des DTOs (input/output) API Platform avec mapping vers les entités
How this skill is triggered — by the user, by Claude, or both
Slash command
/api-platform:make-dtosonnetThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Génère des Data Transfer Objects (DTOs) pour API Platform avec le mapping input/output, les State Providers et Processors associés.
Génère des Data Transfer Objects (DTOs) pour API Platform avec le mapping input/output, les State Providers et Processors associés.
src/Dto/{ResourceName}Input.php (si input)src/Dto/{ResourceName}Output.php (si output)src/State/{ResourceName}Provider.php (si output DTO)src/State/{ResourceName}Processor.php (si input DTO)IMPORTANT : Exécute ce workflow étape par étape :
$ARGUMENTS est fourni, utiliser comme nom de la resourceQuestion: "Pour quelle resource créer des DTOs ?"
Header: "Resource"
src/Entity/Question: "Quel type de DTO créer ?"
Header: "Type"
Options:
- "Input + Output (Recommandé)" : "DTOs distincts pour la lecture et l'écriture"
- "Output uniquement" : "DTO pour personnaliser la représentation en lecture"
- "Input uniquement" : "DTO pour valider et transformer les données en écriture"
composer.json avec Readautoload.psr-4<?php
declare(strict_types=1);
namespace {namespace}\Dto;
final readonly class {ResourceName}Output
{
public function __construct(
public int $id,
// Propriétés exposées en lecture
public string $name,
public string $email,
// Propriétés calculées
public string $displayName,
) {
}
public static function fromEntity({ResourceName} $entity): self
{
return new self(
id: $entity->getId(),
name: $entity->getName(),
email: $entity->getEmail(),
displayName: sprintf('%s (%s)', $entity->getName(), $entity->getEmail()),
);
}
}
<?php
declare(strict_types=1);
namespace {namespace}\Dto;
use Symfony\Component\Validator\Constraints as Assert;
final class {ResourceName}Input
{
public function __construct(
#[Assert\NotBlank]
public readonly string $name,
#[Assert\NotBlank]
#[Assert\Email]
public readonly string $email,
) {
}
public function toEntity(): {ResourceName}
{
// Créer l'entité depuis le DTO
}
public function updateEntity({ResourceName} $entity): {ResourceName}
{
// Mettre à jour l'entité existante
return $entity;
}
}
<?php
declare(strict_types=1);
namespace {namespace}\State;
use ApiPlatform\Metadata\CollectionOperationInterface;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use {namespace}\Dto\{ResourceName}Output;
/**
* @implements ProviderInterface<{ResourceName}Output>
*/
final readonly class {ResourceName}Provider implements ProviderInterface
{
public function __construct(
private ProviderInterface $decorated,
) {
}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
{
$data = $this->decorated->provide($operation, $uriVariables, $context);
if ($operation instanceof CollectionOperationInterface) {
$items = [];
foreach ($data as $entity) {
$items[] = {ResourceName}Output::fromEntity($entity);
}
return $items;
}
if (null === $data) {
return null;
}
return {ResourceName}Output::fromEntity($data);
}
}
<?php
declare(strict_types=1);
namespace {namespace}\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use {namespace}\Dto\{ResourceName}Input;
use {namespace}\Dto\{ResourceName}Output;
/**
* @implements ProcessorInterface<{ResourceName}Input, {ResourceName}Output>
*/
final readonly class {ResourceName}Processor implements ProcessorInterface
{
public function __construct(
private ProcessorInterface $decorated,
) {
}
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): mixed
{
/** @var {ResourceName}Input $data */
$entity = $data->toEntity();
$result = $this->decorated->process($entity, $operation, $uriVariables, $context);
return {ResourceName}Output::fromEntity($result);
}
}
Modifier l'attribut #[ApiResource] pour utiliser les DTOs :
#[ApiResource(
operations: [
new GetCollection(output: {ResourceName}Output::class),
new Get(output: {ResourceName}Output::class),
new Post(input: {ResourceName}Input::class, output: {ResourceName}Output::class),
new Put(input: {ResourceName}Input::class, output: {ResourceName}Output::class),
new Patch(input: {ResourceName}Input::class, output: {ResourceName}Output::class),
new Delete(),
],
provider: {ResourceName}Provider::class,
processor: {ResourceName}Processor::class,
)]
DTOs générés pour {ResourceName}
Fichiers créés :
- src/Dto/{ResourceName}Input.php
- src/Dto/{ResourceName}Output.php
- src/State/{ResourceName}Provider.php
- src/State/{ResourceName}Processor.php
Mapping :
- Input : POST/PUT/PATCH → {ResourceName}Input → Entité
- Output : Entité → {ResourceName}Output → GET
Prochaines étapes :
- Compléter la logique toEntity() et updateEntity()
- Ajouter des validations sur le DTO Input
- Tester : /api-platform:make-test {ResourceName}
final readonly avec factory method fromEntity()final avec validation Symfony et méthodes toEntity() / updateEntity()readonly)npx claudepluginhub atournayre/claude-personas --plugin api-platformMaps Symfony entities to API Platform v4 DTOs using the Symfony Object Mapper (#[Map], stateOptions) for decoupled input/output contracts.
Creates or modifies API Platform resources with DTOs and Object Mapper. Use when adding endpoints, exposing entities over HTTP, defining input/output DTOs, or configuring nested sub-resources.
Generates immutable DTO classes for PHP 8.4 apps, including request/response objects for API boundaries, layer-specific data transfer, serialization methods, and unit tests.