Step 00 — Squelette + intégration naïve
3 Bounded Contexts (Sales, Invoicing, LegacyFulfillment) avec : - Domaines complets (agrégats, VOs, événements, invariants) - Couche application (commands, queries, ports) - Infrastructure in-memory (repos, gateway fake) - Controllers HTTP Symfony - Couplage naïf synchrone entre BC via NaiveSalesEventPublisher - 20 tests unitaires et d'intégration passants
This commit is contained in:
26
src/Sales/Interfaces/Http/CancelOrderController.php
Normal file
26
src/Sales/Interfaces/Http/CancelOrderController.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MiniShop\Sales\Interfaces\Http;
|
||||
|
||||
use MiniShop\Sales\Application\Command\CancelOrder;
|
||||
use MiniShop\Sales\Application\Command\CancelOrderHandler;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
#[Route('/sales/orders/{orderId}/cancel', name: 'sales_cancel_order', methods: ['POST'])]
|
||||
final readonly class CancelOrderController
|
||||
{
|
||||
public function __construct(
|
||||
private CancelOrderHandler $handler,
|
||||
) {}
|
||||
|
||||
public function __invoke(string $orderId): JsonResponse
|
||||
{
|
||||
($this->handler)(new CancelOrder(orderId: $orderId));
|
||||
|
||||
return new JsonResponse(null, Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
}
|
||||
26
src/Sales/Interfaces/Http/ConfirmOrderController.php
Normal file
26
src/Sales/Interfaces/Http/ConfirmOrderController.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MiniShop\Sales\Interfaces\Http;
|
||||
|
||||
use MiniShop\Sales\Application\Command\ConfirmOrder;
|
||||
use MiniShop\Sales\Application\Command\ConfirmOrderHandler;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
#[Route('/sales/orders/{orderId}/confirm', name: 'sales_confirm_order', methods: ['POST'])]
|
||||
final readonly class ConfirmOrderController
|
||||
{
|
||||
public function __construct(
|
||||
private ConfirmOrderHandler $handler,
|
||||
) {}
|
||||
|
||||
public function __invoke(string $orderId): JsonResponse
|
||||
{
|
||||
($this->handler)(new ConfirmOrder(orderId: $orderId));
|
||||
|
||||
return new JsonResponse(null, Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
}
|
||||
44
src/Sales/Interfaces/Http/GetOrderController.php
Normal file
44
src/Sales/Interfaces/Http/GetOrderController.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MiniShop\Sales\Interfaces\Http;
|
||||
|
||||
use MiniShop\Sales\Application\Query\GetOrderById;
|
||||
use MiniShop\Sales\Application\Query\GetOrderByIdHandler;
|
||||
use MiniShop\Sales\Domain\Model\OrderLine;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
#[Route('/sales/orders/{orderId}', name: 'sales_get_order', methods: ['GET'])]
|
||||
final readonly class GetOrderController
|
||||
{
|
||||
public function __construct(
|
||||
private GetOrderByIdHandler $handler,
|
||||
) {}
|
||||
|
||||
public function __invoke(string $orderId): JsonResponse
|
||||
{
|
||||
$order = ($this->handler)(new GetOrderById($orderId));
|
||||
|
||||
return new JsonResponse([
|
||||
'orderId' => $order->id->toString(),
|
||||
'customerId' => $order->customerId->toString(),
|
||||
'status' => $order->status()->value,
|
||||
'total' => [
|
||||
'amount' => $order->total()->amount,
|
||||
'currency' => $order->total()->currency,
|
||||
],
|
||||
'lines' => array_map(
|
||||
static fn (OrderLine $line): array => [
|
||||
'productName' => $line->productName,
|
||||
'quantity' => $line->quantity,
|
||||
'unitPrice' => $line->unitPrice->amount,
|
||||
'currency' => $line->unitPrice->currency,
|
||||
'lineTotal' => $line->lineTotal()->amount,
|
||||
],
|
||||
$order->lines(),
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
36
src/Sales/Interfaces/Http/ListCustomerOrdersController.php
Normal file
36
src/Sales/Interfaces/Http/ListCustomerOrdersController.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MiniShop\Sales\Interfaces\Http;
|
||||
|
||||
use MiniShop\Sales\Application\Query\ListOrdersByCustomer;
|
||||
use MiniShop\Sales\Application\Query\ListOrdersByCustomerHandler;
|
||||
use MiniShop\Sales\Domain\Model\Order;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
#[Route('/sales/customers/{customerId}/orders', name: 'sales_list_customer_orders', methods: ['GET'])]
|
||||
final readonly class ListCustomerOrdersController
|
||||
{
|
||||
public function __construct(
|
||||
private ListOrdersByCustomerHandler $handler,
|
||||
) {}
|
||||
|
||||
public function __invoke(string $customerId): JsonResponse
|
||||
{
|
||||
$orders = ($this->handler)(new ListOrdersByCustomer($customerId));
|
||||
|
||||
return new JsonResponse(array_map(
|
||||
static fn (Order $order): array => [
|
||||
'orderId' => $order->id->toString(),
|
||||
'status' => $order->status()->value,
|
||||
'total' => [
|
||||
'amount' => $order->total()->amount,
|
||||
'currency' => $order->total()->currency,
|
||||
],
|
||||
],
|
||||
$orders,
|
||||
));
|
||||
}
|
||||
}
|
||||
37
src/Sales/Interfaces/Http/PlaceOrderController.php
Normal file
37
src/Sales/Interfaces/Http/PlaceOrderController.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MiniShop\Sales\Interfaces\Http;
|
||||
|
||||
use MiniShop\Sales\Application\Command\PlaceOrder;
|
||||
use MiniShop\Sales\Application\Command\PlaceOrderHandler;
|
||||
use MiniShop\Shared\Technical\UuidGenerator;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
#[Route('/sales/orders', name: 'sales_place_order', methods: ['POST'])]
|
||||
final readonly class PlaceOrderController
|
||||
{
|
||||
public function __construct(
|
||||
private PlaceOrderHandler $handler,
|
||||
) {}
|
||||
|
||||
public function __invoke(Request $request): JsonResponse
|
||||
{
|
||||
/** @var array{customerId: string, lines: list<array{productName: string, quantity: int, unitPriceInCents: int, currency: string}>} $data */
|
||||
$data = json_decode($request->getContent(), true, flags: JSON_THROW_ON_ERROR);
|
||||
|
||||
$orderId = UuidGenerator::generate();
|
||||
|
||||
($this->handler)(new PlaceOrder(
|
||||
orderId: $orderId,
|
||||
customerId: $data['customerId'],
|
||||
lines: $data['lines'],
|
||||
));
|
||||
|
||||
return new JsonResponse(['orderId' => $orderId], Response::HTTP_CREATED);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user