Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

thepsion5's avatar

Removing Controller Boilerplate & Maintaining SRP

So, based on a separate conversation on whether the FormRequest class in Laravel 4.3 is mixing responsibilities too much, I wanted to suggest an alternative that removes the same boilerplate code from controllers without mixing responsibilities.

Every controller function called as part of a route is actually done through through the controller's callAction() function. This means that in our base controller class, we can override that function to provide some of the same boilerplate code in the FormRequest class, specifically:

  1. Redirecting back in response to a Validation Exception
  2. Displaying a 403 page in response to an Authorization Failure

This is an implementation very similar to what I'm currently using in production:

class BaseController extends Controller
{

    public function callAction($method, $params)
    {
        $ajax = Request::isAjax();
        try {
            return parent::callAction($method, $params);
        } catch(ValidationException $exception) {
            return $this->handleValidationException($exception, $ajax);
        } catch(AuthException $exception) {
            return $this->handleAuthException($exception, $ajax);
        }
    }

    protected function handleValidationException(ValidationException $exception, $ajax = false)
    {
        if($ajax) {
            return Response::json(array('errors' => $exception->errors()), 422);
        } else {
            return Redirect::back()->withInput()->withErrors($exception->errors());
        }
    }

    protected function handleAuthException(AuthException $exception, $ajax = false)
    {
        if(Request::isAjax()) {
            return Response::json($exception->getMessage(), 403);
        } else {
            App::abort(403);
        }
    }
}

Now, your extending controllers only need to handle the success case, and validation and auth exceptiosn will automatically be taken care of by the base controller:

<?php
public class FooController extends BaseController
{
    public function __construct(FooService $foos)
    {
        $this->foos = $foos;
    }

    public function store()
    {
        //throws ValidationException on failure
        $foo = $this->foos->create(Input::all());
        return Redirect::route('foos.show', $foo->id);
    }

    public function update($id)
    {
        //throws ValidationException on failure
        //throws AuthException if the current user does not have access to a the relevant resource
        $foo = $this->foos->findAndUpdate($id, Input::all());
        return Redirect::route('foos.show', $foo->id);
    }
}
0 likes
1 reply
thepsion5's avatar

No suggestions or feedback? Man, tough crowd. ;)

Please or to participate in this conversation.