diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 9437bd41..09a5c2f8 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -55,10 +55,6 @@ jobs: symfony-deprecations-helper: "weak" # Test maintained versions of Symfony - - dependencies: "php-http/guzzle6-adapter" - symfony-require: "3.4.*" - php-version: "7.3" - symfony-deprecations-helper: "weak" - dependencies: "php-http/guzzle7-adapter symfony/http-client:^4.4" symfony-require: "4.4.*" php-version: "7.3" diff --git a/CHANGELOG.md b/CHANGELOG.md index badb86bc..9ff0a57a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,11 @@ The change log describes what is "Added", "Removed", "Changed" or "Fixed" between each release. -# 1.24.1 - TBD -- Fixed deprecation notice in PHP 8.1 by adding `= null` to `\Http\HttplugBundle\Collector\Twig\HttpMessageMarkupExtension` -- +# 1.25.0 - TBD +- Added PHP 8.1 support +- Added Symfony 6 support +- Removed Symfony 3.x support + # 1.24.0 - 2021-10-23 - Changed stopwatch category from default to "httplug", so it's more prominent on Execution timeline view - Changed tab texts inside profiler so that it shows ports in URL in case it's non-standard diff --git a/composer.json b/composer.json index f02f6edc..339e63ce 100644 --- a/composer.json +++ b/composer.json @@ -28,18 +28,18 @@ "php": "^7.3 || ^8.0", "php-http/client-common": "^1.9 || ^2.0", "php-http/client-implementation": "^1.0", - "php-http/discovery": "^1.0", + "php-http/discovery": "^1.14", "php-http/httplug": "^1.0 || ^2.0", "php-http/logger-plugin": "^1.1", "php-http/message": "^1.4", "php-http/message-factory": "^1.0.2", "php-http/stopwatch-plugin": "^1.2", "psr/http-message": "^1.0", - "symfony/config": "^3.4.34 || ^4.2.12 || ^5.0", - "symfony/dependency-injection": "^3.4.34 || ^4.2.12 || ^5.0", - "symfony/event-dispatcher": "^3.4.34 || ^4.2.12 || ^5.0", - "symfony/http-kernel": "^3.4.34 || ^4.2.12 || ^5.0", - "symfony/options-resolver": "^3.4.34 || ^4.2.12 || ^5.0" + "symfony/config": "^4.4 || ^5.0 || ^6.0", + "symfony/dependency-injection": "^4.4 || ^5.0 || ^6.0", + "symfony/event-dispatcher": "^4.4 || ^5.0 || ^6.0", + "symfony/http-kernel": "^4.4 || ^5.0 || ^6.0", + "symfony/options-resolver": "^4.4 || ^5.0 || ^6.0" }, "conflict": { "php-http/guzzle6-adapter": "<1.1", @@ -53,16 +53,15 @@ "php-http/cache-plugin": "^1.7", "php-http/mock-client": "^1.2", "php-http/promise": "^1.0", - "polishsymfonycommunity/symfony-mocker-container": "^1.0", - "symfony/browser-kit": "^3.4.34 || ^4.2.12 || ^5.0", - "symfony/cache": "^3.4.35 || ~4.2.12 || ^4.3.8 || ^5.0", - "symfony/dom-crawler": "^3.4.34 || ^4.2.12 || ^5.0", - "symfony/framework-bundle": "^3.4.34 || ^4.2.12 || ^5.0", - "symfony/http-foundation": "^3.4.35 || ~4.2.12 || ^4.3.8 || ^5.0", + "symfony/browser-kit": "^4.4 || ^5.0 || ^6.0", + "symfony/cache": "^4.4 || ^5.0 || ^6.0", + "symfony/dom-crawler": "^4.4 || ^5.0 || ^6.0", + "symfony/framework-bundle": "^4.4 || ^5.0 || ^6.0", + "symfony/http-foundation": "^4.4.19 || ^5.0 || ^6.0", "symfony/phpunit-bridge": "^5.3", - "symfony/stopwatch": "^3.4.34 || ^4.2.12 || ^5.0", - "symfony/twig-bundle": "^3.4.34 || ^4.2.12 || ^5.0", - "symfony/web-profiler-bundle": "^3.4.34 || ^4.2.12 || ^5.0", + "symfony/stopwatch": "^4.4 || ^5.0 || ^6.0", + "symfony/twig-bundle": "^4.4 || ^5.0 || ^6.0", + "symfony/web-profiler-bundle": "^4.4.19 || ^5.0 || ^6.0", "twig/twig": "^1.41 || ^2.10 || ^3.0" }, "suggest": { @@ -95,7 +94,7 @@ ] }, "minimum-stability": "dev", - "prefer-stable": true, + "prefer-stable": false, "scripts": { "test": "vendor/bin/simple-phpunit", "test-ci": "vendor/bin/simple-phpunit --coverage-text --coverage-clover=build/coverage.xml" diff --git a/src/Collector/Collector.php b/src/Collector/Collector.php index 71c16b6d..cc4fb23e 100644 --- a/src/Collector/Collector.php +++ b/src/Collector/Collector.php @@ -43,7 +43,7 @@ public function reset() /** * {@inheritdoc} */ - public function getName() + public function getName(): string { return 'httplug'; } diff --git a/src/Collector/PluginClientFactoryListener.php b/src/Collector/PluginClientFactoryListener.php index 44e0b4e0..4f11f482 100644 --- a/src/Collector/PluginClientFactoryListener.php +++ b/src/Collector/PluginClientFactoryListener.php @@ -48,7 +48,7 @@ public function onEvent(PluginClientFactoryListenerEventClass $e) /** * {@inheritdoc} */ - public static function getSubscribedEvents() + public static function getSubscribedEvents(): array { return [ 'kernel.request' => ['onEvent', 1024], diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 76a60016..00a9ac54 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -54,15 +54,10 @@ public function __construct($debug) /** * {@inheritdoc} */ - public function getConfigTreeBuilder() + public function getConfigTreeBuilder(): TreeBuilder { $treeBuilder = new TreeBuilder('httplug'); - // Keep compatibility with symfony/config < 4.2 - if (!method_exists($treeBuilder, 'getRootNode')) { - $rootNode = $treeBuilder->root('httplug'); - } else { - $rootNode = $treeBuilder->getRootNode(); - } + $rootNode = $treeBuilder->getRootNode(); $this->configureClients($rootNode); $this->configureSharedPlugins($rootNode); @@ -274,12 +269,7 @@ private function configureSharedPlugins(ArrayNodeDefinition $root) private function createClientPluginNode() { $treeBuilder = new TreeBuilder('plugins'); - // Keep compatibility with symfony/config < 4.2 - if (!method_exists($treeBuilder, 'getRootNode')) { - $node = $treeBuilder->root('plugins'); - } else { - $node = $treeBuilder->getRootNode(); - } + $node = $treeBuilder->getRootNode(); /** @var ArrayNodeDefinition $pluginList */ $pluginList = $node @@ -610,12 +600,7 @@ private function addSharedPluginNodes(ArrayNodeDefinition $pluginNode, $disableA private function createAuthenticationPluginNode() { $treeBuilder = new TreeBuilder('authentication'); - // Keep compatibility with symfony/config < 4.2 - if (!method_exists($treeBuilder, 'getRootNode')) { - $node = $treeBuilder->root('authentication'); - } else { - $node = $treeBuilder->getRootNode(); - } + $node = $treeBuilder->getRootNode(); $node ->useAttributeAsKey('name') @@ -707,12 +692,7 @@ private function validateAuthenticationType(array $expected, array $actual, $aut private function createCachePluginNode() { $builder = new TreeBuilder('config'); - // Keep compatibility with symfony/config < 4.2 - if (!method_exists($builder, 'getRootNode')) { - $config = $builder->root('config'); - } else { - $config = $builder->getRootNode(); - } + $config = $builder->getRootNode(); $config ->fixXmlConfig('method') @@ -805,12 +785,7 @@ private function createCachePluginNode() ; $treeBuilder = new TreeBuilder('cache'); - // Keep compatibility with symfony/config < 4.2 - if (!method_exists($treeBuilder, 'getRootNode')) { - $cache = $treeBuilder->root('cache'); - } else { - $cache = $treeBuilder->getRootNode(); - } + $cache = $treeBuilder->getRootNode(); $cache ->canBeEnabled() diff --git a/src/DependencyInjection/HttplugExtension.php b/src/DependencyInjection/HttplugExtension.php index d9d0d49f..1a8aa0cf 100644 --- a/src/DependencyInjection/HttplugExtension.php +++ b/src/DependencyInjection/HttplugExtension.php @@ -23,12 +23,12 @@ use Http\Mock\Client as MockClient; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\UriInterface; +use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\Alias; use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\DefinitionDecorator; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpKernel\DependencyInjection\Extension; @@ -382,14 +382,8 @@ private function configureClient(ContainerBuilder $container, $clientName, array { $serviceId = 'httplug.client.'.$clientName; - if (method_exists($container, 'registerAliasForArgument')) { - $alias = $container->registerAliasForArgument($serviceId, HttpClient::class, $clientName); - - $interfaces = class_implements(HttpClient::class) ?? []; - if (isset($interfaces[ClientInterface::class])) { - $container->registerAliasForArgument($serviceId, ClientInterface::class, $clientName); - } - } + $container->registerAliasForArgument($serviceId, HttpClient::class, $clientName); + $container->registerAliasForArgument($serviceId, ClientInterface::class, $clientName); $plugins = []; foreach ($arguments['plugins'] as $plugin) { @@ -530,7 +524,7 @@ private function configureAutoDiscoveryClients(ContainerBuilder $container, arra /** * {@inheritdoc} */ - public function getConfiguration(array $config, ContainerBuilder $container) + public function getConfiguration(array $config, ContainerBuilder $container): ?ConfigurationInterface { return new Configuration($container->getParameter('kernel.debug')); } @@ -547,7 +541,7 @@ private function configurePlugin(ContainerBuilder $container, $serviceId, $plugi { $pluginServiceId = $serviceId.'.plugin.'.$pluginName; - $definition = $this->createChildDefinition('httplug.plugin.'.$pluginName); + $definition = new ChildDefinition('httplug.plugin.'.$pluginName); $this->configurePluginByName($pluginName, $definition, $pluginConfig, $container, $pluginServiceId); $container->setDefinition($pluginServiceId, $definition); @@ -564,7 +558,7 @@ private function configureVcrPlugin(ContainerBuilder $container, array $config, $recordId = $prefix.'.record'; if ('filesystem' === $recorder) { - $recorderDefinition = $this->createChildDefinition('httplug.plugin.vcr.recorder.filesystem'); + $recorderDefinition = new ChildDefinition('httplug.plugin.vcr.recorder.filesystem'); $recorderDefinition->replaceArgument(0, $config['fixtures_directory']); $recorderId = $prefix.'.recorder'; @@ -573,7 +567,7 @@ private function configureVcrPlugin(ContainerBuilder $container, array $config, if ('default' === $config['naming_strategy']) { $namingStrategyId = $prefix.'.naming_strategy'; - $namingStrategy = $this->createChildDefinition('httplug.plugin.vcr.naming_strategy.path'); + $namingStrategy = new ChildDefinition('httplug.plugin.vcr.naming_strategy.path'); if (!empty($config['naming_strategy_options'])) { $namingStrategy->setArguments([$config['naming_strategy_options']]); @@ -610,18 +604,4 @@ private function configureVcrPlugin(ContainerBuilder $container, array $config, return $plugins; } - - /** - * BC for old Symfony versions. Remove this method and use new ChildDefinition directly when we drop support for Symfony 2. - * - * @param string $parent the parent service id - * - * @return ChildDefinition|DefinitionDecorator - */ - private function createChildDefinition($parent) - { - $definitionClass = class_exists(ChildDefinition::class) ? ChildDefinition::class : DefinitionDecorator::class; - - return new $definitionClass($parent); - } } diff --git a/src/Discovery/ConfiguredClientsStrategyListener.php b/src/Discovery/ConfiguredClientsStrategyListener.php index 621c03c9..82cefcd8 100644 --- a/src/Discovery/ConfiguredClientsStrategyListener.php +++ b/src/Discovery/ConfiguredClientsStrategyListener.php @@ -25,7 +25,7 @@ public function onEvent() * * {@inheritdoc} */ - public static function getSubscribedEvents() + public static function getSubscribedEvents(): array { return [ 'kernel.request' => ['onEvent', 1024], diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml index 8cab29a2..a839d134 100644 --- a/src/Resources/config/services.xml +++ b/src/Resources/config/services.xml @@ -21,7 +21,7 @@ - + diff --git a/tests/Functional/ServiceInstantiationTest.php b/tests/Functional/ServiceInstantiationTest.php index 9bb7d0f3..35dcfffa 100644 --- a/tests/Functional/ServiceInstantiationTest.php +++ b/tests/Functional/ServiceInstantiationTest.php @@ -24,6 +24,7 @@ use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\Kernel; use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\HttpKernel\Profiler\Profiler; class ServiceInstantiationTest extends WebTestCase @@ -125,7 +126,7 @@ public function testProfilingPsr18Decoration(): void /** * {@inheritdoc} */ - protected static function bootKernel(array $options = []) + protected static function bootKernel(array $options = []): KernelInterface { parent::bootKernel($options); @@ -135,11 +136,7 @@ protected static function bootKernel(array $options = []) $class = (Kernel::MAJOR_VERSION >= 5) ? RequestEvent::class : GetResponseEvent::class; $event = new $class(static::$kernel, SymfonyRequest::create('/'), HttpKernelInterface::MASTER_REQUEST); - if (version_compare(Kernel::VERSION, '4.3.0', '>=')) { - $dispatcher->dispatch($event, KernelEvents::REQUEST); - } else { - $dispatcher->dispatch(KernelEvents::REQUEST, $event); - } + $dispatcher->dispatch($event, KernelEvents::REQUEST); return static::$kernel; } diff --git a/tests/Resources/app/AppKernel.php b/tests/Resources/app/AppKernel.php index 1b49d0bc..79e89bd4 100644 --- a/tests/Resources/app/AppKernel.php +++ b/tests/Resources/app/AppKernel.php @@ -2,18 +2,18 @@ declare(strict_types=1); -use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Kernel; -use Symfony\Component\Routing\RouteCollectionBuilder; +use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; +use Symfony\Component\Routing\Loader\PhpFileLoader as RoutingPhpFileLoader; +use Symfony\Component\Routing\Route; +use Symfony\Component\Routing\RouteCollection; class AppKernel extends Kernel { - use MicroKernelTrait; - /** * @var string */ @@ -22,7 +22,7 @@ class AppKernel extends Kernel /** * {@inheritdoc} */ - public function registerBundles() + public function registerBundles(): iterable { $bundles = [ new \Symfony\Bundle\FrameworkBundle\FrameworkBundle(), @@ -37,37 +37,52 @@ public function registerBundles() return $bundles; } - /** - * {@inheritdoc} - */ - protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader): void + public function registerContainerConfiguration(LoaderInterface $loader) { - $loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml'); - if ($this->isDebug()) { - $loader->load(__DIR__.'/config/config_debug.yml'); - } + $loader->load(function (ContainerBuilder $container) use ($loader) { + $container->loadFromExtension('framework', [ + 'router' => [ + 'resource' => 'kernel::loadRoutes', + 'type' => 'service', + 'utf8' => true, + ], + ]); + + $container->register('kernel', static::class) + ->addTag('routing.route_loader') + ->setAutoconfigured(true) + ->setSynthetic(true) + ->setPublic(true) + ; + + $loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml'); + if ($this->isDebug()) { + $loader->load(__DIR__.'/config/config_debug.yml'); + } + }); } - /** - * {@inheritdoc} - */ - protected function configureRoutes(RouteCollectionBuilder $routes): void + public function loadRoutes(LoaderInterface $loader): RouteCollection { - $routes->import('@WebProfilerBundle/Resources/config/routing/wdt.xml', '/_wdt'); - $routes->import('@WebProfilerBundle/Resources/config/routing/profiler.xml', '/_profiler'); - - if (Kernel::MAJOR_VERSION < 4 || (Kernel::MAJOR_VERSION === 4 && Kernel::MINOR_VERSION === 0)) { - $routes->add('/', 'kernel:indexAction'); - } else { - // If 4.1+ - $routes->add('/', 'kernel::indexAction'); - } + $file = (new \ReflectionObject($this))->getFileName(); + /* @var RoutingPhpFileLoader $kernelLoader */ + $kernelLoader = $loader->getResolver()->resolve($file, 'php'); + $kernelLoader->setCurrentDir(\dirname($file)); + + $collection = new RouteCollection(); + $collection->add('/', new Route('/', ['_controller' => 'kernel::indexAction'])); + + $routes = new RoutingConfigurator($collection, $kernelLoader, $file, $file); + $routes->import('@WebProfilerBundle/Resources/config/routing/wdt.xml')->prefix('_wdt'); + $routes->import('@WebProfilerBundle/Resources/config/routing/profiler.xml')->prefix('_profiler'); + + return $collection; } /** * {@inheritdoc} */ - public function getCacheDir() + public function getCacheDir(): string { if (null === self::$cacheDir) { self::$cacheDir = uniqid('cache'); @@ -79,19 +94,11 @@ public function getCacheDir() /** * {@inheritdoc} */ - public function getLogDir() + public function getLogDir(): string { return sys_get_temp_dir().'/httplug-bundle/logs'; } - /** - * {@inheritdoc} - */ - protected function getContainerBaseClass() - { - return '\PSS\SymfonyMockerContainer\DependencyInjection\MockerContainer'; - } - public function indexAction() { return new Response(); diff --git a/tests/Unit/DependencyInjection/ConfigurationTest.php b/tests/Unit/DependencyInjection/ConfigurationTest.php index 35f56953..30796ba8 100644 --- a/tests/Unit/DependencyInjection/ConfigurationTest.php +++ b/tests/Unit/DependencyInjection/ConfigurationTest.php @@ -111,21 +111,6 @@ protected function getConfiguration(): ConfigurationInterface return new Configuration(true); } - public function testEmptyConfiguration(): void - { - $formats = array_map(function ($path) { - return __DIR__.'/../../Resources/Fixtures/'.$path; - }, [ - 'config/empty.yml', - 'config/empty.xml', - 'config/empty.php', - ]); - - foreach ($formats as $format) { - $this->assertProcessedConfigurationEquals($this->emptyConfig, [$format]); - } - } - public function testSupportsAllConfigFormats(): void { if (!class_exists(Client::class)) { diff --git a/tests/Unit/DependencyInjection/HttplugExtensionTest.php b/tests/Unit/DependencyInjection/HttplugExtensionTest.php index 3858010a..e65e977b 100644 --- a/tests/Unit/DependencyInjection/HttplugExtensionTest.php +++ b/tests/Unit/DependencyInjection/HttplugExtensionTest.php @@ -11,7 +11,6 @@ use Http\HttplugBundle\DependencyInjection\HttplugExtension; use Matthias\SymfonyDependencyInjectionTest\PhpUnit\AbstractExtensionTestCase; use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\HttpKernel\Kernel; /** * @author David Buchmann @@ -354,14 +353,6 @@ public function testClientShouldHaveDefaultVisibility(): void ]); $this->assertContainerBuilderHasService('httplug.client.acme'); - - if (version_compare(Kernel::VERSION, '3.4', '>=')) { - // Symfony made services private by default starting from 3.4 - $this->assertTrue($this->container->getDefinition('httplug.client.acme')->isPrivate()); - } else { - // Legacy Symfony - $this->assertTrue($this->container->getDefinition('httplug.client.acme')->isPublic()); - } } public function testFlexibleClientShouldBePrivateByDefault(): void @@ -418,11 +409,6 @@ public function testClientCanBePublic(): void $this->assertContainerBuilderHasService('httplug.client.acme'); $this->assertTrue($this->container->getDefinition('httplug.client.acme')->isPublic()); - - if (version_compare(Kernel::VERSION, '3.4', '>=')) { - // Symfony made services private by default starting from 3.4 - $this->assertFalse($this->container->getDefinition('httplug.client.acme')->isPrivate()); - } } public function testFlexibleClientCanBePublic(): void @@ -438,11 +424,6 @@ public function testFlexibleClientCanBePublic(): void $this->assertContainerBuilderHasService('httplug.client.acme'); $this->assertTrue($this->container->getDefinition('httplug.client.acme.flexible')->isPublic()); - - if (version_compare(Kernel::VERSION, '3.4', '>=')) { - // Symfony made services private by default starting from 3.4 - $this->assertFalse($this->container->getDefinition('httplug.client.acme.flexible')->isPrivate()); - } } public function testHttpMethodsClientCanBePublic(): void @@ -458,11 +439,6 @@ public function testHttpMethodsClientCanBePublic(): void $this->assertContainerBuilderHasService('httplug.client.acme'); $this->assertTrue($this->container->getDefinition('httplug.client.acme.http_methods')->isPublic()); - - if (version_compare(Kernel::VERSION, '3.4', '>=')) { - // Symfony made services private by default starting from 3.4 - $this->assertFalse($this->container->getDefinition('httplug.client.acme.http_methods')->isPrivate()); - } } public function testBatchClientCanBePublic(): void @@ -478,11 +454,6 @@ public function testBatchClientCanBePublic(): void $this->assertContainerBuilderHasService('httplug.client.acme'); $this->assertTrue($this->container->getDefinition('httplug.client.acme.batch_client')->isPublic()); - - if (version_compare(Kernel::VERSION, '3.4', '>=')) { - // Symfony made services private by default starting from 3.4 - $this->assertFalse($this->container->getDefinition('httplug.client.acme.batch_client')->isPrivate()); - } } public function testClientIsTaggedWithHttplugClientTag(): void