emag-tech-labs / annotation-cache-bundle
用于Symfony容器内服务基于注解的缓存
Requires
- php: ^8.0
- doctrine/annotations: ^1.11
- friendsofphp/proxy-manager-lts: ^1.0
- psr/cache: ^1.0|^2.0|^3.0
- psr/log: ^1.1|^2.0|^3.0
- symfony/dependency-injection: ^4.0||^5.1||^6.0
- symfony/yaml: ^4.0||^5.1||^6.0
Requires (Dev)
- infection/infection: ^0.21.0
- php-coveralls/php-coveralls: ^2.4
- phpmd/phpmd: ^2.9
- phpmetrics/phpmetrics: ^2.7
- phpstan/extension-installer: ^1.1
- phpstan/phpstan: ^1.0
- phpstan/phpstan-phpunit: ^1.1
- phpunit/phpunit: ^8.5||^9.0
- squizlabs/php_codesniffer: ^3.5
- symfony/cache: ^4.0||^5.1|^6.0
- symfony/framework-bundle: ^4.0||^5.1|^6.0
- symfony/monolog-bundle: ^3.6
- vimeo/psalm: ^4.4
Suggests
- symfony/cache: ^4.0||^5.1||^6.0
README
用于Symfony容器内方法响应的基于注解的缓存。
此包可以帮助您通过简单的注解或属性添加缓存。您可以将缓存存储在任何实现了PSR-6:Caching Interface的类中,无论是简单的数组还是redis/memcache存储。
工作原理
此包将扫描定义的服务中的所有方法,并查找Cache注解或属性(PHP 8+)。
对于找到Cache注解/属性的任何服务,它将创建一个代理类(使用ocramius/proxy-manager),该类扩展服务类,包含CacheableClassTrait并重写具有Cache注解/属性的方法。
重写的方法包括调用getCached
方法,该方法识别注解详细信息,获取键,获取Cache PSR-6实现,然后从缓存中获取结果。如果没有找到具有生成缓存键的数据,它将调用原始方法,然后将其响应保存到提供的提供者中。
该包有一个CompilerPass实现,将搜索并重写服务定义,以使用上述过程中创建的代理类。
安装
使用Symfony Flex
使用Symfony Flex安装和配置AnnotationCacheBundle的简单方法是使用Symfony Flex
composer require symfony/flex ^1.0
composer config extra.symfony.allow-contrib true
composer require emag-tech-labs/annotation-cache-bundle
Symfony Flex将自动注册和配置此包。
不使用Symfony Flex
如果您的应用程序不使用Symfony Flex,您可以通过以下步骤手动配置此包:
步骤1:下载包
打开命令行,进入项目目录,并执行以下命令以下载此包的最新稳定版本
composer require emag-tech-labs/annotation-cache-bundle
步骤2:启用包
然后,通过将其添加到项目的config/bundles.php
文件中注册的包列表来启用包
// config/bundles.php return [ // ... EmagTechLabs\AnnotationCacheBundle\AnnotationCacheBundle::class => ['all' => true], ];
步骤3:配置
最简单的方法是导出配置并将其复制到configs/packages/emag_annotation_cache.yaml
。
bin/console config:dump-reference AnnotationCacheBundle
配置示例
您必须配置PSR6兼容的服务名称,这意味着它必须实现Psr\Cache\CacheItemPoolInterface
。
# app/config/services.yaml services: cache.array: class: Symfony\Component\Cache\Adapter\ArrayAdapter cache.redis: class: Symfony\Component\Cache\Adapter\RedisAdapter arguments: ['@predis']
#configs/packages/emag_annotation_cache.yaml # Annotation Cache Bundle annotation_cache: provider: default: cache.redis array: cache.array ignore_namespaces: - 'Symfony\\' - 'Doctrine\\' ignore_names: - legacy - type - required
用法
为要缓存的类方法添加Cache注解。
注解参数
cache
- 缓存前缀,字符串,默认值:null(例如:'my_custom_prefix_')key
- 要包括在缓存键哈希生成中的参数名称,字符串,参数名称由逗号分隔,默认值:''(例如:'a,b')ttl
- 缓存存储时间(秒),整型,默认值:600(例如:'3600')reset
- 是否重置缓存,布尔型,默认值:false(例如:'true')storage
- 如果定义了多个提供者,您可以使用它指定要使用的提供者,字符串,默认值:'default'(例如:'array')
使用Doctrine Annotations库定义的注解
use EmagTechLabs\AnnotationCacheBundle\Annotation\Cache; /** * @Cache(cache="<put your prefix>", [key="<name of argument to include in cache key separated by comma>", [ttl=600, [reset=true, [storage=default ]]]]) */
示例
namespace AppCacheBundle\Service; use EmagTechLabs\AnnotationCacheBundle\Annotation\Cache; class AppService { /** * @Cache(cache="app_high_cpu", ttl=60) * * @return int */ public function getHighCPUOperation(): int { sleep(10); // 'Simulate a time consuming operation'; return 20; } }
使用PHP 8属性定义的注解
use EmagTechLabs\AnnotationCacheBundle\Annotation\Cache; #[Cache(cache:'<put your prefix>', key:'<name of argument to include in cache key separated by comma>', ttl:600, reset: true, storage: 'default')]
示例
namespace AppCacheBundle\Service; use EmagTechLabs\AnnotationCacheBundle\Annotation\Cache; class AppService { #[Cache(cache:'app_high_cpu', ttl: 60)] public function getHighCPUOperation(): int { sleep(10); // 'Simulate a time consuming operation'; return 20; } }
用例
以下提供两种使用此包的方法
配置
# app/config/services.yaml services: cache.array: class: Symfony\Component\Cache\Adapter\ArrayAdapter cache.redis: class: Symfony\Component\Cache\Adapter\RedisAdapter arguments: ['@predis']
#configs/packages/emag_annotation_cache.yaml # Annotation Cache Bundle annotation_cache: provider: default: cache.array redis: cache.redis ignore_namespaces: - 'Symfony\\'
服务代码
此包可以以多种方式使用,以下展示两种。
第一种情况是最常见的一种,你有一个执行多个耗时操作的方法,并且你想要在Redis中缓存响应,使用前缀(simple_time_consuming_operation_)和给定的时间(下面示例中的60秒)。这里的逻辑是先在Redis中查找值,如果没有找到,就运行实际的方法,获取结果并缓存起来,以便后续使用,同时考虑到@Cache
注解中传入的参数。
第二种情况可以用于生成缓存命令并预热缓存,或者当某个事件触发时更新缓存,或者更新数据库中的信息。根据下面的示例,你可以设置一个cron任务,每3000秒运行一次,以便在缓存过期之前重新创建缓存。因为我们使用相同的缓存前缀和键,当两个方法(getTimeConsumingOperationValueWithReset
和getTimeConsumingOperationValue
)传入相同的参数值时,生成的缓存键将是相同的,在这个例子中是:time_consuming_operation_7fe49b314fb356bee76dbd3b8716b4d5ab5db600。这意味着两个方法都将(从)同一个缓存键写入(读取)缓存。因为第二个方法将reset
参数设置为true,所以对第二个方法的任何调用都将使用函数的新结果覆盖键time_consuming_operation_7fe49b314fb356bee76dbd3b8716b4d5ab5db600中的缓存值。
namespace AppCacheBundle\Service; use EmagTechLabs\AnnotationCacheBundle\Annotation\Cache; class AppService { /** * @Cache(cache="simple_time_consuming_operation_", ttl=60, storage="redis") * * @param int $a * @param int $b * * @return int */ public function getSimpleTimeConsumingOperationValue(int $a, int $b): int { sleep(10); // 'Simulate a time consuming operation'; return $a + $b; } #[Cache(cache:'time_consuming_operation_', key: 'a,b', ttl: 3600, storage: 'redis')] public function getTimeConsumingOperationValue(int $a, int $b): int { return $this->getTimeConsumingOperationValueWithReset($a, $b); } #[Cache(cache:'time_consuming_operation_', key: 'a,b', ttl: 3600, reset: true, storage: 'redis')] public function getTimeConsumingOperationValueWithReset(int $a, int $b): int { sleep(10); // 'Simulate a time consuming operation'; return $a + $b; } }
服务调用
// from controller /** AppService $appService */ $appService->getTimeConsumingOperationValue(1, 2); // from command /** AppService $appService */ $appService->getTimeConsumingOperationValueWithReset(1, 2);
贡献
感谢您对贡献的兴趣!有许多方式可以为这个项目做出贡献。从这里开始这里。