Clean Architecture Lifecycle
Responsibilities of Presentation, Application, Domain, and Infrastructure layers.
The project architecture is built on strict separation of layer responsibilities. Data flow is unidirectional: from the external world (Controller) to the center (Entity), with dependencies pointing inward.
Layer Structure
1. Presentation Layer (Controllers)
Responsibility: Receive HTTP request, validate data format, delegate control to UseCase.
- Characteristics: Maximally "thin". Contains no business logic.
- Input:
Http Request. - Output:
Response(viaRestResponseFactory).
2. Application Layer (Use Cases)
Responsibility: Orchestration of business scenarios.
- Characteristics: Does not make business rule decisions (if/else), but manages the flow: "Fetch -> Modify -> Save -> Notify".
- Input: Strictly typed
DTO. - Output:
Domain EntityorDTO.
3. Domain Layer (Entities, Services)
Responsibility: Business logic, invariants, state validation rules.
- Characteristics: Pure PHP code, independent of framework or database.
- Components: Entities, Value Objects, Domain Services, Factories.
4. Infrastructure Layer (Repositories, Adapters)
Responsibility: Implementation of interfaces (ports), database operations, external APIs.
- Characteristics: Technical implementation details (Eloquent, Redis, Mailgun).
Data Flow Diagram
textClient Controller UseCase Repository Database │ │ │ │ │ │ POST /api/.. │ │ │ │ │────────────────▶│ │ │ │ │ │ execute(DTO) │ │ │ │ │───────────────▶│ │ │ │ │ │ findById(id) │ │ │ │ │───────────────▶│ │ │ │ │ │ SELECT ... │ │ │ │ │───────────────▶│ │ │ │ │ Row │ │ │ │ Entity │◀───────────────│ │ │ │◀───────────────│ │ │ │ │ │ │ │ │ │ [Update Logic] │ │ │ │ │ (Invariants) │ │ │ │ │ │ │ │ │ │ save(entity) │ │ │ │ │───────────────▶│ │ │ │ │ │ UPDATE ... │ │ │ │ │───────────────▶│ │ │ │ │ │ │ │ Entity │ │ │ │ │◀───────────────│ │ │ │ JSON Response │ │ │ │ │◀────────────────│ │ │ │ │ │ │ │ │
Implementation Example (Cancel Reservation)
Controller
phpreadonly class ReservationCancelController { public function __construct( private ReservationCancelUseCase $useCase, private RestResponseFactory $responseFactory ) {} public function __invoke(string $id): Response { // Errors (EntityNotFound, BusinessException) are caught globally $reservation = $this->useCase->execute($id); return $this->responseFactory->ok(new ReservationResource($reservation)); } }
UseCase
phpreadonly class ReservationCancelUseCase { public function __construct( private ReservationRepository $repository ) {} public function execute(string $id): Reservation { // 1. Find (Fail Fast - throws ModelNotFoundException) $reservation = $this->repository->findById($id); // 2. Business Logic (Rich Model - throws BusinessException if invalid) $reservation->cancel(); // 3. Persistence (Fail Fast - throws EntitySaveException) $this->repository->save($reservation); // 4. Side Effects (Events) ReservationCancelled::dispatch($reservation); return $reservation; } }