diff --git a/.scrutinizer.yml b/.scrutinizer.yml index c6eb21b..ef2824c 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -3,6 +3,7 @@ filter: - src/* excluded_paths: - tests/* + - src/data/* tools: php_code_sniffer: config: diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1c58f27 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Yuuki Takezawa + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md index 927e764..748fb63 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Laravel-Aspect -for laravel framework(use Go!Aop Framework) +for laravel framework [![Build Status](http://img.shields.io/travis/ytake/Laravel-Aspect/master.svg?style=flat-square)](https://travis-ci.org/ytake/Laravel-Aspect) [![Coverage Status](http://img.shields.io/coveralls/ytake/Laravel-Aspect/master.svg?style=flat-square)](https://coveralls.io/r/ytake/Laravel-Aspect?branch=master) @@ -13,7 +13,7 @@ for laravel framework(use Go!Aop Framework) [![Latest Version](http://img.shields.io/packagist/v/ytake/laravel-aspect.svg?style=flat-square)](https://packagist.org/packages/ytake/laravel-aspect) [![Total Downloads](http://img.shields.io/packagist/dt/ytake/laravel-aspect.svg?style=flat-square)](https://packagist.org/packages/ytake/laravel-aspect) -## usage +## usage ### install @@ -41,6 +41,33 @@ $ composer require ytake/laravel-aspect ] ``` +### publish aspect module class + +```bash +$ php artisan ytake:aspect-module-publish +``` +more command options [--help] + +### aspect kernel boot + +added serviceProvider Class + +```php +class AppServiceProvider extends ServiceProvider +{ + /** + * @return void + */ + public function boot() + { + /** @var \Ytake\LaravelAspect\AspectManager $aspect */ + $aspect = $this->app['aspect.manager']; + $aspect->register(\App\Modules\CacheableModule::class); + } + +} +``` + ### publish configure * basic @@ -69,7 +96,7 @@ $ php artisan ytake:aspect-clear-cache ## Annotations -### @Transactional(Around Advice) +### @Transactional for database transaction(illuminate/database) * option @@ -90,7 +117,7 @@ public function save(array $params) } ``` -### @Cacheable(After Advice) +### @Cacheable for cache(illuminate/cache) * option @@ -118,7 +145,7 @@ public function namedMultipleKey($id, $value) } ``` -### @CacheEvict(After Advice) +### @CacheEvict for cache(illuminate/cache) / remove cache * option @@ -144,7 +171,7 @@ public function removeCache() } ``` -### @CachePut(After Advice) +### @CachePut for cache(illuminate/cache) / cache put * option @@ -169,23 +196,38 @@ public function throwExceptionCache() } ``` -## add Interceptors +### @Loggable + +soon -your service provider's +### Annotation Cache Driver + +chose array driver or file cache driver + +use config/ytake-laravel-aspect.php file ```php -public function boot() -{ - $this->app['aspect.annotation.register']->registerAnnotations([ - app_path() . '/Annotation/Finder.php', - ]); - - $this->app['aspect.manager']->setAspects([ - \App\Interceptor\SampleInterceptor::class - ]); -} + 'annotation' => [ + /** + * choose annotation reader + * 'array'(default), 'file'(file cache) + */ + 'default' => env('ASPECT_ANNOTATION_DRIVER', 'array'), + + 'drivers' => [ + 'file' => [ + 'cache_dir' => storage_path('framework/annotation'), + // + 'debug' => env('ASPECT_ANNOTATION_DEBUG', true), + ], + ], + ], ``` +## add Interceptors + +soon + ## for testing use none driver diff --git a/composer.json b/composer.json index e0e590e..57203d8 100644 --- a/composer.json +++ b/composer.json @@ -18,12 +18,14 @@ ], "require": { "php": ">=5.5.9", - "goaop/framework": "~0.0", "illuminate/console": "~5.0", "illuminate/filesystem": "~5.0", "illuminate/support": "~5.0", "illuminate/config": "~5.0", - "doctrine/annotations": "~1.0" + "illuminate/contracts": "~5.0", + "ray/aop": "~2.0", + "doctrine/annotations": "~1.0", + "doctrine/cache": "~1.0" }, "require-dev": { "symfony/framework-bundle": "2.*", @@ -41,7 +43,8 @@ }, "autoload-dev": { "files": [ - "tests/TestCase.php" + "tests/TestCase.php", + "tests/helper.php" ], "psr-4": { "__Test\\": "tests/src" diff --git a/phpunit.xml b/phpunit.xml index 8ad538a..24e3cc5 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -20,6 +20,7 @@ ./src ./src/config + ./src/data ./src/AspectServiceProvider.php ./src/CompileServiceProvider.php ./src/ConsoleServiceProvider.php diff --git a/src/Annotation.php b/src/Annotation.php index 423c9b2..6268c10 100644 --- a/src/Annotation.php +++ b/src/Annotation.php @@ -1,4 +1,5 @@ - * @license http://opensource.org/licenses/MIT MIT */ class Annotation { @@ -34,16 +42,15 @@ public function registerAnnotations(array $files) } /** - * use annotations - * - * @return void + * @throws FileNotFoundException */ public function registerAspectAnnotations() { foreach ($this->files as $file) { - if (file_exists($file)) { - AnnotationRegistry::registerFile($file); + if (!file_exists($file)) { + throw new FileNotFoundException($file); } + AnnotationRegistry::registerFile($file); } AnnotationRegistry::registerFile(__DIR__ . '/Annotation/Transactional.php'); AnnotationRegistry::registerFile(__DIR__ . '/Annotation/Cacheable.php'); diff --git a/src/Annotation/AnnotationReaderTrait.php b/src/Annotation/AnnotationReaderTrait.php new file mode 100644 index 0000000..5226dab --- /dev/null +++ b/src/Annotation/AnnotationReaderTrait.php @@ -0,0 +1,53 @@ +reader = $reader; + } + + /** + * @param string $annotation + */ + public function setAnnotation($annotation) + { + $this->annotation = $annotation; + } +} diff --git a/src/Annotation/CacheEvict.php b/src/Annotation/CacheEvict.php index 60dc77d..be39dcc 100644 --- a/src/Annotation/CacheEvict.php +++ b/src/Annotation/CacheEvict.php @@ -1,4 +1,5 @@ - * @license http://opensource.org/licenses/MIT MIT */ final class CacheEvict extends Annotation { diff --git a/src/Annotation/CachePut.php b/src/Annotation/CachePut.php index e7a0e52..bdd64e7 100644 --- a/src/Annotation/CachePut.php +++ b/src/Annotation/CachePut.php @@ -1,4 +1,5 @@ - * @license http://opensource.org/licenses/MIT MIT */ final class CachePut extends Annotation { diff --git a/src/Annotation/Cacheable.php b/src/Annotation/Cacheable.php index 6760e8d..7c89b48 100644 --- a/src/Annotation/Cacheable.php +++ b/src/Annotation/Cacheable.php @@ -1,4 +1,5 @@ - * @license http://opensource.org/licenses/MIT MIT */ final class Cacheable extends Annotation { diff --git a/src/Annotation/Transactional.php b/src/Annotation/Transactional.php index 63b0400..5b4aff6 100644 --- a/src/Annotation/Transactional.php +++ b/src/Annotation/Transactional.php @@ -1,4 +1,5 @@ - * @license http://opensource.org/licenses/MIT MIT */ final class Transactional extends Annotation { diff --git a/src/AnnotationManager.php b/src/AnnotationManager.php new file mode 100644 index 0000000..15de135 --- /dev/null +++ b/src/AnnotationManager.php @@ -0,0 +1,68 @@ +app['config']->get('ytake-laravel-aop.annotation.default'); + } + + /** + * @return ArrayReader + */ + protected function createArrayDriver() + { + return new ArrayReader(); + } + + /** + * @return FileReader + */ + protected function createFileDriver() + { + return new FileReader($this->getConfigure('file')); + } + + /** + * @param string $driver + * @return string[] + */ + protected function getConfigure($driver) + { + $annotationConfigure = $this->app['config']->get('ytake-laravel-aop.annotation.drivers'); + + return $annotationConfigure[$driver]; + } +} diff --git a/src/NullAspect.php b/src/AnnotationReadable.php similarity index 53% rename from src/NullAspect.php rename to src/AnnotationReadable.php index 1b9b079..64164f5 100644 --- a/src/NullAspect.php +++ b/src/AnnotationReadable.php @@ -1,4 +1,5 @@ - * @license http://opensource.org/licenses/MIT MIT + * Interface AnnotationReadable */ -class NullAspect implements AspectDriverInterface +interface AnnotationReadable { /** - * initialize aspect kernel - * - * @return void - */ - public function register() - { - return; - } - - /** - * @param array $classes + * @return Reader */ - public function setAspects(array $classes) - { - return; - } + public function getReader(); } diff --git a/src/ArrayReader.php b/src/ArrayReader.php new file mode 100644 index 0000000..d4b8bb9 --- /dev/null +++ b/src/ArrayReader.php @@ -0,0 +1,39 @@ + - * @license http://opensource.org/licenses/MIT MIT - */ -final class AspectKernel extends LaravelKernel -{ - /** @var array */ - protected $aspects; - - /** - * @param array $classes - */ - public function setAop(array $classes) - { - $this->aspects = $classes; - } - - /** - * @inheritdoc - */ - protected function configureAop(AspectContainer $container) - { - if ($this->aspects) { - foreach ($this->aspects as $aspect) { - $container->registerAspect($this->laravel->make($aspect)); - } - } - $container->registerAspect(new TransactionalAspect($this->laravel['db'])); - $container->registerAspect(new CacheableAspect($this->laravel['cache'])); - $container->registerAspect(new CacheEvictAspect($this->laravel['cache'])); - $container->registerAspect(new CachePutAspect($this->laravel['cache'])); - } -} diff --git a/src/Aspect/LaravelKernel.php b/src/Aspect/LaravelKernel.php deleted file mode 100644 index 6584369..0000000 --- a/src/Aspect/LaravelKernel.php +++ /dev/null @@ -1,36 +0,0 @@ - - * @license http://opensource.org/licenses/MIT MIT - */ -abstract class LaravelKernel extends CoreKernel -{ - /** @var LaravelApplication */ - protected $laravel; - - /** - * @param LaravelApplication $laravel - */ - public function setLaravel(LaravelApplication $laravel) - { - $this->laravel = $laravel; - } -} diff --git a/src/Aspect/TransactionalAspect.php b/src/Aspect/TransactionalAspect.php deleted file mode 100644 index cfb9381..0000000 --- a/src/Aspect/TransactionalAspect.php +++ /dev/null @@ -1,61 +0,0 @@ - - * @license http://opensource.org/licenses/MIT MIT - */ -class TransactionalAspect implements Aspect -{ - /** @var ConnectionResolverInterface */ - protected $db; - - /** - * @param ConnectionResolverInterface $db - */ - public function __construct(ConnectionResolverInterface $db) - { - $this->db = $db; - } - - /** - * @Around("@annotation(Ytake\LaravelAspect\Annotation\Transactional)") - * @param MethodInvocation $invocation - * @return mixed - */ - public function aroundMethodExecution(MethodInvocation $invocation) - { - $connection = $invocation->getMethod() - ->getAnnotation('Ytake\LaravelAspect\Annotation\Transactional')->value; - $database = $this->db->connection($connection); - $database->beginTransaction(); - try { - $result = $invocation->proceed(); - $database->commit(); - - return $result; - } catch (QueryException $exception) { - $database->rollBack(); - throw $exception; - } - } -} diff --git a/src/AspectDriverInterface.php b/src/AspectDriverInterface.php index 8fefcbd..12ec52a 100644 --- a/src/AspectDriverInterface.php +++ b/src/AspectDriverInterface.php @@ -1,4 +1,5 @@ - * @license http://opensource.org/licenses/MIT MIT */ interface AspectDriverInterface { /** - * @return mixed - */ - public function register(); - - /** - * add user aspect script + * @param null $module + * @return void */ - public function setAspects(array $classes); + public function register($module = null); } diff --git a/src/AspectManager.php b/src/AspectManager.php index 37df790..1b18c3f 100644 --- a/src/AspectManager.php +++ b/src/AspectManager.php @@ -1,4 +1,5 @@ - * @license http://opensource.org/licenses/MIT MIT + * @method void register() register(string $module) */ class AspectManager extends Manager { /** * for go-aop driver * - * @return GoAspect + * @return RayAspectKernel */ - protected function createGoDriver() + protected function createRayDriver() { - return new GoAspect( + return new RayAspectKernel( $this->app, - $this->getConfigure('go') + new Bind(), + $this->getConfigure('ray') ); } + /** + * @return NullAspectKernel + */ protected function createNoneDriver() { - return new NullAspect(); + return new NullAspectKernel(); } /** - * @inheritdoc + * {@inheritdoc} */ public function getDefaultDriver() { - return $this->app['config']->get('ytake-laravel-aop.default'); + return $this->app['config']->get('ytake-laravel-aop.aspect.default'); } /** - * @param $driver - * @return mixed + * @param string $driver + * @return string[] */ protected function getConfigure($driver) { - $aspectConfigure = $this->app['config']->get('ytake-laravel-aop.aop'); + $aspectConfigure = $this->app['config']->get('ytake-laravel-aop.aspect.drivers'); return $aspectConfigure[$driver]; } diff --git a/src/AspectServiceProvider.php b/src/AspectServiceProvider.php index 5472ace..0634f64 100644 --- a/src/AspectServiceProvider.php +++ b/src/AspectServiceProvider.php @@ -1,4 +1,5 @@ - * @license http://opensource.org/licenses/MIT MIT */ class AspectServiceProvider extends ServiceProvider { + /** @var bool */ + protected $defer = true; + /** - * @inheritdoc + * boot serivce */ public function boot() { // register annotation - $this->app->make('aspect.annotation.register')->registerAspectAnnotations(); - // annotation driver - $this->app->make('aspect.manager')->register(); + $this->app['aspect.annotation.register']->registerAspectAnnotations(); } /** - * @inheritdoc + * {@inheritdoc} */ public function register() { @@ -45,7 +53,13 @@ public function register() $this->mergeConfigFrom($configPath, 'ytake-laravel-aop'); $this->publishes([$configPath => config_path('ytake-laravel-aop.php')], 'aspect'); - $this->registerAspectAnnotations(); + $this->app->singleton('aspect.annotation.register', function () { + return new Annotation(); + }); + + $this->app->singleton('aspect.annotation.reader', function ($app) { + return (new AnnotationManager($app))->getReader(); + }); $this->app->singleton('aspect.manager', function ($app) { return new AspectManager($app); @@ -53,12 +67,14 @@ public function register() } /** - * @return void + * {@inheritdoc} */ - protected function registerAspectAnnotations() + public function provides() { - $this->app->singleton('aspect.annotation.register', function () { - return new Annotation(); - }); + return [ + 'aspect.annotation.register', + 'aspect.annotation.reader', + 'aspect.manager' + ]; } } diff --git a/src/CodeGen.php b/src/CodeGen.php new file mode 100644 index 0000000..0f67ee5 --- /dev/null +++ b/src/CodeGen.php @@ -0,0 +1,158 @@ +parser = $parser; + $this->factory = $factory; + $this->printer = $printer; + $this->codeGenMethod = new CodeGenMethod($parser, $factory, $printer); + } + + /** + * @param string $class + * @param \ReflectionClass $sourceClass + * + * @return string + */ + public function generate($class, \ReflectionClass $sourceClass, BindInterface $bind) + { + $methods = $this->codeGenMethod->getMethods($sourceClass, $bind); + $stmt = $this + ->getClass($class, $sourceClass) + ->addStmts($methods) + ->getNode(); + $stmt = $this->addClassDocComment($stmt, $sourceClass); + $code = $this->printer->prettyPrint([$stmt]); + $statements = $this->getUseStatements($sourceClass); + + return $statements . $code; + } + + /** + * @param \ReflectionClass $class + * + * @return string + */ + private function getUseStatements(\ReflectionClass $class) + { + $traverser = new NodeTraverser(); + $useStmtsVisitor = new CodeGenVisitor(); + $traverser->addVisitor($useStmtsVisitor); + // parse + $stmts = $this->parser->parse(file_get_contents($class->getFileName())); + // traverse + $traverser->traverse($stmts); + // pretty print + $code = $this->printer->prettyPrint($useStmtsVisitor()); + + return (string)$code; + } + + /** + * Return class statement + * + * @param string $newClassName + * @param \ReflectionClass $class + * + * @return \PhpParser\Builder\Class_ + */ + private function getClass($newClassName, \ReflectionClass $class) + { + $parentClass = $class->name; + $builder = $this->factory + ->class($newClassName) + ->extend($parentClass) + ->implement('Ray\Aop\WeavedInterface') + ->addStmt( + $this->factory->property('isIntercepting')->makePrivate()->setDefault(true) + )->addStmt( + $this->factory->property('bind')->makePublic() + ); + + return $builder; + } + + /** + * Add class doc comment + * + * @param Class_ $node + * @param \ReflectionClass $class + * + * @return \PHPParser\Node\Stmt\Class_ + */ + private function addClassDocComment(Class_ $node, \ReflectionClass $class) + { + $docComment = $class->getDocComment(); + if ($docComment) { + $node->setAttribute('comments', [new Doc($docComment)]); + } + + return $node; + } +} diff --git a/src/CodeGenMethod.php b/src/CodeGenMethod.php new file mode 100644 index 0000000..3a7e68d --- /dev/null +++ b/src/CodeGenMethod.php @@ -0,0 +1,191 @@ +parser = $parser; + $this->factory = $factory; + $this->printer = $printer; + } + + /** + * @param \ReflectionClass $class + * @param BindInterface $bind + * + * @return array + */ + public function getMethods(\ReflectionClass $class, BindInterface $bind) + { + $bindingMethods = array_keys($bind->getBindings()); + $stmts = []; + $methods = $class->getMethods(); + foreach ($methods as $method) { + $isBindingMethod = in_array($method->getName(), $bindingMethods); + /* @var $method \ReflectionMethod */ + if ($isBindingMethod && $method->isPublic()) { + $stmts[] = $this->getMethod($method); + } + } + + return $stmts; + } + + /** + * Return method statement + * + * @param \ReflectionMethod $method + * + * @return \PhpParser\Node\Stmt\ClassMethod + */ + private function getMethod(\ReflectionMethod $method) + { + $methodStmt = $this->factory->method($method->name); + $params = $method->getParameters(); + foreach ($params as $param) { + $methodStmt = $this->getMethodStatement($param, $methodStmt); + } + $methodInsideStatements = $this->getMethodInsideStatement(); + $methodStmt->addStmts($methodInsideStatements); + $node = $this->addMethodDocComment($methodStmt, $method); + + return $node; + } + + /** + * Return parameter reflection + * + * @param \ReflectionParameter $param + * @param \PHPParser\Builder\Method $methodStmt + * + * @return \PHPParser\Builder\Method + */ + private function getMethodStatement(\ReflectionParameter $param, Method $methodStmt) + { + /** @var $paramStmt Param */ + $paramStmt = $this->factory->param($param->name); + /* @var $param \ReflectionParameter */ + $typeHint = $param->getClass(); + $this->setTypeHint($param, $paramStmt, $typeHint); + $this->setDefault($param, $paramStmt); + $methodStmt->addParam($paramStmt); + + return $methodStmt; + } + + /** + * @param Method $methodStmt + * @param \ReflectionMethod $method + * + * @return \PhpParser\Node\Stmt\ClassMethod + */ + private function addMethodDocComment(Method $methodStmt, \ReflectionMethod $method) + { + $node = $methodStmt->getNode(); + $docComment = $method->getDocComment(); + if ($docComment) { + $node->setAttribute('comments', [new Doc($docComment)]); + } + + return $node; + } + + /** + * @return \PHPParser\Node[] + */ + private function getMethodInsideStatement() + { + // fixed call parent method + $code = file_get_contents(__DIR__ . '/data/CodeTemplate.php'); + $node = $this->parser->parse($code)[0]; + /** @var $node \PHPParser\Node\Stmt\Class_ */ + $node = $node->getMethods()[0]; + + return $node->stmts; + } + + /** + * @param \ReflectionParameter $param + * @param Param $paramStmt + * @param \ReflectionClass $typeHint + */ + private function setTypeHint(\ReflectionParameter $param, Param $paramStmt, \ReflectionClass $typeHint = null) + { + if ($typeHint) { + $paramStmt->setTypeHint($typeHint->name); + } + if ($param->isArray()) { + $paramStmt->setTypeHint('array'); + } + if ($param->isCallable()) { + $paramStmt->setTypeHint('callable'); + } + } + + /** + * @param \ReflectionParameter $param + * @param Param $paramStmt + */ + private function setDefault(\ReflectionParameter $param, $paramStmt) + { + if ($param->isDefaultValueAvailable()) { + $paramStmt->setDefault($param->getDefaultValue()); + } + } +} diff --git a/src/Console/ClearAnnotationCacheCommand.php b/src/Console/ClearAnnotationCacheCommand.php new file mode 100644 index 0000000..6d0bfc0 --- /dev/null +++ b/src/Console/ClearAnnotationCacheCommand.php @@ -0,0 +1,72 @@ +config = $config; + $this->filesystem = $filesystem; + } + + /** + * @return void + */ + public function fire() + { + $configure = $this->config->get('ytake-laravel-aop.annotation'); + if ($configure['default'] === 'file') { + $driverConfig = $configure['drivers']['file']; + $directories = $this->filesystem->glob($driverConfig['cache_dir'] . '/*'); + foreach ($directories as $directory) { + $this->filesystem->deleteDirectory($directory); + } + } + $this->info('annotation cache clear!'); + } +} diff --git a/src/Console/ClearCacheCommand.php b/src/Console/ClearCacheCommand.php index 03d3328..0b6853a 100644 --- a/src/Console/ClearCacheCommand.php +++ b/src/Console/ClearCacheCommand.php @@ -1,4 +1,5 @@ - * @license http://opensource.org/licenses/MIT MIT */ class ClearCacheCommand extends Command { @@ -28,7 +35,7 @@ class ClearCacheCommand extends Command protected $name = 'ytake:aspect-clear-cache'; /** @var string */ - protected $description = 'compiles all known templates'; + protected $description = 'Flush the application aspect code cache'; /** @var ConfigRepository */ protected $config; @@ -52,12 +59,14 @@ public function __construct(ConfigRepository $config, Filesystem $filesystem) */ public function fire() { - $configure = $this->config->get('ytake-laravel-aop'); - - $driverConfig = $configure['aop'][$configure['default']]; - if (isset($driverConfig['cacheDir'])) { - $this->filesystem->cleanDirectory($driverConfig['cacheDir']); + $configure = $this->config->get('ytake-laravel-aop.aspect'); + $driverConfig = $configure['drivers'][$configure['default']]; + if (isset($driverConfig['cache_dir'])) { + $files = $this->filesystem->glob($driverConfig['cache_dir'] . '/*'); + foreach ($files as $file) { + $this->filesystem->delete($file); + } } - $this->info('aspect/annotation cache clear!'); + $this->info('aspect code cache clear!'); } } diff --git a/src/Console/ModulePublishCommand.php b/src/Console/ModulePublishCommand.php new file mode 100644 index 0000000..f3c01eb --- /dev/null +++ b/src/Console/ModulePublishCommand.php @@ -0,0 +1,180 @@ + \Ytake\LaravelAspect\Modules\CacheableModule::class, + 'CacheEvictModule' => \Ytake\LaravelAspect\Modules\CacheEvictModule::class, + 'CachePutModule' => \Ytake\LaravelAspect\Modules\CachePutModule::class, + 'TransactionalModule' => \Ytake\LaravelAspect\Modules\TransactionalModule::class, + ]; + + /** + * @param Filesystem $filesystem + */ + public function __construct(Filesystem $filesystem) + { + parent::__construct(); + $this->filesystem = $filesystem; + } + + /** + * @return void + */ + public function fire() + { + foreach ($this->modules as $className => $module) { + $path = $this->getPath($this->parseClassName($className, $this->argument('module_dir'))); + + if ($this->filesystem->exists($path)) { + continue; + } + $stub = $this->filesystem->get($this->stub); + $extendClassName = $this->getExtendsClassName($module); + $source = str_replace( + [ + 'DummyNamespace', + 'DummyClass', + 'DummyAspectModuleClass', + 'DummyModuleClass' + ], + [ + $this->laravel->getNamespace() . $this->argument('module_dir'), + $className, + $module . ' as ' . $extendClassName, + $extendClassName + ], $stub); + $this->makeDirectory($path); + $this->filesystem->put($path, $source); + $this->info($path . ' created successfully.'); + } + } + + /** + * @return array + */ + protected function getArguments() + { + return [ + ['module_dir', InputArgument::OPTIONAL, 'The name of the class directory', $this->classPath], + ]; + } + + /** + * @param string $name + * @return string + */ + protected function getPath($name) + { + $name = str_replace($this->laravel->getNamespace(), '', $name); + + return $this->laravel['path'] . '/' . str_replace('\\', '/', $name) . '.php'; + } + + /** + * Parse the name and format according to the root namespace. + * + * @param string $name + * @return string + */ + protected function parseClassName($name, $moduleDirectory = null) + { + $rootNamespace = $this->laravel->getNamespace(); + + if (Str::startsWith($name, $rootNamespace)) { + return $name; + } + + if (Str::contains($name, '/')) { + $name = str_replace('/', '\\', $name); + } + + return $this->parseClassName( + trim($rootNamespace, '\\') . '\\' . $moduleDirectory . '\\' . $name + ); + } + + /** + * added custom aspect module, override package modules + * + * @param $module + * @return $this + */ + protected function addModule($module) + { + $this->modules[$module]; + + return $this; + } + + /** + * Build the directory for the class if necessary. + * + * @param string $path + * @return string + */ + protected function makeDirectory($path) + { + if (!$this->filesystem->isDirectory(dirname($path))) { + $this->filesystem->makeDirectory(dirname($path), 0777, true, true); + } + } + + /** + * @param $module + * @return string + */ + protected function getExtendsClassName($module) + { + $shortName = (new \ReflectionClass($module))->getShortName(); + $extendClassName = "Package{$shortName}"; + + return $extendClassName; + } +} diff --git a/src/Console/stub/ModuleStub.stub b/src/Console/stub/ModuleStub.stub new file mode 100644 index 0000000..04381e6 --- /dev/null +++ b/src/Console/stub/ModuleStub.stub @@ -0,0 +1,17 @@ + - * @license http://opensource.org/licenses/MIT MIT */ class ConsoleServiceProvider extends ServiceProvider { /** @var bool */ protected $defer = true; - /** - * @inheritdoc - */ public function boot() { $this->registerCommands(); } /** - * @inheritdoc + * {@inheritdoc} */ public function register() { @@ -50,16 +56,28 @@ protected function registerCommands() $this->app->singleton('command.ytake.aspect.clear-cache', function ($app) { return new ClearCacheCommand($app['config'], $app['files']); }); - $this->commands(['command.ytake.aspect.clear-cache']); + $this->app->singleton('command.ytake.aspect.annotation.clear-cache', function ($app) { + return new ClearAnnotationCacheCommand($app['config'], $app['files']); + }); + $this->app->singleton('command.ytake.aspect.module-publish', function ($app) { + return new ModulePublishCommand($app['files']); + }); + $this->commands([ + 'command.ytake.aspect.clear-cache', + 'command.ytake.aspect.annotation.clear-cache', + 'command.ytake.aspect.module-publish' + ]); } /** - * @inheritdoc + * {@inheritdoc} */ public function provides() { return [ - 'command.ytake.aspect.clear-cache' + 'command.ytake.aspect.clear-cache', + 'command.ytake.aspect.annotation.clear-cache', + 'command.ytake.aspect.module-publish' ]; } } diff --git a/src/Exception/ClassNotFoundException.php b/src/Exception/ClassNotFoundException.php new file mode 100644 index 0000000..e136880 --- /dev/null +++ b/src/Exception/ClassNotFoundException.php @@ -0,0 +1,39 @@ +config = $config; + } + + /** + * @return CachedReader + */ + public function getReader() + { + return new CachedReader( + new AnnotationReader(), + new FilesystemCache($this->config['cache_dir']), + (bool) $this->config['debug'] + ); + } +} diff --git a/src/GoAspect.php b/src/GoAspect.php deleted file mode 100644 index 8358e9c..0000000 --- a/src/GoAspect.php +++ /dev/null @@ -1,66 +0,0 @@ - - * @license http://opensource.org/licenses/MIT MIT - */ -class GoAspect implements AspectDriverInterface -{ - /** @var array */ - protected $configure; - - /** @var LaravelApplication */ - protected $laravel; - - /** @var AspectKernel */ - protected $kernel; - - /** - * @param LaravelApplication $laravel - * @param array $configure - */ - public function __construct(LaravelApplication $laravel, array $configure) - { - $this->laravel = $laravel; - $this->configure = $configure; - $this->kernel = AspectKernel::getInstance(); - } - - /** - * initialize aspect kernel - * - * @return void - */ - public function register() - { - if (!defined('AOP_CACHE_DIR')) { - $this->kernel->setLaravel($this->laravel); - $this->kernel->init($this->configure); - } - } - - /** - * @param array $classes - */ - public function setAspects(array $classes) - { - $this->kernel->setAop($classes); - } -} diff --git a/src/Aspect/AbstractCache.php b/src/Interceptor/AbstractCache.php similarity index 76% rename from src/Aspect/AbstractCache.php rename to src/Interceptor/AbstractCache.php index 41a3fe9..77ffbe7 100644 --- a/src/Aspect/AbstractCache.php +++ b/src/Interceptor/AbstractCache.php @@ -1,4 +1,5 @@ - * @license http://opensource.org/licenses/MIT MIT */ -abstract class AbstractCache implements Aspect +abstract class AbstractCache implements MethodInterceptor { + use AnnotationReaderTrait; + /** @var string */ protected $join = ":"; - /** @var CacheFactory */ - protected $cache; - - /** - * @param CacheFactory $cache - */ - public function __construct(CacheFactory $cache) - { - $this->cache = $cache; - } - /** * @param $name * @param MethodInvocation $invocation @@ -85,7 +83,7 @@ protected function detectCacheKeys(MethodInvocation $invocation, $annotation, $k */ protected function detectCacheRepository($annotation) { - $cache = $this->cache->store($annotation->driver); + $cache = app('cache')->store($annotation->driver); if (count($annotation->tags)) { $cache = $cache->tags($annotation->tags); diff --git a/src/Aspect/CacheEvictAspect.php b/src/Interceptor/CacheEvictInterceptor.php similarity index 58% rename from src/Aspect/CacheEvictAspect.php rename to src/Interceptor/CacheEvictInterceptor.php index 76b81eb..321de88 100644 --- a/src/Aspect/CacheEvictAspect.php +++ b/src/Interceptor/CacheEvictInterceptor.php @@ -1,4 +1,5 @@ - * @license http://opensource.org/licenses/MIT MIT + * Class CacheEvictInterceptor */ -class CacheEvictAspect extends AbstractCache +class CacheEvictInterceptor extends AbstractCache { /** - * @After("@annotation(Ytake\LaravelAspect\Annotation\CacheEvict)") * @param MethodInvocation $invocation * * @return mixed */ - public function afterMethodExecution(MethodInvocation $invocation) + public function invoke(MethodInvocation $invocation) { - $annotation = $invocation->getMethod()->getAnnotation('Ytake\LaravelAspect\Annotation\CacheEvict'); + $result = $invocation->proceed(); + + $annotation = $this->reader + ->getMethodAnnotation($invocation->getMethod(), $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); + if ($annotation->allEntries) { - return $cache->flush(); + $cache->flush(); } + $cache->forget(implode($this->join, $keys)); + return $result; } } diff --git a/src/Aspect/CachePutAspect.php b/src/Interceptor/CachePutInterceptor.php similarity index 63% rename from src/Aspect/CachePutAspect.php rename to src/Interceptor/CachePutInterceptor.php index 169989f..fb48edc 100644 --- a/src/Aspect/CachePutAspect.php +++ b/src/Interceptor/CachePutInterceptor.php @@ -1,4 +1,5 @@ - * @license http://opensource.org/licenses/MIT MIT + * Class AroundCachePutAspect */ -class CachePutAspect extends AbstractCache +class CachePutInterceptor extends AbstractCache { /** - * @Around("@annotation(Ytake\LaravelAspect\Annotation\CachePut)") * @param MethodInvocation $invocation + * * @return mixed */ - public function afterMethodExecution(MethodInvocation $invocation) + public function invoke(MethodInvocation $invocation) { - $annotation = $invocation->getMethod()->getAnnotation('Ytake\LaravelAspect\Annotation\CachePut'); + $annotation = $this->reader + ->getMethodAnnotation($invocation->getMethod(), $this->annotation); $keys = $this->generateCacheName($annotation->cacheName, $invocation); if (!is_array($annotation->key)) { diff --git a/src/Aspect/CacheableAspect.php b/src/Interceptor/CacheableInterceptor.php similarity index 65% rename from src/Aspect/CacheableAspect.php rename to src/Interceptor/CacheableInterceptor.php index 5694e92..a33ec1e 100644 --- a/src/Aspect/CacheableAspect.php +++ b/src/Interceptor/CacheableInterceptor.php @@ -1,4 +1,5 @@ - * @license http://opensource.org/licenses/MIT MIT + * Class CacheableInterceptor */ -class CacheableAspect extends AbstractCache +class CacheableInterceptor extends AbstractCache { /** - * @Around("@annotation(Ytake\LaravelAspect\Annotation\Cacheable)") * @param MethodInvocation $invocation * @return mixed */ - public function aroundMethodExecution(MethodInvocation $invocation) + public function invoke(MethodInvocation $invocation) { - $annotation = $invocation->getMethod()->getAnnotation('Ytake\LaravelAspect\Annotation\Cacheable'); + $annotation = $this->reader + ->getMethodAnnotation($invocation->getMethod(), $this->annotation); + $keys = $this->generateCacheName($annotation->cacheName, $invocation); if (!is_array($annotation->key)) { $annotation->key = [$annotation->key]; @@ -45,7 +52,6 @@ public function aroundMethodExecution(MethodInvocation $invocation) if ($result = $invocation->proceed()) { $cache->add($key, $result, $annotation->lifetime); } - return $result; } } diff --git a/src/Interceptor/TransactionalInterceptor.php b/src/Interceptor/TransactionalInterceptor.php new file mode 100644 index 0000000..cee2ede --- /dev/null +++ b/src/Interceptor/TransactionalInterceptor.php @@ -0,0 +1,61 @@ +reader + ->getMethodAnnotation($invocation->getMethod(), $this->annotation); + + $connection = $annotation->value; + /** @var $database */ + $database = app('db')->connection($connection); + $database->beginTransaction(); + try { + $result = $invocation->proceed(); + $database->commit(); + + return $result; + } catch (QueryException $exception) { + $database->rollBack(); + throw $exception; + } + } +} diff --git a/src/Modules/AspectModule.php b/src/Modules/AspectModule.php new file mode 100644 index 0000000..fa93840 --- /dev/null +++ b/src/Modules/AspectModule.php @@ -0,0 +1,83 @@ +app = $app; + $this->bind = $bind; + } + + /** + * @return void + */ + abstract public function attach(); + + /** + * @param CompilerInterface $compiler + * + * @return $this + */ + public function setCompiler(CompilerInterface $compiler) + { + $this->compiler = $compiler; + return $this; + } + + /** + * @param $class + * @param array $pointcuts + */ + protected function instanceResolver($class, array $pointcuts) + { + $bind = $this->bind->bind($class, $pointcuts); + $compiledClass = $this->compiler->compile($class, $bind); + $this->app->bind($class, function ($app) use ($bind, $compiledClass) { + $instance = $app->make($compiledClass); + $instance->bindings = $bind->getBindings(); + return $instance; + }); + } +} diff --git a/src/Modules/CacheEvictModule.php b/src/Modules/CacheEvictModule.php new file mode 100644 index 0000000..59eb927 --- /dev/null +++ b/src/Modules/CacheEvictModule.php @@ -0,0 +1,42 @@ +app->call([new CacheEvictPointCut, 'configure']); + foreach ($this->classes as $class) { + $this->instanceResolver($class, [$pointcut]); + } + } +} diff --git a/src/Modules/CachePutModule.php b/src/Modules/CachePutModule.php new file mode 100644 index 0000000..1003f10 --- /dev/null +++ b/src/Modules/CachePutModule.php @@ -0,0 +1,42 @@ +app->call([new CachePutPointCut, 'configure']); + foreach ($this->classes as $class) { + $this->instanceResolver($class, [$pointcut]); + } + } +} diff --git a/src/Modules/CacheableModule.php b/src/Modules/CacheableModule.php new file mode 100644 index 0000000..8b50ab0 --- /dev/null +++ b/src/Modules/CacheableModule.php @@ -0,0 +1,42 @@ +app->call([new CacheablePointCut, 'configure']); + foreach ($this->classes as $class) { + $this->instanceResolver($class, [$pointcut]); + } + } +} diff --git a/src/Modules/TransactionalModule.php b/src/Modules/TransactionalModule.php new file mode 100644 index 0000000..8f73aa2 --- /dev/null +++ b/src/Modules/TransactionalModule.php @@ -0,0 +1,42 @@ +app->call([new TransactionalPointCut, 'configure']); + foreach ($this->classes as $class) { + $this->instanceResolver($class, [$pointcut]); + } + } +} diff --git a/src/NullAspectKernel.php b/src/NullAspectKernel.php new file mode 100644 index 0000000..5611ad3 --- /dev/null +++ b/src/NullAspectKernel.php @@ -0,0 +1,37 @@ +setInterceptor(new CacheEvictInterceptor); + + return $this->withAnnotatedAnyInterceptor($app); + } +} diff --git a/src/PointCut/CachePutPointCut.php b/src/PointCut/CachePutPointCut.php new file mode 100644 index 0000000..cadc6a8 --- /dev/null +++ b/src/PointCut/CachePutPointCut.php @@ -0,0 +1,49 @@ +setInterceptor(new CachePutInterceptor); + + return $this->withAnnotatedAnyInterceptor($app); + } +} diff --git a/src/PointCut/CacheablePointCut.php b/src/PointCut/CacheablePointCut.php new file mode 100644 index 0000000..5db6890 --- /dev/null +++ b/src/PointCut/CacheablePointCut.php @@ -0,0 +1,49 @@ +setInterceptor(new CacheableInterceptor); + + return $this->withAnnotatedAnyInterceptor($app); + } +} diff --git a/src/PointCut/CommonPointCut.php b/src/PointCut/CommonPointCut.php new file mode 100644 index 0000000..aaa712e --- /dev/null +++ b/src/PointCut/CommonPointCut.php @@ -0,0 +1,63 @@ +interceptor = $interceptor; + } + + /** + * @param Container $app + * @return Pointcut + */ + protected function withAnnotatedAnyInterceptor(Container $app) + { + $this->interceptor->setReader($app['aspect.annotation.reader']); + $this->interceptor->setAnnotation($this->annotation); + return new Pointcut( + (new Matcher)->any(), + (new Matcher)->annotatedWith($this->annotation), + [$this->interceptor] + ); + } +} diff --git a/src/PointCut/PointCutable.php b/src/PointCut/PointCutable.php new file mode 100644 index 0000000..d372ebc --- /dev/null +++ b/src/PointCut/PointCutable.php @@ -0,0 +1,37 @@ +setInterceptor(new TransactionalInterceptor); + + return $this->withAnnotatedAnyInterceptor($app); + } +} diff --git a/src/RayAspectKernel.php b/src/RayAspectKernel.php new file mode 100644 index 0000000..28e0670 --- /dev/null +++ b/src/RayAspectKernel.php @@ -0,0 +1,88 @@ +app = $app; + $this->configure = $configure; + $this->compiler = $this->getCompiler(); + $this->bind = $bind; + } + + /** + * @param null $module + * @throws ClassNotFoundException + */ + public function register($module = null) + { + if (!class_exists($module)) { + throw new ClassNotFoundException($module); + } + (new $module($this->app, $this->bind))->setCompiler($this->compiler)->attach(); + } + + /** + * @return Compiler + */ + protected function getCompiler() + { + return new Compiler($this->configure['cache_dir'], new CodeGen( + new Parser(new Lexer()), + new BuilderFactory(), + new Standard() + )); + } +} diff --git a/src/config/ytake-laravel-aop.php b/src/config/ytake-laravel-aop.php index acbfde0..f1cda6d 100644 --- a/src/config/ytake-laravel-aop.php +++ b/src/config/ytake-laravel-aop.php @@ -1,4 +1,5 @@ - * @license http://opensource.org/licenses/MIT MIT - */ return [ - /** - * choose aop library - * "go"(go-aop), "none"(for testing) - * - * @see https://github.com/goaop/framework - */ - 'default' => env('ASPECT_DRIVER', 'go'), + 'aspect' => [ + /** + * choose aop library + * "ray"(Ray.Aop), "none"(for testing) + */ + 'default' => env('ASPECT_DRIVER', 'ray'), + + /** + * + */ + 'drivers' => [ + 'ray' => [ + // string Path to the cache directory where compiled classes will be stored + 'cache_dir' => storage_path('framework/aop'), + ], + 'none' => [ + // for testing driver + // no use aspect + ] + ], + ], + + 'annotation' => [ + /** + * choose annotation reader + * 'array'(default), 'file'(file cache) + */ + 'default' => env('ASPECT_ANNOTATION_DRIVER', 'array'), - /** - * - */ - 'aop' => [ - 'go' => [ - // boolean Determines whether or not kernel is in debug mode - 'debug' => env('ASPECT_DEBUG', true), - // string Path to the application root directory. - 'appDir' => app_path(), - // string Path to the cache directory where compiled classes will be stored - 'cacheDir' => storage_path('framework/aop'), - // integer Binary mask of features - // 'features' => 0, - // array WhiteList of directories where aspects should be applied. Empty for everywhere. - 'includePaths' => [ - app_path() + 'drivers' => [ + 'file' => [ + 'cache_dir' => storage_path('framework/annotation'), + // + 'debug' => env('ASPECT_ANNOTATION_DEBUG', true), ], - // array BlackList of directories or files where aspects shouldn't be applied. - // 'excludePaths' => [] ], - 'none' => [ - // for testing driver - // no use aspect - ] ], ]; diff --git a/src/data/CodeTemplate.php b/src/data/CodeTemplate.php new file mode 100644 index 0000000..6936a5a --- /dev/null +++ b/src/data/CodeTemplate.php @@ -0,0 +1,53 @@ + [$interceptorA[]][] + */ + public $bindings; + + /** + * Method Template + */ + public function returnSame($a) + { + if (isset($this->bindings[__FUNCTION__]) === false) { + return call_user_func_array([$this, 'parent::' . __FUNCTION__], func_get_args()); + } + + if ($this->isIntercepting === false) { + $this->isIntercepting = true; + return call_user_func_array([$this, 'parent::' . __FUNCTION__], func_get_args()); + } + + $this->isIntercepting = false; + $invocationResult = (new \Ray\Aop\ReflectiveMethodInvocation( + $this, + new \ReflectionMethod($this, __FUNCTION__), + new \Ray\Aop\Arguments(func_get_args()), + $this->bindings[__FUNCTION__] + ))->proceed(); + $this->isIntercepting = true; + + return $invocationResult; + } +} diff --git a/tests/AnnotationManagerTest.php b/tests/AnnotationManagerTest.php new file mode 100644 index 0000000..7d2c058 --- /dev/null +++ b/tests/AnnotationManagerTest.php @@ -0,0 +1,52 @@ +manager = new \Ytake\LaravelAspect\AnnotationManager($this->app); + } + + public function testReturnDefaultDriverName() + { + $this->assertInternalType('string', $this->manager->getDefaultDriver()); + } + + public function testDefaultDriverInstance() + { + $this->assertInstanceOf( + \Ytake\LaravelAspect\ArrayReader::class, + $this->manager->driver() + ); + } + + public function testAnnotationDriverInstance() + { + $this->assertInstanceOf( + \Ytake\LaravelAspect\ArrayReader::class, + $this->manager->driver('array') + ); + $this->assertInstanceOf( + \Ytake\LaravelAspect\FileReader::class, + $this->manager->driver('file') + ); + } + + public function testAnnotationDriverImplementsAccessor() + { + $fileReader = $this->manager->driver('file'); + $this->assertInstanceOf( + \Doctrine\Common\Annotations\CachedReader::class, + $fileReader->getReader() + ); + $arrayReader = $this->manager->driver('array'); + $this->assertInstanceOf( + \Doctrine\Common\Annotations\AnnotationReader::class, + $arrayReader->getReader() + ); + } +} diff --git a/tests/AspectManagerTest.php b/tests/AspectManagerTest.php index 6cc91c2..a18c539 100644 --- a/tests/AspectManagerTest.php +++ b/tests/AspectManagerTest.php @@ -19,15 +19,14 @@ public function testCreateDriverInstance() public function testCreateGoDriverInstance() { $this->assertInstanceOf( - \Ytake\LaravelAspect\GoAspect::class, $this->manager->driver('go') + \Ytake\LaravelAspect\RayAspectKernel::class, $this->manager->driver('ray') ); } public function testCreateNullDriverInstance() { $driver = $this->manager->driver('none'); - $this->assertInstanceOf(\Ytake\LaravelAspect\NullAspect::class, $driver); - $this->assertNull($driver->setAspects([])); + $this->assertInstanceOf(\Ytake\LaravelAspect\NullAspectKernel::class, $driver); $this->assertNull($driver->register()); $class = new \ReflectionClass($driver); $this->assertSame(0, count($class->getProperties())); diff --git a/tests/CacheEvictTest.php b/tests/CacheEvictTest.php index f2ba557..9f8a8ff 100644 --- a/tests/CacheEvictTest.php +++ b/tests/CacheEvictTest.php @@ -5,8 +5,6 @@ class CacheEvictTest extends \TestCase /** @var \Ytake\LaravelAspect\AspectManager $manager */ protected $manager; - protected static $instance; - protected function setUp() { parent::setUp(); @@ -14,22 +12,16 @@ protected function setUp() $this->resolveManager(); } - /** - * @runInSeparateProcess - */ public function testGenerateCacheNameRemoveNullKey() { - $cache = new \__Test\AspectCacheEvict(); + $cache = $this->app->make(\__Test\AspectCacheEvict::class); $cache->singleCacheDelete(); $this->assertNull($this->app['cache']->get('singleCacheDelete')); } - /** - * @runInSeparateProcess - */ public function testCacheableAndRemove() { - $cache = new \__Test\AspectCacheEvict(); + $cache = $this->app->make(\__Test\AspectCacheEvict::class); $cache->cached(1, 2); $this->assertNotNull($this->app['cache']->tags(['testing1'])->get('testing:1:2')); @@ -45,8 +37,8 @@ protected function resolveManager() { $annotation = new \Ytake\LaravelAspect\Annotation; $annotation->registerAspectAnnotations(); - /** @var \Ytake\LaravelAspect\GoAspect $aspect */ - $aspect = $this->manager->driver('go'); - $aspect->register(); + $aspect = $this->app['aspect.manager']->driver('ray'); + $aspect->register(\__Test\CacheEvictModule::class); + $aspect->register(\__Test\CacheableModule::class); } } diff --git a/tests/CachePutTest.php b/tests/CachePutTest.php index ddf80f9..3846988 100644 --- a/tests/CachePutTest.php +++ b/tests/CachePutTest.php @@ -14,12 +14,9 @@ protected function setUp() $this->resolveManager(); } - /** - * @runInSeparateProcess - */ public function testCachePutReturnUpdatedValue() { - $cache = new \__Test\AspectCachePut; + $cache = $this->app->make(\__Test\AspectCachePut::class); $this->app['cache']->add('singleKey:1000', 1, 120); $result = $cache->singleKey(1000); $this->assertSame(1000, $result); @@ -27,12 +24,11 @@ public function testCachePutReturnUpdatedValue() } /** - * @runInSeparateProcess * @expectedException \InvalidArgumentException */ public function testCacheableGenerateCacheNameSingleKey() { - $cache = new \__Test\AspectCachePut; + $cache = $this->app->make(\__Test\AspectCachePut::class); $cache->throwExceptionCache(); } @@ -43,8 +39,7 @@ protected function resolveManager() { $annotation = new \Ytake\LaravelAspect\Annotation; $annotation->registerAspectAnnotations(); - /** @var \Ytake\LaravelAop\GoAspect $aspect */ - $aspect = $this->manager->driver('go'); - $aspect->register(); + $aspect = $this->manager->driver('ray'); + $aspect->register(\__Test\CachePutModule::class); } } diff --git a/tests/CacheableTest.php b/tests/CacheableTest.php index 42e6335..f9553a7 100644 --- a/tests/CacheableTest.php +++ b/tests/CacheableTest.php @@ -14,56 +14,41 @@ protected function setUp() $this->resolveManager(); } - /** - * @runInSeparateProcess - */ public function testCacheableGenerateCacheNameSingleKey() { - $cache = new \__Test\AspectCacheable; + $cache = $this->app->make(\__Test\AspectCacheable::class); $result = $cache->singleKey(1000); $this->assertSame(1000, $result); $this->assertSame(1000, $this->app['cache']->get('singleKey:1000')); } - /** - * @runInSeparateProcess - */ public function testCacheableGenerateCacheNameMultipleKey() { - $cache = new \__Test\AspectCacheable; + $cache = $this->app->make(\__Test\AspectCacheable::class); $result = $cache->multipleKey(1000, 'testing'); $this->assertSame(1000, $result); $this->assertSame(1000, $this->app['cache']->get('multipleKey:1000:testing')); } - /** - * @runInSeparateProcess - */ public function testCacheableCacheNameMultipleKey() { - $cache = new \__Test\AspectCacheable; + $cache = $this->app->make(\__Test\AspectCacheable::class); $result = $cache->namedMultipleKey(1000, 'testing'); $this->assertSame(1000, $result); $this->assertSame(1000, $this->app['cache']->get('testing1:1000:testing')); } - /** - * @runInSeparateProcess - */ public function testCacheableCacheNameMultipleNameAndKey() { - $cache = new \__Test\AspectCacheable; + $cache = $this->app->make(\__Test\AspectCacheable::class); $result = $cache->namedMultipleNameAndKey(1000, 'testing'); $this->assertSame(1000, $result); $this->assertSame(1000, $this->app['cache']->tags(['testing1', 'testing2'])->get('namedMultipleNameAndKey:1000:testing')); } - /** - * @runInSeparateProcess - */ public function testCacheableCacheObject() { - $cache = new \__Test\AspectCacheable; + $cache = $this->app->make(\__Test\AspectCacheable::class); $class = new \stdClass; $class->title = 'testing'; $result = $cache->cachingKeyObject(1000, $class); @@ -77,7 +62,7 @@ protected function resolveManager() { $annotation = new \Ytake\LaravelAspect\Annotation; $annotation->registerAspectAnnotations(); - $aspect = $this->manager->driver('go'); - $aspect->register(); + $aspect = $this->manager->driver('ray'); + $aspect->register(\__Test\CacheableModule::class); } } diff --git a/tests/Commands/AspectClearCacheCommandTest.php b/tests/Commands/AspectClearCacheCommandTest.php index c49050b..7f4b24f 100644 --- a/tests/Commands/AspectClearCacheCommandTest.php +++ b/tests/Commands/AspectClearCacheCommandTest.php @@ -21,12 +21,9 @@ protected function setUp() $this->command->setLaravel(new MockApplication()); } - /** - * @runInSeparateProcess - */ public function testCacheClearFile() { - $cache = new \__Test\AspectCacheable; + $cache = $this->app->make(\__Test\AspectCacheable::class); $cache->namedMultipleNameAndKey(1000, 'testing'); $output = new \Symfony\Component\Console\Output\BufferedOutput(); @@ -34,12 +31,12 @@ public function testCacheClearFile() new \Symfony\Component\Console\Input\ArrayInput([]), $output ); - $this->assertSame('aspect/annotation cache clear!', trim($output->fetch())); + $this->assertSame('aspect code cache clear!', trim($output->fetch())); $configure = $this->app['config']->get('ytake-laravel-aop'); - $driverConfig = $configure['aop'][$configure['default']]; - if(isset($driverConfig['cacheDir'])) { - $files = $this->app['filesystem']->files($driverConfig['cacheDir']); + $driverConfig = $configure['aspect']['drivers'][$configure['aspect']['default']]; + if (isset($driverConfig['cache_dir'])) { + $files = $this->app['filesystem']->files($driverConfig['cache_dir']); $this->assertCount(0, $files); } } @@ -51,9 +48,8 @@ protected function resolveManager() { $annotation = new \Ytake\LaravelAspect\Annotation; $annotation->registerAspectAnnotations(); - /** @var \Ytake\LaravelAspect\GoAspect $aspect */ - $aspect = $this->manager->driver('go'); - $aspect->register(); + $aspect = $this->manager->driver('ray'); + $aspect->register(\__Test\CacheableModule::class); } protected function tearDown() @@ -78,6 +74,7 @@ public function version() * Get or check the current application environment. * * @param mixed + * * @return string */ public function environment() @@ -111,6 +108,7 @@ public function registerConfiguredProviders() * @param \Illuminate\Support\ServiceProvider|string $provider * @param array $options * @param bool $force + * * @return \Illuminate\Support\ServiceProvider */ public function register($provider, $options = [], $force = false) @@ -123,6 +121,7 @@ public function register($provider, $options = [], $force = false) * * @param string $provider * @param string $service + * * @return void */ public function registerDeferredProvider($provider, $service = null) @@ -144,6 +143,7 @@ public function boot() * Register a new boot listener. * * @param mixed $callback + * * @return void */ public function booting($callback) @@ -155,6 +155,7 @@ public function booting($callback) * Register a new "booted" listener. * * @param mixed $callback + * * @return void */ public function booted($callback) diff --git a/tests/TestCase.php b/tests/TestCase.php index 220c4b1..226b5bc 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -2,9 +2,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\DatabaseManager; -use Illuminate\Database\Eloquent\QueueEntityResolver; use Illuminate\Database\Connectors\ConnectionFactory; -use Illuminate\Database\Eloquent\Factory as EloquentFactory; class TestCase extends \PHPUnit_Framework_TestCase { @@ -61,6 +59,13 @@ protected function registerCache() }); } + protected function registerAnnotationReader() + { + $this->app->singleton('aspect.annotation.reader', function ($app) { + return (new \Ytake\LaravelAspect\AnnotationManager($app))->getReader(); + }); + } + protected function createApplicationContainer() { $this->app = new \Illuminate\Container\Container; @@ -70,11 +75,23 @@ protected function createApplicationContainer() $this->registerConfigure(); $this->registerDatabase(); $this->registerCache(); + $this->registerAnnotationReader(); + $this->app->singleton('aspect.manager', function ($app) { + return new \Ytake\LaravelAspect\AspectManager($app); + }); + $this->app->bind( + \Illuminate\Container\Container::class, + function () { + return $this->app; + } + ); + \Illuminate\Container\Container::setInstance($this->app); } protected function tearDown() { - $this->app['filesystem']->deleteDirectory(__DIR__ . '/storage'); + // $this->app['filesystem']->cleanDirectory(__DIR__ . '/storage/aop'); + // $this->app['filesystem']->cleanDirectory(__DIR__ . '/storage/annotation'); $this->app = null; } } diff --git a/tests/TransactionalTest.php b/tests/TransactionalTest.php index 960517c..a748451 100644 --- a/tests/TransactionalTest.php +++ b/tests/TransactionalTest.php @@ -15,24 +15,20 @@ protected function setUp() $this->resolveManager(); } - /** - * @runInSeparateProcess - */ public function testTransactionalAssertString() { - $transactional = new \__Test\AspectTransactionalString; + $transactional = $this->app->make(\__Test\AspectTransactionalString::class); $this->assertContains('testing', $transactional->start()); } - /** - * @runInSeparateProcess - */ public function testTransactionalDatabase() { - $transactional = new \__Test\AspectTransactionalDatabase($this->app['db']); + $this->app->bind(\__Test\AspectTransactionalDatabase::class, function () { + return new \__Test\AspectTransactionalDatabase($this->app['db']); + }); + $transactional = $this->app->make(\__Test\AspectTransactionalDatabase::class); $this->assertInternalType('array', $transactional->start()); $this->assertInstanceOf('stdClass', $transactional->start()[0]); - } /** @@ -42,8 +38,7 @@ protected function resolveManager() { $annotation = new \Ytake\LaravelAspect\Annotation; $annotation->registerAspectAnnotations(); - /** @var \Ytake\LaravelAspect\GoAspect $aspect */ - $aspect = $this->manager->driver('go'); - $aspect->register(); + $aspect = $this->manager->driver('ray'); + $aspect->register(\__Test\TransactionalModule::class); } } diff --git a/tests/config/ytake-laravel-aop.php b/tests/config/ytake-laravel-aop.php index 10f55db..1abc946 100644 --- a/tests/config/ytake-laravel-aop.php +++ b/tests/config/ytake-laravel-aop.php @@ -1,50 +1,42 @@ - * @license http://opensource.org/licenses/MIT MIT - */ return [ - /** - * choose aop library - * "go"(go-aop), "none"(for testing) - * - * @see https://github.com/goaop/framework - */ - 'default' => 'go', - /** - * - */ - 'aop' => [ - 'go' => [ - // boolean Determines whether or not kernel is in debug mode - 'debug' => true, - // string Path to the application root directory. - 'appDir' => __DIR__ . '/../src', - // string Path to the cache directory where compiled classes will be stored - 'cacheDir' => __DIR__ . '/../storage', - // integer Binary mask of features - // 'features' => 0, - // array WhiteList of directories where aspects should be applied. Empty for everywhere. - 'includePaths' => [ - __DIR__ . '/../src', + 'aspect' => [ + /** + * choose aop library + * "ray"(Ray.Aop), "none"(for testing) + */ + 'default' => 'ray', + + /** + * + */ + 'drivers' => [ + 'ray' => [ + // string Path to the cache directory where compiled classes will be stored + 'cache_dir' => __DIR__ . '/../storage/aop', + ], + 'none' => [ + // for testing driver + // no use aspect + ] + ], + ], + + 'annotation' => [ + /** + * choose annotation reader + * 'array'(default), 'file'(file cache) + */ + 'default' => 'array', + + 'drivers' => [ + 'file' => [ + 'cache_dir' => __DIR__ . '/../storage/annotation', + // + 'debug' => true, ], - // array BlackList of directories or files where aspects shouldn't be applied. - // 'excludePaths' => [] ], - 'none' => [ - // for testing driver - // no use aspect - ] ], ]; diff --git a/tests/helper.php b/tests/helper.php new file mode 100644 index 0000000..c64cd1b --- /dev/null +++ b/tests/helper.php @@ -0,0 +1,21 @@ +make($make, $parameters); + } +} diff --git a/tests/src/AspectTransactionalString.php b/tests/src/AspectTransactionalString.php index c2c56de..1b9207b 100644 --- a/tests/src/AspectTransactionalString.php +++ b/tests/src/AspectTransactionalString.php @@ -5,12 +5,10 @@ namespace __Test; -use Ytake\Lom\Meta\NoArgsConstructor; use Ytake\LaravelAspect\Annotation\Transactional; /** * Class AspectTransactional - * @NoArgsConstructor * @package Test */ class AspectTransactionalString diff --git a/tests/src/CacheEvictModule.php b/tests/src/CacheEvictModule.php new file mode 100644 index 0000000..b977c7d --- /dev/null +++ b/tests/src/CacheEvictModule.php @@ -0,0 +1,13 @@ +