تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Why Cache Queries0:44

to return it outright, and we'll switch to Chrome. And sure enough, we can see all of the records that I have stored. But what this does mean is that for every single visitor to our site, we are performing a database query to fetch all of the articles. And if we imagine that this is our blog, maybe it's only updated once a week, yet for every single request, we perform the exact same query and fetch the exact same collection of data. So this is a good use case for caching. You can cache your database queries. You could even cache HTML fragments. You can cache database queries, or all the way up to caching actual HTML fragments, whatever you want to do here. Okay, so what might we do here? And like I said, we're going to do this incrementally. We're going to write one implementation, and then refactor it to a function, and then take a look at what we can do with Laravel. Okay, so we might say at the top, if Redis, and if we just want to check

Manual Redis Cache Check1:29

to write one implementation, and then refactor it to a function, and then take a look at what we can do with Laravel. Okay, so we might say at the top, if Redis, and if we just want to check if Redis has a particular key, there is no has command, but there is one called exists. So we could do something like this. If a key exists in Redis called articles.all, we have already cached this. So in that case, why don't we return a call to Redis, get articles.all. Next, though, I know that's going to be a collection, right? So that means it's probably encoded. So I will decode it. Otherwise, we're going to fetch the articles, put it into Redis, and then return the results. So fetch the articles, and then say Redis set articles.all, and then we'll feed it the collection. And don't forget, once again, that will automatically be converted to JSON. So it's equivalent to doing this, or equivalent to doing this.

and then we'll feed it the collection. And don't forget, once again, that will automatically be converted to JSON. So it's equivalent to doing this, or equivalent to doing this. Okay, so does this all make sense? A request comes in, and we check to see, well, have we cached this yet? No, we haven't. So we perform a database query, we put it into Redis, we cache it, and then we return the results. But now on the next page request, yes, it does exist in Redis, so we're just going to pull it from memory, and we're never going to perform this database query. Okay, let's try it out. redis-cli, do we have articles.all? No. Come back to Chrome, give it a refresh. We should have performed the database query, and then cached it. So if I run it now, there it is. And now if we come back and give this a refresh, we are no longer performing the database query, we're just fetching it. So that means, for example, if you commented this out,

it now, there it is. And now if we come back and give this a refresh, we are no longer performing the database query, we're just fetching it. So that means, for example, if you commented this out, you'll see that we never even hit that point. Okay, pretty cool. A very simple use case, but you know what? You're going to get a lot of use out of this. However, right now, kind of sucks to write. You can imagine doing this for every query. Well, if it's in Redis, then fetch it. Otherwise, perform the query, then put it into Redis. Naturally, we can refactor this a little bit to make it easier on us. But first, we could do it like this if we want, or we could always just fetch it. So for example, if I were to say getGibberish, it's just going to return null. So that means we could always do something like this, where we say if the value equals redis.get, then it does exist in the cache, and we've already fetched it. So in that case,

So that means we could always do something like this, where we say if the value equals redis.get, then it does exist in the cache, and we've already fetched it. So in that case, just decode the value. Yeah, that's one refactor we could do there. So let's delete articles.all, and if we fetch it, no longer there. Refresh, we perform the database query, we cache it, and on subsequent requests, we're no longer performing that query. And again, think of something very high traffic, where the query is super complex, takes a long time. Well, if you can, you should really try to cache those. Okay, but yeah, we can still do another refactor here. So what is it that we're trying to do? We're basically trying to remember this value. So we're saying, if it exists, then give it to me. Otherwise, I'm going to perform the query, but then I want you to remember this value or this key value pair for future requests.

Building a Remember Helper4:43

we're saying, if it exists, then give it to me. Otherwise, I'm going to perform the query, but then I want you to remember this value or this key value pair for future requests. So maybe we could create, again, just as a second step, and then we're going to delete this entirely. But yeah, maybe we could create our own function called remember, and we could say, give me the key, give me the amount of time to cache it, we'll talk about that in a minute, and then give me a callback, which is what to do if it does not exist in the cache. Okay, what about this minutes section? That doesn't really line up here. Really, what we're doing here is we are caching or remembering it forever. There is no expiration date. Now, you're probably going to want both. Some things you do want to cache, where maybe cache the front page records or results for one day at a time, and then the next day it'll fetch a different random set. You

Adding Cache Expiration5:26

going to want both. Some things you do want to cache, where maybe cache the front page records or results for one day at a time, and then the next day it'll fetch a different random set. You know, that's a good use case for that. While in other situations, you don't need to expire it. So as you'll find with Laravel, there's two separate functions for that. In our case, we're just going to focus on remember, where you do have to provide an expiration date. So with Redis, we haven't talked about this yet, so you're learning it now. We can use setex, which means set a value with an expiration date and seconds. So now, in fact, let's review this completely. I'll comment that out. I'm going to delete this from the cache, and now when we hit it the first time, it will cache it, but only for 60 seconds. So refresh, it's now in the cache. However, I'm going to pause this and come back in 60 seconds, and it will no longer be there.

it the first time, it will cache it, but only for 60 seconds. So refresh, it's now in the cache. However, I'm going to pause this and come back in 60 seconds, and it will no longer be there. All right, I'm hitting pause. Okay, it's been about a minute. So if I fetch it again, it's gone. That's what setting an expiration date does. Okay, anyways, let's go back to our refactor. So we're basically going to reproduce a lot of what we had here, but we'll substitute the variables. So if value equals Redis, get the key, then decode that value. And in fact, we might want to use serialization here instead to keep it more generic. But anyways, otherwise, we're going to perform the query, but yeah, we can't do anything like that. We can't assume that's what you want to do, and that's what the callback is for. You're going to give us a callback that we will trigger, and that will determine what we are caching, and we'll save that to the value. Then we'll tell.

to do, and that's what the callback is for. You're going to give us a callback that we will trigger, and that will determine what we are caching, and we'll save that to the value. Then we'll tell Redis to cache it. Redis::set with an expiration date, the key, the minutes, and then the value. Finally, we can return the value. Okay, so that means we could even put this within here to clean it up a little bit, and that should do it. So now, think about it. We can get rid of this entirely and refactor it to something like this. I want to find the articles.all key in our Redis database, but if it doesn't exist, I'm going to cache it for an hour, maybe in this case, and the logic will be that I want to fetch all articles. Okay, so yeah, this can be refactored to a helper file or something, and now I think you can agree this is a little easier to take in. Give it a key. Give it an expiration date. In this case, 60 seconds times 60 minutes is one hour,

to a helper file or something, and now I think you can agree this is a little easier to take in. Give it a key. Give it an expiration date. In this case, 60 seconds times 60 minutes is one hour, and then finally, if it doesn't exist in the cache, well, we will call the callback right here, save it to $value, and that is what gets stored in Redis. All right, let's try it out. Delete articles.all again. Run it. Okay, but notice we didn't see anything here. We probably didn't return, and we didn't. Okay, one more time. We run it. We perform the query. It is now cached, and now on subsequent requests, we are pulling from the cache, and again, you can prove that by commenting this out entirely, or even you could say die hit, and you'll see that we never actually call that. It only gets called the very first time, like this. All right, makes sense. So now, well, I talked about reviewing what Laravel offers and

Exploring Laravel Cache Internals8:39

and you'll see that we never actually call that. It only gets called the very first time, like this. All right, makes sense. So now, well, I talked about reviewing what Laravel offers and how it would compare to this. Okay, let's take a look. Let's go to the CacheServiceProvider and see what's going on here. Okay, so cache is bound to an instance of CacheManager, and then this key is bound to a call to driver on the CacheManager. Okay, driver. All right, so driver is calling the store method, and here, if we pass something through, like the driver we want to use, Redis or memcached or file, we're going to set that. Otherwise, we will get the default driver. The default driver is going to look into our cache config, so it's going to look in here and figure out, well, what is our default driver, and of course, you'll see that I set that in my .env file. We're, of course, using Redis for this series, so that is what's going

in here and figure out, well, what is our default driver, and of course, you'll see that I set that in my .env file. We're, of course, using Redis for this series, so that is what's going to be returned. If we go back, name equals Redis, so now we get the Redis driver, and here we go. Resolve Redis, and here we go. So there's a method called createRedisDriver that it wants to call on this object. Aha, there it is, and so that's going to return a new instance of repository that accepts a dependency of the Redis store, and that's going to new up a repository. Okay, so kind of complicated. You don't need to know that specifically. It's just to show you that you're going to get this Repository class where the store argument that we pass through the constructor is a Redis implementation. It's the Redis strategy for performing this sort of caching. Anyways, if we take a look at the remember method that you may be familiar with,

constructor is a Redis implementation. It's the Redis strategy for performing this sort of caching. Anyways, if we take a look at the remember method that you may be familiar with, let's see how this compares. So let's open this up in the sidebar. Okay, so here's our little custom implementation, and here is what Laravel provides. They both accept a key, the minutes, and the closure. Let's get rid of this entirely so you can see it. Okay, so Laravel's version is fetching the value, so it calls a get method. That is going to ask our Redis store to get it. Call a get method. Okay, so it finds the Redis connection, and it's calling the get method. That's just like saying Redis::get. It gives it the key. It attaches that prefix that we talked about, and if something was returned from Redis, it's going to unserialize, and that's what I was talking about earlier, where we could do unserialize, and then down here,

talked about, and if something was returned from Redis, it's going to unserialize it, and that's what I was talking about earlier, where we could do unserialize, and then down here, we could serialize the results from that. All right, so so far, pretty similar actually. Go back to remember. So if it is stored with Redis, that's exactly what we're going to return, and that's exactly what we do here. If it's stored in Redis, then return it. Otherwise, we're going to put to Redis, and you'll see that it's basically the same thing that we have here. Let's take a look at that put method. Once again, it's going to defer to Redis's, or the Redis implementation of the put method. If we take a look at that, all right, so here is where we serialize the value, and then we say set x, set with an expiration date, the key, that's what we have, the amount of time, that's what we have, and then the value,

Switching to Cache::remember11:56

all right, so here is where we serialize the value, and then we say set $x, set with an expiration date, the key, that's what we have, the amount of time, that's what we have, and then the value, that's what we have. Finally, if we come back, let's go back to the remember method, it returns the value, and that's what we did here. Okay, so we can see that they're virtually identical, right? That means we can get rid of this completely, and then we can defer to Laravel's cache driver with the understanding that behind the scenes, we wanted to use the Redis driver, and we defined that here. Okay, let's try it. I'm now going to say cache, get rid of Redis entirely, and then say remember articles.all. Once again, an hour is fine, and then return app()->article()->all(). Okay, so we've substituted our custom implementation with what Laravel already provides, and we will return this. Okay, let's try it out. Let's delete

and then return app article all. Okay, so we've substituted our custom implementation with what Laravel already provides, and we will return this. Okay, let's try it out. Let's delete it, come back to Chrome, give it a refresh, and it's now put to Redis. Ah, but we don't see it. Well, remember, it adds the prefix, so we should do Laravel::, and there it is. Anyways, for subsequent requests, once again, like before, it's just pulling from Redis, so if we die and dump here, of course, we're never going to hit that piece of code. All right, so really good stuff to know, right? We could use Redis directly, and in lots of cases, especially for working with hashes or sorted sets, that's exactly what you want to do. However, when it comes to general caching, it's probably better to use Laravel's cache component, and that way, you're not bound or locked into any specific driver, like Redis or File or Memcached,

comes to general caching, it's probably better to use Laravel's cache component, and that way, you're not bound or locked into any specific driver, like Redis or File or Memcached, and of course, the cache API is already there and really nice to work with. Sounds good to me.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟