主要整理了我對 Laravel 的後臺開源專案 Voyager 的一點經驗。
一、簡介
做一個 Web 系統,後臺是必須的,後臺大致可以分為兩類:
後端導向
這裡以 Laravel 為例,這類後臺的特點是可以直接通過關聯了資料表的 Model 來輕易的建立 CURD(增刪改查),這樣可以省去大量控制器 CURD 的程式碼。後端具有更強的主導性。
- Voyager : Blade + Laravel
- Laravel-Admin : Laravel
- Laravel Nova : Laravel 官方開發,但是付費
前端導向
這種前端具有更強的主導性。
- Vue-Element-Admin : Vue + Element
- iView-Admin : Vue + iView
本文重點
在此主要介紹的是 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.png
自己的開發目錄
image-20180821165537551.png
方式一:修改 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.png
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.png
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:
- 如果輸入空白符,前端會認為你填寫了資料而放行,但是後端會報錯
- 對於下拉選擇,如果你選擇的是
None
,並提交而這個欄位又設定未非空的話也會報錯。
所以我建議還是覆寫 edit-add
這個 blade,新增 js 進行控制。
4. Voyager 配置完畢後如何匯出設定
Voyager 的後臺一些設定是儲存在資料庫中的,建議使用 orangehill/iseed
這個外掛來將資料庫的資料轉換為 seeder,然後新增 Git 進行管理即可。
五、總結
Voyager 是一個非常不錯的後臺模板,功能齊全,顏值高,能夠快速的搭建一個好用的後臺,但是其中存在的小 bug 還是比較多,如果是作為開發者內部團隊簡單使用遠遠足夠,但是若作為一個開放給外部使用者使用,還需針對各個小 bug 進行修復,因為只有針對角色的許可權分配,不能根據資源的建立者分配更細的許可權,所以還需額外部署對應的邏輯。