Voyager 的使用及二次開發

skyArony發表於2018-10-23

主要整理了我對 Laravel 的後臺開源專案 Voyager 的一點經驗。

一、簡介

做一個 Web 系統,後臺是必須的,後臺大致可以分為兩類:

後端導向

這裡以 Laravel 為例,這類後臺的特點是可以直接通過關聯了資料表的 Model 來輕易的建立 CURD(增刪改查),這樣可以省去大量控制器 CURD 的程式碼。後端具有更強的主導性。

前端導向

這種前端具有更強的主導性。

本文重點

在此主要介紹的是 Voyager,如上所述,Voyager 可以輕易的根據 Model 自動建立 BREAD(即 CURD),這樣你可以省去寫控制器及方法的程式碼,並且 Voyager 支援二次開發,具有足夠高的定製性。

至於 Voyager 的缺點,主要還是前端是用的 Blade 寫的,雖然 Blade 是 Laravel 自帶提供的前端模板引擎,但是對於飛速發展的前端框架來說,Vue 是個更好的解決方案。

本文主要是介紹我自己在使用 Voyager 中遇到的一些問題和解決方案,和一些二次開發時的經驗。

二、安裝

1. 下載包

先把包下載過來

composer require tcg/voyager

2. 設定語言環境

設定環境為中文

config\app.php

'locale' => 'zh_CN',

3. 執行安裝

# 正常安裝
php artisan voyager:install

# 假資料安裝
php artisan voyager:install --with-dummy

# 把一個使用者設定為可登陸的管理員
php artisan voyager:admin your@email.com

# 新建一個可登陸的管理員
php artisan voyager:admin your@email.com --create

假資料安裝下的賬號和密碼:

email: admin@admin.com
password: password

三、二次開發

Voyager 的二次開發主要有三種形式:覆寫檢視,覆寫路由,繼承控制器。

1. 覆寫檢視

檢視層的二次開發可以參照官方文件,大致思路就是在 resource 下建立一個和 vendor 中包目錄下一樣的目錄結構,複製你想要重寫的檢視內容檔案,然後以此為基礎進行修改即可。

包目錄下的

image-20180821165431966.pngfile

自己的開發目錄

image-20180821165537551.pngfile

方式一:修改 blade

這一層只需要按照 blade 模板引擎的語法對檔案進行修改即可。

同時如果有這樣一個需求:對於所有 post,我只想讓 post 的建立者看到,即每個管理員只能看到自己建立的 post。但是在 Voyager 預設建立好 BREAD 之後,Voyager 中的許可權管理只能做到使用者要麼全看到,要麼全看不到。

這個時候,就可以修改 blade,在其中加一個過濾操作即可解決問題。

但是值得注意的是:這樣並不優雅,因為更好的邏輯應該是在查資料庫時就只取所需的資料,而不是這樣全取出來再過濾。但是這種方法比較簡單,改動的程式碼量也小。所以見仁見智啦。

方式二:Vue 單檔案元件

這種方式是通過 Vue 寫單檔案元件,然後直接像 HTML 標籤一樣插入 Blade 中,然後其中的內容就隨便你 Vue 怎麼寫了。

/resources/assets/js/app.js

// 單檔案元件
Vue.component('worlduc-video', require('./components/Index-Video.vue'));

/resources/views/video.blade.php

<div id="app" style="width:100%;height:100%;">
  <worlduc-video></worlduc-video>
</div>

額外

  • 若是想要新增子頁面,並且是帶那種左側 admin 導航的子頁,在新建的 blade 檔案中新增如下即可:

    @extends('voyager::master')
  • 若是新增的子頁面想要放在登陸保護後,則新增其路由至 admin.user 中介軟體後

    // 自定義的頁要加到認證後的,就加到這個裡面
    Route::group(['middleware' => 'admin.user'], function () {
      // 課程資訊頁
      Route::view('/admin/teams/member/{teamId}', 'addMember');
      // 首頁
      Route::view('/', 'index');
    });
  • 若想要一個使用者可以登入的 Voyager 並看到其中的內容,必須給予 admin 的 browse 許可權,否則無法登陸成功。

2. 覆寫路由

這也是官方文件中明確支援的一種方式,能夠將本來 Voyager 定義的一些路由,比如登陸,用自己的控制器和對應方法去替代。

Route::get('/', function () {
    return view('welcome');
});

Route::group(['prefix' => 'admin'], function () {
    // Voyager 原本的路由
    Voyager::routes();  
    // 覆蓋了原先的登入,新增了自定義的本身認證
    Route::post('login', 'LoginController@postLogin')->name('voyager.login');
    // 覆蓋原先的登出
    Route::post('logout', 'LoginController@postLogout')->name('voyager.logout');
});

3. 覆寫控制器

控制器的重寫,官方文件也寫的足夠詳細了,首先在 config/voyager.php 中如下定義:

'controllers' => [
  'namespace' => 'App\\Http\\Controllers\\Voyager',
],

然後執行 php artisan voyager:controllers,這樣控制器就會被建立到你的控制器目錄,而這些控制器是繼承自包中原先的控制器,如果你不覆寫,還是能正常工作,如果你想進行自己的控制,那麼就可以直接重寫對應的方法。

4. 自定義控制器

除了上面覆寫控制器的方法,你還可以看到在建立 BREAD 時,可以直接選擇控制器,而這個控制器完全可以由你自己寫,但是我並沒有實踐,BREAD 對應的增刪改查操作應該對應的是控制器什麼方法名,有興趣的同學可以去看一下原始碼。

四、其他

除了上面的二次開發外,還有其他一些使用的的經驗和實踐,整理如下:

1. 部分欄位自定義 create

現在有一個需求,我需要在一個表中插入一條資料,這條資料由三個欄位組成,分別為 A、B、C。其中 B、C 我讓使用者自己輸入,但是 A 我想要系統讀取使用者的資訊來自動填入(比如讀取使用者的 ID,用來標識這條資料的建立者)。想想該怎麼做呢?

一般來說,我們可以先考慮一下資料儲存過程中需要用到的兩個東西:Controller 和 Model,其中 Model 可以試著一個 attributes 屬性來設定欄位的預設值,但是這個屬性要求都為靜態值,是無法使用變數的。Controller 的話可以重寫 Controller,修該邏輯即可,但是重寫 Controller 其實程式碼量還是比較大的。有沒有更加簡單的辦法呢?當然是有的!

方法一

在 bread 中設定欄位為 hidden 並在可選細項中設定一個預設值,然後在模型中配置一個修改器,設定成你想要的值即可。

image-20180822145611512.pngfile

public function setCreaterIdAttribute($value)
{
  $this->attributes['creater_id'] = Cookie::get('user_id');
}

為什麼要配置這個預設值呢?因為模型中的修改器只有在這個欄位被設定了值才能成功觸發。

方法二

不在可選細項配置預設值,只新增修改器即可:

// 讓你想要設定的值在其他修改器中順便被新增即可
public function setTeamNameAttribute($value)
{
  $this->attributes['team_name'] = $value;
  $this->attributes['creater_id'] = Cookie::get('user_id');
}

方法三

配置一個關係,按照圖中勾選即可(其實 creater_id 那隻需勾選『新增』便可達到效果,其他不影響)

image-20181023151613114.pngfile

public function setCreaterIdAttribute($value)
{
  $this->attributes['creater_id'] = Cookie::get('id');
}

2. datetimepicker 無法顯示的 bug

覆寫 master.blade.php,新增如下:

<!-- datatimepicker -->
<link rel="stylesheet" href="/css/bootstrap-datetimepicker.min.css">
// 這個 css 新增到上方合適位置
// css 自行下載 https://github.com/Eonasdan/bootstrap-datetimepicker/releases

<script type="text/javascript" src="{{ voyager_asset('js/app.js') }}"></script> 
// 這一行是本來有的

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.19.1/moment-with-locales.js"></script>
<script>
    moment.locale("zh-cn");
</script>
// 上面是設定語言,不過語言設定為中文會格式化報錯

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.47/js/bootstrap-datetimepicker.min.js"></script>

出現 bug 的原因是其引用的一個 js 外掛有 bug,指定一個沒有 bug 的版本即可。

3. 表單欄位可為空如何控制

在進行新建或編輯時,你會發現有些欄位是必填的,而有些欄位是非必填,但是並沒有看到有一個控制的選項。其實這個是根據資料表的欄位是否可為 NULL 控制的。但其實這個設定存在不少 bug:

  1. 如果輸入空白符,前端會認為你填寫了資料而放行,但是後端會報錯
  2. 對於下拉選擇,如果你選擇的是 None ,並提交而這個欄位又設定未非空的話也會報錯。

所以我建議還是覆寫 edit-add 這個 blade,新增 js 進行控制。

4. Voyager 配置完畢後如何匯出設定

Voyager 的後臺一些設定是儲存在資料庫中的,建議使用 orangehill/iseed 這個外掛來將資料庫的資料轉換為 seeder,然後新增 Git 進行管理即可。

五、總結

Voyager 是一個非常不錯的後臺模板,功能齊全,顏值高,能夠快速的搭建一個好用的後臺,但是其中存在的小 bug 還是比較多,如果是作為開發者內部團隊簡單使用遠遠足夠,但是若作為一個開放給外部使用者使用,還需針對各個小 bug 進行修復,因為只有針對角色的許可權分配,不能根據資源的建立者分配更細的許可權,所以還需額外部署對應的邏輯。

相關文章