I’m adding caching to my Laravel app routes. I have a function that renders a blog post on my site:
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'));
}
This is the route that calls the method: Route::get('/blog/{post}', 'PostController@show')->name('posts.show');
so that my blog renders a URL with a slug like: https://employbl.com/blog/laravel-vue-tailwindcss-single-page-application-spa
What is the best way to implement caching on this route so the page loads faster for users?
Would it be something like:
$post = Cache::rememberForever('blog-post' . $post->id, function(){
return $post;
});
Or is caching even necessary with route model binding? Does the cache key need to be unique or can I just use “blog-post” as cache key? Would it be better to cache the $markdown
variable instead of the $post
variable? Both?
2
Answers
You’ve got a few questions in here, so I’ll try to answer each. The answers may not be letter perfect as I am going from memory without any way to reference or confirm them myself at the moment.
If you’re trying to cache the final output of your view, you can effectively do it be replacing your final view call with:
The cache key needs to be unique for the post. The model routing system knows nothing about the cache system, it’s just a way of passing a value to a controller which makes some assumptions about the incoming data based on the URI. So what you are doing currently is fine.
The problem your question about should I cache the post, the markdown or both? is that it probably won’t make a difference
1) You’re calling a model GET route. This has the effect of loading the Post from the DB each time, making the caching of the Post itself irrelevant. This is true even with the caching of the render view itself.
2) Your view call requires the Post itself as a parameter [of compact()]. You’ll need to load it from somewhere, so that means a database call again to retrieve the post.
3) You’re using Cache::rememberForever which means the cache will never expire. So loading the Post after the first time will be pointless, since it will never be used again (the results are cached forever!). Future edits (if any) won’t work unless you invalidate the cache (which makes rememberForever kind of pointless).
So, I recommend, for this case, that you move away from the model route and instead try a traditional id based Route
where ttl is the time for the cache to expire.
I was looking to solve a similar issue with caching models that were bound using Route Model Binding and found the following solution.
The method details can be found here: Customizing Resolution Logic
It’s worth noting that there’s a very possible chance that you’d rather use this without the
Cache::remember()
method so that you’re not caching something that returns null. It may be better to do this in the following way instead: