Skip to content

Cache expression #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"ocramius/proxy-manager": "2.*",
"psr/log": "1.*",
"psr/cache": "1.0.*",
"doctrine/annotations": "1.3.*"
"doctrine/annotations": "1.3.*",
"symfony/expression-language": "3.*"
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expression-language can be put as suggested?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you put it as suggested you can't use @CacheExpression annotation I think.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can put it in both require-dev (so you can test it) and in suggests.
Who requires usage of expression should include the package explictly

"suggest": {
"symfony/cache": "3.*"
Expand Down
74 changes: 74 additions & 0 deletions src/CacheBundle/Annotation/CacheExpression.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php

declare(strict_types=1);

namespace CacheBundle\Annotation;

use CacheBundle\Exception\CacheException;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;

/**
* @Annotation
* @Target({"METHOD"})
*/
class CacheExpression extends Cache
{
/**
* @var ExpressionLanguage
*/
protected $expressionLanguage;

/**
* @var object
*/
private $context;

/**
* @var bool
*/
private $hasEvaluation = false;

/**
* @inheritDoc
*/
public function getCache() : string
{
if (!$this->hasEvaluation) {
$this->cache = $this->getExpressionLanguage()->evaluate($this->cache, ['this' => $this->context]);
$this->hasEvaluation = true;
}

return $this->cache;
}

/**
* @param object $context
*
* @return CacheExpression
*/
public function setContext($context) : self
{
$this->context = $context;

return $this;
}

/**
* @return ExpressionLanguage
*
* @throws CacheException
*/
private function getExpressionLanguage() : ExpressionLanguage
{
if (null === $this->expressionLanguage) {
if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
throw new CacheException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
}

$this->expressionLanguage = new ExpressionLanguage(new FilesystemAdapter('expr_cache'));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we convert this into service based? This way it will be easier if someone wants to use anything else here...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your talkin' about the new FilesystemAdapter?

Copy link
Contributor

@alexbumbacea alexbumbacea Dec 27, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, but also maybe classes that extend the base ExpressionLanguage...


return $this->expressionLanguage;
}
}
4 changes: 4 additions & 0 deletions src/CacheBundle/ProxyManager/CacheableClassTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@


use CacheBundle\Annotation\Cache;
use CacheBundle\Annotation\CacheExpression;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\Reader;
use Psr\Cache\CacheItemPoolInterface;
Expand Down Expand Up @@ -46,6 +47,9 @@ public function getCached(\ReflectionMethod $method, $params)
/** @var Cache $annotation */
$annotation = $this->readerForCacheMethod->getMethodAnnotation($method, Cache::class);

if ($annotation instanceof CacheExpression) {
$annotation->setContext($this);
}
$cacheKey = $this->getCacheKey($method, $params, $annotation);

$cacheItem = $this->cacheServiceForMethod->getItem($cacheKey);
Expand Down
17 changes: 17 additions & 0 deletions tests/CacheWrapperTest.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<?php
namespace CacheBundle\Tests;

use CacheBundle\Annotation\CacheExpression;
use CacheBundle\Tests\Helpers\CacheableClass;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\AnnotationRegistry;
use Monolog\Handler\TestHandler;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
Expand Down Expand Up @@ -129,6 +132,20 @@ public function testAccessToProtectedMethod()

}

public function testCachePrefixExpressions()
{
/** @var CacheableClass $object */
$object = $this->container->get('cache.testservice');
$objectReflectionClass = new \ReflectionClass($object);
$annotationReader = new AnnotationReader();
/** @var CacheExpression $cacheExpressionAnnotation */
$cacheExpressionAnnotation = $annotationReader->getMethodAnnotation(new \ReflectionMethod($objectReflectionClass->getParentClass()->getName(), 'getCachePrefixFromExpression'), CacheExpression::class);
$cacheExpressionAnnotation->setContext($object);

$this->assertContains($object->calculateCachePrefix(), $cacheExpressionAnnotation->getCache());
$this->assertEquals(0, strpos($cacheExpressionAnnotation->getCache(), $object->calculateCachePrefix()));
}

/**
* Get TestHandler object
*
Expand Down
21 changes: 19 additions & 2 deletions tests/Helpers/CacheableClass.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
<?php


namespace CacheBundle\Tests\Helpers;


use CacheBundle\Annotation\Cache;
use CacheBundle\Annotation\CacheExpression;

class CacheableClass
{
Expand Down Expand Up @@ -110,4 +109,22 @@ protected function protectedMethod()
{
return time();
}

/**
* @CacheExpression(cache="this.calculateCachePrefix()")
*
* @return int
*/
public function getCachePrefixFromExpression() : int
{
return rand();
}

/**
* @return string
*/
public function calculateCachePrefix() : string
{
return 'xyz';
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we also update the readme ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep I will.

}