一个文件多个 [请求类] 的另类实现,伪私类写法
在《终于找到了 Laravel-admin 中使用【请求类】验证表单的方法》一文中介绍过,通过覆写larave-admin控制器中的store()和update()方法可以调用请求类验证表单。代码如下
//覆写方式一,过于粗糙
public function update($id) {
app(UserRequest::class);
return $this->form()->update($id);
}
public function store() {
app(UserRequest::class);
return $this->form()->store();
}
但是,创建用户和修改用户所需要的验证规则并非完全一致(例如:新建用户时必须设置密码,但是修改用户时密码并不是必须的)。为此,我们可能需要使用两个类来完成这个任务。类似于下面这样的写法
//覆写方式二,要耗费3个文件
public function update($id) {
app(UserUpdateRequest::class); //更新专用
...
}
public function store() {
app(UserStoreRequest::class); //新建专用
...
}
根据一个类对应一个文件的规则,以上写法的缺点立即显现:区区一个【用户请求相关类】竟然要使用3个文件(UserRequest.php、UserUpdateRequest.php和UserStoreRequest.php),杀鸡用了牛刀的感觉。如果我们强行将新增的两个专用类写在文件UserRequest.php里面行不行?如果可以的话就好了,紧密相关的三个类文件合并成一个,也是合情合理的做法。但是测试发现程序报错,提示新建用户的专用请求类不存在。如下图
即使把 store 函数改写成下面这样依旧报错
//覆写方式三
public function store() {
app('App\Http\Requests\UserStoreRequest'); //报错
...
}
思索N久,最终找到相对优雅的解决方法,仍然可以将3个请求类写在一起(无需配置 composer.json 无需使用 require 语句)。只需要对UserRequest类稍加修改即可,代码如下
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
//以下是 UserRequest 请求类
//此类新增了 update() 和 store() 方法
class UserRequest extends FormRequest
{
...
public function rules() {...}
public function update() {
app(UserUpdateRequest::class);
}
public function store() {
app(UserStoreRequest::class);
}
}
//以下是新建用户时用到的请求类
//必须继承 UserRequest 决不能继承 FormRequest
class UserStoreRequest extends UserRequest {
public function rules() {
return [ 'password' => 'required|min:3' ];
}
}
//以下是更新用户时用到的请求类
//这个类暂时没什么特别的要求,留空备用
class UserUpdateRequest extends UserRequest { }
以上代码中,新增的两个派生类(UserStoreRequest和UserUpdateRequest)和基类依然是写在同一个文件里面的。前文已述,直接访问这两个派生类是要报错的(如上图)。为此,特地在基类中新增了两个方法 UserRequest::update() 和 UserRequest::store() 用以访问派生类,这样就不会报错了。例如,我们可以在laravel-admin的UserController中采用如下方式覆写本文开篇提到的两个函数
//覆写方式四,更好的写法
public function update($id) {
app(UserRequest::class)->update();
return $this->form()->update($id);
}
public function store() {
app(UserRequest::class)->store();
return $this->form()->store();
}
效果如下。首次验证是由基类规则设防;再次验证提示密码必须,这是通过基类的 store() 方法间接访问派生类实现的。
本文提到的两个派生类对外界不可见,有点类似于私有类的味道。但是它们并非真正意义上的对外不可见,在基类文件已被引入的情况下,这两个派生类就会变成可以直接访问的类。鉴于此,称之『伪私有类』,简称伪私类。
本作品采用《CC 协议》,转载必须注明作者和本文链接