首页
留言
动态
归档
推荐
音乐
工具
Search
1
Emby公益服-上万部电影电视剧免费看
60,853 阅读
2
openwrt-docker部署lxk0301京东自动签到脚本
12,439 阅读
3
QuantumultX-京东签到撸京东豆
10,759 阅读
4
LXK0301京东签到脚本-自动提交互助码
9,235 阅读
5
微信-域名被封监测以及自动更换被封域名
8,927 阅读
随便写写
科学上网
Web开发
瞎折腾
登录
Search
标签搜索
quantumultx
laravel
openwrt
laravel nova
laradock
telegram
薅羊毛
google adsense
jd_scripts
京东签到
ubuntu
oh-my-zsh
web开发环境
nginx
工具
shadowsocks shadowsocksR
RBAC
权限管理
内网穿透
Python
orzlee
累计撰写
44
篇文章
累计收到
595
条评论
首页
栏目
随便写写
科学上网
Web开发
瞎折腾
页面
留言
动态
归档
推荐
音乐
工具
搜索到
2
篇与
laravel nova
的结果
2019-05-06
laravel-admin 与 laravel-nova 使用感受
前言 两种后台管理扩展我都使用过,两个扩展既有很多相似点,却又有很多不同。接触过laravel nova之后,再接触laravel admin有种莫名的熟悉感,发现在开发中有很多类似的设计思路。 接触laravel admin时间只有一个来月,时间还不长,随便写写吧。有不足之处还请多多指教。 感受 其实laravel nova就是laravel admin的进化版,显然laravel admin是开源扩展,而laravel nova是付费使用的(99刀一个授权可不便宜),在这不考量两者使用授权方面。 laravel admin是一个中国开发者,做出这样的扩展确实非常了不起。扩展设计合理,但是优化上没有laravel nova那么好。 其实最开始接触laravel nova之前是考虑过laravel admin的,由于laravel admin已经封装好了权限管理,自己替换处理又相对麻烦(其实就是懒),才放弃的。laravel admin的权限管理没有做缓存处理,每次使用都要从数据库查询,其实完全可以缓存起来减轻数据库压力。相对于laravel nova这个功能已经交给开发者实现(我还写过一篇关于 laravel nova 权限管理 的文章)。类似于这样需要缓存的还有菜单功能,因为网站上线后这些几乎不变的的数据却又频繁读取,缓存能解决不少数据库压力(有时间自己处理下)。 laravel admin模板还是使用HTML(对于我这种前端弱的一逼的程序员来说真是非常友好),而laravel nova使用vue.js,相对来说vue.js体验感更好,但是技术要求也相对较高。折腾vue.js多多少少还是要翻几次文档。在扩展字段的时候前端模板就相当重要了(反正我写的CSS无法直视)。 laravel admin更加符合国人操作习惯,我使用admin LTE开发过几个后台,基本上不需要教如何使用,大多数功能、按钮一目了然。而laravel nova很多功能、按钮藏的比较深,很多同事反映过找不到地方... 在代码层面,laravel admin我总感觉没有laravel nova那么简洁、灵活。列表页,详情页,编辑页总共需要些三个不同的模板,我是用laravel localization本地化功能,所以需要将三个模板全部修改翻译,而laravel nova只需要编写一次模板,不需要在某个页面显示的字段可以单独关闭: //laravel admin 列表页、详情页、表单,其实还需要三个控制器动作分别输出不同的模板 /** * Make a grid builder. * * @return Grid */ protected function grid() { $grid = new Grid(new ProductSpecification); $this->gridViewPermission($grid); $grid->id('Id')->sortable(); $grid->name(trans('product/specification.name'))->sortable(); $grid->created_at(trans('admin.created_at'))->sortable(); $grid->updated_at(trans('admin.updated_at'))->sortable(); return $grid; } /** * Make a show builder. * * @param mixed $id * @return Show */ protected function detail($id) { $show = new Show(ProductSpecification::findOrFail($id)); $this->showViewPermission($show); $show->id('Id'); $show->name(trans('product/specification.name')); $show->attributes(trans('product/specification_attribute.index'),function (Grid $attributes){ $this->gridViewPermission($attributes); $attributes->setResource(route('admin.product.specification.attribute.index')); $attributes->id()->sortable(); $attributes->name(trans('product/specification_attribute.name'))->sortable(); $attributes->created_at(trans('admin.created_at'))->sortable(); $attributes->updated_at(trans('admin.updated_at'))->sortable(); }); $show->created_at(trans('admin.created_at')); $show->updated_at(trans('admin.updated_at')); return $show; } /** * Make a form builder. * * @return Form */ protected function form() { $form = new Form(new ProductSpecification); $this->formViewPermission($form); $form->text('name', trans('product/specification.name')) ->rules('unique:product_specifications') ->required(); $form->hasMany('attributes', trans('product/specification_attribute.index'), function (Form\NestedForm $form){ $form->text('name',trans('product/specification_attribute.name'))->required(); }); $form->saved(function (Form $form){ $form->model()->forgetCache(); }); return $form; } ... //laravel nova 表单、列表、详情 public function fields(Request $request) { $guardOptions = collect(config('auth.guards'))->mapWithKeys(function ($value, $key) { return [$key => __('nova-permission-tool::roles.guard_names.'.$key)]; }); $userResource = Nova::resourceForModel(getModelForGuard($this->guard_name)); return [ ID::make()->sortable(), Text::make(__('nova-permission-tool::roles.name'), 'name') ->rules(['required', 'string', 'max:255']) ->creationRules('unique:'.config('permission.table_names.roles')) ->updateRules('unique:'.config('permission.table_names.roles').',name,{{resourceId}}'), Text::make(__('nova-permission-tool::roles.guard_name'), function () { return __('nova-permission-tool::roles.guard_names.'.$this->guard_name); }), Select::make(__('nova-permission-tool::roles.guard_name'), 'guard_name') ->options($guardOptions->toArray()) ->rules(['required', Rule::in(array_keys($guardOptions->toArray()))]) ->onlyOnForms(), DateTime::make(__('nova-permission-tool::roles.created_at'), 'created_at')->exceptOnForms(), DateTime::make(__('nova-permission-tool::roles.updated_at'), 'updated_at')->exceptOnForms(), BelongsToMany::make(__('nova-permission-tool::resources.Permissions'), 'permissions', Permission::class)->searchable(), MorphToMany::make($userResource::label(), 'users', $userResource)->searchable(), ]; } 通过以上代码对比可以看出两个扩展在代码简洁性上有蛮大区别的。一个个字段写入翻译蛮麻烦的。在关系字段处理上需要关联表的控制器,然后增删改查又是一套... 当然这样也是有好处的,高度自定义,只不过一个后台管理用处不多,大多数可以自定义字段扩展出来。 laravel admin几乎把所有字段所需的 javaScript放在后端输出,其实这样对前端不友好,现在都前后端开始分离了,前端代码放在PHP中嵌套写蛮乱的,后期维护也相对困难。 结语 laravel nova和laravel admin都是非常好的扩展,只是国内大多数只知道拿人家的用,却很少去贡献,生态不如国外。两个扩展都朝着相同的目标,节省后台开发时间,但是一个收费,一个开源,而且laravel nova还是laravel作者团队开发的(框架加持)。扩展都是好扩展,要按项目需求和自己的熟练程度来选择使用哪种扩展开发后台,有能力两种都试试,深深体会一下。
2019年05月06日
3,333 阅读
0 评论
1 点赞
2018-12-18
laravel nova 权限管理工具
前言 前几个月一直在折腾laravel nova,不得不说它的扩展性非常强。laravel nova packages每天都会有很多新鲜的扩展包,生态很好。spatie laravel-permission是非常不错的Role-based access control RBAC扩展包,orzlee在laravel 5.3就在使用了,这里主要说说spatie laravel-permission的laravel nova权限管理工具。 Larval nova packages 目前有三款laravel nova packages包是基于spatie laravel-permission开发的,功能上大同小异,各有特色。 1. vyuldashev/nova-permission: 这是最早出现基于spatie laravel-permission的laravel nova packages。支持自定义资源,本地化支持。 orzlee一开始也是使用的这款扩展包,但是没几天我就发现了一个问题,因为laravel nova的Relationships并不会调用spatie laravel-permission自带的权限或角色附加、分离方法,所以在给用户添加权限时不会触发权限缓存更新。这就必须等待缓存过期或者手动清理缓存。 这个问题一直没有解决,orzlee也关注了Issues:Cache not invalidated on attaching a role or permission to user好长一段时间,然而并没有进展。最后还是提问者重新创建了一个新的包insenseanalytics/laravel-nova-permission。 2. insenseanalytics/laravel-nova-permission: 这款包主要是使用ForgetCachedPermissions中间件来判断当前路由是否为附加或分离请求(attach,detach),然后过滤出附加或分离权限的请求,执行缓存清除。 分离时没有问题,但是附加在路由判断上有点问题。orzlee在测试的时候发现附加怎么也无法清除缓存,经过调试发现url没有匹配到。 class ForgetCachedPermissions { /** * Handle the incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * * @return \Illuminate\Http\Response */ public function handle($request, $next) { $response = $next($request); if ($request->is('nova-api/*/detach') || $request->is('nova-api/*/*/attach/*')) { ##作者判断了attach,但是orzlee的请求路由为:http://127.0.0.1:8000/nova-api/admins/1/attach-morphed/permissions $permissionKey = (Nova::resourceForModel(app(PermissionRegistrar::class)->getPermissionClass()))::uriKey(); if ($request->viaRelationship === $permissionKey) { app(PermissionRegistrar::class)->forgetCachedPermissions(); } } return $response; } } orzlee已经向作者提交Issues了。 orzlee在给作者RP包语言本地化时有一个权限搜索翻译的功能没有被作者合并。作者觉得使用自定义资源功能让用户自行实现,这样也不错,不过度化设计。 权限是由开发者添加,而使用的时候基本上是管理员在操作。现在添加权限是一个搜索选择器,管理员需要给某个用户或管理员添加权限就必须搜索。权限在添加时为了多语言化必用标识,管理员在搜索时按照本地化语言搜索会方便很多。 orzlee还是把实现方法分享出来吧: GuardFilterHandelTrait主要功能是按guard_name过滤掉不属于附加用户的权限,防止多guard_name权限混乱。 use Laravel\Nova\Http\Requests\NovaRequest; trait GuardFilterHandelTrait { /** * Override the applyFilters method to add the guard_name condition when filtering * * @param \Laravel\Nova\Http\Requests\NovaRequest $request * @param \Illuminate\Database\Eloquent\Builder $query * @param array $filters * * @return \Illuminate\Database\Eloquent\Builder */ protected static function applyFilters(NovaRequest $request, $query, array $filters) { $query = parent::applyFilters($request, $query, $filters); if ($model = head($request->__memoized)) { $guard_name = $model->guard_name ?? self::getGuardForModel(get_class($model)); $query->where('guard_name', $guard_name); } return $query; } /** * @param string model * * @return string|null */ public static function getGuardForModel(string $model) { return collect(config('auth.guards')) ->map(function ($guard) { return config("auth.providers.{$guard['provider']}.model"); })->search($model); } } PermissionSearchTranslationTrait搜索权限时会按照本地化语言反向找出对应权限。 trait PermissionSearchTranslationTrait { use GuardFilterHandelTrait; /** * Override the applyFilters method,title field translation */ public function title() { return __('laravel-nova-permission::permissions.display_names.'.$this->name); } /** * Rewrite the applySearch method to apply translation field search * * @param \Illuminate\Database\Eloquent\Builder $query * @param string $search * @return \Illuminate\Database\Eloquent\Builder */ protected static function applySearch($query, $search) { return $query->where(function ($query) use ($search) { if (is_numeric($search) && in_array($query->getModel()->getKeyType(), ['int', 'integer'])) { $query->orWhere($query->getModel()->getQualifiedKeyName(), $search); } $model = $query->getModel(); $connectionType = $query->getModel()->getConnection()->getDriverName(); $likeOperator = $connectionType == 'pgsql' ? 'ilike' : 'like'; $trans_search = array_keys(preg_grep("/$search/",array_dot(__('laravel-nova-permission::permissions.display_names')))); foreach (static::searchableColumns() as $column) { $qualify_column = $model->qualifyColumn($column); foreach ($trans_search as $t_search){ $query->orWhere($qualify_column, $likeOperator, '%'.$t_search.'%'); } $query->orWhere($qualify_column, $likeOperator, '%'.$search.'%'); } }); } } 自定义Role & Permission资源(注意命名空间替换成自己项目对应的): use App\Traits\Resources\GuardFilterHandelTrait; use \Insenseanalytics\LaravelNovaPermission\Role as BaseRole; class Role extends BaseRole { use GuardFilterHandelTrait; } use App\Traits\Resources\PermissionSearchTranslationTrait; use \Insenseanalytics\LaravelNovaPermission\Permission as BasePermission; class Permission extends BasePermission { use PermissionSearchTranslationTrait; } 按照作者文档自定义角色和权限类: // in app/Providers/NovaServiceProvider.php public function tools() { return [ // ... \Insenseanalytics\LaravelNovaPermission\LaravelNovaPermission::make() ->roleResource(CustomRole::class) ->permissionResource(CustomPermission::class), ]; } 如果你还没有发布语言文件请执行: php artisan vendor:publish --provider="Insenseanalytics\LaravelNovaPermission\NovaPermissionServiceProvider" 创建自己本地化语言文件,例如在项目路径./resources/lang/vendor/laravel-nova-permission/创建一个zh-CN文件夹,复制en中的所有文件到zh-CN,然后自己翻译。display_names就是权限name对应的本地化翻译。 'display_names' => [ 'test' => '测试', 'delete' => '删除', 'edit' => '编辑', 'create' => '创建', ], 现在应该支持本地化权限搜索了。或者可以直接使用包jianminlee/laravel-nova-filter。 该包还支持基于laravel nova的权限验证,非常方便,在nova资源中使用PermissionsBasedAuthTrait Trait,然后定义一个静态变量: class YourNovaResource extends Resource { use \Insenseanalytics\LaravelNovaPermission\PermissionsBasedAuthTrait; public static $permissionsForAbilities = [ 'viewAny' => 'view products', 'view' => 'view products', 'create' => 'create products', 'update' => 'update products', 'delete' => 'delete products', 'restore' => 'restore products', 'forceDelete' => 'forceDelete products', 'addAttribute' => 'add product attributes', 'attachAttribute' => 'attach product attributes', 'detachAttribute' => 'detach product attributes', ]; .... } 详细文档可以取项目地址查看。insenseanalytics/laravel-nova-permission 3. DigitalCloud/nova-permission-tool: 今天刚刚发布的的,该包根据资源自动生成对应权限,听上去高大上,但是会多出不少多余的权限。因为我们的资源不一定会实现所有功能,到时候添加权限就会眼花缭乱了。orzlee认为还是自定义的好。 作者还自定义角色和权限的字段,在操作上体验好很多。凡是都有两面性,如果项目比较大(权限多)的情况下体验就可想而知了。 结语 这三款包都各有特色,同一功能的包就有这么多,这些还都只是基于spatie laravel-permission的,还有其他作者自己实现的权限管理工具。回过头来,还是得靠自己,工具再多也不一定都适合自己的项目,好好学Vue吧!
2018年12月18日
5,665 阅读
0 评论
0 点赞