Загрузка...

DTO и модели в Laravel: в чём разница и когда что использовать

laravel cover

В Laravel разработке рано или поздно возникает вопрос:
что использовать — Eloquent модель или DTO?

На старте проекта всё просто — модели хватает.
Но по мере роста приложения появляются:

  • сервисный слой
  • очереди
  • интеграции
  • сложная бизнес-логика
  • тестирование

И тут становится очевидно: модель — не всегда правильный инструмент для передачи данных.

В этой статье разберём:

  • что такое DTO в Laravel
  • чем DTO отличается от модели
  • когда использовать DTO
  • как правильно внедрить DTO в архитектуру проекта

Что такое модель в Laravel (Eloquent Model)

Eloquent-модель — это реализация паттерна Active Record, встроенная в Laravel.

Модель отвечает за:

  • работу с базой данных
  • связи (hasOne, belongsTo, hasMany)
  • события (creating, updated)
  • касты атрибутов
  • query builder
  • сохранение и обновление записей

Пример модели:

class User extends Model
{
    protected $fillable = ['name', 'email'];
}

Использование:

$user = User::create([
    'name' => 'Alex',
    'email' => 'alex@example.com',
]);

Важно

Eloquent-модель:

  • связана с БД
  • может выполнять запросы
  • содержит поведение
  • является инфраструктурным слоем

Это не просто объект с данными, а активный объект, который управляет своим состоянием.


Что такое DTO (Data Transfer Object) в Laravel

DTO (Data Transfer Object) — это объект для передачи данных между слоями приложения.

Он:

  • не работает с БД
  • не содержит бизнес-логики
  • не выполняет запросы
  • хранит только данные

Пример DTO:

readonly class CreateUserDTO
{
    public function __construct(
        public string $name,
        public string $email,
        public string $password,
    ) {}
}

DTO используется для:

  • передачи данных из контроллера в сервис
  • передачи данных в Job
  • работы с API
  • разделения слоёв приложения

DTO и модель в Laravel: ключевая разница

Модель (Eloquent) DTO
Связана с БД Не связана с БД
Active Record Data Carrier
Может выполнять запросы Не выполняет запросы
Содержит поведение Только структура данных
Инфраструктурный слой Транспортный слой

Главное отличие:
Модель — это инструмент работы с данными.
DTO — это контейнер для передачи данных.


Когда использовать модель в Laravel

Модель уместна, если:

  • нужно сохранить данные в БД
  • требуется работа со связями
  • используются касты
  • выполняются ORM-запросы
  • это простой CRUD-проект

Пример:

$user = User::find($id);
$user->update([...]);

Здесь DTO не нужен.


Когда использовать DTO в Laravel

DTO становится полезным в следующих случаях.

1. Передача данных в сервисный слой

Плохая практика:

$userService->create($request->all());

Проблемы:

  • передаётся массив
  • нет строгой структуры
  • нет типизации
  • зависимость от HTTP

Правильный подход:

$dto = new CreateUserDTO(
    name: $request->name,
    email: $request->email,
    password: $request->password,
);

$userService->create($dto);

Теперь:

  • сервис не зависит от Request
  • есть контракт
  • код легче тестировать

2. Разделение слоёв архитектуры

Если проект использует:

  • Service Layer
  • Actions
  • Domain-подход
  • Clean Architecture
  • DDD

DTO становится обязательным элементом.

Правильная цепочка:

Controller → FormRequest → DTO → Service → Model

DTO разрывает зависимость между HTTP и инфраструктурой.


3. Использование очередей (Jobs)

Передавать модель напрямую в Job — плохая практика:

SendWelcomeEmail::dispatch($user);

Это может привести к:

  • неожиданной сериализации
  • скрытым запросам
  • ошибкам при изменении модели

Лучше:

SendWelcomeEmail::dispatch(
    new UserDTO(
        id: $user->id,
        email: $user->email,
    )
);

4. Интеграции и API

DTO удобно использовать для:

  • внешних API
  • webhook-обработчиков
  • трансформации данных
  • ответов REST API

Он делает структуру данных явной и стабильной.


DTO vs Model: архитектурный аспект

Ошибка многих Laravel-разработчиков — использовать модель как универсальный объект.

Пример плохой архитектуры:

public function create(User $user)
{
    // бизнес-логика
}

Метод уже зависит от базы данных.

Правильнее:

public function create(CreateUserDTO $dto)
{
    // бизнес-логика
}

Теперь:

  • сервис не знает о БД
  • код легче тестировать
  • архитектура становится чище

DTO и FormRequest — это не одно и то же

FormRequest:

  • валидирует входные данные
  • работает на уровне HTTP

DTO:

  • хранит валидированные данные
  • используется в бизнес-логике

Идеальная схема:

Request → FormRequest (валидация) → DTO → Service → Model

Нужно ли использовать DTO в каждом Laravel-проекте

Нет.

Если проект:

  • небольшой
  • простой CRUD
  • без сложной логики
  • без интеграций
  • без сервисного слоя

DTO может быть избыточным.

Но если проект:

  • растёт
  • становится сложным
  • покрывается тестами
  • использует очереди
  • работает с API

DTO значительно упрощает поддержку.


Лучшие практики использования DTO в Laravel

Делайте DTO неизменяемыми

Используйте readonly (PHP 8.2+):

readonly class UpdateProfileDTO
{
    public function __construct(
        public string $name,
        public string $bio,
    ) {}
}

Используйте фабричный метод fromRequest

class CreateUserDTO
{
    public function __construct(
        public string $name,
        public string $email,
    ) {}

    public static function fromRequest(Request $request): self
    {
        return new self(
            name: $request->string('name'),
            email: $request->string('email'),
        );
    }
}

Контроллер становится чище:

$dto = CreateUserDTO::fromRequest($request);
$userService->create($dto);

Использование пакетов для DTO

Для крупных проектов можно использовать:

  • spatie/laravel-data
  • кастомные трансформеры
  • Value Objects

Но в большинстве случаев достаточно обычных PHP-классов.


Частые ошибки при работе с DTO

❌ Использовать DTO вместо модели для сохранения
❌ Передавать массивы вместо объектов
❌ Передавать Eloquent-модель в сервис
❌ Смешивать DTO и бизнес-логику

DTO должен оставаться простым и предсказуемым.


Итог: что выбрать — DTO или модель

DTO и модель в Laravel не конкурируют.

  • Модель — работа с базой данных.
  • DTO — передача данных между слоями.

Если вы строите масштабируемый Laravel-проект,
DTO делает код:

  • более чистым
  • предсказуемым
  • тестируемым
  • архитектурно устойчивым

Именно поэтому в серьёзных проектах DTO почти всегда присутствует.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *