【问题标题】:Check if model exist and continue routing if not found in Laravel检查模型是否存在,如果在 Laravel 中找不到则继续路由
【发布时间】:2019-06-06 16:43:29
【问题描述】:

我有两个模型,我不想在其 URL 前添加前缀。例如。用户和帖子

如果我有一个 URL https://example.com/title-of-the-posthttps://example.com/username

我会在web.php 路由文件中做这样的事情:

// 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);
});

现在我面临的问题是,即使没有匹配 slug 的模型,输入了第一条路线并且永远不会到达第二条路线。

如果找不到$user,我该如何退出到下一条路线(帖子)?

注意:我尝试了许多不同的退出策略,但似乎都不起作用。

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

提前致谢!

更新

另一个问题是,如果我有其他 resource 路由,它们也会被第一条路由阻塞。

例如如果我有 Route::resource('cars', 'CarController'),它会生成一个与 {slug} 匹配的 /cars 路径,并且也被第一个用户路由阻止。

【问题讨论】:

标签: php laravel routes


【解决方案1】:

您应该在一条路线上同时检查它们:

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);
        }
    }
});

但是,它可以更清洁。但是这个概念是存在的。

【讨论】:

  • 你会如何给这些路线命名?
【解决方案2】:

我想你已经明白了,但我的应用程序中有类似的设置,在我的特殊情况下,我还需要能够捕获多段路由。

这就是我的做法。例如,我的web.php 中的最后一条路线如下。

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

where 类 ->where('catchall', '.*'); 确保我们也能够捕获具有多个段的 slug。

例如,以下路由都会被匹配:

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

然后,在我的SlugRoutesController 中,我可以注入我的其他控制器依赖项。

<?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);
    }
}

我的实际控制器比这要复杂一些,但你明白了。

【讨论】:

  • 这是一个更优雅的解决方案。我仍然希望用中间件来做到这一点。如果我不能很快弄清楚,我将不得不使用这个解决方案
  • 你会如何给这些路线命名?
【解决方案3】:

不确定这是否是最佳做法,但这里是完成我需要的工作。

在 Post 模型上创建了一个函数,用于检查 slug 是否正在调用一个帖子。它同时使用正则表达式和数据库查找。

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

然后我将 Route 包装在这样的 if 语句中。

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

现在该路线仅在实际存在时才使用。您可以将它放在路由文件的底部,以减少对数据库的不必要查找。

【讨论】:

    猜你喜欢
    • 2021-06-13
    • 1970-01-01
    • 2017-07-06
    • 1970-01-01
    • 2019-12-09
    • 1970-01-01
    • 2017-10-02
    • 1970-01-01
    • 2014-07-17
    相关资源
    最近更新 更多