Загрузка...

View Models в Laravel

laravel cover

Что такое View Model

View Model — это класс, который отвечает за подготовку и формирование данных специально для представления (view) в Laravel. Он изолирует логику подготовки данных от контроллера и делает код чище и понятнее.

Проще говоря — это DTO, предназначенный не только для передачи данных, а именно для структурирования данных под потребности представления.


Проблема классического подхода

Обычно контроллеры Laravel выглядят так:

public function index()
{
    $posts = Post::with('author')->where('published', true)->latest()->get();
    $tags = Tag::popular()->get();
    return view('blog.index', compact('posts', 'tags'));
}

Очень быстро код падает в «информационный беспорядок»:

  • контроллер знает слишком много;
  • данные тяжело переиспользовать;
  • сложно управлять кешем;
  • логика подготовки — разбросана.

Зачем нужен View Model

View Models помогают решить эти проблемы:

✅ контроллер становится тонким и понятным;
✅ представление не тянет лишнюю логику;
✅ данные собираются единой точкой;
✅ легко внедрять кеширование.


Первый View Model

Создадим класс View Model:

php artisan make:view-model BlogIndexViewModel

Пример реализации:

use Spatie\ViewModels\ViewModel;

class BlogIndexViewModel extends ViewModel
{
    public function posts()
    {
        return Post::with('author')
            ->where('published', true)
            ->latest()
            ->take(10)
            ->get();
    }

    public function popularTags()
    {
        return Tag::popular()->take(10)->get();
    }

    public function seo(): array
    {
        return [
            'title' => 'Блог',
            'description' => 'Последние статьи'
        ];
    }
}

Контроллер теперь выглядит так:

public function index()
{
    return view('blog.index', new BlogIndexViewModel());
}

Laravel автоматически пробросит методы View Model в шаблон.


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

В шаблоне Blade вы теперь используете данные как обычные переменные:

<h1>{{ $seo['title'] }}</h1>

@foreach ($posts as $post)
<article>
  <h2>{{ $post->title }}</h2>
  <p>Автор: {{ $post->author->name }}</p>
</article>
@endforeach

Преимущества:

  • код читаем;
  • шаблон не «тянет» логику;
  • меньше ошибок.

Добавляем кеширование

Кеширование — естественное место для View Model, ведь подготовка данных всё равно идёт в одном месте.

use Illuminate\Support\Facades\Cache;

public function posts()
{
    return Cache::remember('blog.index.posts', now()->addMinutes(10), function () {
        return Post::with('author')
            ->where('published', true)
            ->latest()
            ->take(10)
            ->get();
    });
}

Теперь контроллер не знает вообще ничего о кешировании — это логически рядом с данными.


Когда использовать View Models

Используйте View Models, когда:

✔ одному view нужен сложный набор данных;
✔ логика подготовки данных растёт;
✔ нужны вычисляемые свойства;
✔ требуется удобная точка кеширования.


Когда View Models — не лучший выбор

❌ данные нужны только как JSON (лучше использовать API Resources);
❌ это бизнес-логика — её место в сервисных классах или репозиториях, а не в View Models.


Архитектурный бонус

View Models хорошо сочетаются с:

  • сервисами (Service Classes);
  • объектами запросов (Query Objects);
  • классами действий (Action Classes);
  • централизованным кешированием.

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


Лучшие практики

Нужно только готовить данные, а не выполнять бизнес-логику.
Логику можно разделить по методам — это улучшает читаемость.
Именуйте методы так, чтобы их было удобно использовать в шаблонах.
Кеш должен быть привязан к данным, а не к контроллеру.
Если View Model становится слишком громоздкой — возможно, пора вынести часть логики в сервисы.


Заключение

View Models — это не просто удобный инструмент Laravel, а принцип архитектурного разделения ответственности, который помогает:

✔ уменьшить связность кода;
✔ сделать контроллеры простыми;
✔ оптимизировать кеширование;
✔ улучшить поддержку шаблонов.

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

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