How do I reduce the if..else soup in this Controller function? The processing is the same, but the response type differs based on whether it's an AJAX request or not.

One way I can think of is to store all the response calls inside closure functions, and return once at the end (twice in the function overall because of the first return). That would only make it look a teensy bit better, in my subjective opinion. Not much of an improvement...

public function post_update()
{
    $submission = Input::all();
    $rules = array(
        'password' =&gt; 'required',
        'password_repeat' =&gt; 'required|same:password',
        'terms_accepted' =&gt; 'required'
    );

    $validator = Validator::make($submission, $rules);
    if (! $validator-&gt;passes()) {
        if (Request::ajax()) {
            return Response::json($validator-&gt;errors, 400);
        } else {
            return Redirect::to('signup/manual_password')-&gt;with_errors($validator);
        }
    }

    $user = Auth::user();
    $user-&gt;password = $submission['password'];
    $user-&gt;set_repeated_password($submission['password_repeat']);
    $user-&gt;password_set_manually = 1;

    try {
        $user-&gt;save_or_ex();

        if (Request::ajax()) {
            return Response::json(Session::get('_next_uri'));
        } else {
            return Redirect::to(Session::get('_next_uri'));
        }

    } catch (ValidationException $e) {

        if (Request::ajax()) {
            return Response::json($e-&gt;getErrors(), 500);
        } else {
            return Response::error(500);
        }

    }
}
Seeing I was asked to post my comment as an answer, I've set about typing this little thing up. It's, essentially, a slightly more verbose version of my initial comment.

Well, all in all, a controller action is a method, so the same "rules" should apply: 1 type of request goes to 1 distinct action method. Your method seems to be dealing with 3 distinct types of requests:


Client requests form page
Client submits form
Ajax submission of form-data


So I'd create 3 distinct actions. That way you can get rid of all those if (Request::ajax()) branches. You should still check if the request is an ajax request, but unless you're in the ajax controller, you can just redirect or return an error.
Since in 2/3 cases, you're validating the same form, you are, of course, free to stash that logic in a private helper method, or in some helper method in the model layer.

Something along these lines (I haven't got much experience with laravel, mind you):

class YourController extends BaseController
{
    public function updateForm()
    {
        //create the form, pass it to the view
    }

    public function ajaxUpdate()
    {
        if (!Request::ajax())
        {
            Response::json(
                array(
                    'message' =&gt; 'Invalid request',
                    'redirect' =&gt; 'some url'
                )
            );
        }
        $validator = $this-&gt;validateInput(Input::all());
        //process resulst
    }

    public function postUpdate()
    {
        if (Request::ajax())
        {
            Response::json(
                array(
                    'message' =&gt; 'Invalid request',
                    'redirect' =&gt; 'some url'
                )
            );
        }
        $validator = $this-&gt;validateInput(Input::all());
        //process resulst
    }

    private function validateInput($submission)
    {//No type-hint, because I'm not sure what type Input::all() returns
        $rules = array(
            'password' =&gt; 'required',
            'password_repeat' =&gt; 'required|same:password',
            'terms_accepted' =&gt; 'required'
        );
        $validator = Validator::make($submission, $rules);
    }
}


Now this may range anywhere from pretty-darn copy-paste ready to bizarre, but it's just to serve as an example of how I would set about this. To my eye, this is pretty clean code, easy to maintain, and, most important of all: Each action method deals with 1 specific request. In order not to repeat myself, I've created a private validateInput method, too, but I take it that's pretty self-evident ;-)