From 4e707484f8b8e5f27e449deaa7f17589214c94ba Mon Sep 17 00:00:00 2001 From: Eric GELOEN Date: Sat, 11 Feb 2017 22:51:45 +0100 Subject: [PATCH] Add event support --- .../Compiler/RegisterListenerPass.php | 29 +++++++ DependencyInjection/Configuration.php | 14 ++++ .../IvorySerializerExtension.php | 25 ++++++ IvorySerializerBundle.php | 2 + README.md | 1 + Resources/config/event.xml | 28 +++++++ Resources/config/navigator.xml | 2 +- Resources/doc/configuration/event.md | 67 +++++++++++++++ Resources/doc/configuration/index.md | 1 + .../AbstractIvorySerializerExtensionTest.php | 23 ++++- Tests/Fixtures/Config/Yaml/event_disabled.yml | 3 + Tests/IvorySerializerBundleTest.php | 84 ------------------- 12 files changed, 192 insertions(+), 87 deletions(-) create mode 100644 DependencyInjection/Compiler/RegisterListenerPass.php create mode 100644 Resources/config/event.xml create mode 100644 Resources/doc/configuration/event.md create mode 100644 Tests/Fixtures/Config/Yaml/event_disabled.yml delete mode 100644 Tests/IvorySerializerBundleTest.php diff --git a/DependencyInjection/Compiler/RegisterListenerPass.php b/DependencyInjection/Compiler/RegisterListenerPass.php new file mode 100644 index 0000000..c1d61ce --- /dev/null +++ b/DependencyInjection/Compiler/RegisterListenerPass.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. + */ + +namespace Ivory\SerializerBundle\DependencyInjection\Compiler; + +use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass as AbstractRegisterListenerPass; + +/** + * @author GeLo + */ +class RegisterListenerPass extends AbstractRegisterListenerPass +{ + public function __construct() + { + parent::__construct( + 'ivory.serializer.event.dispatcher', + 'ivory.serializer.listener', + 'ivory.serializer.subscriber' + ); + } +} diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 1c3c826..751fb41 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -15,6 +15,7 @@ use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; +use Symfony\Component\EventDispatcher\EventDispatcher; /** * @author GeLo @@ -29,6 +30,7 @@ public function getConfigTreeBuilder() $treeBuilder = $this->createTreeBuilder(); $treeBuilder->root('ivory_serializer') ->children() + ->append($this->createEventNode()) ->append($this->createMappingNode()) ->append($this->createTypesNode()) ->append($this->createVisitorsNode()); @@ -74,6 +76,18 @@ private function createMappingNode() ->end(); } + /** + * @return ArrayNodeDefinition + */ + private function createEventNode() + { + return $this->createNode('event') + ->addDefaultsIfNotSet() + ->children() + ->booleanNode('enabled')->defaultValue(class_exists(EventDispatcher::class))->end() + ->end(); + } + /** * @return ArrayNodeDefinition */ diff --git a/DependencyInjection/IvorySerializerExtension.php b/DependencyInjection/IvorySerializerExtension.php index 25ba205..5ddd511 100644 --- a/DependencyInjection/IvorySerializerExtension.php +++ b/DependencyInjection/IvorySerializerExtension.php @@ -40,6 +40,7 @@ protected function loadInternal(array $config, ContainerBuilder $container) $resources = [ 'cache', 'common', + 'event', 'fos', 'mapping', 'navigator', @@ -54,6 +55,7 @@ protected function loadInternal(array $config, ContainerBuilder $container) } $this->loadCache($config, $container); + $this->loadEvent($config['event'], $container); $this->loadMapping($config['mapping'], $container); $this->loadTypes($config['types'], $container); $this->loadVisitors($config['visitors'], $container); @@ -75,6 +77,29 @@ private function loadCache(array $config, ContainerBuilder $container) ->addArgument($cache); } + /** + * @param mixed[] $config + * @param ContainerBuilder $container + */ + private function loadEvent(array $config, ContainerBuilder $container) + { + if ($config['enabled']) { + $container + ->getDefinition('ivory.serializer.mapping.factory') + ->replaceArgument(0, new Reference('ivory.serializer.mapping.factory.event')); + + $container->setAlias('ivory.serializer.navigator', 'ivory.serializer.navigator.event'); + + return; + } + + $container->removeDefinition('ivory.serializer.event.dispatcher'); + $container->removeDefinition('ivory.serializer.mapping.factory.event'); + $container->removeDefinition('ivory.serializer.navigator.event'); + + $container->setAlias('ivory.serializer.navigator', 'ivory.serializer.navigator.default'); + } + /** * @param mixed[] $config * @param ContainerBuilder $container diff --git a/IvorySerializerBundle.php b/IvorySerializerBundle.php index 9ea76f6..0187b87 100644 --- a/IvorySerializerBundle.php +++ b/IvorySerializerBundle.php @@ -13,6 +13,7 @@ use Ivory\SerializerBundle\DependencyInjection\Compiler\RegisterClassMetadataLoaderPass; use Ivory\SerializerBundle\DependencyInjection\Compiler\RegisterFOSServicePass; +use Ivory\SerializerBundle\DependencyInjection\Compiler\RegisterListenerPass; use Ivory\SerializerBundle\DependencyInjection\Compiler\RegisterTypePass; use Ivory\SerializerBundle\DependencyInjection\Compiler\RegisterVisitorPass; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -30,6 +31,7 @@ public function build(ContainerBuilder $container) { $container ->addCompilerPass(new RegisterClassMetadataLoaderPass()) + ->addCompilerPass(new RegisterListenerPass()) ->addCompilerPass(new RegisterFOSServicePass()) ->addCompilerPass(new RegisterTypePass()) ->addCompilerPass(new RegisterVisitorPass()); diff --git a/README.md b/README.md index 75905c6..42a3a92 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ $deserialize = $serializer->deserialize($json, \stdClass::class, Format::JSON); - [Configuration](/Resources/doc/configuration/index.md) - [Mapping](/Resources/doc/configuration/mapping.md) - [Type](/Resources/doc/configuration/type.md) + - [Event](/Resources/doc/configuration/event.md) - [Visitor](/Resources/doc/configuration/visitor.md) - [Cache](/Resources/doc/configuration/cache.md) - [FOSRestBundle Integration](/Resources/doc/configuration/fos_rest.md) diff --git a/Resources/config/event.xml b/Resources/config/event.xml new file mode 100644 index 0000000..58710ef --- /dev/null +++ b/Resources/config/event.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + diff --git a/Resources/config/navigator.xml b/Resources/config/navigator.xml index 44e9f3c..b6d8cb1 100644 --- a/Resources/config/navigator.xml +++ b/Resources/config/navigator.xml @@ -7,7 +7,7 @@ http://symfony.com/schema/dic/services/services-1.0.xsd" > - + diff --git a/Resources/doc/configuration/event.md b/Resources/doc/configuration/event.md new file mode 100644 index 0000000..9541e2b --- /dev/null +++ b/Resources/doc/configuration/event.md @@ -0,0 +1,67 @@ +# Event + +The bundle supports events and allows you to hook into the (de)-serialization process. If you want to learn more about +the supported events, you can read this [documentation](https://github.com/egeloen/ivory-serializer/blob/master/doc/event.md). + +## Register a listener + +In order to register a listener on the event dispatcher, you need to use the `ivory.serializer.listener` tag as well +as the `event` and `method` attributes: + +``` xml + + + + + + + + + +``` + +## Register a subscriber + +To register a subscriber on the event dispatcher, you need to use the `ivory.serializer.subscriber` tag: + +``` xml + + + + + + + + + +``` + +## Disable Events + +If you don't use events, we recommend you to disable it since it adds some overhead: + +``` yaml +ivory_serializer: + event: + enabled: false +``` diff --git a/Resources/doc/configuration/index.md b/Resources/doc/configuration/index.md index dfa22bc..8f0de9e 100644 --- a/Resources/doc/configuration/index.md +++ b/Resources/doc/configuration/index.md @@ -4,6 +4,7 @@ The configuration allows you to set up the serializer the way you want instead o - [Mapping](/Resources/doc/configuration/mapping.md) - [Types](/Resources/doc/configuration/types.md) + - [Visitors](/Resources/doc/configuration/visitors.md) - [Cache](/Resources/doc/configuration/cache.md) - [FOSRestBundle Integration](/Resources/doc/configuration/fos_rest.md) diff --git a/Tests/DependencyInjection/AbstractIvorySerializerExtensionTest.php b/Tests/DependencyInjection/AbstractIvorySerializerExtensionTest.php index 96741a3..13f1c5c 100644 --- a/Tests/DependencyInjection/AbstractIvorySerializerExtensionTest.php +++ b/Tests/DependencyInjection/AbstractIvorySerializerExtensionTest.php @@ -204,7 +204,7 @@ public function testMappingCache() $classMetadataFactoryDefinition = $this->container->getDefinition($classMetadataFactoryService); $this->assertSame( - 'ivory.serializer.mapping.factory.default', + 'ivory.serializer.mapping.factory.event', (string) $classMetadataFactoryDefinition->getArgument(0) ); @@ -227,7 +227,7 @@ public function testCustomMappingCache() $classMetadataFactoryDefinition = $this->container->getDefinition($classMetadataFactoryService); $this->assertSame( - 'ivory.serializer.mapping.factory.default', + 'ivory.serializer.mapping.factory.event', (string) $classMetadataFactoryDefinition->getArgument(0) ); @@ -257,6 +257,25 @@ public function testCacheWarmer() ); } + public function testEventEnabled() + { + $this->container->compile(); + + $this->assertTrue($this->container->has('ivory.serializer.event.dispatcher')); + $this->assertTrue($this->container->has('ivory.serializer.mapping.factory.event')); + $this->assertTrue($this->container->has('ivory.serializer.navigator.event')); + } + + public function testEventDisabled() + { + $this->loadConfiguration($this->container, 'event_disabled'); + $this->container->compile(); + + $this->assertFalse($this->container->has('ivory.serializer.event.dispatcher')); + $this->assertFalse($this->container->has('ivory.serializer.mapping.factory.event')); + $this->assertFalse($this->container->has('ivory.serializer.navigator.event')); + } + public function testDateTimeType() { $this->loadConfiguration($this->container, 'type_date_time'); diff --git a/Tests/Fixtures/Config/Yaml/event_disabled.yml b/Tests/Fixtures/Config/Yaml/event_disabled.yml new file mode 100644 index 0000000..e4f9d71 --- /dev/null +++ b/Tests/Fixtures/Config/Yaml/event_disabled.yml @@ -0,0 +1,3 @@ +ivory_serializer: + event: + enabled: false diff --git a/Tests/IvorySerializerBundleTest.php b/Tests/IvorySerializerBundleTest.php deleted file mode 100644 index 786ccfb..0000000 --- a/Tests/IvorySerializerBundleTest.php +++ /dev/null @@ -1,84 +0,0 @@ - - * - * For the full copyright and license information, please read the LICENSE - * file that was distributed with this source code. - */ - -namespace Ivory\SerializerBundle\Tests; - -use Ivory\SerializerBundle\DependencyInjection\Compiler\RegisterClassMetadataLoaderPass; -use Ivory\SerializerBundle\DependencyInjection\Compiler\RegisterFOSServicePass; -use Ivory\SerializerBundle\DependencyInjection\Compiler\RegisterTypePass; -use Ivory\SerializerBundle\DependencyInjection\Compiler\RegisterVisitorPass; -use Ivory\SerializerBundle\IvorySerializerBundle; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\HttpKernel\Bundle\Bundle; - -/** - * @author GeLo - */ -class IvorySerializerBundleTest extends \PHPUnit_Framework_TestCase -{ - /** - * @var IvorySerializerBundle - */ - private $bundle; - - /** - * {@inheritdoc} - */ - protected function setUp() - { - $this->bundle = new IvorySerializerBundle(); - } - - public function testBundle() - { - $this->assertInstanceOf(Bundle::class, $this->bundle); - } - - public function testBuild() - { - $container = $this->createContainerBuilderMock(); - $container - ->expects($this->at(0)) - ->method('addCompilerPass') - ->with($this->isInstanceOf(RegisterClassMetadataLoaderPass::class)) - ->will($this->returnSelf()); - - $container - ->expects($this->at(1)) - ->method('addCompilerPass') - ->with($this->isInstanceOf(RegisterFOSServicePass::class)) - ->will($this->returnSelf()); - - $container - ->expects($this->at(2)) - ->method('addCompilerPass') - ->with($this->isInstanceOf(RegisterTypePass::class)) - ->will($this->returnSelf()); - - $container - ->expects($this->at(3)) - ->method('addCompilerPass') - ->with($this->isInstanceOf(RegisterVisitorPass::class)) - ->will($this->returnSelf()); - - $this->bundle->build($container); - } - - /** - * @return \PHPUnit_Framework_MockObject_MockObject|ContainerBuilder - */ - private function createContainerBuilderMock() - { - return $this->getMockBuilder(ContainerBuilder::class) - ->setMethods(['addCompilerPass']) - ->getMock(); - } -}