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

Wzorzec Action–Domain–Responder (ADR) w praktyce

Obraz ilustrujacy 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 4

Kategorie

programowanie

Dziękujemy!
()

Powiązane wpisy

Obraz ilustrujacy Automatyczny motyw Bootstrap 53 na bazie pory dnia
4 stycznia 2025 6 min 71

Automatyczny motyw Bootstrap 5.3 na bazie pory dnia

php
Czytaj więcej
Wizualizacja tematu Wyraenia regularne i ich obsuga w PHP oraz JavaScript
1 lutego 2025 5 min 19

Wyrażenia regularne i ich obsługa w PHP oraz JavaScript

php
Czytaj więcej
Ilustracja tematu Klasa Promise w PHP i jej zastosowanie
5 lutego 2025 7 min 39

Klasa Promise w PHP i jej zastosowanie

php
Czytaj więcej
Wymiana doświadczeń

Masz podobne doświadczenia?

Chętnie poznam Twoją perspektywę i porozmawiam o tym temacie szerzej.

Napisz do mnie

Każda perspektywa może wnieść coś wartościowego do dyskusji.

Twoja prywatność i pliki cookies

  1. Ta strona internetowa wykorzystuje wyłącznie niezbędne pliki cookies, które są wymagane do jej prawidłowego działania – m.in. do poprawnego wyświetlania treści, zapamiętania podstawowych ustawień przeglądarki oraz zapewnienia stabilności serwisu.
  2. Nie stosuję plików cookies w celach marketingowych, reklamowych ani analitycznych.
  3. Strona ma charakter wyłącznie informacyjny i nie zawiera formularzy kontaktowych, rejestracyjnych ani zakupowych, przez które dane mogłyby być przesyłane na serwer.
  4. Nie zbieram danych osobowych podczas zwykłego korzystania z witryny.
  5. Serwis nie korzysta z certyfikatu SSL, jednak ze względu na informacyjny charakter strony nie jest wymagane przesyłanie poufnych danych. Zalecam jednak, aby nigdy nie wpisywać haseł ani danych osobowych na stronach bez szyfrowanego połączenia.
  6. Korzystając z tej strony, wyrażasz zgodę na używanie wyłącznie niezbędnych plików cookies.

Więcej informacji znajdziesz w mojej polityce prywatności.