<?php /** * @link http://github.com/zendframework/zend-servicemanager for the canonical source repository * @copyright Copyright (c) 2005-2016 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ namespace Zend\ServiceManager; use Interop\Container\ContainerInterface; use Zend\ServiceManager\Exception\InvalidServiceException; /** * Abstract plugin manager. * * Abstract PluginManagerInterface implementation providing: * * - creation context support. The constructor accepts the parent container * instance, which is then used when creating instances. * - plugin validation. Implementations may define the `$instanceOf` property * to indicate what class types constitute valid plugins, omitting the * requirement to define the `validate()` method. * * The implementation extends `ServiceManager`, thus providing the same set * of capabilities as found in that implementation. */ abstract class AbstractPluginManager extends ServiceManager implements PluginManagerInterface { /** * Whether or not to auto-add a FQCN as an invokable if it exists. * * @var bool */ protected $autoAddInvokableClass = true; /** * An object type that the created instance must be instanced of * * @var null|string */ protected $instanceOf = null; /** * Constructor. * * Sets the provided $parentLocator as the creation context for all * factories; for $config, {@see \Zend\ServiceManager\ServiceManager::configure()} * for details on its accepted structure. * * @param null|ConfigInterface|ContainerInterface $configInstanceOrParentLocator * @param array $config */ public function __construct($configInstanceOrParentLocator = null, array $config = []) { if (null !== $configInstanceOrParentLocator && ! $configInstanceOrParentLocator instanceof ConfigInterface && ! $configInstanceOrParentLocator instanceof ContainerInterface ) { throw new Exception\InvalidArgumentException(sprintf( '%s expects a ConfigInterface or ContainerInterface instance as the first argument; received %s', __CLASS__, (is_object($configInstanceOrParentLocator) ? get_class($configInstanceOrParentLocator) : gettype($configInstanceOrParentLocator) ) )); } if ($configInstanceOrParentLocator instanceof ConfigInterface) { trigger_error(sprintf( 'Usage of %s as a constructor argument for %s is now deprecated', ConfigInterface::class, get_class($this) ), E_USER_DEPRECATED); $config = $configInstanceOrParentLocator->toArray(); } parent::__construct($config); if (! $configInstanceOrParentLocator instanceof ContainerInterface) { trigger_error(sprintf( '%s now expects a %s instance representing the parent container; please update your code', __METHOD__, ContainerInterface::class ), E_USER_DEPRECATED); } $this->creationContext = $configInstanceOrParentLocator instanceof ContainerInterface ? $configInstanceOrParentLocator : $this; } /** * Override configure() to validate service instances. * * If an instance passed in the `services` configuration is invalid for the * plugin manager, this method will raise an InvalidServiceException. * * {@inheritDoc} * @throws InvalidServiceException */ public function configure(array $config) { if (isset($config['services'])) { foreach ($config['services'] as $service) { $this->validate($service); } } parent::configure($config); return $this; } /** * {@inheritDoc} * * @param string $name Service name of plugin to retrieve. * @param null|array $options Options to use when creating the instance. * @return mixed * @throws Exception\ServiceNotFoundException if the manager does not have * a service definition for the instance, and the service is not * auto-invokable. * @throws InvalidServiceException if the plugin created is invalid for the * plugin context. */ public function get($name, array $options = null) { if (! $this->has($name)) { if (! $this->autoAddInvokableClass || ! class_exists($name)) { throw new Exception\ServiceNotFoundException(sprintf( 'A plugin by the name "%s" was not found in the plugin manager %s', $name, get_class($this) )); } $this->setFactory($name, Factory\InvokableFactory::class); } $instance = empty($options) ? parent::get($name) : $this->build($name, $options); $this->validate($instance); return $instance; } /** * {@inheritDoc} */ public function validate($instance) { if (method_exists($this, 'validatePlugin')) { trigger_error(sprintf( '%s::validatePlugin() has been deprecated as of 3.0; please define validate() instead', get_class($this) ), E_USER_DEPRECATED); $this->validatePlugin($instance); return; } if (empty($this->instanceOf) || $instance instanceof $this->instanceOf) { return; } throw new InvalidServiceException(sprintf( 'Plugin manager "%s" expected an instance of type "%s", but "%s" was received', __CLASS__, $this->instanceOf, is_object($instance) ? get_class($instance) : gettype($instance) )); } /** * Implemented for backwards compatibility only. * * Returns the creation context. * * @deprecated since 3.0.0. The creation context should be passed during * instantiation instead. * @param ContainerInterface $container * @return void */ public function setServiceLocator(ContainerInterface $container) { trigger_error(sprintf( 'Usage of %s is deprecated since v3.0.0; please pass the container to the constructor instead', __METHOD__ ), E_USER_DEPRECATED); $this->creationContext = $container; } }