diff --git a/composer.json b/composer.json index 79a56e52..8fedf3fa 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", + "symfony/options-resolver": "^4.4 || ^5 || ^6 || ^7", "psr/cache": "^1 || ^2 || ^3", "psr/simple-cache": "^1 || ^2 || ^3", "psr/event-dispatcher": "^1", @@ -44,27 +44,27 @@ "psr/http-client-implementation": "^1", "psr/http-factory": "^1", "psr/http-factory-implementation": "^1", - "psr/http-message": "^1" + "psr/http-message": "^1 || ^2" }, "require-dev": { "nyholm/psr7": "^1.2", "php-http/mock-client": "^1.2", - "slevomat/coding-standard": "^8.8", - "squizlabs/php_codesniffer": "^3.5.8", - "symfony/cache": "^4.4 || ^5 || ^6", - "symfony/event-dispatcher": "^4.4 || ^5 || ^6", - "phpstan/phpstan": "^1.8.1", - "phpstan/phpstan-deprecation-rules": "^1.1", - "spaze/phpstan-disallowed-calls": "^2.11", - "phpunit/phpunit": "^9.6.3", + "slevomat/coding-standard": "^8.27.1", + "squizlabs/php_codesniffer": "^4.0.1", + "symfony/cache": "^4.4 || ^5 || ^6 || ^7", + "symfony/event-dispatcher": "^4.4 || ^5 || ^6 || ^7", + "phpstan/phpstan": "^2.1.38", + "phpstan/phpstan-deprecation-rules": "^2.0.3", + "spaze/phpstan-disallowed-calls": "^4.7.0", + "phpunit/phpunit": "^9 || ^10 || ^11", "php-http/guzzle7-adapter": "^1.0", "monolog/monolog": "^2.9.1 || ^3.0", - "php-http/cache-plugin": "^1.7", + "php-http/cache-plugin": "^1.7 || ^2.0", "jeroen/psr-log-test-doubles": "^2.1 || ^3" }, "scripts": { "test": "vendor/bin/phpunit", - "test-ci": "vendor/bin/phpunit --coverage-text --coverage-clover=build/coverage.xml coverage", + "test-ci": "vendor/bin/phpunit --coverage-text --coverage-clover=build/coverage.xml", "test-coverage": "php -d xdebug.mode=coverage vendor/bin/phpunit --coverage-html build/coverage", "test-cs": "vendor/bin/phpcs", "test-phpstan": "vendor/bin/phpstan analyse" diff --git a/lib/Tmdb/Api/AbstractApi.php b/lib/Tmdb/Api/AbstractApi.php index aba79069..0b195430 100644 --- a/lib/Tmdb/Api/AbstractApi.php +++ b/lib/Tmdb/Api/AbstractApi.php @@ -196,7 +196,12 @@ private function decodeResponse(ResponseInterface $response) { try { if ($response->getBody() instanceof StreamInterface) { - return json_decode((string)$response->getBody(), true, 512, JSON_THROW_ON_ERROR); + $body = (string)$response->getBody(); + if (trim($body) === '') { + return []; + } + + return json_decode($body, true, 512, JSON_THROW_ON_ERROR); } return []; diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 7538c107..50dbd489 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,78 +1,97 @@ parameters: ignoreErrors: - - message: "#^Instanceof between Psr\\\\Http\\\\Message\\\\StreamInterface and Psr\\\\Http\\\\Message\\\\StreamInterface will always evaluate to true\\.$#" + rawMessage: Instanceof between Psr\Http\Message\StreamInterface and Psr\Http\Message\StreamInterface will always evaluate to true. + identifier: instanceof.alwaysTrue count: 1 path: lib/Tmdb/Api/AbstractApi.php - - message: "#^Unreachable statement \\- code above always terminates\\.$#" + rawMessage: Unreachable statement - code above always terminates. + identifier: deadCode.unreachable count: 1 path: lib/Tmdb/Api/AbstractApi.php - - message: "#^Strict comparison using \\!\\=\\= between null and Psr\\\\Http\\\\Message\\\\StreamInterface will always evaluate to true\\.$#" + rawMessage: 'Strict comparison using !== between null and Psr\Http\Message\StreamInterface will always evaluate to true.' + identifier: notIdentical.alwaysTrue count: 1 path: lib/Tmdb/Event/Listener/Logger/LogHttpMessageListener.php - - message: "#^Parameter \\#3 \\$first of method Http\\\\Client\\\\Common\\\\Plugin\\\\CachePlugin\\:\\:handleRequest\\(\\) expects callable\\(Psr\\\\Http\\\\Message\\\\RequestInterface\\)\\: Http\\\\Promise\\\\Promise, Closure\\(\\)\\: void given\\.$#" + rawMessage: 'Parameter #3 $first of method Http\Client\Common\Plugin\CachePlugin::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 - - message: "#^Property Tmdb\\\\Event\\\\Listener\\\\Psr6CachedRequestListener\\:\\:\\$options is never read, only written\\.$#" + rawMessage: 'Property Tmdb\Event\Listener\Psr6CachedRequestListener::$options is never read, only written.' + identifier: property.onlyWritten count: 1 path: lib/Tmdb/Event/Listener/Psr6CachedRequestListener.php - - message: """ - #^Call to deprecated method setReleases\\(\\) of class Tmdb\\\\Model\\\\Movie\\: - Use the setReleaseDates instead\\.$# - """ + rawMessage: ''' + Call to deprecated method setReleases() of class Tmdb\Model\Movie: + Use the setReleaseDates instead. + ''' + identifier: method.deprecated count: 1 path: lib/Tmdb/Factory/MovieFactory.php - - message: """ - #^Instantiation of deprecated class Tmdb\\\\Model\\\\Movie\\\\Release\\: - Use ReleaseDate instead$# - """ + rawMessage: ''' + Instantiation of deprecated class Tmdb\Model\Movie\Release: + Use ReleaseDate instead + ''' + identifier: new.deprecatedClass count: 1 path: lib/Tmdb/Factory/MovieFactory.php - - message: "#^Return type \\(Tmdb\\\\Model\\\\Collection\\\\People\\) of method Tmdb\\\\Factory\\\\PeopleFactory\\:\\:createCollection\\(\\) should be compatible with return type \\(Tmdb\\\\Model\\\\Common\\\\GenericCollection\\\\) of method Tmdb\\\\Factory\\\\AbstractFactory\\\\:\\:createCollection\\(\\)$#" + rawMessage: 'Return type (Tmdb\Model\Collection\People) of method Tmdb\Factory\PeopleFactory::createCollection() should be compatible with return type (Tmdb\Model\Common\GenericCollection) of method Tmdb\Factory\AbstractFactory::createCollection()' + identifier: method.childReturnType count: 1 path: lib/Tmdb/Factory/PeopleFactory.php - - message: "#^Property Tmdb\\\\HttpClient\\\\HttpClient\\:\\:\\$sessionToken is never written, only read\\.$#" + rawMessage: 'Property Tmdb\HttpClient\HttpClient::$sessionToken (Tmdb\Token\Session\SessionToken|null) is never assigned Tmdb\Token\Session\SessionToken so it can be removed from the property type.' + identifier: property.unusedType count: 1 path: lib/Tmdb/HttpClient/HttpClient.php - - message: """ - #^Access to deprecated property \\$releases of class Tmdb\\\\Model\\\\Movie\\: - Use \\$release_dates instead$# - """ + rawMessage: 'Property Tmdb\HttpClient\HttpClient::$sessionToken is never written, only read.' + identifier: property.onlyRead + count: 1 + path: lib/Tmdb/HttpClient/HttpClient.php + + - + rawMessage: ''' + Access to deprecated property $releases of class Tmdb\Model\Movie: + Use $release_dates instead + ''' + identifier: property.deprecated count: 1 path: lib/Tmdb/Model/Movie.php - - message: """ - #^Return type of method Tmdb\\\\Repository\\\\MovieRepository\\:\\:getReleases\\(\\) has typehint with deprecated class Tmdb\\\\Model\\\\Movie\\\\Release\\: - Use ReleaseDate instead$# - """ + rawMessage: ''' + Return type of method Tmdb\Repository\MovieRepository::getReleases() has typehint with deprecated class Tmdb\Model\Movie\Release: + Use ReleaseDate instead + ''' + identifier: return.deprecatedClass count: 1 path: lib/Tmdb/Repository/MovieRepository.php - - message: "#^Result of \\|\\| is always false\\.$#" + rawMessage: Result of || is always false. + identifier: booleanOr.alwaysFalse count: 1 path: lib/Tmdb/Repository/TvSeasonRepository.php - - message: "#^Strict comparison using \\=\\=\\= between null and int will always evaluate to false\\.$#" + rawMessage: 'Strict comparison using === between null and int will always evaluate to false.' + identifier: identical.alwaysFalse count: 2 path: lib/Tmdb/Repository/TvSeasonRepository.php diff --git a/phpstan.neon.dist b/phpstan.neon.dist index bcbfb51d..6ccd72ae 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -9,9 +9,6 @@ includes: parameters: level: 5 - checkAlwaysTrueCheckTypeFunctionCall: true - checkAlwaysTrueInstanceof: true - checkAlwaysTrueStrictComparison: true checkExplicitMixedMissingReturn: true checkFunctionNameCase: true checkInternalClassCaseSensitivity: true diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 7b2d6040..7cba710b 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,13 +1,13 @@ - - - - lib - - + ./test/ + + + lib + + diff --git a/test/Tmdb/Tests/Api/TestCase.php b/test/Tmdb/Tests/Api/TestCase.php index d7f963b7..862164cc 100644 --- a/test/Tmdb/Tests/Api/TestCase.php +++ b/test/Tmdb/Tests/Api/TestCase.php @@ -67,7 +67,7 @@ protected function getMockedApi(array $methods = [], array $clientMethods = [], } return $this->_api = $this->getMockBuilder($this->getApiClass()) - ->setMethods($methods) + ->onlyMethods($methods) ->setConstructorArgs([$this->_client]) ->getMock(); } diff --git a/test/Tmdb/Tests/TestCase.php b/test/Tmdb/Tests/TestCase.php index cc62ae8a..063259cd 100644 --- a/test/Tmdb/Tests/TestCase.php +++ b/test/Tmdb/Tests/TestCase.php @@ -90,6 +90,8 @@ protected function getClientWithMockedHttpClient(array $options = array()) $options['api_token'] = new ApiToken('abcdef'); $options['http']['client'] = new \Http\Mock\Client(); $response = $this->createMock('Psr\Http\Message\ResponseInterface'); + $streamFactory = Psr17FactoryDiscovery::findStreamFactory(); + $response->method('getBody')->willReturn($streamFactory->createStream('{}')); $options['http']['client']->setDefaultResponse($response); $client = new Client($options); @@ -170,7 +172,7 @@ protected function getMockedHttpClient(array $methods = []) $methods[] = 'send'; } - return $this->getMockBuilder('Guzzle\Http\Client')->setMethods($methods)->getMock(); + return $this->getMockBuilder('Guzzle\Http\Client')->onlyMethods($methods)->getMock(); } /**