Skip to content

Month: July 2015

In Which … J.T. learns how traits work

On the home page of the site I’m building right now, the user is asked to enter a city and state.

Homepage City/State Entry

I’m using Laravel 5.1’s super-simple validation to make sure that both fields are entered:

       $this->validate($request, [
            'facilityCity'=>'required',
            'facilityState'=>'required'
        ]);

That’s all it takes to (1) make sure both fields are present and (2) display an error if they’re not.  The only problem for me is that when validation fails, the user is redirected to the previous page. 99% of the time, this is the desired behavior, but the one place I don’t want it is on the home page. Displaying errors there just ruins the layout.

Here are the highlights from Laravel’s ValidatesRequest trait:

public function validate(...)
{
    ...
    if ($validator->fails()) {
        $this->throwValidationException($request, $validator);
    }
}

protected function buildFailedValidationResponse(...)
{
    ...
    return redirect()->to($this->getRedirectUrl())-> ...
}

protected function getRedirectUrl()
{
    return app('Illuminate\Routing\UrlGenerator')->previous();
}

So if we can just change getRedirectUrl(), everything else should fall into place. Obviously, we don’t want to change anything in the core Laravel files. Can we override a trait function?

190px-Obama_logomarkYES WE CAN

<?php namespace App\Validation;

use Illuminate\Foundation\Validation\ValidatesRequests as BaseValidatesRequests;

trait ValidatesRequests
{
    protected $redirectOnError='';

    use BaseValidatesRequests;

    /**
    * Get the URL we should redirect to.
    *
    * @return string
    */
    protected function getRedirectUrl()
    {
        $urlGenerator = app('Illuminate\Routing\UrlGenerator');
        if ($this->redirectOnError) {
            return $urlGenerator->to($this->redirectOnError);
        }
        return $urlGenerator->previous();
    }
}

Traits don’t use inheritance (we can’t use the extends keyword), but they compose very nicely. By creating a new trait which uses the base ValidationRequests trait, we have all the functions available in that trait and can override one.

Also note the new $redirectOnError variable – we only redirect if this is set.

The base Controller class is updated to point to this new ValidatesRequests trait and all the inheriting controllers now have this feature available.  The new function just has one extra line:

$this->redirectOnError = 'signup/city_state';
$this->validate($request, [
    'facilityCity'=>'required',
    'facilityState'=>'required'
]);
Leave a Comment