rodrigopedra/file-tagged-cache

Laravel 文件标签缓存驱动器

v1.3.0 2023-02-15 15:09 UTC

This package is auto-updated.

Last update: 2024-09-15 18:25:42 UTC


README

本软件包为 Laravel 提供了使用文件驱动器的标签缓存支持

安装

composer require rodrigopedra/file-tagged-cache

配置

安装后,您可以在项目的 ./config/cache.php 文件中配置一个新的缓存存储,并使用 file-tagged 作为缓存驱动器。

// ./config/cache.php

'stores' => [
    // ...

    'posts' => [
        'driver' => 'file-tagged', // custom driver added by this package
        'path' => storage_path('framework/cache/posts'),
    ],
],

存储文件夹

如果您正在使用自定义目录来存储缓存数据,最好在之前创建该目录,并在相关的 .gitignore 文件中列出它。

例如,上面的代码片段将缓存数据配置为存储在 ./storage/framework/cache/posts 目录中。

由于此目录默认情况下不存在于您的 Laravel 安装中,您需要创建它。

例如

./storage
├── app
├── framework
│   ├── cache
│   │   ├── data
│   │   │   └── .gitignore
│   │   ├── posts
│   │   │   └── .gitignore
│   │   └── .gitignore
│   ├── .gitignore
│   ├── sessions
│   ├── testing
│   └── views
└── logs

我们在 ./storage/framework/cache/ 目录中添加了新的 /posts 目录。

./storage/framework/cache/data 目录中的 .gitignore 文件应保持与 Laravel 一起提供的状态。

./storage/framework/cache/posts 目录中的 .gitignore 文件应配置如下

*
!.gitignore

./storage/framework/cache 目录(/data/posts 的父目录)中的 .gitignore 文件应更改,以允许创建的 /posts 目录,如下所示

*
!data/
!posts/
!.gitignore

使用方法

您可以使用 Cache 工厂来获取此自定义存储的实例,并将其用作 Laravel 随带的其他任何标签缓存存储。

use Illuminate\Support\Facades\Cache;

Cache::store('posts')->tags(['a-tag', 'another-tag'])->put('key', 'Hello World!');

如果您不熟悉 Laravel 中标签缓存的工作方式,请参阅相关的 Laravel 文档。

https://laravel.net.cn/docs/8.x/cache#cache-tags

动机

此软件包最初是为了在缺乏更合适的标签缓存解决方案的服务器上提供一个缓存视图的简单方法而构建的,这些视图依赖于 Eloquent 模型。

请注意,此缓存驱动器旨在用于项目内容变化不频繁且变化由少数用户(理想情况下一个用户)同时进行的项目中。

如果您的项目具有更动态的特性或允许许多用户同时编辑相同的内容,请考虑使用 Laravel 随带的其他标签缓存驱动器之一。

与 Eloquent 模型的使用

本节完全可选,此处提供的内容不会干扰缓存驱动器的使用。

本软件包提供了一个观察器、一个契约和一个特性,以便更容易地与 Eloquent 模型一起使用。

让我们考虑一个包含 3 个模型(PostAuthorComment)的博客项目。

我们可以将观察器和特性添加到模型中,如下所示

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use RodrigoPedra\FileTaggedCache\Contracts\CacheTaggable;
use RodrigoPedra\FileTaggedCache\Model\HasCacheTag;
use RodrigoPedra\FileTaggedCache\Model\TaggedCacheObserver;

class Post extends Model implements CacheTaggable
{
    use HasCacheTag;
    
    public function author() {
        return $this->belongsTo(Author::class);
    }
    
    public function comments() {
        return $this->hasMany(Comment::class);
    }
    
    public static function booted() {
        static::observe(TaggedCacheObserver::class);
    }
}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use RodrigoPedra\FileTaggedCache\Contracts\CacheTaggable;
use RodrigoPedra\FileTaggedCache\Model\HasCacheTag;
use RodrigoPedra\FileTaggedCache\Model\TaggedCacheObserver;

class Author extends Model implements CacheTaggable
{
    use HasCacheTag;
    
    public function posts() {
        return $this->hasMany(Post::class);
    }
    
    public static function booted() {
        static::observe(TaggedCacheObserver::class);
    }
}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
    protected $touches = [
        'post',
    ];
    
    public function post() {
        return $this->belongsTo(Post::class);
    }
}
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use RodrigoPedra\FileTaggedCache\Model\TaggedCacheObserver;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->when(TaggedCacheObserver::class)->needs('$store')->give('posts');
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}

CacheTaggable 契约需要实现一个方法:cacheTagKey(),它应返回一个字符串,表示当此模型用作缓存标签时应使用的键。

HasCacheTag 使用一个合理的默认值实现了此方法。您不必使用此特性,并且可以为 cacheTagKey() 方法提供您自己的实现。

TaggedCacheObserver 添加了监听器,当派发更改内容的事件时,将清除由这些模型键标记的缓存项。

《评论》模型不使用任何助手Observer、Contract和Trait。但是,它被配置为“触摸”其父Post模型,当创建或修改评论时,使父Post相关缓存项失效。

如果你不熟悉$touch的工作方式,可以查看相关的Laravel文档。

https://laravel.net.cn/docs/8.x/eloquent-relationships#touching-parent-timestamps

最后,但同样重要,在你的项目的AppServiceProvider中,你需要配置Laravel的服务容器,以向TaggedCacheObserver提供自定义存储标识符。

重要:当通过标准Eloquent方法操作相关模型的数据时,观察者才会触发缓存失效。如果你使用DB外观或直接在数据库中编辑数据,你需要使用Laravel为任何缓存存储提供的相同方法手动使缓存失效。

在控制器中的使用

以下是如何使用上述配置的模型来缓存视图的示例。

<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Str;

class PostsController extends Controller
{
    public function index(Request $request, Post $post)
    {
        $cacheKey = Str::slug($request->path());

        return Cache::store('posts')
            ->tags([$post, $post->author]) // tagging by post and author
            ->sear($cacheKey, function () use ($post) {
                // IMPORTANT: call ->render() to cache the rendered view string
                return view('posts.show', [
                    'post' => $post,
                    'author' => $post->author,
                    'comments' => $post->comments,
                ])->render();
            });
    }
}

在这个例子中,渲染的视图被缓存,在下一次访问时,将提供缓存的内容而不是重新渲染。

此外,由于$post->comments只在闭包内部运行,因此此查询仅在缓存项找不到时执行。

由于在这个例子中,我们为$post$post->author标签了缓存项,所以当这些模型中的任何一个发生变化时,此缓存视图将从缓存存储中删除。

由于我们配置了Comment模型来“触摸”其父Post模型,当添加、更新或删除评论时,此缓存视图也将从缓存存储中删除。

与Laravel Mix一起使用

如果你使用Laravel Mix编译你的前端资产,并使用资产版本化,在更改你的前端资产后,你可能会得到过时的视图。

为了减轻这种情况,你可以在webpack.mix.js脚本中添加一个“after”回调,在编译你的资产后清除缓存。

let {exec} = require('child_process');
let mix = require('laravel-mix');

// ... other mix config

// If you are using Laravel Mix 6, mix.then() is an alias to mix.after()
// "posts" is the custom cache stored we configured above
mix.then(() => exec('php artisan cache:clear posts'));

待办事项

  • 添加测试
  • 考虑向TaggedCacheObserver提供$store的更简单方法

许可证

此软件包是开源软件,受MIT许可证许可。