Laravel 中的 View Composer 該如何使用?

程式技術 sharkHead 10個月前 0

假設有一個網頁,這個網頁有一個區塊是 menubar (選單欄)
menubar 上面有許多連結,這些連結都是儲存在資料表 categories 中
因為這個 menubar 會固定在網頁上方,這代表幾乎所有的 blade 模板都會 include 這個 menubar 的 blade
那麼要如何將連結資料從資料表 categories 撈取出來之後,正確傳給 blade 並顯示呢?

土法煉鋼的作法
是在每個 Controller 裡的每個方法中寫上一段,去撈取資料表 categories 的所有資料

$categories = Category::all();

然後再將變數 $categories 傳給 view

return view('index', ['categories' => $categories]);

在每個 Controller 加上這一段,才能確保不論到哪一頁,menubar 都能確實收到變數 $categories
並正確顯示 menubar 上的所有連結

但在每個 Controller 都加上這一段,工程師才沒這麼勤勞

官方其實還有另外一種方法 View Share,可以直接將參數傳給所有的 blade
但是你很有可能遇到在 migration 時候噴錯,詳情請參考此連結
這時我們可以考慮使用 View Composer,將變數傳給指定的 blade 來使用

首先新增資料夾與檔案 app/Http/View/Composers/CategoryComposer.php

<?php

namespace App\Http\View\Composers;

use App\Models\Category;
use Illuminate\View\View;
use Cache;

class CategoryComposer
{
    // 設定用來依賴注入的變數
    protected $category;

    public function __construct(Category $category)
    {
        // 將 Category Model 依賴注入到 CategoryComposer
        $this->category = $category;
    }

    public function compose(View $view)
    {
    	// 取得所有分類並放入變數 categories
        $categories = this->category->all();
        // 將資料綁定至 blade 模板中
        $view->with('categories', $categories);
    }
}

上段程式碼中,依賴注入的對象是 Model,但官方文件在這裡選擇注入的對象是 Repository
一般來說大型專案會採用下面這種模式,以便於維護

Model ←→ Repository ←→ Service  ←→ Controller

但這個模式並非強求,也有人覺得使用這種模式反而讓程式碼不易閱讀
所以只要專案組員們討論後有共識即可

然後 app/Providers/ 底下新增一個檔案 ViewServiceProvider.php ,內容可以參考官方文件
在 ViewServiceProvider.php 的 boot function 中新增一段程式碼

public function boot()
{
	// 將分類的資料綁定至 View 中
	View::composer(
		['layouts.menubar'], 'App\Http\View\Composers\CategoryComposer'
	);
}

新增的 ViewServiceProvider.php 檔案,必須要在 config.php 中註冊才能使用

'providers' => [
	//視圖合成器
	App\Providers\ViewServiceProvider::class,
]

這時,即使 Controller 沒有特地寫一段來傳遞參數 $categories
resources/views/layouts/menubar.blade.php 這個模板也能獲取 $categories 中的連結資料


Laravel 與 Python 菜雞工程師
喜愛研究程式相關技術
正在學習 TypeScript 與 Vue.js