利用 Laravel Macroable 特性优化多态参数传递的技巧分享
@这是小豪的第四篇文章
这篇文章主要是简单的给大家介绍一下如何利用 Laravel Macroable 特性优化多态参数传递,如果对多态关联这种类型不太熟悉的,建议先看一下《如何更快的找到自己所需的模型关联类型?》。设计思路来自超哥,我只是一个搬运工,哈哈,我是觉得这种实现方式太美妙了,得给大家分享一下。
准备
如果我们现在需要设计这样一个接口:获取指定文章的所有评论 Or 获取指定视频的所有评论。
我们有三张表:
视频表:videos
文章表:posts
评论表:comments
评论表中有这两个字段:commentable_type、commentable_id 分别存储评论主体信息。
他们之间的模型关系为多态关联
,就不再多解释了,哈哈。
当接收到这个需求的时候,你可能会困惑,主体不确定该怎么去设计呢。通过 commentable_type 判断是什么模型,然后再根据确定的类型和 commentable_id 获取到具体的对象吗?此时你脑中的代码是什么样子的呢,反正当时我的脑子里面是一堆乱糟糟的代码,哈哈。现在就来给大家介绍这种优雅的实现方式。
获取可评论对象
首先我们利用 macro
给 Request
定义一个 commentable
:
Request::macro('commentable'), function(bool $required = false){
if (!\request()->has('commentable_type')) {
return $required ? \abort(422, '目标对象不存在') : null;
}
$model = \request()->get('commentable_type');
$model = Relation::getMorphedModel($model) ?? $mode;
$commentable = \call_user_func([$model, 'find'], \request()->get('commentable_id'));
if (!$commentable){
return $required ? \abort(422, '目标对象不存在') : null;
}
return $commentable;
});
可以看到,目标对象的转换就是通过 commentable_type
,commentable_id
这两个参数来的,这段代码不是很难,大家研究一下就看懂哒。可以在 服务提供者
中定义。
控制器
class CommentController extends Controller
{
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
*
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
*/
public function index(Request $request)
{
return CommentResource::collection($request->commentable(true)->comments()->get());
}
}
大家会发现现在已经可以通过 $request->commentable(true)
来获取可评论对象了,但是少了验证,但是这个验证该怎么写呢,现在我们来看一下。
验证规则
class Polymorphic extends Rule
{
/**
* @var string
*/
protected $name;
/**
* @var string
*/
protected $message;
/**
* Create a new rule instance.
*
* @param string $name
* @param string|null $message
*/
public function __construct(string name, string $message = null)
{
$this->name = $name;
$this->message = $message;
}
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
*
* @return bool
*/
public function passes($attribute, $value)
{
$model = request()->get(\sprintf('%s_type'), $this->name);
$model = Relation::getMorphedModel($model) ?? $model;
return \class_exists($model) && (bool) \call_user_func([$model, 'find'], \request()->get(\sprintf('%s_id'), $this->name)));
}
/**
* Get the validation error message.
*
* @return string
*/
public function message()
{
return $this->message ?: '未指定目标对象或目标不存在';
}
}
现在规则定义好了,我们来使用:
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
*
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
*
* @throws \Illuminate\Validation\ValidationException
*/
public function index(Request $request)
{
$this->validate($request, [
'commentable_id' => ['required', new Polymorphic('commentable', '未指定评论对象或对象不存在')],
]);
return CommentResource::collection($request->commentable(true)->comments()->get());
}
结束语
是不是很简单很优雅呀,哈哈。这种方式我觉得忒棒了。
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: