$npx -y skills add aligundogdu/symfony-hexagonal-skill --skill symfony-ports-adaptersSymfony ports and adapters — port interfaces, adapter implementations, dependency injection, autowiring, repository interfaces. Triggers on: port, adapter, interface, repository interface, DI, autowiring, dependency injection, services.yaml, binding
| 1 | # Symfony Ports & Adapters |
| 2 | |
| 3 | You are an expert in the Ports & Adapters pattern within Symfony hexagonal architecture. |
| 4 | |
| 5 | ## When to Activate |
| 6 | |
| 7 | - User needs to define a port (interface) for external dependency |
| 8 | - User needs to implement an adapter |
| 9 | - User asks about DI configuration or autowiring |
| 10 | - User wants to bind an interface to a concrete implementation |
| 11 | |
| 12 | ## Port = Interface in Domain |
| 13 | |
| 14 | Ports are interfaces that define contracts for external dependencies. They live in `Domain/{Module}/Port/`. |
| 15 | |
| 16 | ### Rules |
| 17 | - One interface per concern (Single Responsibility) |
| 18 | - Domain-centric naming (not tech-centric): `UserRepositoryInterface` not `DoctrineUserRepository` |
| 19 | - Only domain types in signatures (value objects, entities, primitives) |
| 20 | - No framework types in port signatures |
| 21 | |
| 22 | ### Common Port Types |
| 23 | |
| 24 | | Port Type | Example | |
| 25 | |-----------|---------| |
| 26 | | Repository | `UserRepositoryInterface` | |
| 27 | | External Service | `PaymentGatewayInterface` | |
| 28 | | Notification | `NotificationServiceInterface` | |
| 29 | | File Storage | `FileStorageInterface` | |
| 30 | | Event Dispatcher | `EventDispatcherInterface` | |
| 31 | |
| 32 | ### Template |
| 33 | ```php |
| 34 | namespace App\Domain\{Module}\Port; |
| 35 | |
| 36 | interface {Concern}Interface |
| 37 | { |
| 38 | public function methodUsingDomainTypes(ValueObject $param): ?Entity; |
| 39 | } |
| 40 | ``` |
| 41 | |
| 42 | ## Adapter = Implementation in Infrastructure |
| 43 | |
| 44 | Adapters implement ports using specific technologies. They live in `Infrastructure/{Module}/`. |
| 45 | |
| 46 | ### Rules |
| 47 | - Implements exactly one port interface |
| 48 | - Contains ALL technology-specific code |
| 49 | - Named with technology prefix: `Doctrine{Entity}Repository`, `Stripe{Payment}Gateway` |
| 50 | - `final readonly class` when possible |
| 51 | |
| 52 | ### Template |
| 53 | ```php |
| 54 | namespace App\Infrastructure\{Module}\Persistence; |
| 55 | |
| 56 | use App\Domain\{Module}\Port\{Repository}Interface; |
| 57 | |
| 58 | final readonly class Doctrine{Entity}Repository implements {Repository}Interface |
| 59 | { |
| 60 | public function __construct( |
| 61 | private EntityManagerInterface $entityManager, |
| 62 | ) { |
| 63 | } |
| 64 | |
| 65 | // implement all port methods |
| 66 | } |
| 67 | ``` |
| 68 | |
| 69 | ## DI Configuration |
| 70 | |
| 71 | ```yaml |
| 72 | # config/services.yaml |
| 73 | services: |
| 74 | # Bind ports to adapters |
| 75 | App\Domain\User\Port\UserRepositoryInterface: |
| 76 | alias: App\Infrastructure\User\Persistence\DoctrineUserRepository |
| 77 | |
| 78 | App\Domain\Payment\Port\PaymentGatewayInterface: |
| 79 | alias: App\Infrastructure\Payment\ExternalService\StripePaymentGateway |
| 80 | |
| 81 | App\Domain\Notification\Port\NotificationServiceInterface: |
| 82 | alias: App\Infrastructure\Notification\ExternalService\SymfonyMailerAdapter |
| 83 | ``` |
| 84 | |
| 85 | ## References |
| 86 | |
| 87 | See `references/` for detailed guides: |
| 88 | - `port-adapter-examples.md` — Full examples for various port types |
| 89 | - `di-configuration.md` — Advanced DI configuration patterns |