From 7fd57c946ac128fc7ba0272ab0edc279a0314cfe Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Tue, 16 May 2017 15:55:37 -0500 Subject: [PATCH 1/2] Ensure `filters` config is honored in non-zend-mvc contexts Per https://discourse.zendframework.com/t/validatormanager-not-calling-custom-validator-factory/109/5?u=matthew the `filters` config key is not honored currently unless the application is within a zend-mvc context. This is due to the fact that `Zend\Filter\Module` wires configuration for the `Zend\ModuleManager\Listener\ServiceListener` in order to push merged service configuration into the plugin during bootstrap; no similar logic is available when not in a zend-mvc context, however. This patch fixes that situation by modifying the `FilterPluginManagerFactory` to do the following: - If a `ServiceListener` service exists, it returns the plugin manager immediately (old behavior). - Otherwise, it checks for the `config` service, and, if found, a `filters` key with an array value. When found, it feeds that value to a `Zend\ServiceManager\Config` instance and uses that to configure the plugin manager before returning it. --- src/FilterPluginManagerFactory.php | 26 ++++++- test/FilterPluginManagerFactoryTest.php | 97 +++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 1 deletion(-) diff --git a/src/FilterPluginManagerFactory.php b/src/FilterPluginManagerFactory.php index 166cb057..de1cda92 100644 --- a/src/FilterPluginManagerFactory.php +++ b/src/FilterPluginManagerFactory.php @@ -8,6 +8,7 @@ namespace Zend\Filter; use Interop\Container\ContainerInterface; +use Zend\ServiceManager\Config; use Zend\ServiceManager\FactoryInterface; use Zend\ServiceManager\ServiceLocatorInterface; @@ -27,7 +28,30 @@ class FilterPluginManagerFactory implements FactoryInterface */ public function __invoke(ContainerInterface $container, $name, array $options = null) { - return new FilterPluginManager($container, $options ?: []); + $pluginManager = new FilterPluginManager($container, $options ?: []); + + // If this is in a zend-mvc application, the ServiceListener will inject + // merged configuration during bootstrap. + if ($container->has('ServiceListener')) { + return $pluginManager; + } + + // If we do not have a config service, nothing more to do + if (! $container->has('config')) { + return $pluginManager; + } + + $config = $container->get('config'); + + // If we do not have filters configuration, nothing more to do + if (! isset($config['filters']) || ! is_array($config['filters'])) { + return $pluginManager; + } + + // Wire service configuration for validators + (new Config($config['filters']))->configureServiceManager($pluginManager); + + return $pluginManager; } /** diff --git a/test/FilterPluginManagerFactoryTest.php b/test/FilterPluginManagerFactoryTest.php index 91f6057e..d4eb27b6 100644 --- a/test/FilterPluginManagerFactoryTest.php +++ b/test/FilterPluginManagerFactoryTest.php @@ -9,6 +9,8 @@ use Interop\Container\ContainerInterface; use PHPUnit_Framework_TestCase as TestCase; +use Zend\Filter\Boolean; +use Zend\Filter\FilterInterface; use Zend\Filter\FilterPluginManager; use Zend\Filter\FilterPluginManagerFactory; use Zend\ServiceManager\ServiceLocatorInterface; @@ -73,4 +75,99 @@ public function testFactoryConfiguresPluginManagerUnderServiceManagerV2() $filters = $factory->createService($container->reveal()); $this->assertSame($filter, $filters->get('test')); } + + public function testConfiguresFilterServicesWhenFound() + { + $filter = $this->prophesize(FilterInterface::class)->reveal(); + $config = [ + 'filters' => [ + 'aliases' => [ + 'test' => Boolean::class, + ], + 'factories' => [ + 'test-too' => function ($container) use ($filter) { + return $filter; + }, + ], + ], + ]; + + $container = $this->prophesize(ServiceLocatorInterface::class); + $container->willImplement(ContainerInterface::class); + + $container->has('ServiceListener')->willReturn(false); + $container->has('config')->willReturn(true); + $container->get('config')->willReturn($config); + + $factory = new FilterPluginManagerFactory(); + $filters = $factory($container->reveal(), 'FilterManager'); + + $this->assertInstanceOf(FilterPluginManager::class, $filters); + $this->assertTrue($filters->has('test')); + $this->assertInstanceOf(Boolean::class, $filters->get('test')); + $this->assertTrue($filters->has('test-too')); + $this->assertSame($filter, $filters->get('test-too')); + } + + public function testDoesNotConfigureFilterServicesWhenServiceListenerPresent() + { + $filter = $this->prophesize(FilterInterface::class)->reveal(); + $config = [ + 'filters' => [ + 'aliases' => [ + 'test' => Boolean::class, + ], + 'factories' => [ + 'test-too' => function ($container) use ($filter) { + return $filter; + }, + ], + ], + ]; + + $container = $this->prophesize(ServiceLocatorInterface::class); + $container->willImplement(ContainerInterface::class); + + $container->has('ServiceListener')->willReturn(true); + $container->has('config')->shouldNotBeCalled(); + $container->get('config')->shouldNotBeCalled(); + + $factory = new FilterPluginManagerFactory(); + $filters = $factory($container->reveal(), 'FilterManager'); + + $this->assertInstanceOf(FilterPluginManager::class, $filters); + $this->assertFalse($filters->has('test')); + $this->assertFalse($filters->has('test-too')); + } + + public function testDoesNotConfigureFilterServicesWhenConfigServiceNotPresent() + { + $container = $this->prophesize(ServiceLocatorInterface::class); + $container->willImplement(ContainerInterface::class); + + $container->has('ServiceListener')->willReturn(false); + $container->has('config')->willReturn(false); + $container->get('config')->shouldNotBeCalled(); + + $factory = new FilterPluginManagerFactory(); + $filters = $factory($container->reveal(), 'FilterManager'); + + $this->assertInstanceOf(FilterPluginManager::class, $filters); + } + + public function testDoesNotConfigureFilterServicesWhenConfigServiceDoesNotContainFiltersConfig() + { + $container = $this->prophesize(ServiceLocatorInterface::class); + $container->willImplement(ContainerInterface::class); + + $container->has('ServiceListener')->willReturn(false); + $container->has('config')->willReturn(true); + $container->get('config')->willReturn(['foo' => 'bar']); + + $factory = new FilterPluginManagerFactory(); + $filters = $factory($container->reveal(), 'FilterManager'); + + $this->assertInstanceOf(FilterPluginManager::class, $filters); + $this->assertFalse($filters->has('foo')); + } } From a0404b2198d1ab217f5233b47a1f18148c73fffc Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Wed, 17 May 2017 13:46:25 -0500 Subject: [PATCH 2/2] Added CHANGELOG for #56 --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16c4130d..de26c9fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,11 @@ All notable changes to this project will be documented in this file, in reverse ### Fixed -- Nothing. +- [#56](https://github.com/zendframework/zend-filter/pull/56) fixes how the + `FilterPluginManagerFactory` factory initializes the plugin manager instance, + ensuring it is injecting the relevant configuration from the `config` service + and thus seeding it with configured translator loader services. This means + that the `filters` configuration will now be honored in non-zend-mvc contexts. ## 2.7.1 - 2016-04-18