分享验证规则层的设计
今天看到了这个问题验证规则写在哪里比较好?,看了一圈下来,大家都有自己的处理方式,但是没有一个比较优雅的解决方案,我来分享一下自己的设计吧。
我们的项目使用Lumen
做API开发,如果把验证规则都写在控制器里面,不仅干扰代码结构,而且规则比较分散,增加维护成本,为了解决这个问题,我设计了Validation
层来完成所有的验证工作,下面是具体实现。
首先在Http目录下新建Validations目录存放所有的验证类:
app
├── Http
│ ├── Controllers
│ │ ├── Controller.php
│ │ └── ExampleController.php
│ └── Validations
│ └── ExampleValidation.php
ExampleController.php
和ExampleValidation.php
在命名上和目录结构上是互相对应的,它们的代码:
<?php
namespace App\Http\Controllers;
class ExampleController extends Controller
{
public function show()
{
}
public function store()
{
}
}
<?php
namespace App\Http\Validations;
class ExampleValidation
{
public function show()
{
return [
'rules' => [
'id' => 'required',
],
'message' => [
],
];
}
public function store()
{
return [
'rules' => [
'id' => 'required',
],
];
}
}
我们约定好,ExampleController
的show
、store
方法,使用ExampleValidation
中对应的show
、store
方法中返回的规则来验证,下面最重要的是能让他们按照约定关联上,我们在ExampleController
的父Controllerapp/Http/Controllers/Controller.php
中实现这个关联:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Laravel\Lumen\Routing\Controller as BaseController;
class Controller extends BaseController
{
public function __construct(Request $request)
{
$this->validateRequest($request);
}
protected function validateRequest(Request $request, $name = null)
{
if (! $validator = $this->getValidator($request, $name)) {
return;
}
$rules = array_get($validator, 'rules', []);
$messages = array_get($validator, 'messages', []);
$this->validate($request, $rules, $messages);
}
protected function getValidator(Request $request, $name = null)
{
list($controller, $method) = explode('@', $request->route()[1]['uses']);
$method = $name ?: $method;
$class = str_replace('Controller', 'Validation', $controller);
if (! class_exists($class) || ! method_exists($class, $method)) {
return false;
}
return call_user_func([new $class, $method]);
}
}
getValidator ()
方法会去检查有没有对应当前控制器方法的验证规则,如果有就使用该规则来验证参数,如果ExampleController
中新增了方法destroy()
需要验证规则,只需要在ExampleValidation
中添加同名的destroy()
方法,return相应的rules和messages即可。
另外,如果ExampleController
中新增了方法update()
需要复用ExampleValidation
中的store()
方法返回的规则,可以这样实现
public function update(Request $request)
{
$this->validateRequest($request, 'store');
//...
}
这个方案能在添加少量代码的情况下实现规则验证和控制器的分离,以及规则的复用,是目前我认为比较优雅的方案了,欢迎拍砖。
如果有其它好的思路,欢迎讨论。
推荐文章: