* @psalm-import-type ServiceManagerConfiguration from ServiceManager */ class RoutePluginManager extends AbstractPluginManager { /** * Only RouteInterface instances are valid * * @var class-string */ protected $instanceOf = RouteInterface::class; /** * Do not share instances. (v3) * * @var bool */ protected $shareByDefault = false; /** * Do not share instances. (v2) * * @var bool */ protected $sharedByDefault = false; /** * Constructor * * Ensure that the instance is seeded with the RouteInvokableFactory as an * abstract factory. * * @param ContainerInterface|ConfigInterface $configOrContainerInstance * @param array $v3config * @psalm-param ServiceManagerConfiguration $v3config */ public function __construct($configOrContainerInstance, array $v3config = []) { $this->addAbstractFactory(RouteInvokableFactory::class); parent::__construct($configOrContainerInstance, $v3config); } /** * Validate a route plugin. (v2) * * @param InstanceType $instance * @throws InvalidServiceException * @psalm-assert InstanceType $instance */ public function validate($instance) { if (! $instance instanceof $this->instanceOf) { throw new InvalidServiceException(sprintf( 'Plugin of type %s is invalid; must implement %s', is_object($instance) ? get_class($instance) : gettype($instance), RouteInterface::class )); } } /** * Validate a route plugin. (v2) * * @param InstanceType $plugin * @throws Exception\RuntimeException * @psalm-assert InstanceType $instance */ public function validatePlugin($plugin) { try { $this->validate($plugin); } catch (InvalidServiceException $e) { throw new Exception\RuntimeException( $e->getMessage(), $e->getCode(), $e ); } } /** * Pre-process configuration. (v3) * * Checks for invokables, and, if found, maps them to the * component-specific RouteInvokableFactory; removes the invokables entry * before passing to the parent. * * @param array $config * @psalm-param ServiceManagerConfiguration $config * @return void */ public function configure(array $config) { if (isset($config['invokables']) && ! empty($config['invokables'])) { $aliases = $this->createAliasesForInvokables($config['invokables']); $factories = $this->createFactoriesForInvokables($config['invokables']); if (! empty($aliases)) { $config['aliases'] = isset($config['aliases']) ? array_merge($config['aliases'], $aliases) : $aliases; } $config['factories'] = isset($config['factories']) ? array_merge($config['factories'], $factories) : $factories; unset($config['invokables']); } parent::configure($config); } /** * Create aliases for invokable classes. * * If an invokable service name does not match the class it maps to, this * creates an alias to the class (which will later be mapped as an * invokable factory). * * @param array $invokables * @return array */ protected function createAliasesForInvokables(array $invokables) { $aliases = []; foreach ($invokables as $name => $class) { if ($name === $class) { continue; } $aliases[$name] = $class; } return $aliases; } /** * Create invokable factories for invokable classes. * * If an invokable service name does not match the class it maps to, this * creates an invokable factory entry for the class name; otherwise, it * creates an invokable factory for the entry name. * * @param array $invokables * @return array */ protected function createFactoriesForInvokables(array $invokables) { $factories = []; foreach ($invokables as $name => $class) { if ($name === $class) { $factories[$name] = RouteInvokableFactory::class; continue; } $factories[$class] = RouteInvokableFactory::class; } return $factories; } }