【发布时间】:2021-03-24 16:15:21
【问题描述】:
我最近更新了我的控制器以在保存之前使用请求来验证数据,最初我在控制器路由中使用了$request->validate(),但我现在正处于我真的需要将其分离到请求中的阶段。
问题
在进行验证之前,我需要更改请求中的一些参数,我发现这可以使用prepareForValidation() 方法完成,而且效果很好,在验证期间请求中的值已被更改。如果验证失败,我的问题就会出现。我需要能够将我已更改的请求返回到视图,目前,在重定向之后,它似乎正在使用该请求,就像我运行 prepareForValidation() 之前一样。 (即,将标题返回为 'ABCDEFG' 而不是 'Changed The Title')。
在阅读了其他 SO 帖子和 Laravel 论坛帖子之后,看起来我需要覆盖 FormRequest::failedValidation() 方法(我已经完成了,请参见下面的代码),但是我仍在努力寻找方法将我更改后的请求传回。我已尝试编辑 failedValidation() 方法,我已在下方提供了详细信息。
期望与现实
期待
- 用户输入“ABCDEFG”作为标题并按保存。
- 请求中的标题(使用
prepareForValidation())被更改为“更改标题”。 - 验证失败,用户被重定向回创建页面。
- 标题字段的内容现在是“更改标题”。
现实
- 用户输入“ABCDEFG”作为标题并按保存。
- 请求中的标题(使用
prepareForValidation())被更改为“更改标题”。 - 验证失败,用户被重定向回创建页面。
- 标题字段的内容显示为“ABCDEFG”。
我尝试过的
将请求传递给ValidationException 类。
深入研究代码后,看起来ValidationException 允许将响应作为参数传递。
protected function failedValidation(Validator $validator)
{
throw (new ValidationException($validator, $this))
->errorBag($this->errorBag)
->redirectTo($this->getRedirectUrl());
}
但是这会导致Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::addCookieToResponse 中的错误Call to undefined method Symfony\Component\HttpFoundation\HeaderBag::setCookie()。
将请求闪烁到会话
我的下一次尝试是将我的请求闪现到会话中,这似乎不起作用,而不是我修改后的请求在会话中,它看起来是我运行 prepareForValidation() 之前的请求。
protected function failedValidation(Validator $validator)
{
$this->flash();
throw (new ValidationException($validator))
->errorBag($this->errorBag)
->redirectTo($this->getRedirectUrl());
}
返回响应而不是异常
我最后一次尝试使用withInput()而不是异常返回响应。
protected function failedValidation(Validator $validator)
{
return redirect($this->getRedirectUrl())
->withErrors($validator)
->withInput();
}
但是看起来代码继续进入BlogPostController::store() 方法,而不是重定向回视图。
此时我没有想法,如果验证失败,我似乎无法将更改后的请求返回到视图!
其他说明
- 我几乎是 Laravel 新手,我曾使用过松散地基于 Laravel 的自定义框架,但这是我的第一个 CMS 项目。
- 我完全理解我可能走错了路,也许有更好的方法来更改请求并在验证失败时将其传回?
- 我这样做的目的是什么?最主要的是活动复选框。默认情况下它被选中(参见下面的刀片),如果用户取消选中它并按下保存,
active不会在 HTTP 请求中传递,因此active在 Laravel 请求对象中不存在并且当用户返回,激活的复选框在不应该被选中时再次被选中。 - 那你为什么在你的例子中使用
title?我在帖子中使用了title,因为我认为更容易看到我想要实现的目标。
感谢任何帮助,因为我目前已经花费了好几个小时试图解决这个问题。 ????
相关代码
BlogPostController.php
<?php
namespace App\Http\Controllers;
use App\BlogPost;
use Illuminate\Http\Request;
use App\Http\Requests\StoreBlogPost;
class BlogPostController extends Controller
{
/**
* Run the auth middleware to make sure the user is authorised.
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
return view('admin.blog-posts.create');
}
/**
* Store a newly created resource in storage.
*
* @param StoreBlogPost $request
* @return \Illuminate\Http\Response
*/
public function store(StoreBlogPost $request)
{
$blogPost = BlogPost::create($request->all());
// Deal with the listing image upload if we have one.
foreach ($request->input('listing_image', []) as $file) {
$blogPost->addMedia(storage_path(getenv('DROPZONE_TEMP_DIRECTORY') . $file))->toMediaCollection('listing_image');
}
// Deal with the main image upload if we have one.
foreach ($request->input('main_image', []) as $file) {
$blogPost->addMedia(storage_path(getenv('DROPZONE_TEMP_DIRECTORY') . $file))->toMediaCollection('main_image');
}
return redirect()->route('blog-posts.edit', $blogPost->id)
->with('success', 'The blog post was successfully created.');
}
}
// Removed unrelated controller methods.
StoreBlogPost.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Validation\ValidationException;
class StoreBlogPost extends FormRequest
{
/**
* 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 [
'title' => 'required',
'url' => 'required',
'description' => 'required',
'content' => 'required',
];
}
/**
* Get the error messages for the defined validation rules.
*
* @return array
*/
public function messages()
{
return [
'title.required' => 'The Title is required',
'url.required' => 'The URL is required',
'description.required' => 'The Description is required',
'content.required' => 'The Content is required',
];
}
/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation()
{
$this->merge([
'active' => $this->active ?? 0,
'title' => 'Changed The Title',
]);
}
/**
* @see FormRequest
*/
protected function failedValidation(Validator $validator)
{
throw (new ValidationException($validator))
->errorBag($this->errorBag)
->redirectTo($this->getRedirectUrl());
}
}
create.blade.php
@extends('admin.layouts.app')
@section('content')
<div class="edit">
<form action="{{ route('blog-posts.store') }}" method="POST" enctype="multipart/form-data">
@method('POST')
@csrf
<div class="container-fluid">
<div class="row menu-bar">
<div class="col">
<h1>Create a new Blog Post</h1>
</div>
<div class="col text-right">
<div class="btn-group" role="group" aria-label="Basic example">
<a href="{{ route('blog-posts.index') }}" class="btn btn-return">
<i class="fas fa-fw fa-chevron-left"></i>
Back
</a>
<button type="submit" class="btn btn-save">
<i class="fas fa-fw fa-save"></i>
Save
</button>
</div>
</div>
</div>
</div>
<div class="container-fluid">
<div class="form-group row">
<label for="content" class="col-12 col-xl-2 text-xl-right col-form-label">Active</label>
<div class="col-12 col-xl-10">
<div class="custom-control custom-switch active-switch">
<input type="checkbox" name="active" value="1" id="active" class="custom-control-input" {{ old('active', '1') ? 'checked' : '' }}>
<label class="custom-control-label" for="active"></label>
</div>
</div>
</div>
<div class="form-group row">
<label for="title" class="col-12 col-xl-2 text-xl-right col-form-label required">Title</label>
<div class="col-12 col-xl-10">
<input type="text" name="title" id="title" class="form-control" value="{{ old('title', '') }}">
</div>
</div>
</div>
</form>
</div>
@endsection
【问题讨论】: