Skip to content

Commit

Permalink
append negative cache (#38)
Browse files Browse the repository at this point in the history
* append annotations / supported negative cache

* append code

* format

* updated
  • Loading branch information
ytake committed Dec 22, 2016
1 parent 3340942 commit 51b7bf3
Show file tree
Hide file tree
Showing 12 changed files with 90 additions and 39 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -172,6 +172,7 @@ you must use the CacheableModule
| driver | Accessing Cache Driver(store) |
| lifetime | cache lifetime (default: 120min) |
| tags | Storing Tagged Cache Items |
| negative(bool) | for null value (default: false) |

```php
use Ytake\LaravelAspect\Annotation\Cacheable;
Expand Down
1 change: 1 addition & 0 deletions composer.json
Expand Up @@ -35,6 +35,7 @@
"satooshi/php-coveralls": "*",
"illuminate/database": "~5.0",
"illuminate/cache": "~5.0",
"illuminate/view": "~5.0",
"sebastian/phpcpd": "*",
"phploc/phploc": "*",
"pdepend/pdepend" : "^2.2.4",
Expand Down
3 changes: 3 additions & 0 deletions src/Annotation/Cacheable.php
Expand Up @@ -39,4 +39,7 @@ final class Cacheable extends Annotation

/** @var array $tags if use array tagging */
public $tags = [];

/** @var bool */
public $negative = false;
}
14 changes: 7 additions & 7 deletions src/Console/ModulePublishCommand.php
Expand Up @@ -43,13 +43,13 @@ class ModulePublishCommand extends Command

/** @var array package modules */
protected $modules = [
'CacheableModule' => 'Ytake\LaravelAspect\Modules\CacheableModule',
'CacheEvictModule' => 'Ytake\LaravelAspect\Modules\CacheEvictModule',
'CachePutModule' => 'Ytake\LaravelAspect\Modules\CachePutModule',
'TransactionalModule' => 'Ytake\LaravelAspect\Modules\TransactionalModule',
'LoggableModule' => 'Ytake\LaravelAspect\Modules\LoggableModule',
'LogExceptionsModule' => 'Ytake\LaravelAspect\Modules\LogExceptionsModule',
'PostConstructModule' => 'Ytake\LaravelAspect\Modules\PostConstructModule',
'CacheableModule' => 'Ytake\LaravelAspect\Modules\CacheableModule',
'CacheEvictModule' => 'Ytake\LaravelAspect\Modules\CacheEvictModule',
'CachePutModule' => 'Ytake\LaravelAspect\Modules\CachePutModule',
'TransactionalModule' => 'Ytake\LaravelAspect\Modules\TransactionalModule',
'LoggableModule' => 'Ytake\LaravelAspect\Modules\LoggableModule',
'LogExceptionsModule' => 'Ytake\LaravelAspect\Modules\LogExceptionsModule',
'PostConstructModule' => 'Ytake\LaravelAspect\Modules\PostConstructModule',
'RetryOnFailureModule' => 'Ytake\LaravelAspect\Modules\RetryOnFailureModule',
];

Expand Down
4 changes: 2 additions & 2 deletions src/ContainerInterceptor.php
Expand Up @@ -18,15 +18,15 @@
namespace Ytake\LaravelAspect;

use Ray\Aop\Bind;
use Illuminate\Container\Container;
use Illuminate\Contracts\Container\Container;
use Ytake\LaravelAspect\Annotation\PostConstruct;

/**
* Class ContainerInterceptor
*/
final class ContainerInterceptor
{
/** @var Container */
/** @var Container|\Illuminate\Container\Container */
private $container;

/**
Expand Down
16 changes: 10 additions & 6 deletions src/Interceptor/AbstractCache.php
Expand Up @@ -17,11 +17,15 @@
*/
namespace Ytake\LaravelAspect\Interceptor;

use Illuminate\Cache\CacheManager;
use Ray\Aop\MethodInvocation;
use Ray\Aop\MethodInterceptor;
use Illuminate\Cache\CacheManager;
use Illuminate\Contracts\Cache\Factory;
use Doctrine\Common\Annotations\Annotation;
use Ytake\LaravelAspect\Annotation\AnnotationReaderTrait;
use Ytake\LaravelAspect\Annotation\Cacheable;
use Ytake\LaravelAspect\Annotation\CacheEvict;
use Ytake\LaravelAspect\Annotation\CachePut;

/**
* Class AbstractCache
Expand Down Expand Up @@ -55,13 +59,13 @@ protected function generateCacheName($name, MethodInvocation $invocation)
}

/**
* @param MethodInvocation $invocation
* @param $annotation
* @param $keys
* @param MethodInvocation $invocation
* @param Annotation|Cacheable|CacheEvict|CachePut $annotation
* @param array $keys
*
* @return array
*/
protected function detectCacheKeys(MethodInvocation $invocation, $annotation, $keys)
protected function detectCacheKeys(MethodInvocation $invocation, Annotation $annotation, array $keys)
{
$arguments = $invocation->getArguments();
foreach ($invocation->getMethod()->getParameters() as $parameter) {
Expand Down Expand Up @@ -91,7 +95,7 @@ protected function detectCacheRepository($annotation)
/** @var Factory|CacheManager $cacheFactory */
$cacheFactory = self::$factory;
$driver = (is_null($annotation->driver)) ? $cacheFactory->getDefaultDriver() : $annotation->driver;
/** @var \Illuminate\Contracts\Cache\Repository $cache */
/** @var \Illuminate\Contracts\Cache\Repository|\Illuminate\Cache\TaggableStore $cache */
$cache = $cacheFactory->store($driver);
if (count($annotation->tags)) {
$cache = $cache->tags($annotation->tags);
Expand Down
11 changes: 9 additions & 2 deletions src/Interceptor/CacheableInterceptor.php
Expand Up @@ -18,6 +18,7 @@
namespace Ytake\LaravelAspect\Interceptor;

use Ray\Aop\MethodInvocation;
use Ytake\LaravelAspect\Annotation\Cacheable;

/**
* Class CacheableInterceptor
Expand All @@ -31,12 +32,12 @@ class CacheableInterceptor extends AbstractCache
*/
public function invoke(MethodInvocation $invocation)
{
/** @var Cacheable $annotation */
$annotation = $invocation->getMethod()->getAnnotation($this->annotation);
$keys = $this->generateCacheName($annotation->cacheName, $invocation);
if (!is_array($annotation->key)) {
$annotation->key = [$annotation->key];
}

$keys = $this->detectCacheKeys($invocation, $annotation, $keys);
// detect use cache driver
$cache = $this->detectCacheRepository($annotation);
Expand All @@ -45,8 +46,14 @@ public function invoke(MethodInvocation $invocation)
return $cache->get($key);
}
$result = $invocation->proceed();
if (!$annotation->negative) {
if ($result) {
$cache->add($key, $result, $annotation->lifetime);
}

if ($result) {
return $result;
}
if (is_null($result)) {
$cache->add($key, $result, $annotation->lifetime);
}

Expand Down
28 changes: 21 additions & 7 deletions src/Interceptor/RetryOnFailureInterceptor.php
Expand Up @@ -29,7 +29,7 @@ class RetryOnFailureInterceptor implements MethodInterceptor
{
use AnnotationReaderTrait;

/** @var int|null */
/** @var array|null */
private static $attempt = null;

/**
Expand All @@ -42,30 +42,44 @@ public function invoke(MethodInvocation $invocation)
{
/** @var RetryOnFailure $annotation */
$annotation = $invocation->getMethod()->getAnnotation($this->annotation);
if (self::$attempt === null) {
self::$attempt = $annotation->attempts;
$key = $this->keyName($invocation);

if (isset(self::$attempt[$key]) === false) {
self::$attempt[$key] = $annotation->attempts;
}

try {
self::$attempt--;
self::$attempt[$key]--;

return $invocation->proceed();
} catch (\Exception $e) {
if (ltrim($annotation->ignore, '\\') === get_class($e)) {
self::$attempt = null;
self::$attempt[$key] = null;
throw $e;
}

$pass = array_filter($annotation->types, function ($values) use ($e) {
return ltrim($values, '\\') === get_class($e);
});
if ($pass !== false) {
if (self::$attempt > 0) {
if (self::$attempt[$key] > 0) {
sleep($annotation->delay);

return $invocation->proceed();
}
}
self::$attempt = null;
self::$attempt[$key] = null;
throw $e;
}
}

/**
* @param MethodInvocation $invocation
*
* @return string
*/
protected function keyName(MethodInvocation $invocation)
{
return $invocation->getMethod()->class . "$" . $invocation->getMethod()->getName();
}
}
27 changes: 13 additions & 14 deletions src/Matcher/AnnotationScanMatcher.php
Expand Up @@ -42,9 +42,19 @@ public function __construct()
* {@inheritdoc}
*/
public function matchesClass(\ReflectionClass $class, array $arguments)
{
return $this->has($class, $arguments[0]);
}

/**
* @param \ReflectionClass $class
* @param $annotation
*
* @return bool
*/
private function has(\ReflectionClass $class, $annotation)
{
$count = 0;
$annotation = $arguments[0];
foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflectionMethod) {
$match = $this->reader->getMethodAnnotation($reflectionMethod, $annotation);
if ($match) {
Expand All @@ -63,19 +73,8 @@ public function matchesClass(\ReflectionClass $class, array $arguments)
*/
public function matchesMethod(\ReflectionMethod $method, array $arguments)
{
$count = 0;
$annotation = $arguments[0];
$reflectionClass = new \ReflectionClass($method->class);
foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflectionMethod) {
$match = $this->reader->getMethodAnnotation($reflectionMethod, $annotation);
if ($match) {
$count++;
}
}
if ($count > 1) {
return false;
}
$class = new \ReflectionClass($method->class);

return true;
return $this->has($class, $arguments[0]);
}
}
2 changes: 1 addition & 1 deletion src/RayAspectKernel.php
Expand Up @@ -176,7 +176,7 @@ protected function registerAspectModule()
}

/**
* @return string[]
* @return array
* @codeCoverageIgnore
*/
protected function aspectConfiguration()
Expand Down
8 changes: 8 additions & 0 deletions tests/CacheableTest.php
Expand Up @@ -65,6 +65,14 @@ public function testCacheableCacheObject()
$this->assertSame(1000, $result);
}

public function testShouldBeNullForNegativeCache()
{
/** @var \__Test\AspectCacheable $cache */
$cache = $this->app->make(\__Test\AspectCacheable::class);
$this->assertNull($cache->negativeCache());
$this->assertNull($this->app['cache']->get('negative'));
}

/**
*
*/
Expand Down
14 changes: 14 additions & 0 deletions tests/src/AspectCacheable.php
Expand Up @@ -17,6 +17,7 @@ class AspectCacheable
/**
* @Cacheable(key="#id",driver="null")
* @param null $id
*
* @return null
*/
public function singleKey($id = null)
Expand All @@ -28,6 +29,7 @@ public function singleKey($id = null)
* @Cacheable(key={"#id","#value"},driver="array")
* @param $id
* @param $value
*
* @return mixed
*/
public function multipleKey($id, $value)
Expand All @@ -39,6 +41,7 @@ public function multipleKey($id, $value)
* @Cacheable(cacheName="testing1",key={"#id","#value"})
* @param $id
* @param $value
*
* @return mixed
*/
public function namedMultipleKey($id, $value)
Expand All @@ -50,6 +53,7 @@ public function namedMultipleKey($id, $value)
* @Cacheable(tags={"testing1","testing2"},key={"#id","#value"})
* @param $id
* @param $value
*
* @return mixed
*/
public function namedMultipleNameAndKey($id, $value)
Expand All @@ -61,10 +65,20 @@ public function namedMultipleNameAndKey($id, $value)
* @Cacheable(tags={"testing1","testing2"},key={"#id","#class"})
* @param $id
* @param \stdClass $class
*
* @return mixed
*/
public function cachingKeyObject($id, \stdClass $class)
{
return $id;
}

/**
* @Cacheable(negative=true,cacheName="negative")
* @return null
*/
public function negativeCache()
{
return null;
}
}

0 comments on commit 51b7bf3

Please sign in to comment.