1

I'm trying to create a route model binding for two models: "User" and "Article"

Route::get('/{user}', 'UsersController@show');

Route::get('/{article}', 'ArticlesController@show');

Problem is, one of these will always take precedence over the other, depending on the order they are declared.

I want the user route to take precedence over the articles route if a user and an article happends to have the same route, but the problem is that laravel returns a 404 page when it does not match a user, even if the route should match an article.

I know that you can use the where() function with regex for this, however both of these models uses the same structure for the route key name (they are both strings). Can I make the regex search a database column or something?

gjerm94
  • 13
  • 3
  • 1
    I would not be a bad idea to choose routes like `/users/{user}` and `/articles/{article}`. It not only prevents this from happening but might also help users to give a sense of where they currently are. Plus debugging. – Thomas Van der Veen Dec 23 '19 at 20:13
  • I agree this is the best. Unfortunately my client wants it this way :) – gjerm94 Dec 23 '19 at 20:37
  • Explain to him the technical issues related with applying that method . I totaly agree with what @ThomasVanderVeen said. But if you want to continue with that. you can solve the problem in the controller. – Samuel Bié Dec 23 '19 at 21:30

1 Answers1

6

You have 2 Options:

  1. Use different routes for each:
Route::get('/users/{user}', 'UsersController@show');

Route::get('/articles/{article}', 'ArticlesController@show');
  1. Customizing The Resolution Logic on your RouteServiceProvider.php:
/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    parent::boot();

    Route::bind('userOrArticle', function ($value) {
        return is_numeric($value)
                    ? App\User::where('id', $value)->firstOrFail()
                    : App\Article::where('title', $value)->firstOrFail();
    });
}
Route::get('/{userOrArticle}', function ($userOrArticle) {
    return $userOrArticle instanceof \App\User
                ? redirect()->action('UsersController@show', ['user' => $userOrArticle]);
                : redirect()->action('ArticlesController@show', ['article' => $userOrArticle]);
});

See 'Customizing The Resolution Logic' section of the docs for more info: https://laravel.com/docs/master/routing#explicit-binding

Hafez Divandari
  • 8,381
  • 4
  • 46
  • 63
  • they are using strings for both – lagbox Dec 23 '19 at 20:33
  • I believe this is what I want, but how do I use different controllers depending on the model? If it's a user it should go to UsersController@show and article should go to ArticlesController@show. – gjerm94 Dec 23 '19 at 20:36
  • @gjerm94 I've updated my answer based on your needs. – Hafez Divandari Dec 23 '19 at 20:51
  • I'm getting an error: "Action App\Http\Controllers\UsersController@show not defined." Not sure what's wrong – gjerm94 Dec 28 '19 at 17:54
  • @gjerm94 have you defined `UsersController` and `show` function on it? however, I prefer to use single name `UserController` I answered based on your question info. – Hafez Divandari Dec 28 '19 at 20:31
  • @HafezDivandari I have a UsersController with a show method. I tried to define the routes beforehand aswell, however that brings back the original problem, where I get 404 errors. I tried with other controllers/methods and they don't work either so it's not a typo – gjerm94 Dec 29 '19 at 19:11
  • @gjerm94 does your controller's method accept route parameter? is it named `user` or `article` as defined on the array? try to change to `['id' => $userOrArticle]` or whatever your method's parameter name are. – Hafez Divandari Dec 29 '19 at 21:44
  • @HafezDivandari Yes, everything seems to be right. I have no idea what could be wrong. – gjerm94 Dec 30 '19 at 18:50
  • Oh well, for now I'll use the other method you posted with UserOrArticleController, where I then new up the appropriate controllers and call the show() method. This is probably not best practice but it seems to work. – gjerm94 Dec 30 '19 at 19:44