При работе над большими Laravel-проектами всегда возникает вопрос: «Каким образом мне организовать весь этот код?» Многие люди начали предлагать новые пути решения данной проблемы. Довольно часто люди создают пространство имен в своих котроллерах, представлениях, составителях (view composers) и сервисе каталогов. Но для меня — это нечто паутины, состоящей из каталогов, и кричащей: «Я просто подгоняю все под MVC». Обычно я наблюдаю, как люди создают пространство имен с названиями типа API, Admin Panel и для самого сайта (Marketing). Таким образом, структура их приложения приобретает некий вид:
app/ |- Controllers/ | |- Admin/ | |- API/ | |- Marketing/ |- Services/ | |- Admin/ | |- API/ | |- Marketing/ | |- // разные общие сервисы |- Views/ | |- admin/ | |- marketing/ | |- // какие-то общие представления |- Models/ |- filters.php |- routes.php
Давайте предположим, что вы нашли ошибку в коде панели управления администратора. Вы начинаете с подтягивания безумно большого файла routes.php, и находите маршрут, который приводит вас в каталог с контроллерами. Из каталога с контроллерами вы переходите в пространство имен PHPAdmin
и неисправный контроллер. Теперь вам необходимо исправить ваше представление, которое, к примеру, вы назвали admin.dashboard.index. Теперь вам нужно вернуться в пространство имен PHPAdmin
, подняться выше к контроллерам, а затем спуститься к вашим представлениям, еще ниже к каталогу admin и наконец, к файлу с представлением index.php.
Все становится сложнее с внутренними названиями. Представления и каталог с представлениями — это camelCase, контроллеры и пространство имен PHP — это PascalCase, URI маршрутов – это snake_case, а названия маршрутов зависят от вашего настроения в день их написания. Отчасти эта мешанина произошла по вине разработчика, отчасти – под влиянием различных соглашений разработчиков прежних PHP MVC-фреймворков. Итак, при работе над большими Laravel-проектами, я предлагаю проделать приличный рефакторинг.
На первом этапе, мы начнем с создания каталога с именем, равным названию нашего приложения, чтобы Composer смог использовать соглашение PSR-0 для выполнения автозагрузки классов. Мы назовем его Blog, и сложим туда папки Admin, API, и Marketing для организации кода. Теперь структура нашего приложения буде выглядеть следующим образом:
app/ |- Blog/ | |- Admin/ | | |- Controllers/ | | |- Services/ | | |- Views/ | |- API/ | | |- Controllers/ | | |- Services/ | |- Marketing/ | | |- Controllers/ | | |- Services/ | | |- Views/ |- Services/ | |- // разные общие сервисы |- Views/ | |- // какие-то общие представления |- Models/ |- filters.php |- routes.php
А для того, чтобы наши представления загрузились, мы должны использовать PHPView::addLocation
для каждого пространства имен. Теперь пространство имен для наших контроллеров и сервисов просто необходимо обновить в routes.php и далее. Но я не рассказал настоящую правду о каталоге представлений… Каждый каталог представления будет иметь те же подкаталоги, как и прежде, аналогичные для PHPAdmin
:
app/ |- Blog/ | |- Admin/ | | |- Controllers/ | | |- Services/ | | |- Views/ | | | |- admin/
Для меня это выглядит немного уродливо, и становится излишним при создании файлов с помощью командной строки (или с помощью плагина для редактора SublimeText2 Advanced New File, который мне нравится использовать). К тому же, мы сделали не так уж много для работы с нашими общими представлениями, фильтрами, или маршрутами. Поэтому теперь я собираюсь добавить поставщиков услуг в наш «общий котёл». Это позволит нам отделить эти места нашего приложения на маленькие приложения MVC с несколькими общими компонентами. Есть несколько трюков, которые мы будем использовать. Мы расположим наши представления в пространстве имен подобно тому, как пакеты регистрируют свои представления с помощью PHPView::addNamespace
. Это позволит исключить из наших представлений дополнительный повторяющийся слой.
Мы начнем с наших общих компонентов и нашего поставщика услуг PHPBlog\ServiceProviders\Application
.
<?php namespace Blog\ServiceProviders;
use Illuminate\Support\ServiceProvider;
class Application extends ServiceProvider
{
public function register()
{
}
public function boot()
{
// Тут будут наши общие фильтры, такие как quest или admin
require_once(__DIR__.'/../filters.php');
View::addNamespace('Application', __DIR__.'/../views/');
}
}
Наши общие представления теперь будут доступны в качестве PHPApplication::whateverViewWeWant
. Еще у нас есть общие представления в нашем приложении. Мы также переместим наши модели и любые общие компоненты в app/Blog/Models.
Теперь, давайте посмотрим, как мы структурируем наши суб-приложения. Для нашего Blog\Applications\Admin\ServiceProviders\Admin сделаем следующее:
<?php namespace Blog\Applications\Admin\ServiceProviders;
use Illuminate\Support\ServiceProvider;
class Application extends ServiceProvider
{
public function register()
{
}
public function boot()
{
require_once(__DIR__.'/../routes.php');
View::addNamespace('Admin', __DIR__.'/../views/');
}
}
Теперь все наши представления панели управления администратора будут доступны как Admin::whatever. Для эстетического удовлетворения я также назвал мои маршруты в соответствии с нашими представлениями, и теперь заглавная страница интерфейса будет следующей — Admin::dashboard.index.
Теперь у нас есть хороший способ хранить наш код в разумном порядке, разделяя его на более мелкие под-приложения.
Если вы знакомы с Django, этот шаблон может показаться вам знакомым, так как я много позаимствовал оттуда за то короткое время, что я работал с Django.