web-id-fr / matryoshka
为 Laravel 提供俄罗斯套娃缓存的包。
Requires
- illuminate/support: ^5.1
Requires (Dev)
- illuminate/cache: ^5.1
- illuminate/database: ^5.1
- phpunit/phpunit: ^5.2
This package is auto-updated.
Last update: 2021-01-26 15:17:27 UTC
README
Matryoshka 是一个 Laravel 包,为您的视图逻辑提供俄罗斯套娃缓存。
想学习如何从头开始制作这个包吗? 请访问 Laracasts.com。
安装
第 1 步:Composer
在命令行中运行
composer require laracasts/matryoshka
第 2 步:服务提供者
对于您的 Laravel 应用,打开 config/app.php
并在 providers
数组中追加
Laracasts\Matryoshka\MatryoshkaServiceProvider::class
这会将包引导到 Laravel。
第 3 步:缓存驱动器
为了使此包正常工作,您必须使用支持标签的 Laravel 缓存驱动器(如 Cache::tags('foo')
)。Memcached 和 Redis 等驱动程序支持此功能。
检查您的 .env
文件,并确保您的 CACHE_DRIVER
选择符合此要求
CACHE_DRIVER=memcached
如果您需要任何帮助,请查看 Laravel 的缓存配置文档。
用法
基础
现在包已安装,您可以在视图的任何地方使用提供的 @cache
Blade 指令,如下所示
@cache('my-cache-key') <div> <h1>Hello World</h1> </div> @endcache
通过将此 HTML 块用 @cache
和 @endcache
指令包围,我们请求包缓存给定的 HTML。现在这个例子很简单,但您可以想象一个更复杂的视图,其中包括各种嵌套缓存以及触发额外数据库查询的懒加载关系调用。在缓存 HTML 片段后的初始页面加载之后,每次刷新都将从缓存中获取。因此,那些额外的数据库查询将永远不会执行。
请注意,在生产环境中,这会“永久”缓存 HTML 片段。另一方面,在本地开发中,我们将自动为您在每次刷新页面时清除相关的缓存。这样,您可以随意更新视图和模板,而无需手动清除缓存。
现在,因为您的生产服务器将永远缓存片段,所以您需要在部署过程中添加一个步骤来清除相关的缓存。
Cache::tags('views')->flush();
缓存模型
虽然您可以随意为缓存键硬编码任何字符串,但俄罗斯套娃缓存的真正力量在于使用基于时间戳的方法。
考虑以下片段
@cache($post) <article> <h2>{{ $post->title }}></h2> <p>Written By: {{ $post->author->username }}</p> <div class="body">{{ $post->body }}</div> </article> @endcache
在这个例子中,我们将 $post
对象本身传递给 @cache
指令,而不是字符串。然后包将寻找模型上的 getCacheKey()
方法。我们已为您完成了这项工作;只需让您的 Eloquent 模型使用 Laracasts\Matryoshka\Cacheable
特性,如下所示
use Laracasts\Matryoshka\Cacheable; class Post extends Eloquent { use Cacheable; }
或者,您可以在扩展了您所有 Eloquent 模型的父类上使用此特性。
这就完成了!现在,此片段的缓存键将包含对象的 id
和 updated_at
时间戳:App\Post/1-13241235123
。
关键是,由于我们将
updated_at
时间戳因素考虑进缓存键中,每次您更新给定的帖子时,缓存键都会改变。这实际上会清除缓存!
触达
为了使这项技术正确运行,我们必须有一些机制来在每次更新模型时提醒父级关系(并随后清除父级缓存)。以下是基本的工作流程
- 模型在数据库中更新。
- 其
updated_at
时间戳被刷新,触发实例的新缓存键。 - 模型“触达”(或ping)其父级。
- 父级的
updated_at
时间戳也被更新,这清除了其相关缓存。 - 只有受影响的片段会重新渲染。所有其他缓存项保持不变。
幸运的是,Laravel自带了“触达”功能。考虑一个需要每次更新时都提醒其父级 Card
关系的 Note
对象。
<?php namespace App; use Laracasts\Matryoshka\Cacheable; use Illuminate\Database\Eloquent\Model; class Note extends Model { use Cacheable; protected $touches = ['card']; public function card() { return $this->belongsTo(Card::class); } }
注意 $touches = ['card']
部分。这指示 Laravel 每次笔记更新时ping card
关系的日期。
现在,一切就绪。您可以像这样渲染视图
resources/views/cards/_card.blade.php
@cache($card) <article class="Card"> <h2>{{ $card->title }}</h2> <ul> @foreach ($card->notes as $note) @include ('cards/_note') @endforeach </ul> </article> @endcache
resources/views/cards/_note.blade.php
@cache($note) <li>{{ $note->body }}</li> @endcache
注意我们缓存的俄罗斯套娃式级联;这是关键。如果任何笔记被更新,其单独的缓存将清除 - 包括其父级 - 但其兄弟姐妹将保持不变。
缓存集合
您不一定想缓存模型实例;您可能还希望缓存 Laravel 集合!没问题。
@cache($posts) @foreach ($posts as $post) @include ('post') @endforeach @endcache
只要 $posts
集合的内容不改变,那么这个 @foreach
部分将永远不会运行。相反,像往常一样,我们将从缓存中提取。
幕后,此包将检测到您已将 Laravel 集合传递给 cache
指令,并随后为集合生成一个唯一的缓存键。
常见问题解答(FAQ)
1. 有没有覆盖模型实例缓存键的方法?
是的。假设你有
@cache($post) <div>view here</div> @endcache
幕后,我们将寻找模型上的 getCacheKey
方法。如上所述,您可以使用 Laracasts\Matryoshka\Cacheable
特性立即导入此功能。或者,您可以通过传递第二个参数给 @cache
指令,如下所示
@cache($post, 'my-custom-key') <div>view here</div> @endcache
这指示包使用 my-custom-key
作为缓存,这对于分页和其他相关任务非常有用。
2. 我在哪里可以了解更多关于这种缓存方法的细节?
请阅读以下两篇文章
- https://signalvnoise.com/posts/3112-how-basecamp-next-got-to-be-so-damn-fast-without-using-much-client-side-ui
- https://signalvnoise.com/posts/3113-how-key-based-cache-expiration-works
如果您喜欢 Laracasts,请在这里观看此包从零开始创建。