diff --git a/.travis.yml b/.travis.yml index 7d2515e4..faac7d4b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,11 +17,23 @@ matrix: - php: 5.5 env: - EXECUTE_CS_CHECK=true + - php: 5.5 + env: + - SERVICE_MANAGER_VERSION="^2.7.5" - php: 5.6 env: - EXECUTE_TEST_COVERALLS=true + - php: 5.6 + env: + - SERVICE_MANAGER_VERSION="^2.7.5" - php: 7 - - php: hhvm + - php: 7 + env: + - SERVICE_MANAGER_VERSION="^2.7.5" + - php: hhvm + - php: hhvm + env: + - SERVICE_MANAGER_VERSION="^2.7.5" allow_failures: - php: 7 @@ -33,9 +45,12 @@ before_install: - if [[ $EXECUTE_TEST_COVERALLS != 'true' ]]; then phpenv config-rm xdebug.ini || return 0 ; fi - composer self-update - if [[ $EXECUTE_TEST_COVERALLS == 'true' ]]; then composer require --dev --no-update satooshi/php-coveralls ; fi + - if [[ $SERVICE_MANAGER_VERSION != '' ]]; then composer require --dev --no-update "zendframework/zend-servicemanager:$SERVICE_MANAGER_VERSION" ; fi + - if [[ $SERVICE_MANAGER_VERSION == '' ]]; then composer require --dev --no-update "zendframework/zend-servicemanager:^3.0.3" ; fi install: - - travis_retry composer install --no-interaction --ignore-platform-reqs + - if [[ $SERVICE_MANAGER_V2 != 'true' ]]; then travis_retry composer install --no-interaction --ignore-platform-reqs ; fi + - if [[ $SERVICE_MANAGER_V2 == 'true' ]]; then travis_retry composer update --no-interaction --ignore-platform-reqs --prefer-lowest ; fi script: - if [[ $EXECUTE_TEST_COVERALLS == 'true' ]]; then ./vendor/bin/phpunit --coverage-clover clover.xml ; fi diff --git a/composer.json b/composer.json index 69a2694f..ef42126c 100644 --- a/composer.json +++ b/composer.json @@ -13,13 +13,13 @@ } }, "require": { - "php": ">=5.5", - "zendframework/zend-filter": "~2.5", - "zendframework/zend-validator": "^2.5.3", - "zendframework/zend-stdlib": "~2.5" + "php": "^5.5 || ^7.0", + "zendframework/zend-filter": "^2.6", + "zendframework/zend-validator": "^2.6", + "zendframework/zend-stdlib": "^2.7 || ^3.0" }, "require-dev": { - "zendframework/zend-servicemanager": "~2.5", + "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3", "fabpot/php-cs-fixer": "1.7.*", "phpunit/PHPUnit": "^4.5" }, diff --git a/src/Factory.php b/src/Factory.php index ecdb2299..5cfa614b 100644 --- a/src/Factory.php +++ b/src/Factory.php @@ -11,7 +11,7 @@ use Traversable; use Zend\Filter\FilterChain; -use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\ServiceManager\ServiceManager; use Zend\Stdlib\ArrayUtils; use Zend\Validator\ValidatorChain; use Zend\Validator\ValidatorInterface; @@ -117,15 +117,7 @@ public function clearDefaultValidatorChain() public function setInputFilterManager(InputFilterPluginManager $inputFilterManager) { $this->inputFilterManager = $inputFilterManager; - $serviceLocator = $this->inputFilterManager->getServiceLocator(); - if ($serviceLocator && $serviceLocator instanceof ServiceLocatorInterface) { - if ($serviceLocator->has('ValidatorManager')) { - $this->getDefaultValidatorChain()->setPluginManager($serviceLocator->get('ValidatorManager')); - } - if ($serviceLocator->has('FilterManager')) { - $this->getDefaultFilterChain()->setPluginManager($serviceLocator->get('FilterManager')); - } - } + $inputFilterManager->populateFactoryPluginManagers($this); return $this; } @@ -135,7 +127,7 @@ public function setInputFilterManager(InputFilterPluginManager $inputFilterManag public function getInputFilterManager() { if (null === $this->inputFilterManager) { - $this->inputFilterManager = new InputFilterPluginManager; + $this->inputFilterManager = new InputFilterPluginManager(new ServiceManager()); } return $this->inputFilterManager; diff --git a/src/InputFilterAbstractServiceFactory.php b/src/InputFilterAbstractServiceFactory.php index 5d8c5506..e91442d2 100644 --- a/src/InputFilterAbstractServiceFactory.php +++ b/src/InputFilterAbstractServiceFactory.php @@ -9,6 +9,7 @@ namespace Zend\InputFilter; +use Interop\Container\ContainerInterface; use Zend\Filter\FilterPluginManager; use Zend\ServiceManager\AbstractFactoryInterface; use Zend\ServiceManager\ServiceLocatorInterface; @@ -22,21 +23,34 @@ class InputFilterAbstractServiceFactory implements AbstractFactoryInterface protected $factory; /** - * @param ServiceLocatorInterface $inputFilters + * @param ContainerInterface $services + * @param string $rName + * @param array $options + * @return InputFilterInterface + */ + public function __invoke(ContainerInterface $services, $rName, array $options = null) + { + $allConfig = $services->get('config'); + $config = $allConfig['input_filter_specs'][$rName]; + $factory = $this->getInputFilterFactory($services); + + return $factory->createInputFilter($config); + } + + /** + * + * @param ContainerInterface $services * @param string $cName * @param string $rName * @return bool */ - public function canCreateServiceWithName(ServiceLocatorInterface $inputFilters, $cName, $rName) + public function canCreate(ContainerInterface $services, $rName) { - $services = $inputFilters->getServiceLocator(); - if (! $services instanceof ServiceLocatorInterface - || ! $services->has('Config') - ) { + if (! $services->has('config')) { return false; } - $config = $services->get('Config'); + $config = $services->get('config'); if (!isset($config['input_filter_specs'][$rName]) || !is_array($config['input_filter_specs'][$rName]) ) { @@ -46,6 +60,27 @@ public function canCreateServiceWithName(ServiceLocatorInterface $inputFilters, return true; } + /** + * Determine if we can create a service with name (v2) + * + * @param ServiceLocatorInterface $serviceLocator + * @param $name + * @param $requestedName + * @return bool + */ + public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName) + { + // v2 => need to get parent service locator + $services = $serviceLocator->getServiceLocator(); + + // No parent locator => cannot create service. + if (! $services) { + return false; + } + + return $this->canCreate($services, $requestedName); + } + /** * @param ServiceLocatorInterface $inputFilters * @param string $cName @@ -54,13 +89,15 @@ public function canCreateServiceWithName(ServiceLocatorInterface $inputFilters, */ public function createServiceWithName(ServiceLocatorInterface $inputFilters, $cName, $rName) { - $services = $inputFilters->getServiceLocator(); - $allConfig = $services->get('Config'); - $config = $allConfig['input_filter_specs'][$rName]; + // v2 => need to get parent service locator + $services = $inputFilters->getServiceLocator(); - $factory = $this->getInputFilterFactory($services); + // No parent locator => cannot create service. + if (! $services) { + return false; + } - return $factory->createInputFilter($config); + return $this($services, $rName); } /** @@ -94,7 +131,7 @@ protected function getFilterPluginManager(ServiceLocatorInterface $services) return $services->get('FilterManager'); } - return new FilterPluginManager(); + return new FilterPluginManager($services); } /** @@ -107,6 +144,6 @@ protected function getValidatorPluginManager(ServiceLocatorInterface $services) return $services->get('ValidatorManager'); } - return new ValidatorPluginManager(); + return new ValidatorPluginManager($services); } } diff --git a/src/InputFilterPluginManager.php b/src/InputFilterPluginManager.php index 3290b102..c9333178 100644 --- a/src/InputFilterPluginManager.php +++ b/src/InputFilterPluginManager.php @@ -9,9 +9,10 @@ namespace Zend\InputFilter; +use Interop\Container\ContainerInterface; use Zend\ServiceManager\AbstractPluginManager; -use Zend\ServiceManager\ConfigInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\ServiceManager\Exception\InvalidServiceException; +use Zend\ServiceManager\Factory\InvokableFactory; use Zend\Stdlib\InitializableInterface; /** @@ -22,55 +23,104 @@ class InputFilterPluginManager extends AbstractPluginManager { /** - * Default set of plugins + * Default alias of plugins * * @var string[] */ - protected $invokableClasses = [ + protected $aliases = [ 'inputfilter' => InputFilter::class, + 'inputFilter' => InputFilter::class, + 'InputFilter' => InputFilter::class, 'collection' => CollectionInputFilter::class, + 'Collection' => CollectionInputFilter::class, ]; /** - * Whether or not to share by default + * Default set of plugins + * + * @var string[] + */ + protected $factories = [ + InputFilter::class => InvokableFactory::class, + CollectionInputFilter::class => InvokableFactory::class, + // v2 canonical FQCN + 'zendinputfilterinputfilter' => InvokableFactory::class, + 'zendinputfiltercollectioninputfilter' => InvokableFactory::class, + ]; + + /** + * Whether or not to share by default (v3) + * + * @var bool + */ + protected $sharedByDefault = false; + + /** + * Whether or not to share by default (v2) * * @var bool */ protected $shareByDefault = false; /** - * @param ConfigInterface $configuration + * @param null|\Zend\ServiceManager\ConfigInterface|ContainerInterface $configOrContainer + * For zend-servicemanager v2, null or a ConfigInterface instance are + * allowed; for v3, a ContainerInterface is expected. + * @param array $v3config Optional configuration array (zend-servicemanager v3 only) */ - public function __construct(ConfigInterface $configuration = null) + public function __construct($configOrContainer = null, array $v3config = []) { - parent::__construct($configuration); - - $this->addInitializer([$this, 'populateFactory']); + $this->initializers[] = [$this, 'populateFactory']; + parent::__construct($configOrContainer, $v3config); } /** * Inject this and populate the factory with filter chain and validator chain * - * @param $inputFilter + * @param mixed $first + * @param mixed $second */ - public function populateFactory($inputFilter) + public function populateFactory($first, $second) { + if ($first instanceof ContainerInterface) { + $container = $first; + $inputFilter = $second; + } else { + $container = $second; + $inputFilter = $first; + } if ($inputFilter instanceof InputFilter) { $factory = $inputFilter->getFactory(); $factory->setInputFilterManager($this); + } + } - if ($this->serviceLocator instanceof ServiceLocatorInterface) { - $factory->getDefaultFilterChain()->setPluginManager($this->serviceLocator->get('FilterManager')); - $factory->getDefaultValidatorChain()->setPluginManager($this->serviceLocator->get('ValidatorManager')); - } + /** + * Populate the filter and validator managers for the default filter/validator chains. + * + * @param Factory $factory + * @return void + */ + public function populateFactoryPluginManagers(Factory $factory) + { + $container = property_exists($this, 'creationContext') + ? $this->creationContext // v3 + : $this->serviceLocator; // v2 + + if ($container && $container->has('FilterManager')) { + $factory->getDefaultFilterChain()->setPluginManager($container->get('FilterManager')); + } + + if ($container && $container->has('ValidatorManager')) { + $factory->getDefaultValidatorChain()->setPluginManager($container->get('ValidatorManager')); } } /** - * {@inheritDoc} + * {@inheritDoc} (v3) */ - public function validatePlugin($plugin) + public function validate($plugin) { if ($plugin instanceof InputFilterInterface || $plugin instanceof InputInterface) { // Hook to perform various initialization, when the inputFilter is not created through the factory @@ -82,11 +132,30 @@ public function validatePlugin($plugin) return; } - throw new Exception\RuntimeException(sprintf( + throw new InvalidServiceException(sprintf( 'Plugin of type %s is invalid; must implement %s or %s', (is_object($plugin) ? get_class($plugin) : gettype($plugin)), InputFilterInterface::class, InputInterface::class )); } + + /** + * Validate the plugin (v2) + * + * Checks that the filter loaded is either a valid callback or an instance + * of FilterInterface. + * + * @param mixed $plugin + * @return void + * @throws Exception\RuntimeException if invalid + */ + public function validatePlugin($plugin) + { + try { + $this->validate($plugin); + } catch (InvalidServiceException $e) { + throw new Exception\RuntimeException($e->getMessage(), $e->getCode(), $e); + } + } } diff --git a/test/FactoryTest.php b/test/FactoryTest.php index 41cd1bda..2be82eba 100644 --- a/test/FactoryTest.php +++ b/test/FactoryTest.php @@ -9,6 +9,7 @@ namespace ZendTest\InputFilter; +use Interop\Container\ContainerInterface; use PHPUnit_Framework_MockObject_MockObject as MockObject; use PHPUnit_Framework_TestCase as TestCase; use Zend\Filter; @@ -45,17 +46,17 @@ public function testCreateInputWithInvalidDataTypeThrowsInvalidArgumentException public function testCreateInputWithTypeAsAnUnknownPluginAndNotExistsAsClassNameThrowException() { - $factory = $this->createDefaultFactory(); $type = 'foo'; - /** @var InputFilterPluginManager|MockObject $pluginManager */ - $pluginManager = $this->getMock(InputFilterPluginManager::class); + $pluginManager = $this->getMockBuilder(InputFilterPluginManager::class) + ->disableOriginalConstructor() + ->getMock(); $pluginManager->expects($this->atLeastOnce()) ->method('has') ->with($type) - ->willReturn(false) - ; - $factory->setInputFilterManager($pluginManager); + ->willReturn(false); + + $factory = new Factory($pluginManager); $this->setExpectedException( RuntimeException::class, @@ -68,13 +69,30 @@ public function testCreateInputWithTypeAsAnUnknownPluginAndNotExistsAsClassNameT ); } + public function testGetInputFilterManagerSettedByItsSetter() + { + $pluginManager = $this->getMockBuilder(InputFilterPluginManager::class) + ->disableOriginalConstructor() + ->getMock(); + $factory = new Factory(); + $factory->setInputFilterManager($pluginManager); + $this->assertSame($pluginManager, $factory->getInputFilterManager()); + } + + public function testGetInputFilterManagerWhenYouConstructFactoryWithIt() + { + $pluginManager = $this->getMockBuilder(InputFilterPluginManager::class) + ->disableOriginalConstructor() + ->getMock(); + $factory = new Factory($pluginManager); + $this->assertSame($pluginManager, $factory->getInputFilterManager()); + } + public function testCreateInputWithTypeAsAnInvalidPluginInstanceThrowException() { - $factory = $this->createDefaultFactory(); $type = 'fooPlugin'; $pluginManager = $this->createInputFilterPluginManagerMockForPlugin($type, 'invalid_value'); - - $factory->setInputFilterManager($pluginManager); + $factory = new Factory($pluginManager); $this->setExpectedException( RuntimeException::class, @@ -283,9 +301,11 @@ public function testFactoryAllowsInjectingValidatorChain() public function testFactoryUsesComposedFilterChainWhenCreatingNewInputObjects() { + $smMock = $this->getMock(ContainerInterface::class); + $factory = $this->createDefaultFactory(); $filterChain = new Filter\FilterChain(); - $pluginManager = new Filter\FilterPluginManager(); + $pluginManager = new Filter\FilterPluginManager($smMock); $filterChain->setPluginManager($pluginManager); $factory->setDefaultFilterChain($filterChain); $input = $factory->createInput([ @@ -299,9 +319,10 @@ public function testFactoryUsesComposedFilterChainWhenCreatingNewInputObjects() public function testFactoryUsesComposedValidatorChainWhenCreatingNewInputObjects() { + $smMock = $this->getMock(ContainerInterface::class); $factory = $this->createDefaultFactory(); $validatorChain = new Validator\ValidatorChain(); - $validatorPlugins = new Validator\ValidatorPluginManager(); + $validatorPlugins = new Validator\ValidatorPluginManager($smMock); $validatorChain->setPluginManager($validatorPlugins); $factory->setDefaultValidatorChain($validatorChain); $input = $factory->createInput([ @@ -315,9 +336,10 @@ public function testFactoryUsesComposedValidatorChainWhenCreatingNewInputObjects public function testFactoryInjectsComposedFilterAndValidatorChainsIntoInputObjectsWhenCreatingNewInputFilterObjects() { + $smMock = $this->getMock(ContainerInterface::class); $factory = $this->createDefaultFactory(); - $filterPlugins = new Filter\FilterPluginManager(); - $validatorPlugins = new Validator\ValidatorPluginManager(); + $filterPlugins = new Filter\FilterPluginManager($smMock); + $validatorPlugins = new Validator\ValidatorPluginManager($smMock); $filterChain = new Filter\FilterChain(); $validatorChain = new Validator\ValidatorChain(); $filterChain->setPluginManager($filterPlugins); @@ -348,11 +370,11 @@ public function testFactoryWillCreateInputWithSuggestedFilters() 'name' => 'foo', 'filters' => [ [ - 'name' => 'string_trim', + 'name' => Filter\StringTrim::class ], $htmlEntities, [ - 'name' => 'string_to_lower', + 'name' => Filter\StringToLower::class, 'options' => [ 'encoding' => 'ISO-8859-1', ], @@ -390,11 +412,11 @@ public function testFactoryWillCreateInputWithSuggestedValidators() 'name' => 'foo', 'validators' => [ [ - 'name' => 'not_empty', + 'name' => Validator\NotEmpty::class, ], $digits, [ - 'name' => 'string_length', + 'name' => Validator\StringLength::class, 'options' => [ 'min' => 3, 'max' => 5, @@ -509,10 +531,10 @@ public function testFactoryWillCreateInputFilterAndAllInputObjectsFromGivenConfi 'required' => false, 'validators' => [ [ - 'name' => 'not_empty', + 'name' => Validator\NotEmpty::class, ], [ - 'name' => 'string_length', + 'name' => Validator\StringLength::class, 'options' => [ 'min' => 3, 'max' => 5, @@ -524,10 +546,10 @@ public function testFactoryWillCreateInputFilterAndAllInputObjectsFromGivenConfi 'allow_empty' => true, 'filters' => [ [ - 'name' => 'string_trim', + 'name' => Filter\StringTrim::class, ], [ - 'name' => 'string_to_lower', + 'name' => Filter\StringToLower::class, 'options' => [ 'encoding' => 'ISO-8859-1', ], @@ -541,10 +563,10 @@ public function testFactoryWillCreateInputFilterAndAllInputObjectsFromGivenConfi 'required' => false, 'validators' => [ [ - 'name' => 'not_empty', + 'name' => Validator\NotEmpty::class, ], [ - 'name' => 'string_length', + 'name' => Validator\StringLength::class, 'options' => [ 'min' => 3, 'max' => 5, @@ -556,10 +578,10 @@ public function testFactoryWillCreateInputFilterAndAllInputObjectsFromGivenConfi 'allow_empty' => true, 'filters' => [ [ - 'name' => 'string_trim', + 'name' => Filter\StringTrim::class ], [ - 'name' => 'string_to_lower', + 'name' => Filter\StringToLower::class, 'options' => [ 'encoding' => 'ISO-8859-1', ], @@ -689,15 +711,15 @@ public function testFactoryWillNotGetPrioritySetting() 'name' => 'foo', 'filters' => [ [ - 'name' => 'string_trim', + 'name' => 'StringTrim', 'priority' => Filter\FilterChain::DEFAULT_PRIORITY - 1 // 999 ], [ - 'name' => 'string_to_upper', + 'name' => 'StringToUpper', 'priority' => Filter\FilterChain::DEFAULT_PRIORITY + 1 //1001 ], [ - 'name' => 'string_to_lower', // default priority 1000 + 'name' => 'StringToLower' // default priority 1000 ] ] ]); @@ -767,13 +789,11 @@ public function testCanSetInputErrorMessage() public function testSetInputFilterManagerWithServiceManager() { - $inputFilterManager = new InputFilterPluginManager; $serviceManager = new ServiceManager\ServiceManager; - $serviceManager->setService('ValidatorManager', new Validator\ValidatorPluginManager); - $serviceManager->setService('FilterManager', new Filter\FilterPluginManager); - $inputFilterManager->setServiceLocator($serviceManager); - $factory = $this->createDefaultFactory(); - $factory->setInputFilterManager($inputFilterManager); + $inputFilterManager = new InputFilterPluginManager($serviceManager); + $serviceManager->setService('ValidatorManager', new Validator\ValidatorPluginManager($serviceManager)); + $serviceManager->setService('FilterManager', new Filter\FilterPluginManager($serviceManager)); + $factory = new Factory($inputFilterManager); $this->assertInstanceOf( Validator\ValidatorPluginManager::class, $factory->getDefaultValidatorChain()->getPluginManager() @@ -786,15 +806,16 @@ public function testSetInputFilterManagerWithServiceManager() public function testSetInputFilterManagerWithoutServiceManager() { - $inputFilterManager = new InputFilterPluginManager(); - $factory = $this->createDefaultFactory(); - $factory->setInputFilterManager($inputFilterManager); + $smMock = $this->getMock(ContainerInterface::class); + $inputFilterManager = new InputFilterPluginManager($smMock); + $factory = new Factory($inputFilterManager); $this->assertSame($inputFilterManager, $factory->getInputFilterManager()); } public function testSetInputFilterManagerOnConstruct() { - $inputFilterManager = new InputFilterPluginManager(); + $smMock = $this->getMock(ContainerInterface::class); + $inputFilterManager = new InputFilterPluginManager($smMock); $factory = new Factory($inputFilterManager); $this->assertSame($inputFilterManager, $factory->getInputFilterManager()); } @@ -885,10 +906,10 @@ public function testCanCreateInputFilterFromProvider() public function testSuggestedTypeMayBePluginNameInInputFilterPluginManager() { - $factory = $this->createDefaultFactory(); - $pluginManager = new InputFilterPluginManager(); + $serviceManager = new ServiceManager\ServiceManager(); + $pluginManager = new InputFilterPluginManager($serviceManager); $pluginManager->setService('bar', new Input('bar')); - $factory->setInputFilterManager($pluginManager); + $factory = new Factory($pluginManager); $input = $factory->createInput([ 'type' => 'bar' @@ -898,9 +919,9 @@ public function testSuggestedTypeMayBePluginNameInInputFilterPluginManager() public function testInputFromPluginManagerMayBeFurtherConfiguredWithSpec() { - $factory = $this->createDefaultFactory(); - $pluginManager = new InputFilterPluginManager(); + $pluginManager = new InputFilterPluginManager(new ServiceManager\ServiceManager()); $pluginManager->setService('bar', $barInput = new Input('bar')); + $factory = new Factory($pluginManager); $this->assertTrue($barInput->isRequired()); $factory->setInputFilterManager($pluginManager); @@ -932,7 +953,10 @@ protected function createDefaultFactory() protected function createInputFilterPluginManagerMockForPlugin($pluginName, $pluginValue) { /** @var InputFilterPluginManager|MockObject $pluginManager */ - $pluginManager = $this->getMock(InputFilterPluginManager::class); + $pluginManager = $this->getMockBuilder(InputFilterPluginManager::class) + ->disableOriginalConstructor() + ->getMock(); + $pluginManager->expects($this->atLeastOnce()) ->method('has') ->with($pluginName) diff --git a/test/InputFilterAbstractServiceFactoryTest.php b/test/InputFilterAbstractServiceFactoryTest.php index 9b081f25..de133421 100644 --- a/test/InputFilterAbstractServiceFactoryTest.php +++ b/test/InputFilterAbstractServiceFactoryTest.php @@ -24,20 +24,25 @@ */ class InputFilterAbstractServiceFactoryTest extends TestCase { - /** @var ServiceManager */ + /** + * @var ServiceManager + */ protected $services; - /** @var InputFilterPluginManager */ + /** + * @var InputFilterPluginManager + */ protected $filters; - /** @var InputFilterAbstractServiceFactory */ + /** + * @var InputFilterAbstractServiceFactory + */ protected $factory; public function setUp() { $this->services = new ServiceManager(); - $this->filters = new InputFilterPluginManager(); - $this->filters->setServiceLocator($this->services); + $this->filters = new InputFilterPluginManager($this->services); $this->services->setService('InputFilterManager', $this->filters); $this->factory = new InputFilterAbstractServiceFactory(); @@ -45,41 +50,86 @@ public function setUp() public function testCannotCreateServiceIfNoConfigServicePresent() { - $this->assertFalse($this->factory->canCreateServiceWithName($this->filters, 'filter', 'filter')); + if (method_exists($this->services, 'configure')) { + // v3 + $method = 'canCreate'; + $args = [$this->getCompatContainer(), 'filter']; + } else { + // v2 + $method = 'canCreateServiceWithName'; + $args = [$this->getCompatContainer(), 'filter', 'filter']; + } + $this->assertFalse(call_user_func_array([$this->factory, $method], $args)); } public function testCannotCreateServiceIfConfigServiceDoesNotHaveInputFiltersConfiguration() { - $this->services->setService('Config', []); - $this->assertFalse($this->factory->canCreateServiceWithName($this->filters, 'filter', 'filter')); + $this->services->setService('config', []); + if (method_exists($this->services, 'configure')) { + // v3 + $method = 'canCreate'; + $args = [$this->getCompatContainer(), 'filter']; + } else { + // v2 + $method = 'canCreateServiceWithName'; + $args = [$this->getCompatContainer(), 'filter', 'filter']; + } + $this->assertFalse(call_user_func_array([$this->factory, $method], $args)); } public function testCannotCreateServiceIfConfigInputFiltersDoesNotContainMatchingServiceName() { - $this->services->setService('Config', [ + $this->services->setService('config', [ 'input_filter_specs' => [], ]); - $this->assertFalse($this->factory->canCreateServiceWithName($this->filters, 'filter', 'filter')); + if (method_exists($this->services, 'configure')) { + // v3 + $method = 'canCreate'; + $args = [$this->getCompatContainer(), 'filter']; + } else { + // v2 + $method = 'canCreateServiceWithName'; + $args = [$this->getCompatContainer(), 'filter', 'filter']; + } + $this->assertFalse(call_user_func_array([$this->factory, $method], $args)); } public function testCanCreateServiceIfConfigInputFiltersContainsMatchingServiceName() { - $this->services->setService('Config', [ + $this->services->setService('config', [ 'input_filter_specs' => [ 'filter' => [], ], ]); - $this->assertTrue($this->factory->canCreateServiceWithName($this->filters, 'filter', 'filter')); + if (method_exists($this->services, 'configure')) { + // v3 + $method = 'canCreate'; + $args = [$this->getCompatContainer(), 'filter']; + } else { + // v2 + $method = 'canCreateServiceWithName'; + $args = [$this->getCompatContainer(), 'filter', 'filter']; + } + $this->assertTrue(call_user_func_array([$this->factory, $method], $args)); } public function testCreatesInputFilterInstance() { - $this->services->setService('Config', [ + $this->services->setService('config', [ 'input_filter_specs' => [ 'filter' => [], ], ]); - $filter = $this->factory->createServiceWithName($this->filters, 'filter', 'filter'); + if (method_exists($this->services, 'configure')) { + // v3 + $method = '__invoke'; + $args = [$this->getCompatContainer(), 'filter']; + } else { + // v2 + $method = 'createServiceWithName'; + $args = [$this->getCompatContainer(), 'filter', 'filter']; + } + $filter = call_user_func_array([$this->factory, $method], $args); $this->assertInstanceOf(InputFilterInterface::class, $filter); } @@ -88,19 +138,19 @@ public function testCreatesInputFilterInstance() */ public function testUsesConfiguredValidationAndFilterManagerServicesWhenCreatingInputFilter() { - $filters = new FilterPluginManager(); + $filters = new FilterPluginManager($this->services); $filter = function ($value) { }; $filters->setService('foo', $filter); - $validators = new ValidatorPluginManager(); + $validators = new ValidatorPluginManager($this->services); /** @var ValidatorInterface|MockObject $validator */ $validator = $this->getMock(ValidatorInterface::class); $validators->setService('foo', $validator); $this->services->setService('FilterManager', $filters); $this->services->setService('ValidatorManager', $validators); - $this->services->setService('Config', [ + $this->services->setService('config', [ 'input_filter_specs' => [ 'filter' => [ 'input' => [ @@ -117,7 +167,17 @@ public function testUsesConfiguredValidationAndFilterManagerServicesWhenCreating ], ]); - $inputFilter = $this->factory->createServiceWithName($this->filters, 'filter', 'filter'); + + if (method_exists($this->services, 'configure')) { + // v3 + $method = '__invoke'; + $args = [$this->getCompatContainer(), 'filter']; + } else { + // v2 + $method = 'createServiceWithName'; + $args = [$this->getCompatContainer(), 'filter', 'filter']; + } + $inputFilter = call_user_func_array([$this->factory, $method], $args); $this->assertTrue($inputFilter->has('input')); $input = $inputFilter->get('input'); @@ -128,7 +188,7 @@ public function testUsesConfiguredValidationAndFilterManagerServicesWhenCreating $this->assertSame($filter, $filterChain->plugin('foo')); $this->assertEquals(1, count($filterChain)); - $validatorChain = $input->getvalidatorChain(); + $validatorChain = $input->getValidatorChain(); $this->assertSame($validators, $validatorChain->getPluginManager()); $this->assertEquals(1, count($validatorChain)); $this->assertSame($validator, $validatorChain->plugin('foo')); @@ -137,19 +197,7 @@ public function testUsesConfiguredValidationAndFilterManagerServicesWhenCreating public function testRetrieveInputFilterFromInputFilterPluginManager() { - $filters = new FilterPluginManager(); - $filter = function ($value) { - }; - $filters->setService('foo', $filter); - - $validators = new ValidatorPluginManager(); - /** @var ValidatorInterface|MockObject $validator */ - $validator = $this->getMock(ValidatorInterface::class); - $validators->setService('foo', $validator); - - $this->services->setService('FilterManager', $filters); - $this->services->setService('ValidatorManager', $validators); - $this->services->setService('Config', [ + $this->services->setService('config', [ 'input_filter_specs' => [ 'foobar' => [ 'input' => [ @@ -165,9 +213,37 @@ public function testRetrieveInputFilterFromInputFilterPluginManager() ], ], ]); + $validators = new ValidatorPluginManager($this->services); + /** @var ValidatorInterface|MockObject $validator */ + $validator = $this->getMock(ValidatorInterface::class); + $this->services->setService('ValidatorManager', $validators); + $validators->setService('foo', $validator); + + $filters = new FilterPluginManager($this->services); + $filter = function ($value) { + }; + $filters->setService('foo', $filter); + + $this->services->setService('FilterManager', $filters); $this->services->get('InputFilterManager')->addAbstractFactory(InputFilterAbstractServiceFactory::class); $inputFilter = $this->services->get('InputFilterManager')->get('foobar'); $this->assertInstanceOf(InputFilterInterface::class, $inputFilter); } + + /** + * Returns appropriate instance to pass to `canCreate()` et al depending on SM version + * + * v3 passes the 'creationContext' (ie the root SM) to the AbstractFactory, whereas v2 passes the PluginManager + */ + protected function getCompatContainer() + { + if (method_exists($this->services, 'configure')) { + // v3 + return $this->services; + } else { + // v2 + return $this->filters; + } + } } diff --git a/test/InputFilterPluginManagerCompatibilityTest.php b/test/InputFilterPluginManagerCompatibilityTest.php new file mode 100644 index 00000000..32de3fb2 --- /dev/null +++ b/test/InputFilterPluginManagerCompatibilityTest.php @@ -0,0 +1,65 @@ +markTestSkipped("InputFilterPluginManager accepts multiple instances"); + } + + protected function getPluginManager() + { + return new InputFilterPluginManager(new ServiceManager()); + } + + protected function getV2InvalidPluginException() + { + return RuntimeException::class; + } + + protected function getInstanceOf() + { + // InputFilterManager accepts multiple instance types + return; + } + + public function testConstructorArgumentsAreOptionalUnderV2() + { + $plugins = $this->getPluginManager(); + if (method_exists($plugins, 'configure')) { + $this->markTestSkipped('zend-servicemanager v3 plugin managers require a container argument'); + } + + $plugins = new InputFilterPluginManager(); + $this->assertInstanceOf(InputFilterPluginManager::class, $plugins); + } + + public function testConstructorAllowsConfigInstanceAsFirstArgumentUnderV2() + { + $plugins = $this->getPluginManager(); + if (method_exists($plugins, 'configure')) { + $this->markTestSkipped('zend-servicemanager v3 plugin managers require a container argument'); + } + + $plugins = new InputFilterPluginManager(new Config([])); + $this->assertInstanceOf(InputFilterPluginManager::class, $plugins); + } +} diff --git a/test/InputFilterPluginManagerTest.php b/test/InputFilterPluginManagerTest.php index 8314e283..a0fdc812 100644 --- a/test/InputFilterPluginManagerTest.php +++ b/test/InputFilterPluginManagerTest.php @@ -18,7 +18,9 @@ use Zend\InputFilter\InputFilterPluginManager; use Zend\InputFilter\InputInterface; use Zend\ServiceManager\AbstractPluginManager; +use Zend\ServiceManager\Exception\InvalidServiceException; use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\ServiceManager\ServiceManager; use Zend\Stdlib\InitializableInterface; use Zend\Validator\ValidatorPluginManager; @@ -32,9 +34,15 @@ class InputFilterPluginManagerTest extends \PHPUnit_Framework_TestCase */ protected $manager; + /** + * @var ServiceManager + */ + protected $services; + public function setUp() { - $this->manager = new InputFilterPluginManager(); + $this->services = new ServiceManager(); + $this->manager = new InputFilterPluginManager($this->services); } public function testIsASubclassOfAbstractPluginManager() @@ -44,13 +52,17 @@ public function testIsASubclassOfAbstractPluginManager() public function testIsNotSharedByDefault() { - $this->assertFalse($this->manager->shareByDefault()); + $property = method_exists($this->manager, 'configure') + ? 'sharedByDefault' // v3 + : 'shareByDefault'; // v2 + + $this->assertAttributeSame(false, $property, $this->manager); } public function testRegisteringInvalidElementRaisesException() { $this->setExpectedException( - RuntimeException::class, + $this->getServiceNotFoundException(), 'must implement Zend\InputFilter\InputFilterInterface or Zend\InputFilter\InputInterface' ); $this->manager->setService('test', $this); @@ -59,7 +71,7 @@ public function testRegisteringInvalidElementRaisesException() public function testLoadingInvalidElementRaisesException() { $this->manager->setInvokableClass('test', get_class($this)); - $this->setExpectedException(RuntimeException::class); + $this->setExpectedException($this->getServiceNotFoundException()); $this->manager->get('test'); } @@ -84,8 +96,6 @@ public function testDefaultInvokableClasses($alias, $expectedInstance) public function testInputFilterInvokableClassSMDependenciesArePopulatedWithoutServiceLocator() { - $this->assertNull($this->manager->getServiceLocator(), 'Plugin manager is expected to no have a service locator'); - /** @var InputFilter $service */ $service = $this->manager->get('inputfilter'); @@ -99,21 +109,15 @@ public function testInputFilterInvokableClassSMDependenciesArePopulatedWithoutSe public function testInputFilterInvokableClassSMDependenciesArePopulatedWithServiceLocator() { - $filterManager = $this->getMock(FilterPluginManager::class); - $validatorManager = $this->getMock(ValidatorPluginManager::class); + $filterManager = $this->getMockBuilder(FilterPluginManager::class) + ->disableOriginalConstructor() + ->getMock(); + $validatorManager = $this->getMockBuilder(ValidatorPluginManager::class) + ->disableOriginalConstructor() + ->getMock(); - $serviceLocator = $this->createServiceLocatorInterfaceMock(); - $serviceLocator->method('get') - ->willReturnMap( - [ - ['FilterManager', $filterManager], - ['ValidatorManager', $validatorManager], - ] - ) - ; - - $this->manager->setServiceLocator($serviceLocator); - $this->assertSame($serviceLocator, $this->manager->getServiceLocator(), 'getServiceLocator() value not match'); + $this->services->setService('FilterManager', $filterManager); + $this->services->setService('ValidatorManager', $validatorManager); /** @var InputFilter $service */ $service = $this->manager->get('inputfilter'); @@ -211,4 +215,12 @@ protected function createServiceLocatorInterfaceMock() return $serviceLocator; } + + protected function getServiceNotFoundException() + { + if (method_exists($this->manager, 'configure')) { + return InvalidServiceException::class; + } + return RuntimeException::class; + } }