5.0 KiB
5.0 KiB
Framework Make Urls
Génère classe Urls + Message CQRS + Handler pour génération d'URLs.
Vue d'ensemble
Cette skill crée un ensemble de classes respectant le pattern CQRS pour gérer la génération d'URLs d'une entité.
Caractéristiques
Classes générées
- Urls - Classe finale readonly encapsulant la génération d'URLs
- UrlsMessage - Query CQRS pour récupérer les URLs
- UrlsMessageHandler - Handler orchestrant récupération entité + génération URLs
Utilisation
Use skill framework:make:urls
Vous serez invité à fournir le nom de l'entité.
Exemple d'utilisation
EntityName: Product
Génère 3 fichiers :
// src/Urls/ProductUrls.php
final readonly class ProductUrls
{
private function __construct(
private UrlGeneratorInterface $urlGenerator,
private Product $product,
) {}
public static function new(
UrlGeneratorInterface $urlGenerator,
Product $product,
): self {
return new self(
urlGenerator: $urlGenerator,
product: $product,
);
}
}
// src/MessageHandler/ProductUrlsMessage.php
final class ProductUrlsMessage extends AbstractQueryEvent implements QueryInterface
{
private function __construct(
public string $id,
) {}
public static function new(string $id): self
{
return new self(id: $id);
}
public function id(): string
{
return $this->id;
}
}
// src/MessageHandler/ProductUrlsMessageHandler.php
#[AsMessageHandler]
final readonly class ProductUrlsMessageHandler
{
public function __construct(
private ProductRepositoryInterface $productRepository,
private UrlGeneratorInterface $urlGenerator,
) {}
public function __invoke(ProductUrlsMessage $message): ProductUrls
{
$product = $this->productRepository->find($message->id());
return ProductUrls::new(
urlGenerator: $this->urlGenerator,
product: $product,
);
}
}
Structure créée
src/
├── Urls/
│ └── {EntityName}Urls.php
└── MessageHandler/
├── {EntityName}UrlsMessage.php
└── {EntityName}UrlsMessageHandler.php
Prérequis
- L'entité doit exister dans
src/Entity/{EntityName}.php - Le repository doit exister dans
src/Repository/{EntityName}Repository.php - L'interface repository doit exister
- Symfony Messenger configuré
- Atournayre packages installés (AbstractQueryEvent, QueryInterface)
Usage recommandé
Dans l'entité
final class Product implements HasUrlsInterface
{
public function urls(): ProductUrls
{
/** @var ProductUrls $urls */
$urls = ProductUrlsMessage::new(
id: $this->id->toRfc4122(),
)->query($this->dependencyInjection()->queryBus());
return $urls;
}
}
Ajout de méthodes d'URLs
final readonly class ProductUrls
{
private function __construct(
private UrlGeneratorInterface $urlGenerator,
private Product $product,
) {}
public static function new(
UrlGeneratorInterface $urlGenerator,
Product $product,
): self {
return new self(
urlGenerator: $urlGenerator,
product: $product,
);
}
public function show(): string
{
return $this->urlGenerator->generate(
'product_show',
['id' => $this->product->id()->toRfc4122()],
UrlGeneratorInterface::ABSOLUTE_URL
);
}
public function edit(): string
{
return $this->urlGenerator->generate(
'product_edit',
['id' => $this->product->id()->toRfc4122()],
UrlGeneratorInterface::ABSOLUTE_URL
);
}
public function api(): string
{
return $this->urlGenerator->generate(
'api_product_get',
['id' => $this->product->id()->toRfc4122()],
UrlGeneratorInterface::ABSOLUTE_URL
);
}
}
Utilisation dans templates Twig
{# product/show.html.twig #}
<a href="{{ product.urls.edit }}">Modifier</a>
<a href="{{ product.urls.delete }}">Supprimer</a>
{# API link #}
<code>{{ product.urls.api }}</code>
Utilisation dans contrôleurs
public function show(Product $product): Response
{
return $this->render('product/show.html.twig', [
'product' => $product,
'editUrl' => $product->urls()->edit(),
]);
}
Architecture CQRS
Flow
- Entité appelle
ProductUrlsMessage::new(id) - Message envoyé au QueryBus
- Handler intercepte le message
- Handler récupère l'entité via repository
- Handler crée et retourne ProductUrls
- URLs disponibles dans l'entité
Avantages
- Séparation des responsabilités
- Testabilité
- Injection de dépendances propre
- Pas de service locator dans l'entité
Principes Elegant Objects appliqués
- Classes finales
- Constructeurs privés
- Factory statiques
- Immutabilité (readonly)
- Encapsulation de la logique d'URLs
- Pas de getters bruts