Framework Foton
Инструмент для профессиональной разработки web приложений
Как создавать DDD на Framework Foton

Вместо сервисов на Framework Foton используются внутренние модули.
Попробуем реализовать гексагональную архитектуру DDD на примере интернет магазина и работы с заказами

/modules/
    order.php                          # Адаптер-фасад для Foton ($this->core->obj('order'))
    order/
    ├──── Domain/
    │   ├── Order.php                       # Агрегат Order (сущность)
    │   ├── OrderItem.php                  # Entity (позиция заказа)
    │   ├── OrderId.php                     # Value Object
    │   ├── Money.php                      # Value Object
    │   ├── OrderStatus.php                # Enum (перечисление статусов)
    │   ├── CustomerId.php                 # Value Object
    │   ├── Event/
    │   │   ├── OrderPlaced.php            # Доменные события
    │   │   └── OrderStatusChanged.php
    │   └── Exception/
    │       ├── EmptyOrderException.php
    │       └── InvalidStatusTransitionException.php
    ├──── Port/
    │   ├── In/                            # Первичные порты (driving) — use case интерфейсы
    │   │   ├── PlaceOrderUseCase.php
    │   │   ├── GetOrderUseCase.php
    │   │   └── ChangeOrderStatusUseCase.php
    │   └── Out/                           # Вторичные порты (driven) — инфраструктурные интерфейсы
    │       ├── OrderRepositoryInterface.php
    │       ├── ProductRepositoryInterface.php
    │       ├── PaymentGatewayInterface.php
    │       └── EventDispatcherInterface.php
    ├──── Application/
    │   ├── Command/
    │   │   ├── PlaceOrderCommand.php      # Input DTO (команда)
    │   │   └── ChangeStatusCommand.php
    │   ├── Result/
    │   │   └── OrderResult.php            # Output DTO
    │   └── Service/
    │       ├── PlaceOrderService.php       # Use case реализация
    │       ├── GetOrderService.php
    │       └── ChangeOrderStatusService.php
    ├──── Adapter/
    │   ├── Out/                           # Secondaire адаптеры (реализации портов)
    │   │   ├── FotonOrderRepository.php
    │   │   ├── FotonProductRepository.php
    │   │   ├── SberPaymentGateway.php
    │   │   └── SyncEventDispatcher.php
    │   └── In/                            # Primary адаптеры (веб-контроллеры, CLI)
    │       └── OrderController.php
    └──── bootstrap.php                      # Связывание портов с адаптерами (DIC)

Сам код здесь приводить не будем, так как его очень много, главное что нужно понимать - при правильной архитектуре абстракции всегда выше на уровень директорий чем реализации, всегда реализации должны использовать верхние уровни (абстракции) и зависеть от них, но не наоборот. В небольшой архитектуре из 2-3 файлов можно использовать такой подход, когда по сути верхний класс является подобием обертки и в зависимости от параметров вызова дергает тот или иной класс, но когда мы говорим именно про DDD очень важно соблюдать именно этот подход.


Ядро (Domain Layer). Здесь находится бизнес-логика: сущности (Entity), объекты-значения (Value Object), доменные сервисы. Ключевое правило: ядро ничего не знает о внешних технологиях.

Entity (Сущность)
Сущность — это объект, обладающий уникальной идентичностью (identity), которая сохраняется во времени, независимо от изменений его атрибутов. Идентичность определяется по ID (уникальному ключу), а не по содержимому.

Примеры:
Order (заказ с ID 123) — даже если меняются позиции или статус, это всё равно одна и та же сущность.
Customer (клиент с уникальным ID).
ProductCategory (категория продукта).

Value Object (Объект-значение)
Объект-значение — это объект, который не имеет собственной идентичности. Он определяется только своими атрибутами (значениями).

Ключевые свойства:
Неизменяемость (immutable) — после создания значения его нельзя изменить.
Структурное равенство — два объекта-значения равны, если все их поля совпадают.

Примеры:
Money (сумма с валютой).
DateRange (диапазон дат).
Address (адрес).
Coordinate (точка).

Агрегат (Aggregate)
Агрегат — это кластер связанных объектов (сущностей и объектов-значений), которые изменяются как единое целое. У агрегата есть корень агрегата (Aggregate Root) — единственная точка входа для внешнего мира.

Особенности:
Все изменения внутри агрегата идут только через корень.
Агрегат определяет границу транзакционной согласованности — в одной транзакции меняется только один агрегат.
Внутри агрегата соблюдаются инварианты (бизнес-правила, которые должны выполняться всегда).

Примеры:
Агрегат Order включает сущность OrderItem и объект-значение DeliveryAddress.
Агрегат User включает сущность Profile и объект-значение ContactInfo.

Порты (Ports). Это интерфейсы, которые ядро объявляет для взаимодействия с внешним миром. Они задают контракт: что нужно сделать, но не как. Пример: OrderRepositoryInterface с методом save(Order $order).

Адаптеры (Adapters). Это конкретные реализации портов. Они находятся снаружи ядра и связывают его с реальным миром. Адаптеры преобразуют данные: из HTTP-запроса в команду для ядра, из результата домена в формат для БД или внешнего API.

Внешние слои.
Первичные адаптеры обрабатывают входящие запросы (контроллеры, CLI-команды).

Вторичные адаптеры работают с внешними сервисами: репозитории БД, клиенты других API, брокеры сообщений.

Поток данных: Входные данные → Первичный адаптер (преобразует в команду) → Application Service (оркестрация: вызывает домен-сервисы) → Ядро (бизнес-логика) → Выходной адаптер (результат в формат для внешнего сервиса) → Результат.



© Copyright 2026 Разработано на Framework Foton
Продукт зарегистрирован в Роспатенте