Voyager 的使用及二次开发

主要整理了我对 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 进行修复,因为只有针对角色的权限分配,不能根据资源的创建者分配更细的权限,所以还需额外部署对应的逻辑。

本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由系统于 5年前 自动加精
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 8

非常不错。之前找后台的时候也找到了这个,苦于对于laravel的研究不深。怕出问题没有及时的解决方案,所以使用了laravel-admin。毕竟国人开发,反馈问题可以得到快速回复。

不过内心还是想使用下voyager的。 先收藏下

5年前 评论
Destiny

快速后台用的最顺手的还是 laravel-admin,本地化后各种改功能很顺手,Nova 使用后还是很不习惯。。。。可能是深度不够。哈哈。。。

5年前 评论

你还是会使用laravel-admin的 因为 太慢了 一个页面几百个查询

5年前 评论
JerryBool 4年前
tkn_laravel_china 3年前

voyager 默认使用的是users表, 怎么修改为admins表? :cry:

4年前 评论

对于Voyager的文档,本人进行了翻译,查看Voyager中文文档,希望对大家有所帮助

4年前 评论

请教下,voyager后台利用file上传的视频文件怎么在前台展示呀? 数据库获取到存储视频的字段内容为:[{"download_link":"blogs\November2022\GlZU26tKxdxZjB7p2uv9.mp4","original_name":"002 \u6536\u8d27 \u8f6c\u5165\u786e\u8ba4 \u8de8\u533a\u8f6c\u5165\u786e\u8ba4.mp4"}]

## 前台视图如何展示视频呀,后台能看到,也能获取到真实地址。

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!