你怎么会忘记Laravel中缓存的Eloquent模型?

时间:2022-10-15 23:12:03

Theoretical question on Laravel here.

关于Laravel的理论问题。

So Example of the caching I'd do is:

所以我要做的缓存示例是:

Article::with('comments')->remember(5)->get();

Ideally I'd like to have an event for Article updates that when the ID of a instance of that model (that's already cached) is updated I want to forget that key (even if it's the whole result of the query that's forgotten instead of just that one model instance), it is possible to do so?

理想情况下,我希望有一个文章更新事件,当该模型的实例的ID(已经缓存)更新时,我想忘记该密钥(即使它是忘记的查询的整个结果而不是仅仅那一个模型实例),有可能这样做吗?

If not is there some way to implement this reasonably cleanly?

如果没有,是否有某种方法可以合理地实现这一点?

4 个解决方案

#1


59  

So i was looking for an answer to the same question as OP but was not really satisfied with the solutions. So i started playing around with this recently and going through the source code of the framework, I found out that the remember() method accepts second param called key and for some reason it has not been documented on their site (Or did i miss that?).

所以我一直在寻找与OP相同问题的答案,但对解决方案并不满意。所以我最近开始玩这个,并通过框架的源代码,我发现remember()方法接受第二个param称为key,由于某种原因它没有在他们的网站上记录(或者我错过了?)。

Now good thing about this is that, The database builder uses the same cache driver which is configured under app/config/cache.php Or should i say the same cache system that has been documented here - Cache. So if you pass min and key to remember(), you can use the same key to clear the cache using Cache::forget() method and in fact, you can pretty much use all the Cache methods listed on the official site, like Cache::get(), Cache::add(), Cache::put(), etc. But i don't recommend you to use those other methods unless you know what you're doing.

现在好消息是,数据库构建器使用在app / config / cache.php下配置的相同缓存驱动程序。或者我应该说这里记录的相同缓存系统 - 缓存。因此,如果你将min和key传递给remember(),你可以使用相同的键来使用Cache :: forget()方法清除缓存,事实上,你几乎可以使用官方网站上列出的所有Cache方法,比如Cache :: get(),Cache :: add(),Cache :: put()等。但我不建议您使用其他方法,除非您知道自己在做什么。

Here's an example for you and others to understand what i mean.

以下是您和其他人了解我的意思的示例。

Article::with('comments')->remember(5, 'article_comments')->get();

Article :: with('comments') - >记住(5,'article_comments') - > get();

Now the above query result will be cached and will be associated with the article_comments key which can then be used to clear it anytime (In my case, I do it when i update).

现在上面的查询结果将被缓存,并将与article_comments键相关联,然后可以随时用它来清除它(在我的情况下,我在更新时这样做)。

So now if i want to clear that cache regardless of how much time it remembers for. I can just do it by calling Cache::forget('article_comments'); and it should work just as expected.

所以现在,如果我想清除缓存,无论它记住多少时间。我可以通过调用Cache :: forget('article_comments')来做到这一点;它应该像预期的那样工作。

Hope this helps everyone :)

希望这有助于每个人:)

#2


12  

I think a good way to do is like this:

我认为一个好的方法是这样的:

$value = Cache::remember('users', $minutes, function()
{
    return DB::table('users')->get();
});

and then use Model Observers to detect the event of updating the model

然后使用Model Observers检测更新模型的事件

class UserObserver {

    public function saving($model)
    {
        //
    }

    public function saved($model)
    {
        // forget from cache
        Cache::forget('users');
    }

}

User::observe(new UserObserver);

#3


0  

Currently there are no easy way. However I found this workaround, which so far worked for me.

目前还没有简单的方法。但是我发现这个解决方法,到目前为止对我有用。

First you have to extend Illuminate\Database\Query\Builder.

首先,您必须扩展Illuminate \ Database \ Query \ Builder。

<?php 

class ModifiedBuilder extends Illuminate\Database\Query\Builder {
    protected $forgetRequested = false;

    public function forget() 
    {
        $this->forgetRequested = true;
    }

    public function getCached($columns = array('*'))
    {
        if (is_null($this->columns)) $this->columns = $columns;

        list($key, $minutes) = $this->getCacheInfo();

        // If the query is requested ot be cached, we will cache it using a unique key
        // for this database connection and query statement, including the bindings
        // that are used on this query, providing great convenience when caching.
        $cache = $this->connection->getCacheManager();

        $callback = $this->getCacheCallback($columns);

        if($this->forgetRequested) {
            $cache->forget($key);
            $this->forgetRequested = false;
        }

        return $cache->remember($key, $minutes, $callback);
    }
}

Then you have to create new class which extends Eloquent Model.

然后你必须创建扩展Eloquent Model的新类。

<?php

class BaseModel extends Eloquent {
    protected function newBaseQueryBuilder() {
        $conn = $this->getConnection();

        $grammar = $conn->getQueryGrammar();

        return new ModifiedBuilder($conn, $grammar, $conn->getPostProcessor());
    }
}

Now when creating Eloquent Models, instead of extending Eloquent Models extend newly created BaseModel.

现在,在创建Eloquent模型时,不是扩展Eloquent模型,而是扩展新创建的BaseModel。

Now you can remember query result as usual.

现在你可以像往常一样记住查询结果。

YourModel::remember(10)->get();

When you want to discard the cached result all you have to do is

当你想要丢弃缓存的结果时,你所要做的就是

YourModel::forget()->get();

If you remember the result previously, after clearing the cached result, model will continue to remember the result for that amount of time.

如果您以前记得结果,在清除缓存结果后,模型将继续记住该时间段的结果。

Hope this helps.

希望这可以帮助。

#4


0  

I was testing for debug mode. So I found that if you put a test for app.debug in a constructor you are able to clear the cache associated with a key. Saves you having to duplicate the code for every function.

我正在测试调试模式。所以我发现如果你在构造函数中对app.debug进行测试,你就可以清除与密钥相关的缓存。保存您不得不复制每个功能的代码。

class Events {
    public function __construct() {
        if (\Config::get('app.debug')) {
            Cache::forget('events');
        }
    }

    public static function all() {
        $events = \DB::table('events as e')
            ->select('e.*')
            ->where('enabled', 1)
            ->remember(30, 'events')
            ->get();

        return $events;
    }
}

#1


59  

So i was looking for an answer to the same question as OP but was not really satisfied with the solutions. So i started playing around with this recently and going through the source code of the framework, I found out that the remember() method accepts second param called key and for some reason it has not been documented on their site (Or did i miss that?).

所以我一直在寻找与OP相同问题的答案,但对解决方案并不满意。所以我最近开始玩这个,并通过框架的源代码,我发现remember()方法接受第二个param称为key,由于某种原因它没有在他们的网站上记录(或者我错过了?)。

Now good thing about this is that, The database builder uses the same cache driver which is configured under app/config/cache.php Or should i say the same cache system that has been documented here - Cache. So if you pass min and key to remember(), you can use the same key to clear the cache using Cache::forget() method and in fact, you can pretty much use all the Cache methods listed on the official site, like Cache::get(), Cache::add(), Cache::put(), etc. But i don't recommend you to use those other methods unless you know what you're doing.

现在好消息是,数据库构建器使用在app / config / cache.php下配置的相同缓存驱动程序。或者我应该说这里记录的相同缓存系统 - 缓存。因此,如果你将min和key传递给remember(),你可以使用相同的键来使用Cache :: forget()方法清除缓存,事实上,你几乎可以使用官方网站上列出的所有Cache方法,比如Cache :: get(),Cache :: add(),Cache :: put()等。但我不建议您使用其他方法,除非您知道自己在做什么。

Here's an example for you and others to understand what i mean.

以下是您和其他人了解我的意思的示例。

Article::with('comments')->remember(5, 'article_comments')->get();

Article :: with('comments') - >记住(5,'article_comments') - > get();

Now the above query result will be cached and will be associated with the article_comments key which can then be used to clear it anytime (In my case, I do it when i update).

现在上面的查询结果将被缓存,并将与article_comments键相关联,然后可以随时用它来清除它(在我的情况下,我在更新时这样做)。

So now if i want to clear that cache regardless of how much time it remembers for. I can just do it by calling Cache::forget('article_comments'); and it should work just as expected.

所以现在,如果我想清除缓存,无论它记住多少时间。我可以通过调用Cache :: forget('article_comments')来做到这一点;它应该像预期的那样工作。

Hope this helps everyone :)

希望这有助于每个人:)

#2


12  

I think a good way to do is like this:

我认为一个好的方法是这样的:

$value = Cache::remember('users', $minutes, function()
{
    return DB::table('users')->get();
});

and then use Model Observers to detect the event of updating the model

然后使用Model Observers检测更新模型的事件

class UserObserver {

    public function saving($model)
    {
        //
    }

    public function saved($model)
    {
        // forget from cache
        Cache::forget('users');
    }

}

User::observe(new UserObserver);

#3


0  

Currently there are no easy way. However I found this workaround, which so far worked for me.

目前还没有简单的方法。但是我发现这个解决方法,到目前为止对我有用。

First you have to extend Illuminate\Database\Query\Builder.

首先,您必须扩展Illuminate \ Database \ Query \ Builder。

<?php 

class ModifiedBuilder extends Illuminate\Database\Query\Builder {
    protected $forgetRequested = false;

    public function forget() 
    {
        $this->forgetRequested = true;
    }

    public function getCached($columns = array('*'))
    {
        if (is_null($this->columns)) $this->columns = $columns;

        list($key, $minutes) = $this->getCacheInfo();

        // If the query is requested ot be cached, we will cache it using a unique key
        // for this database connection and query statement, including the bindings
        // that are used on this query, providing great convenience when caching.
        $cache = $this->connection->getCacheManager();

        $callback = $this->getCacheCallback($columns);

        if($this->forgetRequested) {
            $cache->forget($key);
            $this->forgetRequested = false;
        }

        return $cache->remember($key, $minutes, $callback);
    }
}

Then you have to create new class which extends Eloquent Model.

然后你必须创建扩展Eloquent Model的新类。

<?php

class BaseModel extends Eloquent {
    protected function newBaseQueryBuilder() {
        $conn = $this->getConnection();

        $grammar = $conn->getQueryGrammar();

        return new ModifiedBuilder($conn, $grammar, $conn->getPostProcessor());
    }
}

Now when creating Eloquent Models, instead of extending Eloquent Models extend newly created BaseModel.

现在,在创建Eloquent模型时,不是扩展Eloquent模型,而是扩展新创建的BaseModel。

Now you can remember query result as usual.

现在你可以像往常一样记住查询结果。

YourModel::remember(10)->get();

When you want to discard the cached result all you have to do is

当你想要丢弃缓存的结果时,你所要做的就是

YourModel::forget()->get();

If you remember the result previously, after clearing the cached result, model will continue to remember the result for that amount of time.

如果您以前记得结果,在清除缓存结果后,模型将继续记住该时间段的结果。

Hope this helps.

希望这可以帮助。

#4


0  

I was testing for debug mode. So I found that if you put a test for app.debug in a constructor you are able to clear the cache associated with a key. Saves you having to duplicate the code for every function.

我正在测试调试模式。所以我发现如果你在构造函数中对app.debug进行测试,你就可以清除与密钥相关的缓存。保存您不得不复制每个功能的代码。

class Events {
    public function __construct() {
        if (\Config::get('app.debug')) {
            Cache::forget('events');
        }
    }

    public static function all() {
        $events = \DB::table('events as e')
            ->select('e.*')
            ->where('enabled', 1)
            ->remember(30, 'events')
            ->get();

        return $events;
    }
}