具有多个场景的Laravel 5 FormRequest验证器

时间:2015-06-16 09:09:42

标签: laravel laravel-5 laravel-validation

我想问一下如何在L5中使用FormRequest处理多个场景的验证?我知道,我被告知我可以创建saparate FormRequest文件来处理不同的验证,但它非常冗余,并且还注意到我需要使用use FormRequest;关键字将其注入控制器。之前在L4.2中做的是我可以在我的customValidator.php中定义一个新函数,然后在控制器验证期间通过trycatch调用,然后使用以下实现通过服务验证数据。

class somethingFormValidator extends \Core\Validators\LaravelValidator 
{
    protected $rules = array(
        'title'             =>  'required',
        'fullname'          =>  'required',
        // and many more
        );


    public function scenario($scene)
    {
        switch ($scene) {
            case 'update':
                $this->rules = array(
                        'title'             =>  'required',
                        'fullname'          =>  'required',
                        // and other update validated inputs
                    break;
        }

        return $this;
    } 
}

然后在我的LaravelValidator.php

<?php namespace Core\Validators;

use Validator;

abstract class LaravelValidator {

        /**
         * Validator
         *
         * @var \Illuminate\Validation\Factory
         */
        protected $validator;

        /**
         * Validation data key => value array
         *
         * @var Array
         */
        protected $data = array();

        /**
         * Validation errors
         *
         * @var Array
         */
        protected $errors = array();

        /**
         * Validation rules
         *
         * @var Array
         */
        protected $rules = array();

        /**
         * Custom validation messages
         *
         * @var Array
         */
        protected $messages = array();

        public function __construct(Validator $validator)
        {
                $this->validator = $validator;
        }

        /**
         * Set data to validate
         *
         * @return \Services\Validations\AbstractLaravelValidator
         */
        public function with(array $data)
        {
                $this->data = $data;

                return $this;
        }

        /**
         * Validation passes or fails
         *
         * @return Boolean
         */
        public function passes()
        {
                $validator = Validator::make(
                        $this->data,
                        $this->rules,
                        $this->messages
                );

                if ($validator->fails())
                {
                        $this->errors = $validator->messages();

                        return false;
                }

                return true;
        }

        /**
         * Return errors, if any
         *
         * @return array
         */
        public function errors()
        {
                return $this->errors;
        }

}

然后最后这就是我如何调用像这样的服务中的场景

public function __construct(somethingFormValidator $v)
    {
        $this->v = $v;
    }

public function updateSomething($array)
    {
         if($this->v->scenario('update')->with($array)->passes())
          {
            //do something
          else 
          {
            throw new ValidationFailedException(
                    'Validation Fail',
                    null,
                    $this->v->errors()
                    );
          }
    }

所以现在问题是因为我已经迁移到L5而L5使用FormRequest,我应该如何在我的代码中使用场景验证?

<?php namespace App\Http\Requests;

use App\Http\Requests\Request;

class ResetpasswordRequest extends Request {

    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
        'login_email'           =>  'required',
        'g-recaptcha-response'  =>  'required|captcha',
        ];
    }


    public function messages()
    {
        return [
            'login_email.required'              =>  'Email cannot be blank',
            'g-recaptcha-response.required'     =>  'Are you a robot?',
            'g-recaptcha-response.captcha'      =>  'Captcha session timeout'
        ];
    }

    public function scenario($scene)
    {
        switch ($scene) {
            case 'scene1':
                $this->rules = array(
                        //scenario rules
                        );
                    break;
        }

        return $this;
    } 

}

我该如何在控制器中调用它?

public function postReset(ResetpasswordRequest $request)
    {
        $profile = ProfileService::getProfileByEmail(Request::input('login_email'));

        if($profile == null)
        {
            $e = array('login_email' => 'This email address is not registered');
            return redirect()->route('reset')->withInput()->withErrors($e);
        }
        else
        {
            //$hash = ProfileService::createResetHash($profile->profile_id);
            $time = strtotime('now');
            $ip = Determinator::getClientIP();
            MailProcessor::sendResetEmail(array('email' => $profile->email, 
                            'ip' => $ip, 'time' => $time,));
        }
    }

2 个答案:

答案 0 :(得分:1)

我相信手头的真正问题是,在表单请求对象到达您的控制器之前,所有内容都会通过表单请求对象进行验证,而您无法设置相应的验证规则。

我能想到的最好的解决方案是在表单请求对象的构造函数中设置验证规则。不幸的是,我不确定您是如何或在何处提出$scene var,因为它在您的示例中似乎是'update'的硬编码。

我确实想到了这一点。希望在构造函数中阅读我的注释会有所帮助。

namespace App\Http\Requests;

use App\Http\Requests\Request;

class TestFormRequest extends Request
{

    protected $rules = [
        'title'             =>  'required',
        'fullname'          =>  'required',
        // and many more
    ];

    public function __construct()
    {
        call_user_func_array(array($this, 'parent::__construct'), func_get_args());

        // Not sure how to come up with the scenario.  It would be easiest to add/set a hidden form field
        // and set it to 'scene1' etc...
        $this->scenario($this->get('scenario'));

        // Could also inspect the route to set the correct scenario if that would be helpful?
        // $this->route()->getUri();
    }

    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return $this->rules;
    }

    public function scenario($scene)
    {
        switch ($scene) {
            case 'scene1':
                $this->rules = [
                    //scenario rules
                ];
                break;
        }
    }
}

答案 1 :(得分:0)

您可以使用laratalks/validator包来验证laravel中的多个方案。 see this repo