diff --git a/composer.json b/composer.json index 8fedf3fa..9f91ec5f 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,7 @@ "require": { "php": "^7.3 || ^8.0", "ext-json": "*", - "symfony/options-resolver": "^4.4 || ^5 || ^6 || ^7", + "symfony/options-resolver": "^4.4 || ^5 || ^6 || ^7 || ^8", "psr/cache": "^1 || ^2 || ^3", "psr/simple-cache": "^1 || ^2 || ^3", "psr/event-dispatcher": "^1", diff --git a/lib/Tmdb/Client.php b/lib/Tmdb/Client.php index 36468168..3e231265 100644 --- a/lib/Tmdb/Client.php +++ b/lib/Tmdb/Client.php @@ -95,7 +95,7 @@ protected function configureOptions(array $options) 'base_uri' => null, 'api_token' => null, 'guest_session_token' => null, - 'http' => function (OptionsResolver $optionsResolver) { + 'http' => $http = function (OptionsResolver $optionsResolver) { $optionsResolver->setDefaults( [ 'client' => null, @@ -120,7 +120,7 @@ protected function configureOptions(array $options) $optionsResolver->setAllowedTypes('stream_factory', [StreamFactoryInterface::class, 'null']); $optionsResolver->setAllowedTypes('uri_factory', [UriFactoryInterface::class, 'null']); }, - 'hydration' => function (OptionsResolver $optionsResolver) { + 'hydration' => $hydration = function (OptionsResolver $optionsResolver) { $optionsResolver->setDefaults( [ 'event_listener_handles_hydration' => false, @@ -131,7 +131,7 @@ protected function configureOptions(array $options) // @todo 4.1 validate these are actually models $optionsResolver->setAllowedTypes('only_for_specified_models', ['array']); }, - 'event_dispatcher' => function (OptionsResolver $optionsResolver) { + 'event_dispatcher' => $eventDispatcher = function (OptionsResolver $optionsResolver) { $optionsResolver->setDefaults( [ 'adapter' => null @@ -144,6 +144,17 @@ protected function configureOptions(array $options) ] ); + // symfony/options-resolver 8.0 removed nested-options-via-Closure passed to setDefaults(); + // setOptions() is the replacement, available from 7.3. The runtime guard supports older + // versions still allowed by composer.json; PHPStan tautology errors are silenced in + // phpstan-baseline.neon for both true and false outcomes (analysis runs against a single + // installed OptionsResolver version, but the guard is genuine across the supported range). + if (method_exists($resolver, 'setOptions')) { + $resolver->setOptions('http', $http); + $resolver->setOptions('hydration', $hydration); + $resolver->setOptions('event_dispatcher', $eventDispatcher); + } + $resolver->setRequired( [ 'host', diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 50dbd489..5318f2fd 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -18,12 +18,34 @@ parameters: count: 1 path: lib/Tmdb/Event/Listener/Logger/LogHttpMessageListener.php + # The method_exists(setOptions) guard supports symfony/options-resolver versions both + # with and without the method. PHPStan resolves against the installed version on each + # CI job, so exactly one of these two outcomes fires per job; reportUnmatched silences + # the other. - - rawMessage: 'Parameter #3 $first of method Http\Client\Common\Plugin\CachePlugin::handleRequest() expects callable(Psr\Http\Message\RequestInterface): Http\Promise\Promise, Closure(): void given.' + rawMessage: "Call to function method_exists() with Symfony\\Component\\OptionsResolver\\OptionsResolver and 'setOptions' will always evaluate to true." + identifier: function.alreadyNarrowedType + reportUnmatched: false + path: lib/Tmdb/Client.php + + - + rawMessage: "Call to function method_exists() with Symfony\\Component\\OptionsResolver\\OptionsResolver and 'setOptions' will always evaluate to false." + identifier: function.impossibleType + reportUnmatched: false + path: lib/Tmdb/Client.php + + - + rawMessage: 'Parameter #3 $first of method Http\Client\Common\Plugin\AbstractCachePlugin::handleRequest() expects callable(Psr\Http\Message\RequestInterface): Http\Promise\Promise, Closure(): void given.' identifier: argument.type count: 1 path: lib/Tmdb/Event/Listener/Psr6CachedRequestListener.php + - + rawMessage: 'Call to method handleRequest() of internal class Http\Client\Common\Plugin\AbstractCachePlugin from outside its root namespace Http.' + identifier: method.internalClass + count: 1 + path: lib/Tmdb/Event/Listener/Psr6CachedRequestListener.php + - rawMessage: 'Property Tmdb\Event\Listener\Psr6CachedRequestListener::$options is never read, only written.' identifier: property.onlyWritten