Skip to content
Development
Skill

/symfony-ports-adapters

Symfony ports and adapters: port interfaces in Domain, adapter implementations in Infrastructure, dependency injection, autowiring, services.yaml aliases, #[AsAlias], environment-specific and decorated adapters, in-memory test adapters. Use when: port, adapter, interface,

From plugin
symfony-hexagonal
3510 skills2 agents1 hook

Claude Code

$ npx -y skills add aligundogdu/symfony-hexagonal-skill --skill symfony-ports-adapters --agent claude-code

SKILL.md

symfony-ports-adapters.SKILL.md
name: symfony-ports-adapters
description: "Symfony ports and adapters: port interfaces in Domain, adapter implementations in Infrastructure, dependency injection, autowiring, services.yaml aliases, #[AsAlias], environment-specific and decorated adapters, in-memory test adapters. Use when: port, adapter, interface, repository interface, DI, autowiring, dependency injection, services.yaml, binding, decorator, AsAlias"

Symfony Ports & Adapters

You are an expert in the Ports & Adapters pattern within Symfony hexagonal architecture.

When to Activate

  • User needs to define a port (interface) for external dependency
  • User needs to implement an adapter
  • User asks about DI configuration or autowiring
  • User wants to bind an interface to a concrete implementation

Version Notes

| Feature | Requires | Fallback | |---|---|---| | `alias:` in `services.yaml` | all versions | - | | `when@test:` / `when@dev:` blocks | Symfony 5.3 | `services_test.yaml` | | `#[AsAlias(PortInterface::class)]` on the adapter | Symfony 6.3 | YAML alias | | `#[AsAlias(..., when: 'test')]` | Symfony 7.3 | `when@test:` YAML block | | `#[AsDecorator(decorates: ...)]` | Symfony 6.1 | `decorates:` in YAML | | Repeatable `#[AsDecorator]` | Symfony 7.4 | one decorator per class |

Default to YAML aliases: they work on every version and keep all bindings visible in one file.

Port = Interface in Domain

Ports are interfaces that define contracts for external dependencies. They live in `Domain/{Module}/Port/` (shared ones in `Domain/Shared/Port/`).

Rules

  • One interface per concern (Single Responsibility)
  • Domain-centric naming (not tech-centric): `UserRepositoryInterface`, not `DoctrineUserRepository`
  • Only domain types in signatures (value objects, entities, read models, scalars)
  • No framework types in port signatures (`Request`, `Collection`, `UploadedFile`, `Uuid`, ...)
  • IDs, clocks and password hashing are ports too

Common Port Types

| Port Type | Example | |-----------|---------| | Repository (write) | `UserRepositoryInterface` | | Read repository | `UserReadRepositoryInterface` | | External Service | `PaymentGatewayInterface` | | Notification | `NotificationServiceInterface` | | File Storage | `FileStorageInterface` | | Identity | `IdGeneratorInterface` | | Security | `PasswordHasherInterface` |

Template

namespace App\Domain\{Module}\Port;

use App\Domain\{Module}\Entity\{Entity};
use App\Domain\{Module}\ValueObject\{Entity}Id;

interface {Entity}RepositoryInterface
{
    public function save({Entity} $entity): void;

    public function findById({Entity}Id $id): ?{Entity};
}

Adapter = Implementation in Infrastructure

Adapters implement ports using specific technologies. They live in `Infrastructure/{Module}/`.

Rules

  • Implements exactly one port interface
  • Contains ALL technology-specific code
  • Named with technology prefix: `Doctrine{Entity}Repository`, `Stripe{Payment}Gateway`
  • `final readonly class` when possible
  • Translates technology exceptions into domain exceptions where callers need to react

Template

namespace App\Infrastructure\{Module}\Persistence;

use App\Domain\{Module}\Port\{Entity}RepositoryInterface;
use Doctrine\ORM\EntityManagerInterface;

final readonly class Doctrine{Entity}Repository implements {Entity}RepositoryInterface
{
    public function __construct(
        private EntityManagerInterface $entityManager,
    ) {
    }

    // implement all port methods
}

DI Configuration

# config/services.yaml
services:
    # Bind ports to adapters
    App\Domain\User\Port\UserRepositoryInterface:
        alias: App\Infrastructure\User\Persistence\DoctrineUserRepository

    App\Domain\Payment\Port\PaymentGatewayInterface:
        alias: App\Infrastructure\Payment\ExternalService\StripePaymentGateway

    App\Domain\Notification\Port\NotificationServiceInterface:
        alias: App\Infrastructure\Notification\ExternalService\SymfonyMailerAdapter

Attribute alternative (Symfony 6.3+), on the adapter:

use Symfony\Component\DependencyInjection\Attribute\AsAlias;

#[AsAlias(UserRepositoryInterface::class)]
final readonly class DoctrineUserRepository implements UserRepositoryInterface { /* ... */ }

References

See `references/` for detailed guides:

  • `port-adapter-examples.md` - Full examples for various port types
  • `di-configuration.md` - Advanced DI configuration patterns
Read more
@aligundogdu
Ships withsymfony-hexagonal

A Claude Code plugin that enforces hexagonal architecture (ports & adapters) in Symfony projects. Works with both new projects (full scaffolding) and existing projects (progressive, module-by-module refactoring).

3510 skills2 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
35
Star history of aligundogdu/symfony-hexagonal-skill on GitHub, a chart by star-history.com

Other skills on symfony-hexagonal.

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills12d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc13d293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react3d252k
@facebook@facebookInstall Skill

Questions about symfony-ports-adapters.

Which coding agents can use symfony-ports-adapters?
symfony-ports-adapters installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.