如何在laravel中验证后修改请求输入?

时间:2015-07-27 20:46:23

标签: php laravel

我找到了方法Request::replace,它允许替换Request中的输入参数。

但是目前我只能看到一种方法来实现它 - 在每个控制器动作中编写相同的替换输入代码。

是否有可能以某种方式对代码进行分组,这将在请求成功验证后执行,但在控制器操作开始之前执行?

例如,我需要在我的api中支持ISO2语言,但在引擎盖下,我必须将它们转换为遗留的,真正存储在数据库中。目前我在控制器中有这个代码:

// Controller action context
$iso = $request->input('language');
$legacy = Language::iso2ToLegacy($iso);
$request->replace(['language' => $legacy]);

// Controller action code starts

3 个答案:

答案 0 :(得分:1)

我认为您正在寻找的是 passedValidation() trait 中的 ValidatesWhenResolvedTrait 方法

使用方法:

  1. 创建自定义请求:php artisan make:request UpdateLanguageRequest
  2. 将验证规则放入 rules() 类中的 UpdateLanguageRequest 方法
  3. 使用 passedValidation() 方法在验证成功后对请求对象进行任何操作
namespace App\Http\Requests;

use App\...\Language;

class UpdateLanguageRequest extends FormRequest
{
    public function authorize()
    {
        return true;
    }


    public function rules()
    {
        return [
            // here goes your rules, f.e.:
            'language' => ['max:255']
        ];
    }


    protected function passedValidation()
    {
        $this->replace(['language' => Language::iso2ToLegacy($this->language)]);
    }
}

  1. 在您的控制器中使用 UpdateLanguageRequest 类代替 Request
public function someControllerMethod(UpdateLanguageRequest $request){
    // the $request->language data was already modified at this point
}

*也许您想使用 merge 而不是 replace 方法,因为 replace 将替换请求中的所有其他数据,而 merge 方法将仅替换特定值

答案 1 :(得分:0)

  

是否可能以某种方式对代码进行分组,之后将执行   请求成功验证,但在控制器操作之前   开始?

您可以使用中间件作为验证器,例如:

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\JsonResponse;

class InputValidator
{
    public function handle($request, Closure $next, $fullyQualifiedNameOfModel)
    {
        $model = app($fullyQualifiedNameOfModel);

        $validator = app('validator')->make($request->input(), $model->rules($request));

        if ($validator->fails()) {

            return $this->response($request, $validator->errors());
        }

        return $next($request);
    }

    protected function response($request, $errors)
    {
        if($request->ajax()) {
            return new JsonResponse($errors, 422);
        }

        return redirect()->back()->withErrors($errors)->withInput();
    }
}

$routeMiddleware课程中的App\Http\Kernel.php末尾添加以下条目:

'validator' => 'App\Http\Middleware\InputValidator'

rules中添加Eloquent Model方法,例如app\Product.php是模型,rules方法声明如下:

/**
 * Get the validation rules that apply to the request.
 *
 * @return array
 */
public function rules(\Illuminate\Http\Request $request)
{
    return [
        'title' => 'required|unique:products,title,'.$request->route()->parameter('id'),
        'slug' => 'required|unique:products,slug,'.$request->route()->parameter('id'),
    ];
}

声明这样的路线:

$router->get('create', [
    'uses' => 'ProductController@create',
    'as' => 'Product.create',
    'permission' => 'manage_tag',
    'middleware' => 'validator:App\Product' // Fully qualified model name
]);

您可以使用数组添加更多middleware,例如:

'middleware' => ['auth', 'validator:App\Product']

这是一种使用单个FormRequest替换middleware的方法。我使用此middlewaremodel name作为参数,使用单个middleware代替每个控制器的单个FormRequest类来验证我的所有模型。

此处,validatormiddlewareApp\Product是我作为参数传递的模型名称,并且来自middleware我验证该模型。

根据您的问题,控制器内的代码只有在输入验证通过后才会执行,否则redirect/ajax response将完成。出于特定原因,您可以创建特定的middleware。这只是一个可以在您的IMO案例中使用的想法,我的意思是您可以在验证通过后添加用于替换特定middleware中的输入的代码。

答案 2 :(得分:0)

根据上面的 Alexander Ivashchenko 回答,此解决方案对我有用:

<?php

namespace App\Http\Requests\User;

class UserUpdateRequest extends UserRequest
{

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules(): array
    {
        return [
            'name'=>'required|string',
            'email'=>'required|string|email',
            'password'=>'min:8'
        ];
    }
}

我们的父 UserRequest 类:

<?php

namespace App\Http\Requests\User;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Hash;

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

    /**
     * Handle a passed validation attempt.
     *
     * @return void
     */
    protected function passedValidation()
    {
        if ($this->has('password')) {
            $this->merge(
                ['password' => Hash::make($this->input('password'))]
            );
        }
    }

    public function validated(): array
    {
        if ($this->has('password')) {
            return array_merge(parent::validated(), ['password' => $this->input('password')]);
        }
        return parent::validated();
    }
}

我也在覆盖经过验证的方法。如果我们单独访问每个输入元素,他的答案有效,但为了在我们的控制器中使用批量分配,我们需要 validated 覆盖。

...
public function update(UserUpdateRequest $request, User $user): JsonResource
{
    $user->update($request->validated());
    ...
}
...

发生这种情况是因为 validated 方法直接从验证器而不是请求中获取数据。另一种可能的解决方案可能是使用 DTO 方法的自定义验证器,但对于上面的简单内容就足够了。