Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions rector.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Rector\Config\RectorConfig;
use Rector\Php70\Rector\StmtsAwareInterface\IfIssetToCoalescingRector;
use Rector\TypeDeclaration\Rector\Class_\AddTestsVoidReturnTypeWhereNoReturnRector;
use Rector\TypeDeclaration\Rector\StmtsAwareInterface\DeclareStrictTypesRector;

// @see https://github.com/rectorphp/rector/blob/main/docs/rector_rules_overview.md for more rules
Expand All @@ -16,6 +17,7 @@
])
->withRules([
DeclareStrictTypesRector::class,
AddTestsVoidReturnTypeWhereNoReturnRector::class,
])
->withSkip([
// better explicit readability
Expand Down
8 changes: 4 additions & 4 deletions src/Document.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ abstract class Document implements DocumentInterface, \JsonSerializable, HasLink
/**
* encode to json with these default options
*/
'encodeOptions' => JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE,
'encodeOptions' => JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR,

/**
* encode to human-readable json, useful when debugging
Expand Down Expand Up @@ -253,6 +253,9 @@ public function toArray(): array {
return $array;
}

/**
* @throws \JsonException
*/
public function toJson(array $options=[]): string {
$options = array_merge(self::$defaults, $options);

Expand All @@ -263,9 +266,6 @@ public function toJson(array $options=[]): string {
}

$json = json_encode($array, $options['encodeOptions']);
if ($json === false) {
throw new Exception('failed to generate json: '.json_last_error_msg());
}

if ($options['jsonpCallback'] !== null) {
$json = $options['jsonpCallback'].'('.$json.')';
Expand Down
23 changes: 12 additions & 11 deletions src/helpers/RequestParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ class RequestParser {
* @param string $selfLink the uri used to make this request {@see getSelfLink()}
* @param array<string, string|array<array-key, string>> $queryParameters all query parameters defined by the specification
* @param array<string, mixed> $document the request jsonapi document
*
* @throws \JsonException if $document's content type is json but it can't be json decoded
*/
public function __construct(
private readonly string $selfLink='',
Expand All @@ -49,18 +51,21 @@ public static function fromSuperglobals(): self {
$documentIsJsonapi = (str_contains((string) $_SERVER['CONTENT_TYPE'], ContentTypeEnum::Official->value));
$documentIsJson = (str_contains((string) $_SERVER['CONTENT_TYPE'], ContentTypeEnum::Debug->value));

if ($documentIsJsonapi || $documentIsJson) {
$document = json_decode(file_get_contents('php://input'), true);

if ($document === null) {
$document = [];
}
$document = file_get_contents('php://input');
if ($document === '') {
$document = [];
}
elseif ($documentIsJsonapi || $documentIsJson) {
$document = json_decode($document, true, flags: JSON_THROW_ON_ERROR);
}
}

return new self($selfLink, $queryParameters, $document);
}

/**
* @throws \JsonException if the requests' document can't be json decoded
*/
public static function fromPsrRequest(ServerRequestInterface|RequestInterface $request): self {
$selfLink = (string) $request->getUri();

Expand All @@ -76,11 +81,7 @@ public static function fromPsrRequest(ServerRequestInterface|RequestInterface $r
$document = [];
}
else {
$document = json_decode($request->getBody()->getContents(), true);

if ($document === null) {
$document = [];
}
$document = json_decode($request->getBody()->getContents(), true, flags: JSON_THROW_ON_ERROR);
}

return new self($selfLink, $queryParameters, $document);
Expand Down
170 changes: 85 additions & 85 deletions tests/CollectionDocumentTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,111 +11,111 @@
use alsvanzelf\jsonapi\objects\ResourceObject;

class CollectionDocumentTest extends TestCase {
public function testConstructor_NoResources() {
public function testConstructor_NoResources(): void {
$document = new CollectionDocument();

$array = $document->toArray();

$this->assertArrayHasKey('data', $array);
$this->assertSame([], $array['data']);
parent::assertArrayHasKey('data', $array);
parent::assertSame([], $array['data']);
}

public function testAdd_WithIdentifiers() {
public function testAdd_WithIdentifiers(): void {
$document = new CollectionDocument();

$document->add('user', 1);
$document->add('user', 42);

$array = $document->toArray();

$this->assertArrayHasKey('data', $array);
$this->assertArrayNotHasKey('included', $array);
$this->assertCount(2, $array['data']);

$this->assertCount(2, $array['data'][0]);
$this->assertArrayHasKey('type', $array['data'][0]);
$this->assertArrayHasKey('id', $array['data'][0]);
$this->assertArrayNotHasKey('attributes', $array['data'][0]);
$this->assertSame('user', $array['data'][0]['type']);
$this->assertSame('1', $array['data'][0]['id']);

$this->assertCount(2, $array['data'][1]);
$this->assertArrayHasKey('type', $array['data'][1]);
$this->assertArrayHasKey('id', $array['data'][1]);
$this->assertArrayNotHasKey('attributes', $array['data'][1]);
$this->assertSame('user', $array['data'][1]['type']);
$this->assertSame('42', $array['data'][1]['id']);
parent::assertArrayHasKey('data', $array);
parent::assertArrayNotHasKey('included', $array);
parent::assertCount(2, $array['data']);

parent::assertCount(2, $array['data'][0]);
parent::assertArrayHasKey('type', $array['data'][0]);
parent::assertArrayHasKey('id', $array['data'][0]);
parent::assertArrayNotHasKey('attributes', $array['data'][0]);
parent::assertSame('user', $array['data'][0]['type']);
parent::assertSame('1', $array['data'][0]['id']);

parent::assertCount(2, $array['data'][1]);
parent::assertArrayHasKey('type', $array['data'][1]);
parent::assertArrayHasKey('id', $array['data'][1]);
parent::assertArrayNotHasKey('attributes', $array['data'][1]);
parent::assertSame('user', $array['data'][1]['type']);
parent::assertSame('42', $array['data'][1]['id']);
}

public function testAdd_WithAttributes() {
public function testAdd_WithAttributes(): void {
$document = new CollectionDocument();

$document->add('user', 1, ['name' => 'foo']);
$document->add('user', 42, ['name' => 'bar']);

$array = $document->toArray();

$this->assertArrayHasKey('data', $array);
$this->assertArrayNotHasKey('included', $array);
$this->assertCount(2, $array['data']);
parent::assertArrayHasKey('data', $array);
parent::assertArrayNotHasKey('included', $array);
parent::assertCount(2, $array['data']);

$firstResource = $array['data'][0];
$this->assertCount(3, $firstResource);
$this->assertArrayHasKey('type', $firstResource);
$this->assertArrayHasKey('id', $firstResource);
$this->assertArrayHasKey('attributes', $firstResource);
$this->assertSame('user', $firstResource['type']);
$this->assertSame('1', $firstResource['id']);
$this->assertArrayHasKey('name', $firstResource['attributes']);
$this->assertSame('foo', $firstResource['attributes']['name']);
parent::assertCount(3, $firstResource);
parent::assertArrayHasKey('type', $firstResource);
parent::assertArrayHasKey('id', $firstResource);
parent::assertArrayHasKey('attributes', $firstResource);
parent::assertSame('user', $firstResource['type']);
parent::assertSame('1', $firstResource['id']);
parent::assertArrayHasKey('name', $firstResource['attributes']);
parent::assertSame('foo', $firstResource['attributes']['name']);

$secondResource = $array['data'][1];
$this->assertCount(3, $secondResource);
$this->assertArrayHasKey('type', $secondResource);
$this->assertArrayHasKey('id', $secondResource);
$this->assertArrayHasKey('attributes', $secondResource);
$this->assertSame('user', $secondResource['type']);
$this->assertSame('42', $secondResource['id']);
$this->assertArrayHasKey('name', $secondResource['attributes']);
$this->assertSame('bar', $secondResource['attributes']['name']);
parent::assertCount(3, $secondResource);
parent::assertArrayHasKey('type', $secondResource);
parent::assertArrayHasKey('id', $secondResource);
parent::assertArrayHasKey('attributes', $secondResource);
parent::assertSame('user', $secondResource['type']);
parent::assertSame('42', $secondResource['id']);
parent::assertArrayHasKey('name', $secondResource['attributes']);
parent::assertSame('bar', $secondResource['attributes']['name']);
}

public function testSetPaginationLinks_HappyPath() {
public function testSetPaginationLinks_HappyPath(): void {
$document = new CollectionDocument();
$baseUrl = 'https://jsonapi.org/?page=';

$document->setPaginationLinks($baseUrl.'prev', $baseUrl.'next', $baseUrl.'first', $baseUrl.'last');

$array = $document->toArray();

$this->assertArrayHasKey('links', $array);
$this->assertCount(4, $array['links']);
$this->assertArrayHasKey('prev', $array['links']);
$this->assertArrayHasKey('next', $array['links']);
$this->assertArrayHasKey('first', $array['links']);
$this->assertArrayHasKey('last', $array['links']);
$this->assertSame($baseUrl.'prev', $array['links']['prev']);
$this->assertSame($baseUrl.'next', $array['links']['next']);
$this->assertSame($baseUrl.'first', $array['links']['first']);
$this->assertSame($baseUrl.'last', $array['links']['last']);
parent::assertArrayHasKey('links', $array);
parent::assertCount(4, $array['links']);
parent::assertArrayHasKey('prev', $array['links']);
parent::assertArrayHasKey('next', $array['links']);
parent::assertArrayHasKey('first', $array['links']);
parent::assertArrayHasKey('last', $array['links']);
parent::assertSame($baseUrl.'prev', $array['links']['prev']);
parent::assertSame($baseUrl.'next', $array['links']['next']);
parent::assertSame($baseUrl.'first', $array['links']['first']);
parent::assertSame($baseUrl.'last', $array['links']['last']);
}

#[DataProvider('dataProviderSetPaginationLinks_IndividualLinks')]
public function testSetPaginationLinks_IndividualLinks($key, $previous, $next, $first, $last) {
public function testSetPaginationLinks_IndividualLinks($key, $previous, $next, $first, $last): void {
$document = new CollectionDocument();

$document->setPaginationLinks($previous, $next, $first, $last);

$array = $document->toArray();

if ($key === null) {
$this->assertArrayNotHasKey('links', $array);
parent::assertArrayNotHasKey('links', $array);
}
else {
$this->assertArrayHasKey('links', $array);
$this->assertCount(1, $array['links']);
$this->assertArrayHasKey($key, $array['links']);
$this->assertSame('https://jsonapi.org', $array['links'][$key]);
parent::assertArrayHasKey('links', $array);
parent::assertCount(1, $array['links']);
parent::assertArrayHasKey($key, $array['links']);
parent::assertSame('https://jsonapi.org', $array['links'][$key]);
}
}

Expand All @@ -129,19 +129,19 @@ public static function dataProviderSetPaginationLinks_IndividualLinks() {
];
}

public function testAddResource_HappyPath() {
public function testAddResource_HappyPath(): void {
$document = new CollectionDocument();
$document->addResource(new ResourceObject('user', 42));

$array = $document->toArray();

$this->assertCount(1, $array['data']);
$this->assertSame('user', $array['data'][0]['type']);
$this->assertSame('42', $array['data'][0]['id']);
$this->assertArrayNotHasKey('attributes', $array['data'][0]);
parent::assertCount(1, $array['data']);
parent::assertSame('user', $array['data'][0]['type']);
parent::assertSame('42', $array['data'][0]['id']);
parent::assertArrayNotHasKey('attributes', $array['data'][0]);
}

public function testAddResource_WithIncluded() {
public function testAddResource_WithIncluded(): void {
$relatedResourceObject = new ResourceObject('user', 24);
$relatedResourceObject->add('foo', 'bar');

Expand All @@ -153,16 +153,16 @@ public function testAddResource_WithIncluded() {

$array = $document->toArray();

$this->assertArrayHasKey('data', $array);
$this->assertArrayHasKey('included', $array);
$this->assertArrayHasKey('relationships', $array['data'][0]);
$this->assertArrayHasKey('attributes', $array['included'][0]);
$this->assertSame('42', $array['data'][0]['id']);
$this->assertSame('24', $array['data'][0]['relationships']['foo']['data']['id']);
$this->assertSame('24', $array['included'][0]['id']);
parent::assertArrayHasKey('data', $array);
parent::assertArrayHasKey('included', $array);
parent::assertArrayHasKey('relationships', $array['data'][0]);
parent::assertArrayHasKey('attributes', $array['included'][0]);
parent::assertSame('42', $array['data'][0]['id']);
parent::assertSame('24', $array['data'][0]['relationships']['foo']['data']['id']);
parent::assertSame('24', $array['included'][0]['id']);
}

public function testAddResource_DoNotIncludeContainedResources() {
public function testAddResource_DoNotIncludeContainedResources(): void {
$relatedResourceObject = new ResourceObject('user', 24);
$relatedResourceObject->add('foo', 'bar');

Expand All @@ -176,50 +176,50 @@ public function testAddResource_DoNotIncludeContainedResources() {

$array = $document->toArray();

$this->assertArrayHasKey('data', $array);
$this->assertArrayNotHasKey('included', $array);
$this->assertArrayHasKey('relationships', $array['data'][0]);
$this->assertSame('42', $array['data'][0]['id']);
$this->assertSame('24', $array['data'][0]['relationships']['foo']['data']['id']);
parent::assertArrayHasKey('data', $array);
parent::assertArrayNotHasKey('included', $array);
parent::assertArrayHasKey('relationships', $array['data'][0]);
parent::assertSame('42', $array['data'][0]['id']);
parent::assertSame('24', $array['data'][0]['relationships']['foo']['data']['id']);
}

public function testAddResource_RequiresIdentification() {
public function testAddResource_RequiresIdentification(): void {
$document = new CollectionDocument();

$this->expectException(InputException::class);

$document->addResource(new ResourceObject());
}

public function testAddResource_RequiresFullIdentification() {
public function testAddResource_RequiresFullIdentification(): void {
$document = new CollectionDocument();

$this->expectException(InputException::class);

$document->addResource(new ResourceObject('user'));
}

public function testGetContainedResources_HappyPath() {
public function testGetContainedResources_HappyPath(): void {
$document = new CollectionDocument();

$this->assertCount(0, $document->getContainedResources());
parent::assertCount(0, $document->getContainedResources());

$document->add('user', 42);

$this->assertCount(1, $document->getContainedResources());
parent::assertCount(1, $document->getContainedResources());

$document->add('user', 24);

$this->assertCount(2, $document->getContainedResources());
parent::assertCount(2, $document->getContainedResources());
}

public function testGetContainedResources_NoNestedResources() {
public function testGetContainedResources_NoNestedResources(): void {
$document = new CollectionDocument();

$resourceObject = new ResourceObject('user', 42);
$resourceObject->addRelationship('foo', new ResourceObject('user', 24));
$document->addResource($resourceObject);

$this->assertCount(1, $document->getContainedResources());
parent::assertCount(1, $document->getContainedResources());
}
}
Loading