ZANIN блог
Контакты
Крути вниз
Фильтр по:
//Post title

Архитектура Laravel приложения

24 Окт 2021Категория : Laravel 8

Архитектура Laravel приложения

Ссылка на репозиторий с кодом примеров.

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

Структура папок будет для продукта такой. В этой структуре контроллер лежит сразу в папке Products, как основная точка входа, для работы с продуктами в админке. Папка Entity - содержит DTO(Data Transfer Object) объекты, по сути сущности для удобной работы. Папка DataProvider - содержит провайдеры данных, которые предоставляют результирующие данные, которые были запрошены или отправлены из контроллера в провайдер данных. В провайдер данных сами данные уже попадают из репозитория (папка Repository) - тут содержится логика запросов (модели Eloquent или сырые SQL запросы). При необходимости данные могут быть обработаны сервисом (папка Service). Папка Utils может содержать общие методы и классы полезные для работы. Папка Interfaces - содержит интерфейсы, по сути при такой архитектур вся суть именно в них.

Laravel 8 - архитектура

Класс контроллер будет таким. В нем я обозначаю приватную переменную $productDataProvider, которая соответствует интерфейсу IProductDataProvider. Экземпляр класса, который соответствует данному интерфейсу инстанцируется через статический метод сервисного контейнера. ProductServiceContainer этот аналог DI контейнера для локального модуля Products. В Laravel работает внедрение зависимостей DI (dependency injection) через имена классов, но если DI делать через интерфейсы, то необходимо больше изменений. Поэтому для этого примера в контроллер отдается сервисный контейнер ProductServiceContainer.

Laravel 8 - архитектура

Далее в контроллере пойдем к методу index(). В нем, через инстанс дата провайдера $this->productDataProvider я обращаюсь к доступным методам этого провайдера.

Laravel 8 - архитектура

Доступные для работы с дата провайдером методы содержатся в его интерфейсе. Это можно увидеть в подсказках PHPStorm. Хотя точно такие же подсказки будут и при наличии в классе просто публичных методов, но в данном случае интерфейс определяет контракт того, как можно взаимодействовать с классом, не зная его внутренней реализации. Внутреннюю реализацию в таком случае стоит реализовывать в приватных методах.

Laravel 8 - архитектура

Реализация класса ProductDataProvider. В его конструктор передается экземпляр класса ProductRepository, реализующего интерфейс IProductRepository. В этом случае мы можем легко заменить класс ProductRepository любым другим классом, который реализует этот интерфейс, что по сути уменьшает связность классов, в отличие от того, если бы мы инстанцировали репозиторий в классе дата провайдера через new.

Laravel 8 - архитектура

Перейдем к методу getLatestProducts в дата провайдере, который вызывается в методе index в контроллере. Этот метод принимает аргумент типа int и отдает массив. В PHPDoc я обозначил, что это массив DTO объектов. В самом методе идет обращение к экземпляру репозитория и к его методу, который также есть в интерфейсе репозитория.

Laravel 8 - архитектура

Класс репозитория. В нем идет обращение к модели Products. Через модель Products мы получаем записи из базы данных, обходим эти записи в цикле и передаем каждую отдельную запись в DTO объект, чтобы потом наполнить массив созданными DTO объектами.

Laravel 8 - архитектура

DTO объект создается таким образом.

Laravel 8 - архитектура

Laravel 8 - архитектура

После того, как мы получили массив объектов из репозитория, он попадает в дата провайдер. В случае сложной логики, эти данные в дата провайдере передаются в сервисный слой, который преобразует эти данные. Таким образом легко выносится логика различных преобразований в сервис, и потом этот сервис легко тестировать, так как обычно он на вход принимает массив или объекты и отдает преобразованные данные, и в нем нет никаких зависимостей в идеале. На этом этапе сервис у меня не добавлен, поэтому добавлю и протестирую его чуть ниже.

Объясню суть ProductServiceContainer. Он отвечает за внедрение зависимостей в наш дата провайдер. Сейчас в дата провайдер передается экземпляр репозитория реализующего определенный интерфейс, который определен в сигнатуре конструктора в дата провайдере.

Laravel 8 - архитектура

Если проще, то: экземпляр класса ProductRepository удовлетворяет интерфейсу IProductRepository. Этот интерфейс определен в сигнатуре дата провайдера.

Laravel 8 - архитектура

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

Laravel 8 - архитектура

  • 687

01. Об авторе

Александр Занин

Занимаюсь разработкой на Django,
а также бэкенд разработкой на PHP (Laravel, Slim).

Find on :

02. Свежие статьи

Готовы заказать проект?

© ZANIN 2019 / All rights reserved.
Контакты
Close