Wabbitseason
Wabbitseason

Reputation: 5691

How to check the existence DRY & Laravel-style of an object that many controller methods are working with?

In a Laravel controller I have a couple of methods that all begin by fetching a database record, then after checking if data has been found either continue by rendering a view, or, in case of no data, go to a 404 page.

Here's an example:

<?php

function get_show_user($id)
{
    $user = static::get_user($user_id);
    if (!$user) {
        return Response::error('404', static::$some_common_error404_message);
    }
    return View::make('users.show_readonly_user_data')->with('user', $user);
}

function get_edit_user($id)
{
    $user = static::get_user($user_id);
    if (!$user) {
        return Response::error('404', static::$some_common_error404_message);
    }

    return View::make('users.display_edit_user_form')->with('user', $user);
}

I'm repeating the entire if (!$user) statement in these methods, even if they all do the same thing.

I'd rather like to do something like this:

function get_show_user($id)
{
    $user = Users::find($id);
    static::go404_if_null($user);
    return View::make('users.show_readonly_user_data')->with('user', $user);
}

function get_edit_user($id)
{
    $user = Users::find($id);
    static::go404_if_null($user);
    return View::make('users.display_edit_user_form')->with('user', $user);
}

What would be the best way to implement such a DRY feature?

Obviously a simple return Response::error('404') would not work in the common existence checker method, since it would only return from that method.

It seems that an Event::fire('404') is not ideal either since it does not terminate the method it has been triggered in.

Perhaps using an exception would be required here, but I'm unsure about this, or how it should be done in Laravel. Where should I catch a 404 Exception of a controller?

Upvotes: 4

Views: 1302

Answers (1)

William Cahill-Manley
William Cahill-Manley

Reputation: 2405

I think the best way to approach this would be a before filter on your controller.

public static $require_user = array(
    'edit_user',
    'show_user',
);

public function before()
{
    $route = Request::route();
    if ( in_array( $route->controller_action, static::$require_user ) )
    {
        $this->user = User::find( $route->parameters[0] );
        if ( is_null($this->user) ) return Response::error('404');
    }
}

Before filters get called after your controller is constructed but before the method is called. If a before filter returns anything other than null, the method is not called and thus execution is stopped.

Here we obtain the current route being executed so we can check which method is going to be called against our array $require_user. This lets us use methods that don't require a user id, such as login.

Then we retrieve the user instance, getting the id from what would have been passed to the method. You should probably add more error handling here.

Lastly, we check if the user returned was null, meaning not found. If that is the case we return a 404 response, stopping execution of the method.

I hope this helps!

Upvotes: 1

Related Questions