diff --git a/README.md b/README.md index 6c136a9..f6ba963 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Read more about it at [jsonapi.org](https://jsonapi.org/). composer require alsvanzelf/jsonapi ``` -The library supports, and is is tested on, php versions 5.6, 7 and 8. +The library requires php 8.2. For lower versions see [v2](/releases/tag/v2.5.0). #### Upgrading from v1 diff --git a/composer.json b/composer.json index d244643..95de189 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ } ], "require": { - "php": ">=5.6", + "php": ">=8.2", "ext-json": "*" }, "autoload": { diff --git a/composer.lock b/composer.lock index 59b7f8a..c3d435c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "263d00c16803c650bac943c2a0287fcf", + "content-hash": "5a2e5669cfe43c78a4d50be96e5dc550", "packages": [], "packages-dev": [ { @@ -2176,7 +2176,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=5.6", + "php": ">=8.2", "ext-json": "*" }, "platform-dev": {}, diff --git a/examples/bootstrap_examples.php b/examples/bootstrap_examples.php index 33abef7..98d2a93 100644 --- a/examples/bootstrap_examples.php +++ b/examples/bootstrap_examples.php @@ -92,14 +92,13 @@ public static function findEntities($type) { } class ExampleUser { - public $id; public $name; public $heads; public $unknown; - public function __construct($id) { - $this->id = $id; - } + public function __construct( + public $id, + ) {} function getCurrentLocation() { return 'Earth'; diff --git a/rector.php b/rector.php index 03c18b2..f49a0df 100644 --- a/rector.php +++ b/rector.php @@ -26,7 +26,7 @@ ->withIndent(indentChar: "\t", indentSize: 1) // slowly increase php version - ->withPhpSets(php56: true) + ->withPhpSets(php82: true) // slowly increase levels ->withTypeCoverageLevel(1) diff --git a/src/DataDocument.php b/src/DataDocument.php index a1667c1..470fcef 100644 --- a/src/DataDocument.php +++ b/src/DataDocument.php @@ -41,7 +41,7 @@ public function addIncludedResourceObject(ResourceObject ...$resourceObjects) { try { $this->validator->claimUsedResourceIdentifier($resourceObject); } - catch (DuplicateException $e) { + catch (DuplicateException) { // silently skip duplicates continue; } diff --git a/src/Document.php b/src/Document.php index be79032..cd26fcc 100644 --- a/src/Document.php +++ b/src/Document.php @@ -288,7 +288,7 @@ public function toArray() { public function toJson(array $options=[]) { $options = array_merge(self::$defaults, $options); - $array = ($options['array'] !== null) ? $options['array'] : $this->toArray(); + $array = $options['array'] ?? $this->toArray(); if ($options['prettyPrint']) { $options['encodeOptions'] |= JSON_PRETTY_PRINT; @@ -314,7 +314,7 @@ public function sendResponse(array $options=[]) { return; } - $json = ($options['json'] !== null) ? $options['json'] : $this->toJson($options); + $json = $options['json'] ?? $this->toJson($options); http_response_code($this->httpStatusCode); diff --git a/src/ErrorsDocument.php b/src/ErrorsDocument.php index 4a8b4d1..69163db 100644 --- a/src/ErrorsDocument.php +++ b/src/ErrorsDocument.php @@ -44,17 +44,11 @@ public function __construct(?ErrorObject $errorObject=null) { */ /** - * @param \Exception|\Throwable $exception + * @param \Throwable $exception * @param array $options optional {@see ErrorsDocument::$defaults} * @return ErrorsDocument - * - * @throws InputException if $exception is not \Exception or \Throwable */ - public static function fromException($exception, array $options=[]) { - if ($exception instanceof \Exception === false && $exception instanceof \Throwable === false) { - throw new InputException('input is not a real exception in php5 or php7'); - } - + public static function fromException(\Throwable $exception, array $options=[]) { $options = array_merge(self::$defaults, $options); $errorsDocument = new self(); @@ -68,16 +62,10 @@ public static function fromException($exception, array $options=[]) { * * recursively adds multiple ErrorObjects if $exception carries a ->getPrevious() * - * @param \Exception|\Throwable $exception + * @param \Throwable $exception * @param array $options optional {@see ErrorsDocument::$defaults} - * - * @throws InputException if $exception is not \Exception or \Throwable */ - public function addException($exception, array $options=[]) { - if ($exception instanceof \Exception === false && $exception instanceof \Throwable === false) { - throw new InputException('input is not a real exception in php5 or php7'); - } - + public function addException(\Throwable $exception, array $options=[]) { $options = array_merge(self::$defaults, $options); $this->addErrorObject(ErrorObject::fromException($exception, $options)); @@ -152,7 +140,7 @@ public function toArray() { */ protected function determineHttpStatusCode($httpStatusCode) { // add the new code - $category = substr($httpStatusCode, 0, 1); + $category = substr((string) $httpStatusCode, 0, 1); $this->httpStatusCodes[$category][$httpStatusCode] = true; $advisedStatusCode = $httpStatusCode; diff --git a/src/helpers/AtMemberManager.php b/src/helpers/AtMemberManager.php index fbc8b7c..78cbf3e 100644 --- a/src/helpers/AtMemberManager.php +++ b/src/helpers/AtMemberManager.php @@ -22,7 +22,7 @@ trait AtMemberManager { * @param mixed $value */ public function addAtMember($key, $value) { - if (strpos($key, '@') === 0) { + if (str_starts_with($key, '@')) { $key = substr($key, 1); } diff --git a/src/helpers/ExtensionMemberManager.php b/src/helpers/ExtensionMemberManager.php index 4261628..1bfd257 100644 --- a/src/helpers/ExtensionMemberManager.php +++ b/src/helpers/ExtensionMemberManager.php @@ -26,7 +26,7 @@ trait ExtensionMemberManager { public function addExtensionMember(ExtensionInterface $extension, $key, $value) { $namespace = $extension->getNamespace(); - if (strpos($key, $namespace.':') === 0) { + if (str_starts_with($key, $namespace.':')) { $key = substr($key, strlen($namespace.':')); } diff --git a/src/helpers/RequestParser.php b/src/helpers/RequestParser.php index d65b180..b672ff7 100644 --- a/src/helpers/RequestParser.php +++ b/src/helpers/RequestParser.php @@ -24,23 +24,17 @@ class RequestParser { */ 'useAnnotatedSortFields' => true, ]; - /** @var string */ - private $selfLink = ''; - /** @var array */ - private $queryParameters = []; - /** @var array */ - private $document = []; /** * @param string $selfLink the uri used to make this request {@see getSelfLink()} * @param array $queryParameters all query parameters defined by the specification * @param array $document the request jsonapi document */ - public function __construct($selfLink='', array $queryParameters=[], array $document=[]) { - $this->selfLink = $selfLink; - $this->queryParameters = $queryParameters; - $this->document = $document; - } + public function __construct( + private $selfLink='', + private array $queryParameters=[], + private array $document=[], + ) {} /** * @return self @@ -55,8 +49,8 @@ public static function fromSuperglobals() { $document = $_POST; if ($document === [] && isset($_SERVER['CONTENT_TYPE'])) { - $documentIsJsonapi = (strpos($_SERVER['CONTENT_TYPE'], Document::CONTENT_TYPE_OFFICIAL) !== false); - $documentIsJson = (strpos($_SERVER['CONTENT_TYPE'], Document::CONTENT_TYPE_DEBUG) !== false); + $documentIsJsonapi = (str_contains((string) $_SERVER['CONTENT_TYPE'], Document::CONTENT_TYPE_OFFICIAL)); + $documentIsJson = (str_contains((string) $_SERVER['CONTENT_TYPE'], Document::CONTENT_TYPE_DEBUG)); if ($documentIsJsonapi || $documentIsJson) { $document = json_decode(file_get_contents('php://input'), true); @@ -131,7 +125,7 @@ public function getIncludePaths(array $options=[]) { return []; } - $includePaths = explode(',', $this->queryParameters['include']); + $includePaths = explode(',', (string) $this->queryParameters['include']); $options = array_merge(self::$defaults, $options); if ($options['useNestedIncludePaths'] === false) { @@ -171,7 +165,7 @@ public function getSparseFieldset($type) { return []; } - return explode(',', $this->queryParameters['fields'][$type]); + return explode(',', (string) $this->queryParameters['fields'][$type]); } /** @@ -200,7 +194,7 @@ public function getSortFields(array $options=[]) { return []; } - $fields = explode(',', $this->queryParameters['sort']); + $fields = explode(',', (string) $this->queryParameters['sort']); $options = array_merge(self::$defaults, $options); if ($options['useAnnotatedSortFields'] === false) { @@ -211,7 +205,7 @@ public function getSortFields(array $options=[]) { foreach ($fields as $field) { $order = RequestParser::SORT_ASCENDING; - if (strpos($field, '-') === 0) { + if (str_starts_with($field, '-')) { $field = substr($field, 1); $order = RequestParser::SORT_DESCENDING; } diff --git a/src/objects/ErrorObject.php b/src/objects/ErrorObject.php index 29e9ae7..f0fc317 100644 --- a/src/objects/ErrorObject.php +++ b/src/objects/ErrorObject.php @@ -63,22 +63,16 @@ public function __construct($genericCode=null, $genericTitle=null, $specificDeta */ /** - * @param \Exception|\Throwable $exception - * @param array $options optional {@see ErrorObject::$defaults} + * @param \Throwable $exception + * @param array $options optional {@see ErrorObject::$defaults} * @return ErrorObject - * - * @throws InputException if $exception is not \Exception or \Throwable */ - public static function fromException($exception, array $options=[]) { - if ($exception instanceof \Exception === false && $exception instanceof \Throwable === false) { - throw new InputException('input is not a real exception in php5 or php7'); - } - + public static function fromException(\Throwable $exception, array $options=[]) { $options = array_merge(self::$defaults, $options); $errorObject = new self(); - $className = get_class($exception); + $className = $exception::class; if (strpos($className, '\\')) { $exploded = explode('\\', $className); $className = end($exploded); @@ -91,7 +85,7 @@ public static function fromException($exception, array $options=[]) { } $metaObject = MetaObject::fromArray([ - 'type' => get_class($exception), + 'type' => $exception::class, 'message' => $exception->getMessage(), 'code' => $exception->getCode(), 'file' => $filePath, diff --git a/tests/ErrorsDocumentTest.php b/tests/ErrorsDocumentTest.php index d7be29b..151f44e 100644 --- a/tests/ErrorsDocumentTest.php +++ b/tests/ErrorsDocumentTest.php @@ -5,7 +5,6 @@ use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use alsvanzelf\jsonapi\ErrorsDocument; -use alsvanzelf\jsonapi\exceptions\InputException; use alsvanzelf\jsonapi\objects\ErrorObject; class ErrorsDocumentTest extends TestCase { @@ -32,9 +31,6 @@ public function testFromException_HappyPath() { $this->assertSame(self::class, $array['errors'][0]['meta']['trace'][0]['class']); } - /** - * @group non-php5 - */ public function testFromException_AllowsThrowable() { $document = ErrorsDocument::fromException(new \Error('foo', 42)); @@ -58,12 +54,6 @@ public function testFromException_AllowsThrowable() { $this->assertSame(self::class, $array['errors'][0]['meta']['trace'][0]['class']); } - public function testFromException_BlocksNonException() { - $this->expectException(InputException::class); - - ErrorsDocument::fromException(new \stdClass()); - } - public function testAddException_WithPrevious() { $exception = new \Exception('foo', 1, new \Exception('bar', 2)); @@ -98,14 +88,6 @@ public function testAddException_SkipPrevious() { $this->assertSame('foo', $array['errors'][0]['meta']['message']); } - public function testAddException_BlocksNonException() { - $document = new ErrorsDocument(); - - $this->expectException(InputException::class); - - $document->addException(new \stdClass()); - } - public function testToArray_EmptyErrorObject() { $document = new ErrorsDocument(); $document->addErrorObject(new ErrorObject('foo')); @@ -127,7 +109,6 @@ public function testDetermineHttpStatusCode_HappyPath(int $expectedAdvisedErrorC $document = new ErrorsDocument(); $method = new \ReflectionMethod($document, 'determineHttpStatusCode'); - $method->setAccessible(true); $advisedErrorCode = null; foreach ($allErrorCodes as $errorCode) { diff --git a/tests/ValidatorTest.php b/tests/ValidatorTest.php index 8fbdd55..0a373c6 100644 --- a/tests/ValidatorTest.php +++ b/tests/ValidatorTest.php @@ -86,7 +86,7 @@ public function testClearUsedFields_FreesForAnotherNamespace() { $objectContainer = Validator::OBJECT_CONTAINER_RELATIONSHIPS; $validator->claimUsedFields($fieldNames, $objectContainer); } - catch (DuplicateException $e) { + catch (DuplicateException) { $thrown = true; } $this->assertTrue($thrown); diff --git a/tests/example_output/ExampleUser.php b/tests/example_output/ExampleUser.php index 4228214..5f342d7 100644 --- a/tests/example_output/ExampleUser.php +++ b/tests/example_output/ExampleUser.php @@ -3,14 +3,13 @@ namespace alsvanzelf\jsonapiTests\example_output; class ExampleUser { - public $id; public $name; public $heads; public $unknown; - public function __construct($id) { - $this->id = $id; - } + public function __construct( + public $id, + ) {} function getCurrentLocation() { return 'Earth'; diff --git a/tests/helpers/TestableNonInterfaceRequestInterface.php b/tests/helpers/TestableNonInterfaceRequestInterface.php index 9bfbd07..e2d26da 100644 --- a/tests/helpers/TestableNonInterfaceRequestInterface.php +++ b/tests/helpers/TestableNonInterfaceRequestInterface.php @@ -9,15 +9,11 @@ use Psr\Http\Message\UriInterface; class TestableNonInterfaceRequestInterface implements RequestInterface { - protected $selfLink; - protected $queryParameters; - protected $document; - - public function __construct($selfLink, $queryParameters, $document) { - $this->selfLink = $selfLink; - $this->queryParameters = $queryParameters; - $this->document = $document; - } + public function __construct( + protected $selfLink, + protected $queryParameters, + protected $document, + ) {} /** * RequestInterface diff --git a/tests/helpers/TestableNonInterfaceStreamInterface.php b/tests/helpers/TestableNonInterfaceStreamInterface.php index fb36096..79f22ca 100644 --- a/tests/helpers/TestableNonInterfaceStreamInterface.php +++ b/tests/helpers/TestableNonInterfaceStreamInterface.php @@ -5,11 +5,9 @@ use Psr\Http\Message\StreamInterface; class TestableNonInterfaceStreamInterface implements StreamInterface { - protected $document; - - public function __construct($document) { - $this->document = $document; - } + public function __construct( + protected $document, + ) {} /** * StreamInterface @@ -24,7 +22,7 @@ public function getContents() { } // not used in current implementation - public function __toString() { + public function __toString(): string { return ''; } diff --git a/tests/helpers/TestableNonInterfaceUriInterface.php b/tests/helpers/TestableNonInterfaceUriInterface.php index bdb9af8..aad6bd1 100644 --- a/tests/helpers/TestableNonInterfaceUriInterface.php +++ b/tests/helpers/TestableNonInterfaceUriInterface.php @@ -5,13 +5,10 @@ use Psr\Http\Message\UriInterface; class TestableNonInterfaceUriInterface implements UriInterface { - protected $selfLink; - protected $queryParameters; - - public function __construct($selfLink, $queryParameters) { - $this->selfLink = $selfLink; - $this->queryParameters = $queryParameters; - } + public function __construct( + protected $selfLink, + protected $queryParameters, + ) {} /** * UriInterface @@ -21,8 +18,8 @@ public function getQuery() { return http_build_query($this->queryParameters); } - public function __toString() { - return $this->selfLink; + public function __toString(): string { + return (string) $this->selfLink; } // not used in current implementation diff --git a/tests/objects/ErrorObjectTest.php b/tests/objects/ErrorObjectTest.php index 9463a1c..a57fe18 100644 --- a/tests/objects/ErrorObjectTest.php +++ b/tests/objects/ErrorObjectTest.php @@ -87,9 +87,6 @@ public function testFromException_NamespacedException() { $this->assertSame('alsvanzelf\jsonapi\exceptions\InputException', $array['meta']['type']); } - /** - * @group non-php5 - */ public function testFromException_NamespacedThrowable() { $exception = new TestError(); $errorObject = ErrorObject::fromException($exception); @@ -103,12 +100,6 @@ public function testFromException_NamespacedThrowable() { $this->assertSame('alsvanzelf\jsonapiTests\objects\TestError', $array['meta']['type']); } - public function testFromException_BlocksNonException() { - $this->expectException(InputException::class); - - ErrorObject::fromException(new \stdClass()); - } - /** * @deprecated array links are not supported anymore */ @@ -199,6 +190,4 @@ public function testToArray_WithExtensionMembers() { } } -if (PHP_MAJOR_VERSION >= 7) { - class TestError extends \Error {} -} +class TestError extends \Error {} diff --git a/tests/profiles/CursorPaginationProfileTest.php b/tests/profiles/CursorPaginationProfileTest.php index 82ab110..0244a67 100644 --- a/tests/profiles/CursorPaginationProfileTest.php +++ b/tests/profiles/CursorPaginationProfileTest.php @@ -319,7 +319,6 @@ public function testGetRangePaginationNotSupportedErrorObject_HappyPath() { public function testSetQueryParameter_HappyPath() { $profile = new CursorPaginationProfile(); $method = new \ReflectionMethod($profile, 'setQueryParameter'); - $method->setAccessible(true); $url = '/people?sort=x&page[size]=10&page[after]=foo'; $key = 'page[after]'; @@ -333,7 +332,6 @@ public function testSetQueryParameter_HappyPath() { public function testSetQueryParameter_EncodedUrl() { $profile = new CursorPaginationProfile(); $method = new \ReflectionMethod($profile, 'setQueryParameter'); - $method->setAccessible(true); $url = '/people?sort=x&page%5Bsize%5D=10&page%5Bafter%5D=foo'; $key = 'page[after]';