Framework: How to renew or reset when using Eloquent cache?

Created on 25 Nov 2013  路  16Comments  路  Source: laravel/framework

If I am caching the results of a Eloquent object using

$articles = Countries::remember(5)->get();

or

$articles = Countries::rememberForever()->get();

how can i renew or reset this to fill in fresh data from the database to the cache?

Most helpful comment

@anlutro wouldn't it be nice to have Countries::clearAndRemember()->get(); to force clear cache and generate a new cache.

p/s: Not entirely agree with the method name.

All 16 comments

You mean without doing artisan cache:clear ? Like just empty Eloquent's cache ? Not sure if that's possible.

@Anahkiasen, yes. without using artisan cache:clear. I don't wish to clear the entire cache. Lets say, I added a new country to my country table and want to clear the cache specific to the data when I did $articles = Countries::remember(5)->get();. How do I do that?

Didn't I tell this on irc a while ago?

$query = Countries::newQuery()->remember(5);
Cache::forget($query->getCacheKey());
$countries = $query->get();

@anlutro wouldn't it be nice to have Countries::clearAndRemember()->get(); to force clear cache and generate a new cache.

p/s: Not entirely agree with the method name.

@anlutro, Don't seem to have noticed it on IRC. I will try to check the messages again. Thnx for notifying again. Appreciate your help.

@crynobone, I was thinking on the same terms as well

Or maybe just the option to do $query->forget() or $query->clearCache() - would be handy.

IMO $query->forget() or $query->clearCache() means more like clearing the cache of a a single query. Model::clearCache or Model::forget() would make more sense.

I don't think Model::forget() could work. remember() saves the results with the SQL query string as a key, so without a query builder there isn't really anything to clear.

Maybe in 4.1 cached queries can be tagged with eloquent:<class> so both is possible...

@Stayallive

Model::whereUserId(5)->remember()->get();

// and

Model::whereId(5)->remember()->get();

should both generate two different key, if we tagged it with just eloquent:<class>, both would be flushed.

@crynobone: Yeah thats the idea ;)

There could be 2 options to have a little something something for everyone:

First: Model::clearCache(), wich is using the tags.
Second: $query->flushCache(), wich is using the actual query cache key.

Using the cache key attribute can be helpful :

// get last 5 users
$users = User::remember(60, 'last_5_users')->orderBy('created_at', 'desc')->take(5)->get();

// delete this specific cache entry
Cache::forget('last_5_users');

Yes, I would just pass a cache key as noted by @semalead.

@taylorotwell, @semalead, could you advice on how should the implementation be in case of the below scenario:

Countries Table

id     |    name
----------------------
1      |    Australia
2      |    Austria
3      |    Algeria
4      |    Angola
//Retrieves all the countries and stores them on the cache
$countries = Countries::rememberForever('countries')->get();  

//Retreives all the countries starting with letter `A`
$countries_starting_with_a = Countries::rememberForever('countries_a')->where('name','like','A%')->get();

//Inserting a new country with letter `A`
Countries::create(array('Andorra'));

Cache::forget('countries'); only clears the cache with key countries and not the cache countries_a.

So calling

$countries_starting_with_a = Countries::rememberForever('countries_a')->where('name','like','A%')->get();

will retrieve all countries starting with the letter A except the one that was inserted later Andorra.

Is there a way to clear all cache that belong to the model Countries? Please advice

Discussed with @taylorotwell over IRC, and we can use the tags method of the query builder to do this.

Countries::remember(5,'countries')->tags(array('countries'))->get();
Countries::remember(5,'countries_a')->tags(array('countries'))->where('name','like','A%')->get();

And you can use the flush method of the Cache tags in Laravel 4.1 to flush them.

Cache::tags('countries')->flush();

Thnx @taylorotwell. Laravel is super cool...

Reading the documentation of Laravel 4.2 it seems that the correct way of implementing the tagging is to write the following:

Countries::cacheTags(array('countries'))->remember(5,'countries')->get();

Note the cacheTags-method instead of tags-method and putting it before remember-method.

So that the flushing of tags will work:

Cache::tags('countries')->flush();

And it is worth noting that you have to use the memcached driver for this to work.

I'm just starting to look into this, having some issues. But it's an promising solution...
But am I on the correct path?

@taylorotwell @abishekrsrikaanth

My issue now is that Cache::tags('my-tag')->flush(); don't seem to work, I still get the result with a removed instance of my model, so I have to elaborate a bit more regarding this. The only difference from what I wrote here, except model name and tag name is that I don't supply a second parameter to remember-function.

Edit:
I got it working, my problem was related to a separate model serving as a sorted index (has a huge collection that needs advanced sorting) where the row that referred to the model instance was not deleted when deleting the instance of the model. Removing that row on the sorted index model and cache those queries with same tag made my code work.

Both Model::cacheTag(array('my-tag')->rememberForever()->get(); and Cache::tags('my-tag')->rememberForever('cache_key', function () {}); was perfectly playing along with calling Cache::tags('my-tag')->flush(); when model collection and instances (and in my case sorted index-tables) changes.

In short, the approach works great, if implemented correctly... ;)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

felixsanz picture felixsanz  路  3Comments

ghost picture ghost  路  3Comments

iivanov2 picture iivanov2  路  3Comments

SachinAgarwal1337 picture SachinAgarwal1337  路  3Comments

RomainSauvaire picture RomainSauvaire  路  3Comments