From c3597cbc33896bd39880ee6ec6068c32b041c527 Mon Sep 17 00:00:00 2001 From: Serge Smertin Date: Wed, 20 Jun 2012 03:38:05 +0300 Subject: [PATCH 1/2] added proxy matcher --- .../Compiler/PointcutMatchingPass.php | 13 ++--- Proxy/ProxyMatcher.php | 51 ++++++++++++++++++ Proxy/ProxyPromise.php | 27 ++++++++++ Resources/config/services.xml | 5 ++ Tests/bootstrap.php | 15 ++++++ phpunit.xml.dist | 52 +++++++++---------- 6 files changed, 129 insertions(+), 34 deletions(-) create mode 100644 Proxy/ProxyMatcher.php create mode 100644 Proxy/ProxyPromise.php create mode 100644 Tests/bootstrap.php diff --git a/DependencyInjection/Compiler/PointcutMatchingPass.php b/DependencyInjection/Compiler/PointcutMatchingPass.php index 51967a6..5eb5695 100644 --- a/DependencyInjection/Compiler/PointcutMatchingPass.php +++ b/DependencyInjection/Compiler/PointcutMatchingPass.php @@ -40,7 +40,6 @@ class PointcutMatchingPass implements CompilerPassInterface { private $pointcuts; - private $cacheDir; private $container; public function __construct(array $pointcuts = null) @@ -51,7 +50,6 @@ public function __construct(array $pointcuts = null) public function process(ContainerBuilder $container) { $this->container = $container; - $this->cacheDir = $container->getParameter('jms_aop.cache_dir').'/proxies'; $pointcuts = $this->getPointcuts(); $interceptors = array(); @@ -150,12 +148,11 @@ private function processDefinition(Definition $definition, $pointcuts, &$interce if ($file) { $generator->setRequiredFile($file); } - $enhancer = new Enhancer($class, array(), array( - $generator - )); - $enhancer->writeClass($filename = $this->cacheDir.'/'.str_replace('\\', '-', $class->name).'.php'); - $definition->setFile($filename); - $definition->setClass($enhancer->getClassName($class)); + + $matcher = $this->container->get('jms_aop.proxy_matcher'); + $proxy = $matcher->getEnhanced($definition); + $proxy->addGenerator($generator); + $definition->addMethodCall('__CGInterception__setLoader', array( new Reference('jms_aop.interceptor_loader') )); diff --git a/Proxy/ProxyMatcher.php b/Proxy/ProxyMatcher.php new file mode 100644 index 0000000..af5b4a1 --- /dev/null +++ b/Proxy/ProxyMatcher.php @@ -0,0 +1,51 @@ +cacheDir = $cacheDir; + $this->storage = new \SplObjectStorage(); + } + + /** + * @param Definition $definition + * @return ProxyPromise + */ + public function getEnhanced(Definition $definition) + { + $promise = new ProxyPromise($this); + $this->storage[$definition] = $promise; + return $promise; + } + + public function writeProxyFiles() + { + foreach($this->storage as $definition => $promise) { + $class = new \ReflectionClass($definition->getClass()); + $enhancer = $promise->getEnhancer($class); + + $filename = $this->cacheDir.'/'.str_replace('\\', '-', $class->name).'.php'; + $proxyClassName = $enhancer->getClassName($class); + + $enhancer->writeClass($filename); + $definition->setFile($filename); + $definition->setClass($proxyClassName); + } + } +} diff --git a/Proxy/ProxyPromise.php b/Proxy/ProxyPromise.php new file mode 100644 index 0000000..b0f158d --- /dev/null +++ b/Proxy/ProxyPromise.php @@ -0,0 +1,27 @@ +generators[] = $generator; + } + + public function getEnhancer(ReflectionClass $class) + { + return new Enhancer($class, array(), $this->generators); + } +} diff --git a/Resources/config/services.xml b/Resources/config/services.xml index c1caed4..fb4c855 100644 --- a/Resources/config/services.xml +++ b/Resources/config/services.xml @@ -6,6 +6,7 @@ JMS\AopBundle\Aop\InterceptorLoader + JMS\AopBundle\Proxy\ProxyMatcher @@ -14,5 +15,9 @@ + + + %jms_aop.cache_dir%/proxies + diff --git a/Tests/bootstrap.php b/Tests/bootstrap.php new file mode 100644 index 0000000..2634e18 --- /dev/null +++ b/Tests/bootstrap.php @@ -0,0 +1,15 @@ + - - - - - - ./Tests - - - - - - performance - - - + + + + + + + ./Tests + + + + + + performance + + + From 35e6eed48cf5cf30b5a037b8563c616b7091f0da Mon Sep 17 00:00:00 2001 From: Serge Smertin Date: Wed, 20 Jun 2012 04:27:08 +0300 Subject: [PATCH 2/2] finished proxy matching feature and added tests to support this concept --- .../Compiler/WriteProxiesPass.php | 18 +++++ JMSAopBundle.php | 2 + Proxy/ProxyMatcher.php | 8 +- .../Compiler/PointcutMatchingPassTest.php | 6 +- Tests/Proxy/Fixture/AnotherPass.php | 26 +++++++ Tests/Proxy/Fixture/FirstPass.php | 26 +++++++ Tests/Proxy/Fixture/SomeGenerator.php | 34 ++++++++ Tests/Proxy/Fixture/TestService.php | 16 ++++ Tests/Proxy/ProxyMatcherTest.php | 78 +++++++++++++++++++ 9 files changed, 212 insertions(+), 2 deletions(-) create mode 100644 DependencyInjection/Compiler/WriteProxiesPass.php create mode 100644 Tests/Proxy/Fixture/AnotherPass.php create mode 100644 Tests/Proxy/Fixture/FirstPass.php create mode 100644 Tests/Proxy/Fixture/SomeGenerator.php create mode 100644 Tests/Proxy/Fixture/TestService.php create mode 100644 Tests/Proxy/ProxyMatcherTest.php diff --git a/DependencyInjection/Compiler/WriteProxiesPass.php b/DependencyInjection/Compiler/WriteProxiesPass.php new file mode 100644 index 0000000..dac11fa --- /dev/null +++ b/DependencyInjection/Compiler/WriteProxiesPass.php @@ -0,0 +1,18 @@ +get('jms_aop.proxy_matcher'); + $matcher->writeProxyFiles(); + } +} diff --git a/JMSAopBundle.php b/JMSAopBundle.php index 5bf3c35..0673fe6 100644 --- a/JMSAopBundle.php +++ b/JMSAopBundle.php @@ -20,6 +20,7 @@ use Symfony\Component\DependencyInjection\Compiler\PassConfig; use JMS\AopBundle\DependencyInjection\Compiler\PointcutMatchingPass; +use JMS\AopBundle\DependencyInjection\Compiler\WriteProxiesPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; @@ -30,5 +31,6 @@ class JMSAopBundle extends Bundle public function build(ContainerBuilder $container) { $container->addCompilerPass(new PointcutMatchingPass(), PassConfig::TYPE_AFTER_REMOVING); + $container->addCompilerPass(new WriteProxiesPass(), PassConfig::TYPE_AFTER_REMOVING); } } diff --git a/Proxy/ProxyMatcher.php b/Proxy/ProxyMatcher.php index af5b4a1..a7965ef 100644 --- a/Proxy/ProxyMatcher.php +++ b/Proxy/ProxyMatcher.php @@ -29,6 +29,10 @@ public function __construct($cacheDir) */ public function getEnhanced(Definition $definition) { + if (isset($this->storage[$definition])) { + return $this->storage[$definition]; + } + $promise = new ProxyPromise($this); $this->storage[$definition] = $promise; return $promise; @@ -36,7 +40,9 @@ public function getEnhanced(Definition $definition) public function writeProxyFiles() { - foreach($this->storage as $definition => $promise) { + foreach($this->storage as $definition) { + $promise = $this->storage[$definition]; + $class = new \ReflectionClass($definition->getClass()); $enhancer = $promise->getEnhancer($class); diff --git a/Tests/DependencyInjection/Compiler/PointcutMatchingPassTest.php b/Tests/DependencyInjection/Compiler/PointcutMatchingPassTest.php index b75151c..6ae0079 100644 --- a/Tests/DependencyInjection/Compiler/PointcutMatchingPassTest.php +++ b/Tests/DependencyInjection/Compiler/PointcutMatchingPassTest.php @@ -22,7 +22,8 @@ use Symfony\Component\DependencyInjection\Compiler\ResolveParameterPlaceHoldersPass; use JMS\AopBundle\DependencyInjection\JMSAopExtension; use JMS\AopBundle\DependencyInjection\Compiler\PointcutMatchingPass; -use Symfony\Component\HttpKernel\Util\Filesystem; +use JMS\AopBundle\DependencyInjection\Compiler\WriteProxiesPass; +use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\DependencyInjection\ContainerBuilder; class PointcutMatchingPassTest extends \PHPUnit_Framework_TestCase @@ -92,5 +93,8 @@ private function process(ContainerBuilder $container) $pass = new PointcutMatchingPass(); $pass->process($container); + + $pass = new WriteProxiesPass(); + $pass->process($container); } } \ No newline at end of file diff --git a/Tests/Proxy/Fixture/AnotherPass.php b/Tests/Proxy/Fixture/AnotherPass.php new file mode 100644 index 0000000..efc571c --- /dev/null +++ b/Tests/Proxy/Fixture/AnotherPass.php @@ -0,0 +1,26 @@ +get('jms_aop.proxy_matcher'); + $generator = new SomeGenerator($methodName); + + $definition = $container->getDefinition('test'); + + $proxy = $matcher->getEnhanced($definition); + $proxy->addGenerator($generator); + $definition->addMethodCall($methodName); + } +} \ No newline at end of file diff --git a/Tests/Proxy/Fixture/FirstPass.php b/Tests/Proxy/Fixture/FirstPass.php new file mode 100644 index 0000000..349b47a --- /dev/null +++ b/Tests/Proxy/Fixture/FirstPass.php @@ -0,0 +1,26 @@ +get('jms_aop.proxy_matcher'); + $generator = new SomeGenerator($methodName); + + $definition = $container->getDefinition('test'); + + $proxy = $matcher->getEnhanced($definition); + $proxy->addGenerator($generator); + $definition->addMethodCall($methodName); + } +} \ No newline at end of file diff --git a/Tests/Proxy/Fixture/SomeGenerator.php b/Tests/Proxy/Fixture/SomeGenerator.php new file mode 100644 index 0000000..5bab437 --- /dev/null +++ b/Tests/Proxy/Fixture/SomeGenerator.php @@ -0,0 +1,34 @@ +methodName = $methodName; + } + + /** + * Generates the necessary changes in the class. + * + * @param \ReflectionClass $originalClass + * @param PhpClass $generatedClass The generated class + * @return void + */ + function generate(\ReflectionClass $originalClass, PhpClass $generatedClass) + { + $method = PhpMethod::create($this->methodName) + ->setBody("\$this->things[] = '{$this->methodName}';"); + $generatedClass->setMethod($method); + } +} diff --git a/Tests/Proxy/Fixture/TestService.php b/Tests/Proxy/Fixture/TestService.php new file mode 100644 index 0000000..fd9257b --- /dev/null +++ b/Tests/Proxy/Fixture/TestService.php @@ -0,0 +1,16 @@ +things; + } +} diff --git a/Tests/Proxy/ProxyMatcherTest.php b/Tests/Proxy/ProxyMatcherTest.php new file mode 100644 index 0000000..b6bf3ab --- /dev/null +++ b/Tests/Proxy/ProxyMatcherTest.php @@ -0,0 +1,78 @@ +getContainer(); + $container->register('test', 'JMS\AopBundle\Tests\Proxy\Fixture\TestService'); + + $this->process($container); + + $service = $container->get('test'); + $this->assertInstanceOf('JMS\AopBundle\Tests\Proxy\Fixture\TestService', $service); + + $this->assertEquals(array('__fistPassMethod', '__ultimatelyAnotherMethod'), $service->getThings()); + } + + protected function setUp() + { + $this->cacheDir = sys_get_temp_dir() . '/jms_aop_test'; + $this->fs = new Filesystem(); + + if (is_dir($this->cacheDir)) { + $this->fs->remove($this->cacheDir); + } + + if (false === @mkdir($this->cacheDir, 0777, true)) { + throw new RuntimeException(sprintf('Could not create cache dir "%s".', $this->cacheDir)); + } + } + + protected function tearDown() + { + $this->fs->remove($this->cacheDir); + } + + private function getContainer() + { + $container = new ContainerBuilder(); + + $extension = new JMSAopExtension(); + $extension->load(array(array('cache_dir' => $this->cacheDir)), $container); + + return $container; + } + + private function process(ContainerBuilder $container) + { + $pass = new ResolveParameterPlaceHoldersPass(); + $pass->process($container); + + $pass = new FirstPass(); + $pass->process($container); + + $pass = new AnotherPass(); + $pass->process($container); + + $pass = new WriteProxiesPass(); + $pass->process($container); + } +}