Przejdź do głównej treści
Grafika przedstawia ukryty obrazek

Wzorzec Action–Domain–Responder (ADR) w praktyce

Grafika przedstawia Wzorzec ActionDomainResponder ADR w praktyce

Wprowadzenie

Action–Domain–Responder (ADR) to wzorzec architektoniczny przeznaczony głównie dla aplikacji webowych. Powstał jako odpowiedź na problemy klasycznego MVC, w którym kontrolery często stają się zbyt rozbudowane, łącząc w sobie obsługę HTTP, logikę biznesową i przygotowanie odpowiedzi.

ADR skupia się na wyraźnym rozdzieleniu odpowiedzialności i bardzo dobrze sprawdza się w frameworkach, które nie narzucają ciężkiej struktury – takich jak Koseven.

Na czym polega ADR?

ADR dzieli obsługę jednego żądania HTTP na trzy jasno określone role:

  1. Action – obsługa żądania
  2. Domain – logika biznesowa
  3. Responder – przygotowanie odpowiedzi HTTP

Schemat przepływu:

Request → Action → Domain → Responder → Response

Każda z tych warstw ma jedno zadanie i nie wchodzi w kompetencje pozostałych.

1. Action

Action to punkt wejścia dla żądania HTTP.

Odpowiedzialności:

  • pobranie danych z requestu
  • wywołanie logiki domenowej
  • przekazanie wyniku do Respondera

Cechy:

  • brak logiki biznesowej
  • brak formatowania odpowiedzi
  • zazwyczaj jedna klasa = jeden use‑case

W Koseven rola Action jest naturalnie realizowana przez kontroler obsługujący jedno żądanie.

2. Domain

Domain zawiera całą logikę biznesową aplikacji.

Odpowiedzialności:

  • reguły biznesowe
  • walidacja domenowa
  • operacje na modelach / repozytoriach

Cechy:

  • brak zależności od HTTP
  • brak zależności od frameworka
  • łatwa do testowania

Domain zwraca wynik operacji (np. DTO) albo zgłasza wyjątek domenowy.

3. Responder

Responder odpowiada za stworzenie odpowiedzi HTTP.

Odpowiedzialności:

  • wybór formatu odpowiedzi (JSON / View / Redirect)
  • ustawienie statusu HTTP
  • przygotowanie nagłówków

Cechy:

  • nie zna requestu
  • nie zawiera logiki biznesowej

ADR w czystym PHP (bez frameworka)

Zanim przejdziemy do implementacji w Koseven, warto zobaczyć jak ADR wygląda w najczystszej postaci, bez żadnego frameworka. Pozwala to lepiej zrozumieć podział odpowiedzialności i zobaczyć, że ADR nie jest zależny od narzędzi, a jedynie od architektury.

Poniższy przykład pokazuje ten sam przypadek użycia: utworzenie użytkownika.

Struktura katalogów (czyste PHP)

src/
├── Action/
│   └── CreateUserAction.php
├── Domain/
│   ├── CreateUser.php
│   └── UserDTO.php
├── Responder/
│   └── CreateUserResponder.php
└── Http/
    ├── Request.php
    └── Response.php

Action

class CreateUserAction
{
    public function __construct(
        private CreateUser $domain,
        private CreateUserResponder $responder
    ) {}

    public function __invoke(Request $request): Response
    {
        try {
            $result = $domain->handle($request->post());
            return $this->responder->success($result);
        } catch (DomainException $e) {
            return $this->responder->error($e->getMessage());
        }
    }
}

Action:

  • przyjmuje request
  • deleguje logikę do Domain
  • nie zna formatu odpowiedzi

Domain

class CreateUser
{
    public function handle(array $data): UserDTO
    {
        if (empty($data['email'])) {
            throw new DomainException('Email is required');
        }

        // przykładowa logika biznesowa
        return new UserDTO(1, $data['name'], $data['email']);
    }
}

DTO:

class UserDTO
{
    public function __construct(
        public int $id,
        public string $name,
        public string $email
    ) {}
}

Domain:

  • nie zna HTTP
  • nie zna frameworka
  • zawiera wyłącznie reguły biznesowe

Responder

class CreateUserResponder
{
    public function success(UserDTO $user): Response
    {
        return new Response(
            json_encode([
                'id' => $user->id,
                'name' => $user->name,
                'email' => $user->email,
            ]),
            201
        );
    }

    public function error(string $message): Response
    {
        return new Response(
            json_encode(['error' => $message]),
            422
        );
    }
}

Responder:

  • odpowiada wyłącznie za HTTP
  • wybiera status i format odpowiedzi

Wniosek

Ten przykład pokazuje, że ADR jest wzorcem niezależnym od frameworka. Koseven (i każdy inny framework) pełni jedynie rolę infrastruktury, która:

  • dostarcza Request i Response
  • obsługuje routing
  • ułatwia integrację

Z tą wiedzą przejście do implementacji ADR w Koseven staje się naturalne.

Dlaczego ADR pasuje do Koseven?

Koseven (fork Kohany) bardzo dobrze wspiera ADR, ponieważ:

  • nie narzuca rozbudowanego MVC
  • kontrolery są lekkie
  • routing jest elastyczny
  • framework nie wymusza ORM ani struktury domeny

W praktyce:

Controller w Koseven = Action w ADR

Przykładowa struktura projektu

application/
├── classes/
│   ├── Controller/
│   │   └── Action/
│   │       └── User/
│   │           └── Create.php
│   ├── Domain/
│   │   └── User/
│   │       ├── CreateUser.php
│   │       └── UserDTO.php
│   ├── Responder/
│   │   └── User/
│   │       └── CreateResponder.php
│   └── Model/
│       └── User.php

Przykład: tworzenie użytkownika (POST /users)

Action (Controller)

class Controller_Action_User_Create extends Controller
{
    public function action_index()
    {
        $data = $this->request->post();

        $domain = new Domain_User_CreateUser();
        $responder = new Responder_User_CreateResponder();

        try {
            $result = $domain->handle($data);
            $this->response = $responder->success($result);
        } catch (DomainException $e) {
            $this->response = $responder->error($e->getMessage());
        }
    }
}

Action:

  • pobiera dane z requestu
  • deleguje logikę do Domain
  • przekazuje wynik do Respondera

Domain – logika biznesowa

class Domain_User_CreateUser
{
    public function handle(array $data): Domain_User_UserDTO
    {
        if (empty($data['email'])) {
            throw new DomainException('Email is required');
        }

        if (ORM::factory('User')->where('email', '=', $data['email'])->find()->loaded()) {
            throw new DomainException('Email already exists');
        }

        $user = ORM::factory('User');
        $user->values([
            'name' => $data['name'],
            'email' => $data['email'],
        ])->save();

        return new Domain_User_UserDTO(
            $user->id,
            $user->name,
            $user->email
        );
    }
}

DTO:

class Domain_User_UserDTO
{
    public function __construct(
        public int $id,
        public string $name,
        public string $email
    ) {}
}

Responder – odpowiedź HTTP

class Responder_User_CreateResponder
{
    public function success(Domain_User_UserDTO $user): Response
    {
        return Response::factory()
            ->status(201)
            ->body(json_encode([
                'id' => $user->id,
                'name' => $user->name,
                'email' => $user->email,
            ]));
    }

    public function error(string $message): Response
    {
        return Response::factory()
            ->status(422)
            ->body(json_encode([
                'error' => $message
            ]));
    }
}

Routing w Koseven

Route::set('user.create', 'users')
    ->defaults([
        'controller' => 'Action_User_Create',
        'action' => 'index',
    ]);

ADR vs klasyczne MVC

MVC ADR
Kontroler robi wszystko Action tylko koordynuje
Logika w kontrolerze Logika w Domain
Widok w kontrolerze Widok w Responderze
Trudne testy Łatwe testy

Zalety ADR

  • czytelny podział odpowiedzialności
  • brak „grubych kontrolerów”
  • łatwe testowanie logiki biznesowej
  • dobra skalowalność
  • świetne dopasowanie do API

Kiedy warto stosować ADR?

  • w dużych aplikacjach
  • w API
  • przy refaktoryzacji starego MVC
  • w projektach z DDD lub CQRS
  • gdy zależy Ci na czystej architekturze

Podsumowanie

ADR to prosty, ale bardzo skuteczny wzorzec architektoniczny. W połączeniu z Koseven pozwala budować aplikacje:

  • modularne
  • łatwe w utrzymaniu
  • odporne na rozrost złożoności

Dzięki temu, że framework nie narzuca ciężkiej struktury, ADR w Koseven jest naturalnym i eleganckim wyborem.

13 stycznia 2026 3

Kategorie

programowanie

Dziękujemy!
()

Powiązane wpisy


Informacja o cookies

Moja strona internetowa wykorzystuje wyłącznie niezbędne pliki cookies, które są wymagane do jej prawidłowego działania. Nie używam ciasteczek w celach marketingowych ani analitycznych. Korzystając z mojej strony, wyrażasz zgodę na stosowanie tych plików. Możesz dowiedzieć się więcej w mojej polityce prywatności.