分类管理
/**
* 分类管理
*/
// 分类禁用和启用
$api->patch('category/{category}/status', [\App\Http\Controllers\Admin\CategoryController::class, 'status'])->name('category.status');
// 分类管理资源路由
$api->resource('category', \App\Http\Controllers\Admin\CategoryController::class, [
'except' => ['destroy']
]);
控制器
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\BaseController;
use App\Models\Category;
use Illuminate\Http\Request;
class CategoryController extends BaseController
{
/**
* 分类列表
*/
public function index(Request $request)
{
$type = $request->input('type');
if ($type == 'all') {
return cache_category_all();
} else {
return cache_category();
}
}
/**
* 添加分类 最大2级分类
*/
public function store(Request $request)
{
$insertData = $this->checkInput($request);
if (!is_array($insertData)) return $insertData;
Category::create($insertData);
return $this->response->created();
}
/**
* 分类详情
*/
public function show(Category $category)
{
return $category;
}
/**
* 更新分类
*/
public function update(Request $request, Category $category)
{
if ($category->id < 42) return $this->response->errorBadRequest('系统数据禁止编辑, 请自行创建数据');
$updateData = $this->checkInput($request);
if (!is_array($updateData)) return $updateData;
$category->update($updateData);
return $this->response->noContent();
}
/**
* 验证提交的参数
*/
protected function checkInput($request)
{
// 验证参数
$request->validate([
'name' => 'required|max:16'
], [
'name.required' => '分类名称 不能为空'
]);
// 获取分组
$group = $request->input('group', 'goods');
// 获取pid
$pid = $request->input('pid', 0);
// 计算level
$level = $pid == 0 ? 1 : (Category::find($pid)->level + 1);
// 不能超过3级分类
if ($level > 2) {
return $this->response->errorBadRequest('不能超过二级分类');
}
return [
'name' => $request->input('name'),
'pid' => $pid,
'level' => $level,
'group' => $group
];
}
/**
* 状态禁用和启用
*/
public function status(Category $category)
{
if ($category->id < 42) return $this->response->errorBadRequest('系统数据禁止编辑, 请自行创建数据');
$category->status = $category->status == 1 ? 0 : 1;
$category->save();
return $this->response->noContent();
}
}
Helpers.php
/**
* 缓存没被禁用的分类
*/
if (!function_exists('cache_category')) {
function cache_category ()
{
return cache()->rememberForever('cache_category', function () {
return categoryTree('goods', 1);
});
}
}
/**
* 缓存所有的分类
*/
if (!function_exists('cache_category_all')) {
function cache_category_all ()
{
return cache()->rememberForever('cache_category_all', function () {
return categoryTree('goods');
});
}
}
/**
* 清空分类缓存
*/
if (!function_exists('forget_cache_category')) {
function forget_cache_category ()
{
cache()->forget('cache_category');
cache()->forget('cache_category_all');
}
}
class CategoryTransformer extends TransformerAbstract
{
public function transform(Category $category)
{
return [
'id' => $category->id,
'pid' => $category->pid,
'name' => $category->name,
];
}
}
商品管理
路由
/**
* 商品管理
*/
// 是否上架
$api->patch('goods/{good}/on', [\App\Http\Controllers\Admin\GoodsController::class, 'isOn'])->name('goods.on');
// 是否推荐
$api->patch('goods/{good}/recommend', [\App\Http\Controllers\Admin\GoodsController::class, 'isRecommend'])->name('goods.recommend');
// 商品管理资源路由
$api->resource('goods', \App\Http\Controllers\Admin\GoodsController::class, [
'except' => ['destroy']
]);
控制器
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\BaseController;
use App\Http\Requests\Admin\GoodsRequest;
use App\Models\Category;
use App\Models\Good;
use App\Transformers\GoodTransformer;
use Illuminate\Http\Request;
class GoodsController extends BaseController
{
/**
* 商品列表
*/
public function index(Request $request)
{
$title = $request->query('title');
$category_id = $request->query('category_id');
$is_on = $request->query('is_on', false);
$is_recommend = $request->query('is_recommend', false);
$goods = Good::when($title, function ($query) use ($title) {
$query->where('title', 'like', "%$title%");
})
->when($category_id, function ($query) use ($category_id) {
$query->where('category_id', $category_id);
})
->when($is_on !== false, function ($query) use ($is_on) {
$query->where('is_on', $is_on);
})
->when($is_recommend !== false, function ($query) use ($is_recommend) {
$query->where('is_recommend', $is_recommend);
})
->orderBy('updated_at', 'desc')
->paginate($request->query('pageSize', 10), ['*'], 'current');
return $this->response->paginator($goods, new GoodTransformer());
}
/**
* 添加商品
*/
public function store(GoodsRequest $request)
{
// 对分类进行一下检查, 只能使用3级分类, 并且分类不能被禁用
$catagory = Category::find($request->category_id);
if (!$catagory) return $this->response->errorBadRequest('分类不存在');
if ($catagory->status == 0) return $this->response->errorBadRequest('分类被禁用');
if ($catagory->level != 2) return $this->response->errorBadRequest('只能向2级分类添加商品');
$user_id = auth('api')->id();
// 追加user_id字段
// $insertData = $request->all();
// $insertData['user_id'] = $user_id;
// Good::create($insertData);
// 追加user_id字段
$request->offsetSet('user_id', $user_id);
Good::create($request->all());
return $this->response->created();
}
/**
* 商品详情
*/
public function show(Good $good)
{
return $this->response->item($good, new GoodTransformer());
}
/**
* 更新商品
*/
public function update(GoodsRequest $request, Good $good)
{
if ($good->id < 237) return $this->response->errorBadRequest('系统数据禁止编辑, 请自行创建数据');
// 对分类进行一下检查, 只能使用3级分类, 并且分类不能被禁用
$catagory = Category::find($request->category_id);
if (!$catagory) return $this->response->errorBadRequest('分类不存在');
// if ($catagory->status == 0) return $this->response->errorBadRequest('分类被禁用');
if ($catagory->level != 2) return $this->response->errorBadRequest('只能向2级分类添加商品');
$good->update($request->all());
return $this->response->noContent();
}
/**
* 是否上架
*/
public function isOn(Good $good)
{
$good->is_on = $good->is_on == 0 ? 1 : 0;
$good->save();
return $this->response->noContent();
}
/**
* 是否推荐
*/
public function isRecommend(Good $good)
{
$good->is_recommend = $good->is_recommend == 0 ? 1 : 0;
$good->save();
return $this->response->noContent();
}
}
<?php
namespace App\Transformers;
use App\Models\Category;
use App\Models\Good;
use League\Fractal\TransformerAbstract;
class GoodTransformer extends TransformerAbstract
{
protected $availableIncludes = ['category', 'user', 'comments'];
public function transform(Good $good)
{
$pics_url = [];
if (!empty($good->pics)) {
foreach ($good->pics as $p) {
array_push($pics_url, oss_url($p));
}
}
return [
'id' => $good->id,
'title' => $good->title,
'category_id' => $good->category_id,
'user_id' => $good->user_id,
// 'category_name' => Category::find($good->category_id)->name,
'description' => $good->description,
'price' => $good->price,
'stock' => $good->stock,
'sales' => $good->sales,
'cover' => $good->cover,
'cover_url' => oss_url($good->cover),
'pics' => $good->pics,
'pics_url' => $pics_url,
'details' => $good->details,
'is_on' => $good->is_on,
'is_recommend' => $good->is_recommend,
'created_at' => empty($good->created_at) ? $good->created_at : $good->created_at->toDateTimeString(),
'updated_at' => empty($good->updated_at) ? $good->updated_at : $good->updated_at->toDateTimeString(),
];
}
/**
* 额外的分类数据
*/
public function includeCategory(Good $good)
{
return $this->item($good->category, new CategoryTransformer());
}
/**
* 额外的用户数据
*/
public function includeUser(Good $good)
{
return $this->item($good->user, new UserTransformer());
}
/**
* 额外的评价数据
*/
public function includeComments(Good $good)
{
return $this->collection($good->comments, new CommentTransformer());
}
}
OSS 存储
接入阿里云OSS
- 开通阿里云OSS
- 购买资源包
- 创建Bucket
- 设置跨域规则
其他说明
安装oss组件:
$ composer require "iidestiny/laravel-filesystem-oss"
OSS文档地址:
创建控制器
php artisan make:controller Auth/OssController
添加路由
$api->get('oss/token', [\App\Http\Controllers\Auth\OssController::class, 'token']);
$disk = Storage::disk('oss');
$config = $disk->signatureConfig($prefix = '/', $callBackUrl = '', $customData = [], $expire = 300);
$configArr = json_decode($config, true);
return $this->response->array($configArr);
if (!function_exists('oss_url')) {
function oss_url($key)
{
// 如果没有$key
if (empty($key)) return '';
// 如果$key包含了http等, 是一个完整的地址, 直接返回
if (strpos($key, 'http://') !== false
|| strpos($key, 'https://') !== false
|| strpos($key, 'data:image') !== false) {
return $key;
}
return config('filesystems')['disks']['oss']['bucket_url'] . '/' . $key;
}
}
什么是多用户角色
举个例子,例如我们平常使用的论坛
站长 ——— 拥有最高权限,最主要的是能够对用户进行管理的权限
管理员 ——- 对一些文章的管理,不会造成对网站有较大的影响
vip ——- 对一些资源有下载权限
普通用户 —— 只能够进行简单的对自己文章的增删改、评论等
游客 —— 只能进行基本的浏览
建表
roles ———- 角色信息:站长等
permissions ———- 权限信息:管理内容等
model_has_roles ———- 模型对应角色 = 用户对应的角色
role_has_permissions ———- 角色对应权限 = 角色有什么权限
model_has_permissions ———- 模型对应权限 = 用户有权限
我们来梳理一下关联关系
权限(permissions)与 角色(roles) ,一个 权限 可能被多个 角色 拥有,一个 角色 可能有多个 权限,关联关系:多对多(role_has_permissions)
用户 与 权限 一对多(model_has_permissions)
用户 与 角色 一对多(model_has_roles)
由次来说,关系明确了,当用户有什么角色 或者 有什么权限,即执行相应的操作
laravel-permission
laravel-permission 基于上面 的表情况,将用户与权限和角色相关联
1. 安装扩展包
通过 Composer 安装:
$ composer require "spatie/laravel-permission"
生成数据库迁移文件:
php artisan vendor:publish —provider=”Spatie\Permission\PermissionServiceProvider”
在migration目录下可看到相关表信息,执行数据库迁移
php artisan migrate
在User 模型下加载
.....
use Spatie\Permission\Traits\HasRoles; // use
class User extends Authenticatable
{
use HasRoles; // 加载角色相关信息
.....
修改迁移文件添加为权限和角色添加cn_name
$table->string('cn_name');
// 创建数据填充
php artisan make:seeder PermissionSeeder
修改DatabaseSeeder
public function run()
{
$this->call(PermissionSeeder::class);
}
public function run()
{
// 清空缓存
app()['cache']->forget('spatie.permission.cache');
// 添加权限
$permissions = [
['name' => 'users.index', 'cn_name' => '用户列表', 'guard_name' => 'api'],
['name' => 'users.show', 'cn_name' => '用户详情', 'guard_name' => 'api'],
['name' => 'users.lock', 'cn_name' => '用户禁用启用', 'guard_name' => 'api'],
];
foreach ($permissions as $p) {
Permission::create($p);
}
// 添加角色
$role = Role::create(['name' => 'super-admin', 'cn_name' => '超级管理员', 'guard_name' => 'api']);
// 为角色添加权限
$role->givePermissionTo(Permission::all());
}
执行dbseed
php artisan db:seed --class PermissionSeeder
创建用户DBSEED
php artisan make:seed UserSeeder
<?php
namespace Database\Seeders;
use App\Models\User;
use Illuminate\Database\Seeder;
class UserSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
// 创建用户
$user = User::create([
'name' => '超级管理员',
'email' => 'super@a.com',
'password' => bcrypt('123123')
]);
// 给用户分配角色
$user->assignRole('super-admin');
}
}
验证权限
创建一个中间件
php artisan make:middleware CheckPermission
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
// 验证用户是否具有请求权限
$user = auth('api')->user();
if (!$user->can($request->route()->getName())) {
abort(403);
}
return $next($request);
}
app/Http/Kernel.php
protected $routeMiddleware = [
....
'check.permission' => \App\Http\Middleware\CheckPermission::class
];
路由上添加中间件
$api->group(['prefix' => 'admin','middleware' => ['api.auth','check.permission']], function ($api) {
使用
为用户添加权限
$user->givePermissionTo('edit articles');
为用户添加角色
$user->assignRole('writer');
$user->assignRole(['writer', 'admin']);
给用户删除权限
$user->revokePermissionTo('edit articles');
给角色添加权限
$role->givePermissionTo('edit articles');
为角色添加权限
$role->givePermissionTo('edit articles');
撤销一个权限 并且 添加一个新权限
$user->syncPermissions(['edit articles', 'delete articles']);
获得当前用户的角色集合
$user->getRoleNames();
将多个角色同步到权限
$role->syncPermissions($permissions); // @param array $permissions
$permission->syncRoles($roles);
从角色中删除权限
$role->revokePermissionTo($permission);
$permission->removeRole($role);
获取当前的用户的权限列表
$permissions = $user->permissions;
获取用户的所有权限,或者直接权限 (odel_has_permissions),或者从角色获取,或者从两者获取
$permissions = $user->getDirectPermissions();
$permissions = $user->getPermissionsViaRoles();
$permissions = $user->getAllPermissions();
获取用户的角色集合 collection
$roles = $user->getRoleNames(); // Returns a collection
返回指定角色的用户 | Returns only users with the role ‘writer’
$users = User::role('writer')->get(); //
返回指定权限的用户
$users = User::permission('edit articles')->get();
用户有什么角色
$user->hasRole('writer');
验证类
检查是否有某个权限
$user->hasPermissionTo('edit articles');
$user->can('edit articles');
检查是否有某个角色|或者列
$user->hasRole('writer');
$user->hasAnyRole(Role::all());
$user->hasAllRoles(Role::all());
传递id值进行判断是否有某个权限
$user->hasPermissionTo('1');
$user->hasPermissionTo(Permission::find(1)->id);
$user->hasPermissionTo($somePermission->id);
是否拥有一组权限
$user->hasAnyPermission(['edit articles', 'publish articles', 'unpublish articles']);
检查一个角色是否有某些权限 | 删除某些权限
$role->hasPermissionTo('edit articles');
$role->revokePermissionTo('edit articles'); // 删除
模板使用
@role('writer')
I am a writer!
@else
I am not a writer...
@endrole
------------------------
@hasrole('writer')
I am a writer!
@else
I am not a writer...
@endhasrole
------------------------
@can('edit articles') // 拥有某个权限 可执行操作
//
@endcan
数据填充
use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
class RolesAndPermissionsSeeder extends Seeder
{
public function run()
{
// Reset cached roles and permissions
app()['cache']->forget('spatie.permission.cache');
// create permissions
Permission::create(['name' => 'edit articles']);
Permission::create(['name' => 'delete articles']);
Permission::create(['name' => 'publish articles']);
Permission::create(['name' => 'unpublish articles']);
// create roles and assign created permissions
$role = Role::create(['name' => 'writer']);
$role->givePermissionTo('edit articles');
$role = Role::create(['name' => 'moderator']);
$role->givePermissionTo(['publish articles', 'unpublish articles']);
$role = Role::create(['name' => 'super-admin']);
$role->givePermissionTo(Permission::all());
}
}
提示:如果在数据库权限相关信息表的修改,必须掉用清除 缓存的方法
// 命令删除
php artisan cache:forget spatie.permission.cache
app()[‘cache’]->forget(‘spatie.permission.cache’);