简体   繁体   中英

Check if model exist and continue routing if not found in Laravel

I have two models that I don't want to have a prefix in front of its URLs. Eg Users and Posts

If I have a URL https://example.com/title-of-the-post and https://example.com/username

I will do something like this in the web.php routes file:

// User
Route::get('{slug}', function ($slug) {
    $user = User::whereSlug($slug)->get();
    return view('users.show', $user);
});

// Post
Route::get('{slug}', function ($slug) {
    $post = Post::whereSlug($slug)->get();
    return view('posts.show', $user);
});

Now the issue I am facing is that the first route is entered and will never reach the second even if there is no model with a matching slug.

How can I exit to the next route (Post) if $user is not found?

Note: I have tried many different exit strategies but none seem to work.

return;
return false;
return null;
// and return nothing

Thanks in advance!

UPDATE :

Another issue is that if I have other resource routes they too get blocked by the first route.

Eg If I have Route::resource('cars', 'CarController') it generates a /cars path which matches the {slug} and is also being blocked by first User route.

I think you already got the idea but I ,kind of, have a similar setup in my application and in my particular case, I also needed to be able to catch multi-segments routes.

So here's how I did it. For example, the last route in my web.php is the following.

Route::get('{catchall}', 'SlugRoutesController@route')->where('catchall', '.*');

The where class ->where('catchall', '.*'); ensures that we are also able to catch slugs that have multiple segments.

For example, the following routes will all be matched:

/blog/this-is-an-article
/user/mozammil/articles

Then, in my SlugRoutesController , I am able to inject my other Controller dependencies.

<?php

namespace App\Http\Controllers;

use App\Post; 
use App\User; 
use PostController;
use UserController; 
use Illuminate\Http\Request;

class HomeController extends Controller
{
    private $postController;
    private $userController;

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct(UserController $userController, PostController $postController)
    {
        $this->userController = $userController; 
        $this->postController = $postController; 
    }

    public function route(Request $request, string $slug)
    {
        $post = Post::where('slug', $slug)->first(); 
        if(post) {
            return $this->postController->index($request); 
        }

        $user = User::where('slug', $slug)->first(); 
        if($user) {
            return $this->userController->index($request); 
        }

        abort(404);
    }
}

My actual controller is a bit more complex than that, but you get the idea.

You should check both of them in one route :

Route::get('{slug}', function ($slug)
{
    $user = User::whereSlug($slug)->first();

    if ($user)
    {
        return view('users.show', $user);
    }
    else
    {
        $post = Post::whereSlug($slug)->first();

        if ($post)
        {
            return view('posts.show', $post);
        }
        else
        {
            abort(404);
        }
    }
});

However, it can be more cleaner. But the concept is there.

Not sure if this is best practice but here is what was done to accomplish what I needed.

Created a function on the Post model that checks if the slug is calling a post. It uses both a regex and database lookup.

public static function isRequestedPathAPost() {
    return !preg_match('/[^\w\d\-\_]+/', \Request::path()) &&
        Post::whereSlug(\Request::path())->exists();
}

Then I wrap the Route in a if statement like this.

if (\App\Models\Post::isRequestedPathAPost()) {
    Route::get('{slug}', 'PostController@show');
}

Now the route is only used if it actually exist. You can put this at the bottom of the route file to reduce unnecessary lookups to the database.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM