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

06.10.2020

Теги: LaravelPHPWeb-разработкаПеременнаяТеорияФреймворкШаблонизаторШаблонСайта

При разработке сайтов часто возникает ситуация, когда некие данные являются общими для для многих или вообще всех страниц. Например — навигация в шапке или подвале, блок с популярными записами блога, меню каталога и т.д. Именно для таких случаев в Laravel предусмотрено готовое решение — View Composers.

Допустим, пункты меню мы будем хранить в базе данных.

> php artisan make:model MenuItems -m
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateMenuItemsTable extends Migration {
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up() {
        Schema::create('menu_items', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('url');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down() {
        Schema::dropIfExists('menu_items');
    }
}
> php artisan migrate

namespace App;

use Illuminate\Database\Eloquent\Model;

class MenuItem extends Model {
    // .....
}

Соответственно, при отрисовке какой-либо страницы, надо передать эти данные в представление. В первую очередь вынесем html-код навигации в отдельный файл. Для этого создадим в директории resources/views/layouts поддиректорию parts, в которой создадим файл menu.blade.php — где и разместим наше меню.

<ul>
@foreach($items as $item)
    <li><a href="{{ $item->url }}">{{ $item->name }}</a></li>
@endforeach
</ul>

Включим этот файл в шаблон с помощью @include():

@include('layouts.parts.menu')

Теперь создадим поставщика услуг:

> php artisan make:provider ComposerServiceProvider

И сразу добавим его в массив providers файла конфигурации config/app.php:

return [
    /* ... */
    'providers' => [
        /* ... */
        App\Providers\ComposerServiceProvider::class,
        /* ... */
    ],
    /* ... */
];

Далее редактируем созданный app/Providers/ComposerServiceProvider.php:

namespace App\Providers;

use App\MenuItem;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;

class ComposerServiceProvider extends ServiceProvider {
    /**
     * Register services.
     *
     * @return void
     */
    public function register() {
        // .....
    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot() {
        View::composer('layouts.parts.menu', function($view) {
            $view->with(['items' => MenuItem::all()]);
        });
    }
}

Если нужно отправить данные в несколько представлений:

class ComposerServiceProvider extends ServiceProvider {
    /* ... */
    public function boot() {
        View::composer(['layouts.parts.header', 'layouts.parts.footer'], function($view) {
            $view->with(['items' => MenuItem::all()]);
        });
    }
}

Если нужно отправить данные во все представления:

class ComposerServiceProvider extends ServiceProvider {
    /* ... */
    public function boot() {
        View::composer('*', function($view) {
            $view->with(['items' => MenuItem::all()]);
        });
    }
}

Если нужно отправить разные данные в разные представления:

class ComposerServiceProvider extends ServiceProvider {
    /* ... */
    public function boot() {
        View::composer('layouts.parts.header', function($view) {
            $view->with(['items' => MenuItem::header()]);
        });
        View::composer('layouts.parts.footer', function($view) {
            $view->with(['items' => MenuItem::footer()]);
        });
    }
}
namespace App;

use Illuminate\Database\Eloquent\Model;

class MenuItem extends Model {
    public static function header() {
        return self::where('place', 'header')->get();
    }
    public static function footer() {
        return self::where('place', 'footer')->get();
    }
}

Метод composer() может принимать не только callback-функцию, но и класс. Давайте в app/Http создадим директорию ViewComposers, а внутри нее два файла — NavHeaderComposer.php и NavFooterComposer.php.

namespace App\Http\ViewComposers;

use App\MenuItem;
use Illuminate\View\View;

class NavHeaderComposer {
    public function compose(View $view) {
        return $view->with('items', MenuItem::header());
    }
}
namespace App\Http\ViewComposers;

use App\MenuItem;
use Illuminate\View\View;

class NavFooterComposer {
    public function compose(View $view) {
        return $view->with('items', MenuItem::footer());
    }
}

Поскольку теперь мы используем класс, следует подкорректировать и файл ComposerServiceProvider.php:

namespace App\Providers;

use App\Http\ViewComposers\NavHeaderComposer;
use App\Http\ViewComposers\NavFooterComposer;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;

class ComposerServiceProvider extends ServiceProvider {
    /* ... */
    public function boot() {
        View::composer('layouts.parts.header', NavHeaderComposer::class);
        View::composer('layouts.parts.footer', NavFooterComposer::class);
        /*
        view()->composer('layouts.parts.header', NavHeaderComposer::class);
        view()->composer('layouts.parts.footer', NavFooterComposer::class);
        */
    }
}

Перед началом отображения шаблона композер вызовет метод compose() с экземпляром Illuminate\View\View в качестве первого параметра.

Поиск: Laravel • PHP • Web-разработка • Переменная • Теория • Фреймворк • Шаблонизатор • Шаблон сайта

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.