├── CHANGELOG.md ├── composer.json └── src ├── Attribute ├── Middleware.php └── Reader │ ├── AttributeReader.php │ ├── CacheAttributesReader.php │ └── ClassMethodAttributeReader.php ├── DependencyInjection ├── AttributeReaderCompilerPass.php ├── Configuration.php ├── SymiddlewareCompilerPass.php └── SymiddlewareExtension.php ├── Integration ├── ControllerListener.php └── ControllerReplacer.php ├── Middleware ├── MiddlewareAction.php ├── MiddlewareGatherer.php ├── MiddlewareNotConfigured.php ├── MiddlewareRunner.php ├── Registry │ ├── MiddlewareRegistry.php │ └── ServiceLocatorMiddlewareRegistry.php ├── StackMiddleware.php └── SymfonyActionRequestHandler.php ├── Psr ├── Adapter │ ├── PsrHttpMessageBridgePsrRequestTransformer.php │ └── PsrHttpMessageBridgePsrResponseTransformer.php ├── DefaultPsrRequestCloner.php ├── PsrRequestCloner.php ├── PsrRequestTransformer.php └── PsrResponseTransformer.php ├── Resources └── config │ └── symiddleware.php └── SymiddlewareBundle.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Symfony Middleware Change Log 2 | 3 | ## 0.2.1 August 24, 2021 4 | 5 | - First release: middleware groups, global and single middlewares. 6 | 7 | ## 0.3.0 December 1, 2021 8 | 9 | - Second release: update Symfony and php version. 10 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kafkiansky/symfony-middleware", 3 | "description": "PSR-15 Middleware for symfony.", 4 | "type": "library", 5 | "keywords": [ 6 | "symfony", 7 | "psr-15", 8 | "middleware" 9 | ], 10 | "autoload": { 11 | "psr-4": { 12 | "Kafkiansky\\SymfonyMiddleware\\": "src/" 13 | } 14 | }, 15 | "autoload-dev": { 16 | "psr-4": { 17 | "Kafkiansky\\SymfonyMiddleware\\Tests\\": "tests/" 18 | } 19 | }, 20 | "require": { 21 | "php": "^8.2", 22 | "symfony/dependency-injection": "^7.0", 23 | "symfony/event-dispatcher": "^7.0", 24 | "symfony/http-kernel": "^7.0", 25 | "symfony/config": "^7.0", 26 | "symfony/http-foundation": "^7.0", 27 | "psr/http-server-middleware": "^1.0", 28 | "psr/http-server-handler": "^1.0", 29 | "symfony/psr-http-message-bridge": "^7.0", 30 | "nyholm/psr7": "^1.4", 31 | "symfony/cache": "^7.0" 32 | }, 33 | "require-dev": { 34 | "phpunit/phpunit": "^10.0", 35 | "vimeo/psalm": "^5.0" 36 | }, 37 | "license": "MIT", 38 | "authors": [ 39 | { 40 | "name": "v.zanfir", 41 | "email": "vadimzanfir@gmail.com" 42 | } 43 | ], 44 | "minimum-stability": "stable", 45 | "scripts": { 46 | "lint": "./vendor/bin/psalm --no-cache", 47 | "test": "./vendor/bin/phpunit --do-not-cache-result --no-coverage" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Attribute/Middleware.php: -------------------------------------------------------------------------------- 1 | []|string[] $list 14 | */ 15 | public function __construct(public readonly array $list) 16 | { 17 | } 18 | 19 | /** 20 | * @return class-string[]|string[] 21 | */ 22 | public function toArray(): array 23 | { 24 | return $this->list; 25 | } 26 | 27 | /** 28 | * @param class-string[]|string[] $list 29 | * 30 | * @return Middleware 31 | */ 32 | public static function fromArray(array $list): Middleware 33 | { 34 | return new Middleware($list); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Attribute/Reader/AttributeReader.php: -------------------------------------------------------------------------------- 1 | cache->getItem($cacheKey); 33 | 34 | if ($item->isHit()) { 35 | /** @var array $cachedMiddlewares */ 36 | $cachedMiddlewares = $item->get(); 37 | 38 | $middlewares = $this->normalizeFromCache($cachedMiddlewares); 39 | } else { 40 | $middlewares = $this->delegate->read($class, $method); 41 | 42 | $item->set($this->normalizeToCache($middlewares)); 43 | 44 | $this->cache->save($item); 45 | } 46 | 47 | return $middlewares; 48 | } 49 | 50 | /** 51 | * @param array $cachedMiddlewares 52 | * 53 | * @return Middleware[] 54 | */ 55 | private function normalizeFromCache(array $cachedMiddlewares): array 56 | { 57 | $middlewares = []; 58 | 59 | /** @var class-string[]|string[] $item */ 60 | foreach ($cachedMiddlewares as $item) { 61 | $middlewares[] = Middleware::fromArray($item); 62 | } 63 | 64 | return $middlewares; 65 | } 66 | 67 | /** 68 | * @param Middleware[] $middlewares 69 | * 70 | * @return array 71 | */ 72 | private function normalizeToCache(array $middlewares): array 73 | { 74 | $normalized = []; 75 | 76 | foreach ($middlewares as $middleware) { 77 | $normalized[] = $middleware->toArray(); 78 | } 79 | 80 | return $normalized; 81 | } 82 | 83 | private static function cacheKey(object $class, ?string $method = null): string 84 | { 85 | $key = 'symfony.middleware.'.str_replace('\\', '', $class::class); 86 | 87 | if ($method !== null) { 88 | $key .= '.'.$method; 89 | } 90 | 91 | return $key; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/Attribute/Reader/ClassMethodAttributeReader.php: -------------------------------------------------------------------------------- 1 | getAttributes(AttributeReader::ATTRIBUTE); 17 | 18 | if ($method !== null) { 19 | $attributes = array_merge( 20 | $attributes, 21 | (new \ReflectionMethod($class, $method))->getAttributes(AttributeReader::ATTRIBUTE) 22 | ); 23 | } 24 | 25 | return array_map(static function (\ReflectionAttribute $attribute): object { 26 | /** @var Middleware */ 27 | return $attribute->newInstance(); 28 | }, $attributes); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/DependencyInjection/AttributeReaderCompilerPass.php: -------------------------------------------------------------------------------- 1 | hasDefinition(AttributeReader::class) && $this->shouldBeCached($container)) { 21 | $definition = $container->findDefinition(AttributeReader::class); 22 | 23 | $container->setDefinition(AttributeReader::class, new Definition(CacheAttributesReader::class, [ 24 | new Reference(CacheItemPoolInterface::class), 25 | new Reference($definition->getClass() ?: ClassMethodAttributeReader::class), 26 | ])); 27 | } 28 | } 29 | 30 | private function shouldBeCached(ContainerBuilder $container): bool 31 | { 32 | if ($container->hasParameter('app.cache_middleware')) { 33 | return (bool) $container->getParameter('app.cache_middleware'); 34 | } 35 | 36 | return $container->getParameter('kernel.environment') === 'prod'; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/DependencyInjection/Configuration.php: -------------------------------------------------------------------------------- 1 | getRootNode(); 25 | 26 | $rootNode 27 | ->children() 28 | ->arrayNode('global') 29 | ->scalarPrototype() 30 | ->isRequired() 31 | ->beforeNormalization() 32 | ->always($this->createMiddlewareNormalizer()) 33 | ->end() 34 | ->end() 35 | ->end() 36 | ->arrayNode('groups') 37 | ->arrayPrototype() 38 | ->children() 39 | ->scalarNode('if')->end() 40 | ->arrayNode('middlewares') 41 | ->scalarPrototype() 42 | ->isRequired() 43 | ->beforeNormalization() 44 | ->always($this->createMiddlewareNormalizer()) 45 | ->end() 46 | ->end() 47 | ->end() 48 | ->end() 49 | ->end() 50 | ->end() 51 | ; 52 | 53 | return $tree; 54 | } 55 | 56 | /** 57 | * @return \Closure(mixed): string 58 | */ 59 | private function createMiddlewareNormalizer(): callable 60 | { 61 | return function (mixed $middlewareName): string { 62 | return match (true) { 63 | \is_string($middlewareName) && \class_exists($middlewareName) && \is_a($middlewareName, MiddlewareInterface::class, true) => $middlewareName, 64 | \is_string($middlewareName) && !\class_exists($middlewareName) => $middlewareName, 65 | default => throw new \RuntimeException( 66 | vsprintf('Each middleware must implements the "%s" interface, but "%s" doesn\'t.', [ 67 | MiddlewareInterface::class, 68 | \is_string($middlewareName) ? $middlewareName : get_debug_type($middlewareName), 69 | ]) 70 | ) 71 | }; 72 | }; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/DependencyInjection/SymiddlewareCompilerPass.php: -------------------------------------------------------------------------------- 1 | hasDefinition(MiddlewareRegistry::class) === false) { 19 | return; 20 | } 21 | 22 | $definition = $container->findDefinition(MiddlewareRegistry::class); 23 | 24 | $found = []; 25 | 26 | /** @var class-string $middleware */ 27 | foreach ($container->findTaggedServiceIds('kafkiansky.symfony.middleware') as $middleware => $_tags) { 28 | $found[$middleware] = service($middleware); 29 | } 30 | 31 | $definition->replaceArgument(0, service_locator($found)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/DependencyInjection/SymiddlewareExtension.php: -------------------------------------------------------------------------------- 1 | registerForAutoconfiguration(MiddlewareInterface::class) 22 | ->addTag('kafkiansky.symfony.middleware'); 23 | 24 | $loader = new PhpFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 25 | $loader->load('symiddleware.php'); 26 | 27 | $configuration = $this->getConfiguration($configs, $container); 28 | 29 | if ($configuration === null) { 30 | return; 31 | } 32 | 33 | /** @var array{groups: array, global?: string[]} $config */ 34 | $config = $this->processConfiguration($configuration, $configs); 35 | 36 | $config['groups']['global'] = [ 37 | 'if' => true, // global middleware should run always. 38 | 'middlewares' => $config['global'] ?? [], 39 | ]; 40 | 41 | unset($config['global']); 42 | 43 | // We will replace empty service locator in compiler pass when all middlewares will be found. 44 | $container->setDefinition( 45 | MiddlewareRegistry::class, 46 | new Definition(ServiceLocatorMiddlewareRegistry::class, [service_locator([]), $config['groups']]) 47 | ); 48 | } 49 | 50 | public function getAlias(): string 51 | { 52 | return 'symiddleware'; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Integration/ControllerListener.php: -------------------------------------------------------------------------------- 1 | getController(); 30 | $method = null; // null if controller is invokable. 31 | 32 | if (\is_array($controller)) { 33 | list($controller, $method) = $controller; 34 | } 35 | 36 | $attributes = $this->reader->read($controller, $method); 37 | 38 | $middlewares = $this->middlewareGatherer->gather($attributes); 39 | 40 | if (count($middlewares) > 0) { 41 | /** @psalm-var callable(): Response $originalController */ 42 | $originalController = $event->getController(); 43 | 44 | $event->setController($this->controllerReplacer->createController( 45 | $originalController, 46 | $event->getArguments(), 47 | $middlewares, 48 | $event->getRequest() 49 | )); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Integration/ControllerReplacer.php: -------------------------------------------------------------------------------- 1 | createMiddlewareRunner($middlewares, $originalController, $arguments, $symfonyRequest), 42 | $this->psrRequestTransformer->toPsrRequest($symfonyRequest) 43 | ); 44 | } 45 | 46 | /** 47 | * @param MiddlewareInterface[] $middlewares 48 | */ 49 | private function createMiddlewareRunner( 50 | array $middlewares, 51 | callable $destination, 52 | array $arguments, 53 | Request $symfonyRequest 54 | ): MiddlewareRunner { 55 | return new MiddlewareRunner( 56 | $middlewares, 57 | new SymfonyActionRequestHandler( 58 | function (Request $request) use ($destination, $arguments): Response { 59 | /** @var Response */ 60 | return $destination(...$this->withReplacedRequest($request, $arguments)); 61 | }, 62 | $symfonyRequest, 63 | $this->psrResponseTransformer, 64 | $this->psrRequestCloner, 65 | ), 66 | $this->psrResponseTransformer, 67 | ); 68 | } 69 | 70 | private function withReplacedRequest(Request $request, array $arguments): array 71 | { 72 | $updatedArguments = []; 73 | 74 | /** @var object|scalar $argument */ 75 | foreach ($arguments as $argument) { 76 | if ($argument instanceof Request) { 77 | $argument = $request; 78 | } 79 | 80 | $updatedArguments[] = $argument; 81 | } 82 | 83 | return $updatedArguments; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Middleware/MiddlewareAction.php: -------------------------------------------------------------------------------- 1 | middlewareRunner->run($this->serverRequest); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Middleware/MiddlewareGatherer.php: -------------------------------------------------------------------------------- 1 | $middleware->list, $attributes)), 34 | ); 35 | 36 | $middlewares = $this->middlewareRegistry->byName(self::GLOBAL_MIDDLEWARE_GROUP); 37 | 38 | foreach ($middlewaresOrGroups as $middlewareOrGroup) { 39 | $middlewares = array_merge($middlewares, $this->middlewareRegistry->byName($middlewareOrGroup)); 40 | } 41 | 42 | return array_values(array_unique($middlewares, SORT_REGULAR)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Middleware/MiddlewareNotConfigured.php: -------------------------------------------------------------------------------- 1 | middlewares), 31 | /** @param \Closure(ServerRequestInterface): ResponseInterface $stack */ 32 | function (\Closure $stack, MiddlewareInterface $middleware): \Closure { 33 | return function (ServerRequestInterface $request) use ($middleware, $stack): ResponseInterface { 34 | return $middleware->process($request, new StackMiddleware($stack)); 35 | }; 36 | }, 37 | fn (ServerRequestInterface $request): ResponseInterface => $this->requestHandler->handle($request), 38 | ); 39 | 40 | return $this->psrResponseTransformer->fromPsrResponse($processor($serverRequest)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Middleware/Registry/MiddlewareRegistry.php: -------------------------------------------------------------------------------- 1 | |string $middlewareFqcnOrGroup 14 | * 15 | * @throws MiddlewareNotConfigured 16 | * 17 | * @return MiddlewareInterface[] 18 | */ 19 | public function byName(string $middlewareFqcnOrGroup): array; 20 | } 21 | -------------------------------------------------------------------------------- /src/Middleware/Registry/ServiceLocatorMiddlewareRegistry.php: -------------------------------------------------------------------------------- 1 | >} 13 | */ 14 | final class ServiceLocatorMiddlewareRegistry implements MiddlewareRegistry 15 | { 16 | /** @var array[]> */ 17 | private readonly array $enabledMiddlewareGroups; 18 | 19 | /** 20 | * @psalm-param array $groups 21 | * 22 | * @throws MiddlewareNotConfigured 23 | */ 24 | public function __construct( 25 | private readonly ContainerInterface $container, 26 | private readonly array $groups, 27 | ) { 28 | $this->enabledMiddlewareGroups = self::normalizeGroups($this->groups); 29 | } 30 | 31 | /** 32 | * {@inheritdoc} 33 | */ 34 | public function byName(string $middlewareFqcnOrGroup): array 35 | { 36 | if (!$this->container->has($middlewareFqcnOrGroup) && !isset($this->groups[$middlewareFqcnOrGroup])) { 37 | throw MiddlewareNotConfigured::forMiddleware($middlewareFqcnOrGroup); 38 | } 39 | 40 | if ($this->container->has($middlewareFqcnOrGroup)) { 41 | /** @var MiddlewareInterface[] */ 42 | return [$this->container->get($middlewareFqcnOrGroup)]; 43 | } 44 | 45 | return array_map(function (string $middleware): MiddlewareInterface { 46 | /** @var MiddlewareInterface */ 47 | return $this->container->get($middleware); 48 | }, $this->enabledMiddlewareGroups[$middlewareFqcnOrGroup] ?? []); 49 | } 50 | 51 | /** 52 | * @param array $groups 53 | * 54 | * @throws MiddlewareNotConfigured 55 | * 56 | * @return array[]> 57 | */ 58 | private static function normalizeGroups(array $groups): array 59 | { 60 | $middlewareGroups = []; 61 | 62 | foreach ($groups as $name => $group) { 63 | if ($group['if'] ?? true) { 64 | $middlewareGroups[$name] = self::normalizeMiddlewares($groups, $group['middlewares'] ?? throw MiddlewareNotConfigured::becauseGroupIsEmpty($name)); 65 | } 66 | } 67 | 68 | return $middlewareGroups; 69 | } 70 | 71 | /** 72 | * @param array $groups 73 | * @param list> $middlewares 74 | * 75 | * @throws MiddlewareNotConfigured 76 | * 77 | * @return class-string[] 78 | */ 79 | private static function normalizeMiddlewares(array $groups, array $middlewares): array 80 | { 81 | $groupMiddlewares = []; 82 | 83 | foreach ($middlewares as $middleware) { 84 | if (\is_a($middleware, MiddlewareInterface::class, true)) { 85 | $groupMiddlewares = array_merge($groupMiddlewares, [$middleware]); 86 | } elseif (isset($groups[$middleware]) && ($groups[$middleware]['if'] ?? true)) { 87 | $groupMiddlewares = array_merge( 88 | $groupMiddlewares, 89 | self::normalizeMiddlewares($groups, $groups[$middleware]['middlewares'] ?? throw MiddlewareNotConfigured::becauseGroupIsEmpty($middleware)), 90 | ); 91 | } elseif(!isset($groups[$middleware])) { 92 | throw MiddlewareNotConfigured::forMiddleware($middleware); 93 | } 94 | } 95 | 96 | return $groupMiddlewares; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/Middleware/StackMiddleware.php: -------------------------------------------------------------------------------- 1 | stack)($request); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Middleware/SymfonyActionRequestHandler.php: -------------------------------------------------------------------------------- 1 | destination = $destination; 32 | } 33 | 34 | public function handle(ServerRequestInterface $request): ResponseInterface 35 | { 36 | $clonedSymfonyRequest = $this->psrRequestCloner->clone($this->symfonyRequest, $request); 37 | 38 | $response = ($this->destination)($clonedSymfonyRequest); 39 | 40 | return $this->psrResponseTransformer->toPsrResponse($response); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Psr/Adapter/PsrHttpMessageBridgePsrRequestTransformer.php: -------------------------------------------------------------------------------- 1 | httpMessageFactory->createRequest($symfonyRequest); 24 | } 25 | 26 | public function fromPsrRequest(ServerRequestInterface $request): SymfonyRequest 27 | { 28 | return $this->httpFoundationFactory->createRequest($request); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Psr/Adapter/PsrHttpMessageBridgePsrResponseTransformer.php: -------------------------------------------------------------------------------- 1 | httpMessageFactory->createResponse($symfonyResponse); 24 | } 25 | 26 | public function fromPsrResponse(ResponseInterface $response): SymfonyResponse 27 | { 28 | return $this->httpFoundationFactory->createResponse($response); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Psr/DefaultPsrRequestCloner.php: -------------------------------------------------------------------------------- 1 | attributes->replace($psrRequest->getAttributes()); 15 | $symfonyRequest->headers->replace($psrRequest->getHeaders()); 16 | $symfonyRequest->query->replace($psrRequest->getQueryParams()); 17 | 18 | if (\is_array($parsedBody = $psrRequest->getParsedBody())) { 19 | $symfonyRequest->request->replace($parsedBody); 20 | } 21 | 22 | return $symfonyRequest; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Psr/PsrRequestCloner.php: -------------------------------------------------------------------------------- 1 | services(); 10 | 11 | $services->set(Kafkiansky\SymfonyMiddleware\Attribute\Reader\ClassMethodAttributeReader::class); 12 | 13 | $services 14 | ->set( 15 | Kafkiansky\SymfonyMiddleware\Attribute\Reader\AttributeReader::class, 16 | Kafkiansky\SymfonyMiddleware\Attribute\Reader\ClassMethodAttributeReader::class, 17 | ); 18 | 19 | $services 20 | ->set( 21 | Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface::class, 22 | Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory::class 23 | ); 24 | 25 | $services->set(Nyholm\Psr7\Factory\Psr17Factory::class, Nyholm\Psr7\Factory\Psr17Factory::class); 26 | 27 | $services 28 | ->set( 29 | Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface::class, 30 | Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory::class, 31 | ) 32 | ->args([ 33 | '$serverRequestFactory' => service(Nyholm\Psr7\Factory\Psr17Factory::class), 34 | '$streamFactory' => service(Nyholm\Psr7\Factory\Psr17Factory::class), 35 | '$uploadedFileFactory' => service(Nyholm\Psr7\Factory\Psr17Factory::class), 36 | '$responseFactory' => service(Nyholm\Psr7\Factory\Psr17Factory::class), 37 | ]); 38 | 39 | $services 40 | ->set( 41 | Kafkiansky\SymfonyMiddleware\Psr\PsrRequestTransformer::class, 42 | Kafkiansky\SymfonyMiddleware\Psr\Adapter\PsrHttpMessageBridgePsrRequestTransformer::class 43 | ) 44 | ->args([ 45 | service(Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface::class), 46 | service(Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface::class), 47 | ]); 48 | 49 | $services 50 | ->set( 51 | Kafkiansky\SymfonyMiddleware\Psr\PsrResponseTransformer::class, 52 | Kafkiansky\SymfonyMiddleware\Psr\Adapter\PsrHttpMessageBridgePsrResponseTransformer::class 53 | ) 54 | ->args([ 55 | service(Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface::class), 56 | service(Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface::class), 57 | ]); 58 | 59 | $services 60 | ->set( 61 | Kafkiansky\SymfonyMiddleware\Middleware\MiddlewareGatherer::class, 62 | Kafkiansky\SymfonyMiddleware\Middleware\MiddlewareGatherer::class 63 | ) 64 | ->args([ 65 | service(Kafkiansky\SymfonyMiddleware\Middleware\Registry\MiddlewareRegistry::class), 66 | ]) 67 | ; 68 | 69 | $services->set( 70 | Kafkiansky\SymfonyMiddleware\Psr\PsrRequestCloner::class, 71 | Kafkiansky\SymfonyMiddleware\Psr\DefaultPsrRequestCloner::class, 72 | ); 73 | 74 | $services 75 | ->set( 76 | Kafkiansky\SymfonyMiddleware\Integration\ControllerReplacer::class, 77 | Kafkiansky\SymfonyMiddleware\Integration\ControllerReplacer::class, 78 | ) 79 | ->args([ 80 | service(Kafkiansky\SymfonyMiddleware\Psr\PsrRequestTransformer::class), 81 | service(Kafkiansky\SymfonyMiddleware\Psr\PsrResponseTransformer::class), 82 | service(Kafkiansky\SymfonyMiddleware\Psr\PsrRequestCloner::class), 83 | ]); 84 | 85 | $services->set(Kafkiansky\SymfonyMiddleware\Integration\ControllerListener::class) 86 | ->tag('kernel.event_listener', [ 87 | 'event' => Symfony\Component\HttpKernel\KernelEvents::CONTROLLER_ARGUMENTS, 88 | 'method' => 'onControllerArguments', 89 | ]) 90 | ->args([ 91 | service(Kafkiansky\SymfonyMiddleware\Middleware\MiddlewareGatherer::class), 92 | service(Kafkiansky\SymfonyMiddleware\Attribute\Reader\AttributeReader::class), 93 | service(Kafkiansky\SymfonyMiddleware\Integration\ControllerReplacer::class), 94 | ]) 95 | ; 96 | }; 97 | -------------------------------------------------------------------------------- /src/SymiddlewareBundle.php: -------------------------------------------------------------------------------- 1 | addCompilerPass(new SymiddlewareCompilerPass()); 21 | $container->addCompilerPass(new AttributeReaderCompilerPass()); 22 | } 23 | 24 | public function getContainerExtension(): ExtensionInterface 25 | { 26 | return new SymiddlewareExtension(); 27 | } 28 | } 29 | --------------------------------------------------------------------------------