-
Notifications
You must be signed in to change notification settings - Fork 50
ServiceManager v2-v3 compatibility #95
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,9 +9,11 @@ | |
|
||
namespace Zend\InputFilter; | ||
|
||
use Interop\Container\ContainerInterface; | ||
use Zend\Filter\FilterPluginManager; | ||
use Zend\ServiceManager\AbstractFactoryInterface; | ||
use Zend\ServiceManager\ServiceLocatorInterface; | ||
use Zend\ServiceManager\ServiceManager; | ||
use Zend\Validator\ValidatorPluginManager; | ||
|
||
class InputFilterAbstractServiceFactory implements AbstractFactoryInterface | ||
|
@@ -21,22 +23,47 @@ 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) | ||
{ | ||
// v2 - get parent service manager | ||
if (! method_exists($services, 'configure')) { | ||
$services = $services->getServiceLocator(); | ||
} | ||
|
||
$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') | ||
) { | ||
// v2 - get parent service manager | ||
if (! method_exists($services, 'configure')) { | ||
$services = $services->getServiceLocator(); | ||
} | ||
|
||
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 +73,19 @@ 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) | ||
{ | ||
return $this->canCreate($serviceLocator, $requestedName); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method, when invoked, can only happen from v2, so this is where the check for the parent locator should occur (versus in |
||
} | ||
|
||
/** | ||
* @param ServiceLocatorInterface $inputFilters | ||
* @param string $cName | ||
|
@@ -54,13 +94,7 @@ 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]; | ||
|
||
$factory = $this->getInputFilterFactory($services); | ||
|
||
return $factory->createInputFilter($config); | ||
return $this($inputFilters, $rName); | ||
} | ||
|
||
/** | ||
|
@@ -94,7 +128,7 @@ protected function getFilterPluginManager(ServiceLocatorInterface $services) | |
return $services->get('FilterManager'); | ||
} | ||
|
||
return new FilterPluginManager(); | ||
return new FilterPluginManager(new ServiceManager()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I'll make that change on merge. |
||
} | ||
|
||
/** | ||
|
@@ -107,6 +141,6 @@ protected function getValidatorPluginManager(ServiceLocatorInterface $services) | |
return $services->get('ValidatorManager'); | ||
} | ||
|
||
return new ValidatorPluginManager(); | ||
return new ValidatorPluginManager(new ServiceManager()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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,100 @@ | |
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 ContainerInterface $parentLocator | ||
* @param array $config | ||
*/ | ||
public function __construct(ConfigInterface $configuration = null) | ||
public function __construct(ContainerInterface $parentLocator, array $config = []) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. First argument must also accept null for full BC with v2; I'll update that when merging. (Discovered this the hard way with zend-view 2.6.0.) |
||
{ | ||
parent::__construct($configuration); | ||
|
||
parent::__construct($parentLocator, $config); | ||
$this->addInitializer([$this, 'populateFactory']); | ||
} | ||
|
||
/** | ||
* 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')); | ||
} | ||
public function populateFactoryPluginManagers(Factory $factory) | ||
{ | ||
if (property_exists($this, 'creationContext')) { | ||
// v3 | ||
$container = $this->creationContext; | ||
} else { | ||
// v2 | ||
$container = $this->serviceLocator; | ||
} | ||
|
||
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 +128,35 @@ 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) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Never mind, was confusing this with the next line. Nothing to see here, move along... |
||
throw new Exception\RuntimeException($e->getMessage(), $e->getCode(), $e); | ||
} | ||
} | ||
|
||
public function shareByDefault() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are you adding this? |
||
{ | ||
return $this->sharedByDefault; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I disagree with this. The correct is to test lowest version (composer --prefer-lowest) and newest versions. All versions released in the middle are expected to be compatible and fulfill the API contract.
When we should to test specific versions? When the code HAS an specific logic branch testing if some feature is available i.e.
(component_version >= 5.0) ? new API : old API
. And this thing should be do with only 1 PHP version and not 5.5. and 5.6 whcih make me the following question?Why PHP 7 and HHVM are not duplicated?
I think the test matrix proposed in this PR is not necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hum, OK, didn't know about --prefer-lowest (not my preference often ;) I've just been following what I've seen @weierophinney do in PRs for zend-i18n etc.
I noticed @ezimuel has done it slightly differently, with a SERVICE_MANAGER_V2=(true|false). So something like:
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/composer install/composer update/ - install doesn't do
--prefer-lowest