vatvit/freshen-symfony 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

vatvit/freshen-symfony

Composer 安装命令:

composer require vatvit/freshen-symfony

包简介

Symfony bundle for Freshen — drop-in stale-while-revalidate cache with stampede prevention.

README 文档

README

⚠️ Read-only mirror. This repository is the Packagist publish mirror of packages/symfony in the Freshen monorepo. Source, issues, and pull requests live there — please don't open them here. Install with composer require vatvit/freshen-symfony.

Freshen — Symfony bundle

Packagist Version PHP Version License

Security — tracked by the Packagist security advisory database; run composer audit to check your install. Report privately via GitHub Security Advisories; policy in SECURITY.md.

vatvit/freshen-symfony is the drop-in Symfony bundle for Freshen, the stale-while-revalidate cache with stampede prevention. It wires the manual pool/loader/listener setup from the core README into declarative config: composer require + a little YAML gives you one autowired, per-dataset Freshen\Cache per data structure, injected by name, with async invalidation already registered.

Install

composer require vatvit/freshen-symfony

Register the bundle (Symfony Flex does this automatically):

// config/bundles.php
return [
    // ...
    Freshen\Bridge\Symfony\FreshenBundle::class => ['all' => true],
];

Configure

Freshen\Cache is per-dataset — each cache binds one loader + TTL — so you declare named caches. Each references a loader service (yours, implementing Freshen\Interface\LoaderInterface) and a \Redis client service.

A Freshen cache is one dataset, so you define one entry per data structure (top sellers, prices, …) — a real app has several:

# config/packages/freshen.yaml
freshen:
    connection: Redis                 # shared \Redis client service id (optional if each cache sets its own)
    caches:
        top_sellers:
            loader: App\Cache\TopSellersLoader   # required — Freshen\Interface\LoaderInterface service
            hard_ttl: 3600                        # required, seconds (>= 1)
            precompute: 60                        # default 0 — soft window before hard TTL
            jitter: 15                            # default 15 (percent)
            fail_open: true                       # default true
            # connection: Redis                   # optional per-cache override
            # metrics: App\Cache\Metrics          # optional — Freshen\Interface\MetricsInterface service
        prices:                                   # a second dataset — its own loader + TTLs
            loader: App\Cache\PricesLoader
            hard_ttl: 600
            precompute: 30

The connection value is a service id for a connected \Redis client. Bring your own, e.g.:

# config/services.yaml
services:
    Redis:
        class: Redis
        calls:
            - connect: ['%env(REDIS_HOST)%', '%env(int:REDIS_PORT)%']

Use

Inject each cache by name with named-argument autowiring — the argument name is the camel-cased cache name plus Cache. This is how you reference a dataset whether you have one cache or many (there is no bare Freshen\Cache "default" — with several datasets it would be ambiguous, and it would silently break the day you add the second one):

public function __construct(
    private \Freshen\Cache $topSellersCache,   // freshen.caches.top_sellers
    private \Freshen\Cache $pricesCache,       // freshen.caches.prices
) {}

$key    = new \Freshen\Key('product', 'detail', $id);
$result = $this->topSellersCache->get($key);
$result->value();                          // fresh or stale-while-revalidate value
$this->topSellersCache->invalidate($key);  // async by default — see below

Async invalidation

The bundle registers each cache's Freshen\AsyncHandler on Symfony's PSR-14 event_dispatcher, so invalidate() / invalidateExact() / refresh() (async by default) dispatch Freshen\{Invalidate,InvalidateExact,Refresh}Event and are handled without you wiring listeners.

Caveat — shared dispatcher fan-out. These events carry a key only, not a cache id, so an async invalidate($key) is delivered to every configured cache's handler. Where a cache doesn't hold that key it's a harmless no-op, but caches that use colliding key namespaces would cross-invalidate. Give each cache a distinct Key domain/facet (they naturally differ per dataset) and this is a non-issue.

Versioning

Independent SemVer, released as symfony-vX.Y.Z. Depends on vatvit/freshen-php via ^1.0@rc (→ ^1.0 once core is stable). A core patch/minor needs no bridge release; a core major does. See the monorepo RELEASING.md.

Links

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 1
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-07-11

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固