The problem hexagonal architecture solves
- The business domain, independent of any framework
- Ports, interfaces that define what the domain needs
- Adapters, which implement those ports with a concrete technology (Doctrine, SOAP, REST, etc.)
Typical structure
src/
├── Domain/
│ ├── Model/
│ └── Port/
├── Application/
│ └── UseCase/
└── Infrastructure/
├── Persistence/
└── Http/
The domain never knows about Symfony, Doctrine, or an HTTP library. It only defines interfaces (ports). Infrastructure implements those interfaces.
Concrete example: a persistence port
Php
// Domain/Port/BeneficiaireRepositoryInterface.php
interface BeneficiaireRepositoryInterface
{
public function findByNir(string $nir): ?Beneficiaire;
}
Php
// Infrastructure/Persistence/DoctrineBeneficiaireRepository.php
final class DoctrineBeneficiaireRepository implements BeneficiaireRepositoryInterface
{
public function findByNir(string $nir): ?Beneficiaire
{
// Doctrine logic here, invisible to the domain
}
}
Benefits observed in practice
- Fast unit tests on business logic, with no full Symfony bootstrap (the framework's startup sequence — loading configuration, initializing services, etc. — that normally runs before every test)
- Easier infrastructure changes: replacing a SOAP call with a REST API becomes a change localized to the adapter, without touching the domain
- More readable separation of concerns for code reviews