1

Let's say I have 2 urls:

  • localhost/backend/admin
  • localhost/backend/admin/users

In my routes.php, I would have a route that looks like this:

Route::group(array('prefix' => 'backend', 'before' => 'auth'), function(){

    // Some methods I have on this controller are: getIndex, postUpdate, etc...
    Route::controller('admin', 'AppBackend\Controllers\Admin\AdminController');

    // Some methods I have on this controller are: getIndex, postUpdate, etc...
    Route::controller('admin/users', 'AppBackend\Controllers\Admin\Users\UsersController');
});

The problem is that when I enter admin/users into the browser, Laravel thinks that I'm trying to call a method on the AdminController and finds it doesn't exist among the methods I have for this controller. It seems it would be more ideal, if a method is not found, for Laravel to continue down the routes file and hit my admin/users route and call UsersController.

2 Possible solution that I'm not fully satisfied with:

  1. Reverse the order of the routes. This won't read as naturally as I would like it to, from top to bottom. Plus, I don't know how this solution will hold up over time with every case I have in the future.
  2. Switch to using resource routes. I don't like using PUT/DELETE when it's not supported by some browsers. I like having my own set of action words (and simply renaming and adding to the default resources is not enough or becomes clunky). See also What is the value of using PUT/DELETE with Laravel?

Are there any other good solutions?

Community
  • 1
  • 1
prograhammer
  • 20,132
  • 13
  • 91
  • 118
  • 2
    The best of all is to write all your routes one by one. Seems like a lot of work, but it isn't. Take a look at this article: http://philsturgeon.co.uk/blog/2013/07/beware-the-route-to-evil. I've never used resource nor restful routes again. – Antonio Carlos Ribeiro Mar 12 '14 at 16:54
  • `I don't like using PUT/DELETE when it's not supported by some browsers.` laravel just mimicks the PUT/DELETE request. it will be supported by any browser which supports POST request. – itachi Mar 12 '14 at 17:46
  • @AntonioCarlosRibeiro Phil's article got me thinking...hmmm – prograhammer Mar 12 '14 at 18:18
  • @itachi It mimics it only if you create your forms a certain way. It'll add a hidden input to do this. But I use a different library for my inputs. – prograhammer Mar 12 '14 at 18:19
  • @AntonioCarlosRibeiro so you even list out every route for the CRUD stuff? A route for create, a route for delete, etc. That could mean like 5 lines of route code to cover for what would normally be one route. Won't this create a rather large routes.php? – prograhammer Mar 12 '14 at 18:23
  • Internally Laravel will add all those routes to the route listing. In terms of performance, no difference. The only I can see is that you are creating all of them manually. – Antonio Carlos Ribeiro Mar 12 '14 at 18:26
  • @AntonioCarlosRibeiro Seems like there should be some sort of balance...where some stuff is always going to be a method, and other stuff that varies should be explicitly written out on it's own line in the routes.php. `Create` would always be a method...yet something like `grid` could be a method or a url so it should have it's own route line to be clearer. – prograhammer Mar 12 '14 at 18:27
  • Yeah, maybe it is better just to list them all out – prograhammer Mar 12 '14 at 18:28
  • @AntonioCarlosRibeiro Put your suggestion into a nice answer and I can accept it. It answers the question I had of: Are there any other good solutions. – prograhammer Mar 12 '14 at 18:30
  • @AntonioCarlosRibeiro BTW...Do you still do route grouping and do you still handle your authorization in the routes.php? – prograhammer Mar 12 '14 at 18:33
  • 1
    Yeah, everything else I do in my routes.php file. Auth and Roles using filters. I will post my answer with an example. – Antonio Carlos Ribeiro Mar 12 '14 at 18:37

1 Answers1

3

The best way of doing routes until now is to make them all manually one by one. In this article Phil Sturgeon pushed me to start to do that and I finally realized that I was having too much trouble using resourceful and restful for a little gain.

It's better to have control of your route listing. Resourceful controllers add too much info, like route parameters, and, to make resourceful controllers not create a bunch of routes I don't use I have to filter what should be generated. In the end it was simply easier to create one route every time I was creating a functionality on my application.

As far as I can tell, to process all your routes in the correct order, Laravel builds a list of your routes, exactly the same way if we were doing it manually. So, there is no performance penalty in doing them manually.

This is an example of my routes in an application I'm just starting:

// Firewall Blacklisted IPs blocked from all routes
Route::group(['before' => 'fw-block-bl'], function()
{
    Route::group(['namespace' => 'Application\Controllers'], function()
    {
        // Pretty error message goes to this route
        Route::get('error', ['as' => 'error', 'uses' => 'Error@show']);

        Route::get('coming/soon', ['as' => 'coming.soon', 'uses' => 'ComingSoon@index']);
        Route::post('coming/soon', ['as' => 'coming.soon.post', 'uses' => 'ComingSoon@register']);
        Route::get('coming/soon/register', ['as' => 'coming.soon.register', 'uses' => 'ComingSoon@register']);
        Route::post('coming/soon/audit', ['as' => 'coming.soon.audit', 'uses' => 'ComingSoon@audit']);
        Route::get('coming/soon/activate/{code}', ['as' => 'coming.soon.activate', 'uses' => 'ComingSoon@activate']);

        // Whitelisted on firewall will have access to those routes, 
        // otherwise will be redirected to the coming/soon page
        Route::group(['before' => 'fw-allow-wl'], function()
        {
            Route::get('user/activate/{code}', ['as' => 'user/activate', 'uses' => 'User@activate']);
            Route::get('user/activation/send/{email?}', ['as' => 'user/activation', 'uses' => 'User@sendActivation']);

            Route::get('login', ['as' => 'login', 'uses' => 'Logon@loginForm']);
            Route::post('login', ['as' => 'login', 'uses' => 'Logon@doLogin']);
            Route::get('logout', ['as' => 'logout', 'uses' => 'Logon@doLogout']);

            Route::get('register', ['as' => 'register', 'uses' => 'Register@registerForm']);

            Route::get('user/recoverPassword/{code}', ['as' => 'user/recoverPassword', 'uses' => 'User@recoverPassword']);
            Route::post('user/changePassword', ['as' => 'user/changePassword', 'uses' => 'User@changePassword']);

            // Must be authenticated
            Route::group(['before' => 'auth'], function()
            {
                Route::get('/', ['as' => 'home', 'uses' => 'Home@index']);
                Route::get('profile', ['as' => 'profile', 'uses' => 'User@profile']);

                Route::group(['prefix' => 'offices'], function()
                {
                    Route::get('/', ['uses' => 'Offices@index']);
                    Route::get('create', ['uses' => 'Offices@create']);
                });

                Route::group(['prefix' => 'users'], function()
                {
                    Route::get('/', ['uses' => 'Users@index']);
                    Route::get('create', ['uses' => 'Users@create']);
                });
            });
        });
    });
});

All controllers will be namespaced in Application\Controllers and all methods (or subroutes) are prefixed.

EDIT

I'm starting to think I dont name my routes too, I'm not really using them, but I'm still not certain of this, so routes names are not really clear in this raw example. Some also have a 'uses' that could be removed and they will as soon as I decide myself by using names or not.

EDIT 2

I don't do ->before() in routes, because I like to read my routes files sometimes and this method may only be visible after a big list of routes.

Community
  • 1
  • 1
Antonio Carlos Ribeiro
  • 86,191
  • 22
  • 213
  • 204
  • +1 for mentioning the idea of how I can release features internally before going public with them (using the whitelist/firewall filter)...especially if I don't have a dev server. I never thought of that! Thank You! – prograhammer Mar 12 '14 at 19:01
  • 1
    Haha, yeah! I'm using my own package to provide that: https://github.com/antonioribeiro/firewall. – Antonio Carlos Ribeiro Mar 12 '14 at 19:02
  • I've also got a question related to this...trying to figure out how to **[route with URL query parameters here](http://stackoverflow.com/questions/22391035/how-to-build-a-laravel-route-that-requires-a-specific-url-query-parameter)** – prograhammer Mar 13 '14 at 21:16