
Використання View Composers в Laravel
11.06.2018 17:29 | Laravel
При розробці сайтів ми стикаємося з ситуаціями, коли деякі дані є загальними для багатьох або навіть всіх сторінок. Найпростіші приклади - навігація в хедері або футері, блок з популярними статтями і т.д. Саме для таких випадків в Laravel передбачено елегантне рішення - View Composers. Давайте подивимося, як з ним працювати.
Припустимо, що пункти меню зберігаються у базі даних. Відповідно, кожного разу, коли генерується будь-яка сторінка, нам треба передати ці дані в вид (view). В першу чергу винесемо html-код навігації в окремий файл. Як варіант, створимо в директорії resources/views/layouts
піддиректорію partials
, у якій створимо файл nav.blade.php
– де і розмістимо наше меню. Включимо цей файл в шаблон в такий спосіб::
@include('layouts.partials.nav')
Що стосується передачі даних - є кілька варіантів. Примітивне рішення "в лоб" - просто-напросто дублювати фетчінг даних в кожному контролері, що абсолютно не кошерно. Другий варіант - винаходити якісь свої велосипеди, щоб уникнути дублювання коду. Але навіщо? Адже третій варіант - готове рішення в Laravel, яким і скористаємося.
Створимо постачальника послуг командою у консолі:
php artisan make:provider ComposerServiceProvider
І відразу додамо його в масив providers
файла конфігурації config/app.php
:
...
'providers' => [
...
/*
* Application Service Providers...
*/
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
],
...
Далі переходимо в створений нами app/Providers/ComposerServiceProvider.php
та вставляємо наступне (виходимо з припущення, що у нас в базі даних є таблиця menu_items
і відповідна їй модель MenuItem
):
<?php
namespace App\Providers;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
use App\MenuItem;
class ComposerServiceProvider extends ServiceProvider
{
public function boot()
{
View::composer('layouts.partials.nav', function($view) {
$view->with(['menuitems' => MenuItem::get()]);
});
}
public function register()
{
//
}
}
Прозоріше нікуди, але все ж: перший аргумент - це вид, в який ми передаємо дані, а другий - колбек, в якому ми, власне, і вказуємо, які дані передаємо. Якщо ж потрібно відправити дані в кілька видів, тоді першим аргументом буде масив. Тобто цей код міг би виглядати, наприклад, так:
View::composer(['layouts.partials.nav', 'layouts.partials.footer'], function($view) {
$view->with(['menuitems' => MenuItem::get()]);
});
Якщо ж дані потрібні у всіх в'ю, то перший аргумент буде таким: '*'
.
Здавалося б, тут можна було б сказати that’s it, але пропоную піти трохи далі, адже метод composer()
може приймати не тілько колбек, а й клас. Давайте подивимося і на цей варіант. В app/Http
створимо директорію ViewComposers
, і у ній файл NavigationComposer.php
з наступним змістом:
<?php
namespace App\Http\ViewComposers;
use App\MenuItem;
use Illuminate\View\View;
class NavigationComposer
{
public function compose(View $view)
{
return $view->with('mainitems', MenuItem::get());
}
}
Оскільки тепер ми використовуємо клас, слід підкоригувати і файл ComposerServiceProvider.php
. Ну і щоб показати, що "можна й так", давайте замінимо фасад виду на функцію-хелпер view()
:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Http\ViewComposers\NavigationComposer;
use App\MenuItem;
class ComposerServiceProvider extends ServiceProvider
{
public function boot()
{
view()->composer('layouts.partials.nav', NavigationComposer::class);
}
public function register()
{
//
}
}
Просто і красиво. Наостанок скажу, що особисто я рідко користуюся колбеками, оскільки не завжди ми тільки "дістаємо" дані - часом потрібні різні перевірки. І, якщо в постачальника ми передаємо дані в різні в'ю, його код швидко розростається, стаючи менш читабельним. Тому вважаю за краще використовувати класи.