Skip to content

Commit bc0387c

Browse files
authored
allowed selecting caching service in annotation (#30)
* allowed selecting caching service in annotation * fix 2.8 compatibility * added requirements for ServiceLocator dropping support for 2.8, add php 7.2
1 parent d327049 commit bc0387c

File tree

11 files changed

+212
-24
lines changed

11 files changed

+212
-24
lines changed

.travis.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,14 @@ cache:
77
php:
88
- 7.0
99
- 7.1
10+
- 7.2
1011

1112
env:
12-
- SYMFONY_VERSION=2.8.*
1313
- SYMFONY_VERSION=3.0.*
1414
- SYMFONY_VERSION=3.1.*
1515
- SYMFONY_VERSION=3.2.*
1616
- SYMFONY_VERSION=3.3.*
1717

18-
1918
before_install:
2019
- if [ "$SYMFONY_VERSION" != "" ]; then composer require --no-update symfony/framework-bundle "$SYMFONY_VERSION"; fi
2120

composer.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
"ocramius/proxy-manager": "2.*",
1515
"psr/log": "1.*",
1616
"psr/cache": "1.0.*",
17-
"doctrine/annotations": "~1.3"
17+
"doctrine/annotations": "~1.3",
18+
"psr/container": "^1.0",
19+
"symfony/dependency-injection": ">3.3"
1820
},
1921
"suggest": {
2022
"symfony/cache": "3.*"
@@ -28,7 +30,8 @@
2830
"symfony/cache": "3.*",
2931
"satooshi/php-coveralls": "~1.0",
3032
"symfony/monolog-bundle": "@stable",
31-
"symfony/framework-bundle": "@stable"
33+
"symfony/framework-bundle": "@stable",
34+
"symfony/http-kernel": "3.*"
3235
},
3336
"autoload": {
3437
"psr-4": { "Emag\\CacheBundle\\": "src/" },

src/Annotation/Cache.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99
class Cache
1010
{
11+
const STORAGE_LABEL_DEFAULT = 'default';
1112
/**
1213
* @var string
1314
*/
@@ -28,6 +29,11 @@ class Cache
2829
*/
2930
protected $reset = false;
3031

32+
/**
33+
* @var string
34+
*/
35+
protected $storage = self::STORAGE_LABEL_DEFAULT;
36+
3137
/**
3238
* Cache constructor.
3339
*
@@ -47,6 +53,10 @@ public function __construct(array $options)
4753
if (array_key_exists('reset', $options)) {
4854
$this->reset = (bool)$options['reset'];
4955
}
56+
57+
if (array_key_exists('storage', $options)) {
58+
$this->storage = (string)$options['storage'];
59+
}
5060
}
5161

5262
/**
@@ -80,4 +90,12 @@ public function isReset() : bool
8090
{
8191
return $this->reset;
8292
}
93+
94+
/**
95+
* @return string
96+
*/
97+
public function getStorage(): string
98+
{
99+
return $this->storage;
100+
}
83101
}

src/DependencyInjection/Compiler/CacheCompilerPass.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,16 @@ public function process(ContainerBuilder $container)
2929
* @param ContainerBuilder $container
3030
*
3131
* @return void
32+
* @throws \ReflectionException
3233
*/
3334
protected function analyzeServicesTobeCached(ContainerBuilder $container)
3435
{
3536
$annotationReader = new AnnotationReader();
3637
$annotationReaderReference = new Reference("annotation_reader");
3738
$proxyWarmup = $container->getDefinition('emag.cache.warmup');
3839
$cacheProxyFactory = new Reference('emag.cache.proxy.factory');
39-
$cacheServiceReference = new Reference('emag.cache.service');
40+
$cacheServiceReference = new Reference('emag.cache.service.locator');
41+
4042

4143
foreach ($container->getDefinitions() as $serviceId => $definition) {
4244
if (!class_exists($definition->getClass()) || $this->isFromIgnoredNamespace($container, $definition->getClass())) {
@@ -67,7 +69,7 @@ protected function analyzeServicesTobeCached(ContainerBuilder $container)
6769
->setMethodCalls($definition->getMethodCalls())
6870
->setProperties($definition->getProperties())
6971
->addMethodCall('setReaderForCacheMethod', [$annotationReaderReference])
70-
->addMethodCall('setCacheServiceForMethod', [$cacheServiceReference])
72+
->addMethodCall('setServiceLocatorCache', [$cacheServiceReference])
7173
;
7274

7375
$proxyWarmup->addMethodCall('addClassToGenerate', [$definition->getClass()]);

src/DependencyInjection/Configuration.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Emag\CacheBundle\DependencyInjection;
44

5+
use Emag\CacheBundle\Annotation\Cache;
56
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
67
use Symfony\Component\Config\Definition\ConfigurationInterface;
78

@@ -37,7 +38,13 @@ public function getConfigTreeBuilder()
3738

3839
$rootNode
3940
->children()
40-
->scalarNode('provider')->cannotBeEmpty()->isRequired()->end()
41+
->arrayNode('provider')
42+
->useAttributeAsKey('name')
43+
->beforeNormalization()->ifString()->then(function($v) {
44+
return [Cache::STORAGE_LABEL_DEFAULT => $v];
45+
})->end()
46+
->prototype('scalar')->end()
47+
->end()
4148
->arrayNode('ignore_namespaces')
4249
->prototype('scalar')->end()
4350
->end()

src/DependencyInjection/EmagCacheExtension.php

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Symfony\Component\DependencyInjection\ContainerBuilder;
99
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
1010
use Symfony\Component\DependencyInjection\Loader;
11+
use Symfony\Component\DependencyInjection\Reference;
1112
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
1213

1314
/**
@@ -23,13 +24,16 @@ class EmagCacheExtension extends Extension implements PrependExtensionInterface
2324
public function prepend(ContainerBuilder $container)
2425
{
2526
$configuration = new Configuration($this->getAlias());
26-
$config = $this->processConfiguration($configuration, $container->getExtensionConfig($this->getAlias()));
27-
if (!$container->hasDefinition($config['provider'])) {
28-
throw new CacheException(sprintf('You\'ve referenced a un-existing service of name "%s", please provide another!', $config['provider']));
29-
}
30-
$provider = new \ReflectionClass($container->getDefinition($config['provider'])->getClass());
31-
if (!$provider->implementsInterface(CacheItemPoolInterface::class)) {
32-
throw new CacheException(sprintf('You\'ve referenced a service "%s" that can not be used for caching!', $config['provider']));
27+
$config = $this->processConfiguration($configuration, $container->getExtensionConfig($this->getAlias()));
28+
foreach ($config['provider'] as $alias => $serviceId) {
29+
if (!$container->hasDefinition($serviceId)) {
30+
throw new CacheException(sprintf('You\'ve referenced a un-existing service of name "%s", please provide another!', $serviceId));
31+
}
32+
$provider = new \ReflectionClass($container->getDefinition($serviceId)->getClass());
33+
if (!$provider->implementsInterface(CacheItemPoolInterface::class)) {
34+
throw new CacheException(sprintf('You\'ve referenced a service "%s" that can not be used for caching!', $serviceId));
35+
}
36+
3337
}
3438
}
3539

@@ -39,13 +43,21 @@ public function prepend(ContainerBuilder $container)
3943
public function load(array $configs, ContainerBuilder $container)
4044
{
4145
$configuration = new Configuration($this->getAlias());
42-
$config = $this->processConfiguration($configuration, $configs);
46+
$config = $this->processConfiguration($configuration, $configs);
4347

44-
$container->setAlias('emag.cache.service', $config['provider']);
4548
$container->setParameter('emag.cache.ignore.namespaces', $config['ignore_namespaces']);
4649

47-
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
50+
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
4851
$loader->load('services.yml');
52+
53+
$locatorDefinition = $container->getDefinition('emag.cache.service.locator');
54+
$locatorArguments = [];
55+
foreach ($config['provider'] as $alias => $serviceId) {
56+
$locatorArguments[$alias] = new Reference($serviceId);
57+
}
58+
$locatorDefinition->setArguments([
59+
$locatorArguments,
60+
]);
4961
}
5062

5163
/**

src/ProxyManager/CacheableClassTrait.php

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,17 @@
77
use Doctrine\Common\Annotations\AnnotationReader;
88
use Doctrine\Common\Annotations\Reader;
99
use Psr\Cache\CacheItemPoolInterface;
10+
use Psr\Container\ContainerExceptionInterface;
11+
use Psr\Container\ContainerInterface;
12+
use Psr\Container\NotFoundExceptionInterface;
1013

1114
trait CacheableClassTrait
1215
{
1316
/**
1417
* Long name to avoid collision
15-
* @var CacheItemPoolInterface
18+
* @var ContainerInterface
1619
*/
17-
protected $cacheServiceForMethod;
20+
protected $serviceLocatorCache;
1821

1922
/**
2023
* Long name to avoid colision
@@ -24,11 +27,11 @@ trait CacheableClassTrait
2427
protected $readerForCacheMethod;
2528

2629
/**
27-
* @param CacheItemPoolInterface $cacheServiceForMethod
30+
* @param ContainerInterface $serviceLocatorCache
2831
*/
29-
public function setCacheServiceForMethod(CacheItemPoolInterface $cacheServiceForMethod)
32+
public function setServiceLocatorCache(ContainerInterface $serviceLocatorCache)
3033
{
31-
$this->cacheServiceForMethod = $cacheServiceForMethod;
34+
$this->serviceLocatorCache = $serviceLocatorCache;
3235
}
3336

3437
/**
@@ -39,6 +42,13 @@ public function setReaderForCacheMethod(Reader $readerForCacheMethod)
3942
$this->readerForCacheMethod = $readerForCacheMethod;
4043
}
4144

45+
/**
46+
* @param \ReflectionMethod $method
47+
* @param $params
48+
* @return mixed
49+
* @throws CacheException
50+
* @throws \Psr\Cache\InvalidArgumentException
51+
*/
4252
public function getCached(\ReflectionMethod $method, $params)
4353
{
4454
$method->setAccessible(true);
@@ -47,7 +57,15 @@ public function getCached(\ReflectionMethod $method, $params)
4757

4858
$cacheKey = $this->getCacheKey($method, $params, $annotation);
4959

50-
$cacheItem = $this->cacheServiceForMethod->getItem($cacheKey);
60+
try {
61+
$cacheItemPool = $this->getCacheService($annotation->getStorage());
62+
} catch (NotFoundExceptionInterface $e) {
63+
throw new CacheException('Requested cache service not found', $e->getCode(), $e);
64+
} catch (ContainerExceptionInterface $e) {
65+
throw new CacheException($e->getMessage(), $e->getCode(), $e);
66+
}
67+
68+
$cacheItem = $cacheItemPool->getItem($cacheKey);
5169

5270
if ($cacheItem->isHit() && !$annotation->isReset()) {
5371
return $cacheItem->get();
@@ -57,7 +75,7 @@ public function getCached(\ReflectionMethod $method, $params)
5775

5876
$cacheItem->set($result);
5977
$cacheItem->expiresAfter($annotation->getTtl());
60-
$this->cacheServiceForMethod->save($cacheItem);
78+
$cacheItemPool->save($cacheItem);
6179

6280
return $result;
6381
}
@@ -120,4 +138,15 @@ protected function getCacheKey(\ReflectionMethod $method, $params, Cache $cacheO
120138

121139
return $cacheKey;
122140
}
141+
142+
/**
143+
* @param string $label
144+
* @return CacheItemPoolInterface
145+
* @throws \Psr\Container\ContainerExceptionInterface
146+
* @throws \Psr\Container\NotFoundExceptionInterface
147+
*/
148+
protected function getCacheService(string $label): CacheItemPoolInterface
149+
{
150+
return $this->serviceLocatorCache->get($label);
151+
}
123152
}

src/Resources/config/services.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ parameters:
77
emag.cache.proxy.configuration.class: ProxyManager\Configuration
88
emag.cache.proxy.persister.class: ProxyManager\GeneratorStrategy\FileWriterGeneratorStrategy
99
emag.cache.proxy.locator.class: ProxyManager\FileLocator\FileLocator
10+
emag.cache.proxy.cache-locator.class: Symfony\Component\DependencyInjection\ServiceLocator
1011

1112
services:
1213

@@ -51,3 +52,11 @@ services:
5152
class: '%emag.cache.proxy.locator.class%'
5253
arguments: ["%emag.cacheable.service.path%"]
5354
public: false
55+
56+
emag.cache.service.locator:
57+
class: '%emag.cache.proxy.cache-locator.class%'
58+
arguments:
59+
- []
60+
tags:
61+
- { name: 'container.service_locator'}
62+
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
namespace Emag\CacheBundle\Tests\Helpers;
4+
5+
use Emag\CacheBundle\Annotation\Cache;
6+
7+
class MultiEngineCachableClass
8+
{
9+
/**
10+
* @Cache(cache="xxx", ttl=30)
11+
*
12+
* @return int
13+
*/
14+
public function getCachedTime() : int
15+
{
16+
return rand();
17+
}
18+
19+
/**
20+
* @Cache(cache="xxx", ttl=30, storage="default")
21+
*
22+
* @return int
23+
*/
24+
public function getCachedTimeDefault() : int
25+
{
26+
return rand();
27+
}
28+
29+
/**
30+
* @Cache(cache="xxx", ttl=30, storage="alternative")
31+
*
32+
* @return int
33+
*/
34+
public function getCachedTimeAlternative() : int
35+
{
36+
return rand();
37+
}
38+
}

tests/MultiCacheEngineTest.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
namespace Emag\CacheBundle\Tests;
4+
5+
6+
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
7+
use Symfony\Component\Config\Loader\LoaderInterface;
8+
use Symfony\Component\HttpKernel\Kernel;
9+
10+
class MultiCacheEngineTest extends KernelTestCase
11+
{
12+
protected static function getKernelClass()
13+
{
14+
return get_class(new class('test_missing_service', []) extends Kernel
15+
{
16+
public function registerBundles()
17+
{
18+
return [
19+
new \Emag\CacheBundle\EmagCacheBundle(),
20+
];
21+
}
22+
23+
public function registerContainerConfiguration(LoaderInterface $loader)
24+
{
25+
$loader->load(__DIR__ . '/config_multi_service.yml');
26+
}
27+
28+
public function __construct($environment, $debug)
29+
{
30+
require __DIR__ . '/../vendor/autoload.php';
31+
32+
parent::__construct($environment, $debug);
33+
34+
$this->rootDir = __DIR__ . '/app/';
35+
}
36+
});
37+
}
38+
39+
public function testWith2Adapters()
40+
{
41+
static::$class = null;
42+
self::bootKernel(['environment' => 'multi_service']);
43+
44+
$service = self::$kernel->getContainer()->get('service');
45+
46+
47+
$normal = $service->getCachedTime();
48+
$explicit = $service->getCachedTimeDefault();
49+
$alternative = $service->getCachedTimeAlternative();
50+
51+
$this->assertEquals($normal, $explicit);
52+
53+
$this->assertNotEquals($alternative, $explicit);
54+
55+
}
56+
}

0 commit comments

Comments
 (0)