【问题标题】:Laravel cache with route model binding?Laravel 缓存与路由模型绑定?
【发布时间】:2020-05-05 06:15:30
【问题描述】:

我正在向我的 Laravel 应用程序路由添加缓存。我有一个在我的网站上呈现博客文章的功能:

    public function show(Post $post)
    {
        SEO::setTitle($post->title);
        SEO::setDescription($post->subtitle);
        SEO::setCanonical('https://employbl.com/blog/' . $post->slug);
        SEO::opengraph()->setUrl('https://employbl.com/blog/' . $post->slug);
        SEO::opengraph()->addProperty('type', 'article');
        SEO::opengraph()->addImage($post->featured_image);
        SEO::twitter()->setSite('@Employbl_Jobs');

        $markdown = Markdown::parse($post->body);

        return view('blog.post', compact('post', 'markdown'));
    }

这是调用该方法的路由:Route::get('/blog/{post}', 'PostController@show')->name('posts.show');,这样我的博客就会呈现一个带有类似以下内容的 URL:https://employbl.com/blog/laravel-vue-tailwindcss-single-page-application-spa

在此路由上实现缓存以便用户更快地加载页面的最佳方法是什么?

会不会是这样的:

$post = Cache::rememberForever('blog-post' . $post->id, function(){
     return $post;
});

或者路由模型绑定是否需要缓存?缓存键是否需要唯一,或者我可以只使用“博客文章”作为缓存键吗?缓存$markdown 变量而不是$post 变量会更好吗?两者都有?

【问题讨论】:

  • 取决于您要缓存的内容,如果是静态内容,您可能希望缓存整个页面内容
  • 是的,它是存储在posts 表中的静态内容。为上述方法缓存整个页面内容的最佳方法是什么?
  • 好吧,我不知道缓存数据库可以执行的最简单查询之一(通过主键检索记录)获得了多少性能改进,但您也可以尝试缓存完整的 html 内容。我相信我曾经看过一个这样做的包裹。基本上它是一个缓存最终的response 的中间件,如果它已经被缓存,则立即返回它。

标签: php laravel laravel-5 caching


【解决方案1】:

这里有几个问题,所以我会尽力回答每个问题。答案可能并不完美,因为我是凭记忆回忆的,目前无法自己参考或确认。

如果您尝试缓存视图的最终输出,则可以有效地将最终的 view 调用替换为:

return Cache::rememberForever('blog-post' . $post->id, function() use ($post) {

    // Do your SEO and markdown stuff here

    return view('blog.post', compact('post', 'markdown'))->render();
});

帖子的缓存键必须是唯一的。模型路由系统对缓存系统一无所知,它只是将值传递给控制器​​的一种方式,控制器根据 URI 对传入数据进行一些假设。所以你现在做的很好。

你的问题是我应该缓存帖子、降价还是两者兼而有之?是它可能不会有什么不同

1) 您正在调用模型 GET 路由。这具有每次从数据库加载 Post 的效果,使 Post 本身的缓存无关紧要。即使渲染视图本身的缓存也是如此。

2) 您的 view 调用需要 Post 本身作为参数 [of compact()]。您需要从某个地方加载它,这意味着再次调用数据库来检索帖子。

3) 您正在使用 Cache::rememberForever,这意味着缓存永远不会过期。所以在第一次之后加载 Post 是没有意义的,因为它永远不会被再次使用(结果被永久缓存!)。除非您使缓存无效(这使得 rememberForever 有点毫无意义),否则未来的编辑(如果有的话)将不起作用。

因此,对于这种情况,我建议您远离模型路线,而是尝试使用传统的基于 id 的路线

public function show(Request $request, $id)
{
    return Cache::remember('blog-post'.$id, ttl, function() use($id) {
      $post = Post::find($id);
      // Do SEO and markdown stuff
      return view('blog.post', compact('post', 'markdown'))->render();
    });
}

其中ttl是缓存过期的时间。

【讨论】:

    【解决方案2】:

    我正在寻求解决使用路由模型绑定绑定的缓存模型的类似问题,并找到了以下解决方案。

    // On the Model class add the following method.
    
    public function resolveRouteBinding($value, $field = null): ?Model
    {
        return Cache::remember('my.custom.key'.$value, 3600, function () use ($value) {
            return $this->where('slug', $value)->firstOrFail();
        });
    }
    

    方法详情可以在这里找到:Customizing Resolution Logic

    值得注意的是,您很有可能宁愿在没有 Cache::remember() 方法的情况下使用它,这样您就不会缓存返回 null 的内容。改用以下方式可能会更好:

    // On the Model class add the following method.
    
    public function resolveRouteBinding($value, $field = null): ?Model
    {
        $cacheName = "my.custom.key.{$value}";
    
        if (Cache::has($cacheName)) {
            return Cache::get($cacheName);
        }
    
        $result = $this->query('slug', $value)->firstOrFail();
        Cache::put($cacheName, $result, 3600);
    
        return $result;
    }
    

    【讨论】:

      猜你喜欢
      • 2021-05-24
      • 1970-01-01
      • 2016-06-04
      • 2017-06-22
      • 1970-01-01
      • 1970-01-01
      • 2017-07-06
      • 2018-12-17
      • 2015-07-12
      相关资源
      最近更新 更多