2

I'm using the Post/Redirect/Get (PRG) pattern in my Laravel controllers to prevent duplicate form submission.

It works well when I don't use layouts or when my layouts don't use any variable. The problem is my layout uses a variable named $title. When I load the view and the layout without redirect it works well, the title set in the controller is passed to the layout, but after processing a form and redirecting to the same route which uses the same layout and the same controller method I get a "Undefined variable: title" error coming from my layout file.

Here is my code:

File: app/routes.php

Route::get('contact', array('as' => 'show.contact.form', 'uses' => 'HomeController@showContactForm'));
Route::post('contact', array('as' => 'send.contact.email', 'uses' => 'HomeController@sendContactEmail'));

File: app/controllers/HomeController.php

class HomeController extends BaseController {

    protected $layout = 'layouts.master';

    public function showContactForm()
    {
        $this->layout->title = 'Contact form';
        $this->layout->content = View::make('contact-form');
    }

    public function sendContactEmail()
    {
        $rules = ['email' => 'required|email', 'message' => 'required'];
        $input = Input::only(array_keys($rules));
        $validator = Validator::make($input, $rules);

        if($validator->fails())
            return Redirect::back()->withInput($input)->withErrors($validator);

        // Code to send email omitted as is not relevant

        Redirect::back()->withSuccess('Message sent!');
    }
}

File: app/views/layouts/master.blade.php

<!DOCTYPE html>
<html>
    <head>
        <title>{{{ $title }}}</title>
    </head>
    <body>
        @yield('body')
    </body>
</html>

File: app/views/contact-form.blade.php

@section('body')
    @if (Session::has('success'))
        <div class="success">{{ Session::get('success') }}</div>
    @endif

    {{
        Form::open(['route' => 'send.contact.email']),
        Form::email('email', null, ['placeholder' => 'E-mail']),
        Form::textarea('message', null, ['placeholder' => 'Message']),
        Form::submit(_('Send')),
        Form::close()
    }}
@stop

I don't understand why after redirecting the next line of code is ignored

$this->layout->title = 'Contact form';

I've tried with Redirect::action('HomeController@sendContactEmail'); or Redirect::route('show.contact.form'); but the result is the same.

The controller in charge of rendering that view is exactly the same before the redirect than after the redirect, and it has no business logic at all, so why it only works on the first case but not in the second?

4

3 回答 3

1

这个

Redirect::back()->withSuccess('Message sent!');

应该

return Redirect::back()->withSuccess('Message sent!');

layout在控制器中设置属性并且方法没有返回任何响应时,控制器会尝试呈现layout. 在您的方法中,两个条件都满足并且控制器在设置sendContactEmail()之前尝试渲染布局。$title

见。callAction()_Illuminate\Routing\Controllers\controller

http://laravel.com/api/source-class-Illuminate.Routing.Controllers.Controller.html#93-127

于 2013-11-13T20:24:16.410 回答
0

Redirect::back() 使用当前 HTTP 请求的引用值创建 302。我首先将初始表单请求与重定向请求进行比较,看看是否会产生任何线索。你也可以试试...

Redirect::route('HomeController@showContactForm')->withInput()...

我知道它的动态性较低,但它会生成 URL,而不是依赖 HTTP 标头中的引用值。

于 2013-11-14T20:57:16.497 回答
0

您是否尝试过使用

return View::make('contact-form', array('title' => 'Contact Form'));

而不是直接与布局交互?

于 2013-11-13T20:08:58.043 回答