Back to Main Site

缓存管理:面向开发人员的钩子驱动缓存系统

Last updated on Jun 24, 2026 01:50

PolyCMS 附带一个集中式缓存管理系统,为管理员提供用于检查和清除缓存的 UI,并为开发人员提供强大的钩子驱动 API,以集成他们自己的缓存逻辑,而不会与核心或其他模块发生冲突。

本指南涵盖了架构、可用的挂钩以及想要扩展、替换缓存操作或对缓存操作做出反应的模块和主题开发人员的实际示例。

架构概述

CacheService (app/Services/CacheService.php) 是所有缓存操作的单一入口点。它维护一个缓存类型的注册表,分为四类:

集团 描述 内置类型
laravel Laravel 框架缓存 应用程序、视图、配置、路由、事件
polycms PolyCMS 内部服务缓存 主题、模块、设置、模板解析器
server 服务器级缓存 PHP OPcache
module 模块注册缓存 (您的模块在此处添加)

系统公开了模块可用于参与缓存管理的 7 个挂钩和过滤器

挂钩和过滤器参考

过滤器(值转换器)

这些钩子允许模块在使用数据之前修改数据。

cache.types — 注册自定义缓存类型

将您自己的缓存类型添加到系统中。您的类型将与核心类型一起显示在管理缓存管理页面中。

签名: 数组$类型

use App\Facades\Hook;

Hook::addFilter('cache.types', function (array $types) {
    $types[] = [
        'key'         => 'cdn_purge',
        'label'       => 'CDN Cache',
        'description' => 'Purge Cloudflare or Fastly edge cache',
        'group'       => 'module',   // Use 'module' for custom types
        'clearable'   => true,
    ];
    return $types;
});

每种类型必填字段:

领域 类型 描述
key string 独特的 slug(在 API 调用中使用)
label string 人类可读的名称
description string 管理 UI 中显示的简短说明
group string laravelpolycmsservermodule
clearable bool 是否应出现“清除”按钮

cache.type.handler — 声明缓存类型的所有权

这就是冲突预防机制。当模块声明缓存类型时,核心将跳过该类型自己的清除逻辑,并将完全委托给模块的“cache.clear.{type}”操作挂钩。

签名: ?string $handler, string $type

用例: 您正在构建一个专用的 Redis 管理模块,并且希望以不同于默认的“php artisan cache:clear”的方式处理“application”缓存。

Hook::addFilter('cache.type.handler', function (?string $handler, string $type) {
    if ($type === 'application') {
        return 'RedisManager'; // Your module name — core skips its clear logic
    }
    return $handler; // Return null for types you don't handle
}, 10, 2);

设置处理程序后,管理 UI 会显示一个徽章,显示哪个模块管理该缓存类型。

cache.status — 丰富状态数据

将自定义指标或诊断添加到缓存状态响应。

签名: 数组$status

Hook::addFilter('cache.status', function (array $status) {
    // Add Redis memory info to the status payload
    $status['redis_info'] = [
        'used_memory_mb' => Redis::info()['used_memory_human'] ?? 'N/A',
        'connected_clients' => Redis::info()['connected_clients'] ?? 0,
    ];
    return $status;
});

操作(事件回调)

这些钩子在特定的生命周期点触发。它们不返回值。

cache.clearing — 清除类型之前

在清除任何缓存类型之前立即触发。用于记录或预清除快照。

签名: 字符串$类型

Hook::addAction('cache.clearing', function (string $type) {
    Log::info("Cache clear starting: {$type}");
});

cache.clear.{type} — 处理特定类型的清除

这是实现您自己的清算逻辑的主要钩子。如果您的模块通过“cache.type.handler”声明了一个类型,那么这就是实际工作发生的地方。

签名: 无效

// Handle clearing for your custom CDN cache type
Hook::addAction('cache.clear.cdn_purge', function () {
    CloudflareApi::purgeEverything(config('services.cloudflare.zone_id'));
});

// Or override the core's application cache clearing
Hook::addAction('cache.clear.application', function () {
    Redis::connection('cache')->flushdb();
});

cache.cleared — 清除类型后

在清除(或尝试)缓存类型后触发,并带有成功标志。

签名: string $type, bool $success

Hook::addAction('cache.cleared', function (string $type, bool $success) {
    if ($success) {
        Log::info("Cache cleared successfully: {$type}");
    } else {
        Log::warning("Cache clear failed: {$type}");
    }
}, 10, 2);

cache.clear_all.before / cache.clear_all.after

在批量清除操作之前和之后触发(当管理员单击“清除所有缓存”时)。

Hook::addAction('cache.clear_all.before', function (array $types) {
    // $types = ['application', 'view', 'config', 'route', 'event', ...]
    Log::info('Bulk cache clear starting for: ' . implode(', ', $types));
});

Hook::addAction('cache.clear_all.after', function (array $results) {
    // $results = ['application' => 'success', 'view' => 'success', ...]
    $failed = array_filter($results, fn($r) => $r !== 'success');
    if (empty($failed)) {
        Log::info('All caches cleared successfully');
    }
});

REST API 端点

缓存管理系统公开两个经过身份验证的 API 端点:

GET /api/v1/system/cache/status

返回所有已注册缓存类型的当前状态。

回复:

{
  "data": {
    "driver": "file",
    "store": "file",
    "types": [
      {
        "key": "application",
        "label": "Application Cache",
        "description": "General key-value cache store",
        "group": "laravel",
        "clearable": true,
        "handler": null,
        "info": { "driver": "file" }
      },
      {
        "key": "view",
        "label": "View Cache",
        "group": "laravel",
        "clearable": true,
        "handler": null,
        "info": { "compiled_count": 75 }
      }
    ]
  }
}

POST /api/v1/system/cache/clear

清除一种或多种缓存类型。

请求正文:

{
  "types": ["view", "config", "theme"]
}

或者清除所有内容:

{
  "types": ["all"]
}

回复:

{
  "success": true,
  "results": {
    "view": "success",
    "config": "success",
    "theme": "success"
  },
  "message": "All selected caches cleared successfully."
}

实际例子

示例 1:CDN 清除模块

注册 CDN 缓存类型并处理其清除的完整模块:

// In your module's ServiceProvider boot() method

use App\Facades\Hook;

public function boot(): void
{
    // Register the cache type
    Hook::addFilter('cache.types', function (array $types) {
        $types[] = [
            'key'         => 'cdn',
            'label'       => 'CDN Edge Cache',
            'description' => 'Purge Cloudflare edge cache for all zones',
            'group'       => 'module',
            'clearable'   => true,
        ];
        return $types;
    });

    // Handle clearing
    Hook::addAction('cache.clear.cdn', function () {
        $zoneId = config('services.cloudflare.zone_id');
        $apiToken = config('services.cloudflare.api_token');

        Http::withToken($apiToken)
            ->post("https://api.cloudflare.com/client/v4/zones/{$zoneId}/purge_cache", [
                'purge_everything' => true,
            ]);
    });
}

示例2:全页缓存模块(接管核心)

使用基于 Varnish 的解决方案替换默认应用程序缓存处理程序的模块:

public function boot(): void
{
    // Claim the 'application' cache type
    Hook::addFilter('cache.type.handler', function (?string $handler, string $type) {
        if ($type === 'application') {
            return 'VarnishCache';
        }
        return $handler;
    }, 10, 2);

    // Provide custom clearing logic
    Hook::addAction('cache.clear.application', function () {
        // Ban all objects from Varnish
        Http::withHeaders(['X-Purge' => '.*'])
            ->request('BAN', config('services.varnish.host'));

        // Also clear Laravel's cache store
        Artisan::call('cache:clear');
    });
}

示例 3:主题功能 — 设置保存时自动清除

保存主题选项时清除其自身编译资源的主题:

// In themes/my-theme/functions.php

Hook::addAction('cache.cleared', function (string $type, bool $success) {
    if ($type === 'theme' && $success) {
        // Regenerate compiled theme CSS
        $css = MyTheme::compileStyles();
        file_put_contents(public_path('themes/my-theme/compiled.css'), $css);
    }
}, 10, 2);

主题上传时自动清除

通过管理面板上传或更新主题时,PolyCMS 会自动清除以下缓存:

查看缓存 — 删除过时的已编译 Blade 模板

配置缓存 — 确保加载新的 functions.php 设置定义

OPcache — 刷新 PHP 字节码缓存,以便新编译新的 PHP 文件

主题缓存 — 清除 ThemeManager 的内部注册表

设置缓存 - 重新加载自动加载的设置(包括新的主题选项)

模板缓存 - 刷新TemplateResolver的视图路径分辨率

这消除了主题更新后不出现新主题选项或视图的常见问题。

管理界面

缓存管理页面可通过设置中心 → 系统 → 缓存(或直接在“/admin/settings/cache”)访问。它提供:

顶部缓存驱动程序信息(文件、数据库、redis 等)

按 Laravel、PolyCMS、服务器和模块组织的分组缓存类型卡

状态徽章显示编译视图计数、缓存/未缓存状态、OPcache 命中率

每个缓存类型都有单独的清除按钮以及加载状态

**“清除所有缓存”**主按钮

处理程序徽章显示哪个模块管理特定类型

完整的黑暗模式支持

最佳实践

**使用“cache.type.handler”来防止冲突。**如果您的模块接管缓存类型,请始终注册一个处理程序,以便核心和其他模块知道不会干扰。

**保持“cache.clear.{type}”处理程序快速运行。**管理员希望缓存清除能够近乎即时。对于缓慢的操作(例如 CDN 清除),请考虑对作业进行排队并立即返回。

**始终在过滤器链中返回“$handler”。**如果您正在检查特定类型的“cache.type.handler”,请始终返回您不管理的类型的原始“$handler”。

**分组为“模块”。**注册自定义缓存类型时,请使用“组”=>“模块”,以便它们显示在管理 UI 的“模块扩展”部分中。

记录缓存事件。 使用“cache.clearing”和“cache.cleared”进行审计跟踪,尤其是在生产环境中。

相关资源

Hooks & Filters:扩展核心 — 了解 PolyCMS Hook 系统的基础知识。

核心钩子和过滤器参考 — 核心中所有可用的约 90 个钩子的完整参考。

模块开发:入门 — 如何从头开始创建 PolyCMS 模块。