603 lines
18 KiB
PHP
603 lines
18 KiB
PHP
<?php
|
|
|
|
/*
|
|
* This file is part of JSON-API.
|
|
*
|
|
* (c) Toby Zerner <toby.zerner@gmail.com>
|
|
*
|
|
* For the full copyright and license information, please view the LICENSE
|
|
* file that was distributed with this source code.
|
|
*/
|
|
|
|
namespace Tobscure\Tests\JsonApiServer;
|
|
|
|
use Tobscure\JsonApiServer\Api;
|
|
use Tobscure\JsonApiServer\Exception\BadRequestException;
|
|
use Tobscure\JsonApiServer\Serializer;
|
|
use Tobscure\JsonApiServer\Schema\Builder;
|
|
use Psr\Http\Message\ServerRequestInterface as Request;
|
|
use JsonApiPhp\JsonApi;
|
|
use Zend\Diactoros\ServerRequest;
|
|
use Zend\Diactoros\Uri;
|
|
|
|
class ShowTest extends AbstractTestCase
|
|
{
|
|
public function testResourceWithNoFields()
|
|
{
|
|
$api = new Api('http://example.com');
|
|
$api->resource('users', new MockAdapter(), function (Builder $schema) {
|
|
// no fields
|
|
});
|
|
|
|
$request = $this->buildRequest('GET', '/users/1');
|
|
$response = $api->handle($request);
|
|
|
|
$this->assertEquals($response->getStatusCode(), 200);
|
|
$this->assertEquals(
|
|
[
|
|
'type' => 'users',
|
|
'id' => '1',
|
|
'links' => [
|
|
'self' => 'http://example.com/users/1'
|
|
]
|
|
],
|
|
json_decode($response->getBody(), true)['data']
|
|
);
|
|
}
|
|
|
|
public function testAttributes()
|
|
{
|
|
$adapter = new MockAdapter([
|
|
'1' => (object) [
|
|
'id' => '1',
|
|
'attribute1' => 'value1',
|
|
'property2' => 'value2',
|
|
'property3' => 'value3'
|
|
]
|
|
]);
|
|
|
|
$request = $this->buildRequest('GET', '/users/1');
|
|
|
|
$api = new Api('http://example.com');
|
|
|
|
$api->resource('users', $adapter, function (Builder $schema) {
|
|
$schema->attribute('attribute1');
|
|
$schema->attribute('attribute2', 'property2');
|
|
$schema->attribute('attribute3')->property('property3');
|
|
});
|
|
|
|
$response = $api->handle($request);
|
|
|
|
$this->assertArraySubset(
|
|
[
|
|
'attributes' => [
|
|
'attribute1' => 'value1',
|
|
'attribute2' => 'value2',
|
|
'attribute3' => 'value3'
|
|
]
|
|
],
|
|
json_decode($response->getBody(), true)['data']
|
|
);
|
|
}
|
|
|
|
public function testAttributeGetter()
|
|
{
|
|
$adapter = new MockAdapter([
|
|
'1' => $model = (object) ['id' => '1']
|
|
]);
|
|
|
|
$request = $this->buildRequest('GET', '/users/1');
|
|
|
|
$api = new Api('http://example.com');
|
|
|
|
$api->resource('users', $adapter, function (Builder $schema) use ($model, $request) {
|
|
$schema->attribute('attribute1')
|
|
->get(function ($arg1, $arg2) use ($model, $request) {
|
|
$this->assertEquals($model, $arg1);
|
|
$this->assertEquals($request, $arg2);
|
|
return 'value1';
|
|
});
|
|
});
|
|
|
|
$response = $api->handle($request);
|
|
|
|
$this->assertEquals($response->getStatusCode(), 200);
|
|
$this->assertArraySubset(
|
|
[
|
|
'attributes' => [
|
|
'attribute1' => 'value1'
|
|
]
|
|
],
|
|
json_decode($response->getBody(), true)['data']
|
|
);
|
|
}
|
|
|
|
public function testAttributeVisibility()
|
|
{
|
|
$adapter = new MockAdapter([
|
|
'1' => $model = (object) ['id' => '1']
|
|
]);
|
|
|
|
$request = $this->buildRequest('GET', '/users/1');
|
|
|
|
$api = new Api('http://example.com');
|
|
$api->resource('users', $adapter, function (Builder $schema) use ($model, $request) {
|
|
$schema->attribute('visible1');
|
|
|
|
$schema->attribute('visible2')->visible();
|
|
|
|
$schema->attribute('visible3')->visibleIf(function ($arg1, $arg2) use ($model, $request) {
|
|
$this->assertEquals($model, $arg1);
|
|
$this->assertEquals($request, $arg2);
|
|
return true;
|
|
});
|
|
|
|
$schema->attribute('visible4')->hiddenIf(function ($arg1, $arg2) use ($model, $request) {
|
|
$this->assertEquals($model, $arg1);
|
|
$this->assertEquals($request, $arg2);
|
|
return false;
|
|
});
|
|
|
|
$schema->attribute('hidden1')->hidden();
|
|
|
|
$schema->attribute('hidden2')->visibleIf(function () {
|
|
return false;
|
|
});
|
|
|
|
$schema->attribute('hidden3')->hiddenIf(function () {
|
|
return true;
|
|
});
|
|
});
|
|
|
|
$response = $api->handle($request);
|
|
|
|
$attributes = json_decode($response->getBody(), true)['data']['attributes'];
|
|
|
|
$this->assertArrayHasKey('visible1', $attributes);
|
|
$this->assertArrayHasKey('visible2', $attributes);
|
|
$this->assertArrayHasKey('visible3', $attributes);
|
|
$this->assertArrayHasKey('visible4', $attributes);
|
|
|
|
$this->assertArrayNotHasKey('hidden1', $attributes);
|
|
$this->assertArrayNotHasKey('hidden2', $attributes);
|
|
$this->assertArrayNotHasKey('hidden3', $attributes);
|
|
}
|
|
|
|
public function testHasOneRelationship()
|
|
{
|
|
$phonesAdapter = new MockAdapter([
|
|
'1' => $phone1 = (object) ['id' => '1', 'number' => '8881'],
|
|
'2' => $phone2 = (object) ['id' => '2', 'number' => '8882'],
|
|
'3' => $phone3 = (object) ['id' => '3', 'number' => '8883']
|
|
]);
|
|
|
|
$usersAdapter = new MockAdapter([
|
|
'1' => (object) [
|
|
'id' => '1',
|
|
'phone' => $phone1,
|
|
'property2' => $phone2,
|
|
'property3' => $phone3,
|
|
]
|
|
]);
|
|
|
|
$request = $this->buildRequest('GET', '/users/1');
|
|
|
|
$api = new Api('http://example.com');
|
|
|
|
$api->resource('users', $usersAdapter, function (Builder $schema) {
|
|
$schema->hasOne('phone')
|
|
->included();
|
|
|
|
$schema->hasOne('phone2', 'phones', 'property2')
|
|
->included();
|
|
|
|
$schema->hasOne('phone3')
|
|
->resource('phones')
|
|
->property('property3')
|
|
->included();
|
|
});
|
|
|
|
$api->resource('phones', $phonesAdapter, function (Builder $schema) {
|
|
$schema->attribute('number');
|
|
});
|
|
|
|
$response = $api->handle($request);
|
|
|
|
$this->assertArraySubset(
|
|
[
|
|
'relationships' => [
|
|
'phone' => [
|
|
'data' => ['type' => 'phones', 'id' => '1']
|
|
],
|
|
'phone2' => [
|
|
'data' => ['type' => 'phones', 'id' => '2']
|
|
],
|
|
'phone3' => [
|
|
'data' => ['type' => 'phones', 'id' => '3']
|
|
]
|
|
]
|
|
],
|
|
json_decode($response->getBody(), true)['data']
|
|
);
|
|
|
|
$this->assertEquals(
|
|
[
|
|
[
|
|
'type' => 'phones',
|
|
'id' => '1',
|
|
'attributes' => ['number' => '8881'],
|
|
'links' => [
|
|
'self' => 'http://example.com/phones/1'
|
|
]
|
|
],
|
|
[
|
|
'type' => 'phones',
|
|
'id' => '2',
|
|
'attributes' => ['number' => '8882'],
|
|
'links' => [
|
|
'self' => 'http://example.com/phones/2'
|
|
]
|
|
],
|
|
[
|
|
'type' => 'phones',
|
|
'id' => '3',
|
|
'attributes' => ['number' => '8883'],
|
|
'links' => [
|
|
'self' => 'http://example.com/phones/3'
|
|
]
|
|
]
|
|
],
|
|
json_decode($response->getBody(), true)['included']
|
|
);
|
|
}
|
|
|
|
public function testHasOneRelationshipInclusion()
|
|
{
|
|
$phonesAdapter = new MockAdapter([
|
|
'1' => $phone1 = (object) ['id' => '1', 'number' => '8881'],
|
|
'2' => $phone2 = (object) ['id' => '2', 'number' => '8882']
|
|
]);
|
|
|
|
$usersAdapter = new MockAdapter([
|
|
'1' => (object) [
|
|
'id' => '1',
|
|
'phone' => $phone1,
|
|
'property2' => $phone2
|
|
]
|
|
]);
|
|
|
|
$request = $this->buildRequest('GET', '/users/1');
|
|
|
|
$api = new Api('http://example.com');
|
|
|
|
$api->resource('users', $usersAdapter, function (Builder $schema) {
|
|
$schema->hasOne('phone');
|
|
|
|
$schema->hasOne('phone2', 'phones', 'property2')
|
|
->included();
|
|
});
|
|
|
|
$api->resource('phones', $phonesAdapter, function (Builder $schema) {
|
|
$schema->attribute('number');
|
|
});
|
|
|
|
$response = $api->handle($request);
|
|
|
|
$this->assertArraySubset(
|
|
[
|
|
'relationships' => [
|
|
'phone2' => [
|
|
'data' => ['type' => 'phones', 'id' => '2']
|
|
]
|
|
]
|
|
],
|
|
json_decode($response->getBody(), true)['data']
|
|
);
|
|
|
|
$this->assertEquals(
|
|
[
|
|
[
|
|
'type' => 'phones',
|
|
'id' => '2',
|
|
'attributes' => ['number' => '8882'],
|
|
'links' => [
|
|
'self' => 'http://example.com/phones/2'
|
|
]
|
|
]
|
|
],
|
|
json_decode($response->getBody(), true)['included']
|
|
);
|
|
|
|
$response = $api->handle(
|
|
$request->withQueryParams(['include' => 'phone'])
|
|
);
|
|
|
|
$this->assertArraySubset(
|
|
[
|
|
'relationships' => [
|
|
'phone' => [
|
|
'data' => ['type' => 'phones', 'id' => '1']
|
|
]
|
|
]
|
|
],
|
|
json_decode($response->getBody(), true)['data']
|
|
);
|
|
|
|
$this->assertEquals(
|
|
[
|
|
[
|
|
'type' => 'phones',
|
|
'id' => '1',
|
|
'attributes' => ['number' => '8881'],
|
|
'links' => [
|
|
'self' => 'http://example.com/phones/1'
|
|
]
|
|
]
|
|
],
|
|
json_decode($response->getBody(), true)['included']
|
|
);
|
|
}
|
|
|
|
public function testHasManyRelationshipNotIncludableByDefault()
|
|
{
|
|
$api = new Api('http://example.com');
|
|
|
|
$api->resource('users', new MockAdapter(), function (Builder $schema) {
|
|
$schema->hasMany('groups');
|
|
});
|
|
|
|
$request = $this->buildRequest('GET', '/users/1')
|
|
->withQueryParams(['include' => 'groups']);
|
|
|
|
$this->expectException(BadRequestException::class);
|
|
$this->expectExceptionMessage('Invalid include [groups]');
|
|
|
|
$api->handle($request);
|
|
}
|
|
|
|
public function testHasManyRelationshipNotIncludedByDefault()
|
|
{
|
|
$usersAdapter = new MockAdapter([
|
|
'1' => (object) [
|
|
'id' => '1',
|
|
'groups' => [
|
|
(object) ['id' => '1'],
|
|
(object) ['id' => '2'],
|
|
]
|
|
]
|
|
]);
|
|
|
|
$api = new Api('http://example.com');
|
|
|
|
$api->resource('users', $usersAdapter, function (Builder $schema) {
|
|
$schema->hasMany('groups');
|
|
});
|
|
|
|
$api->resource('groups', new MockAdapter());
|
|
|
|
$request = $this->buildRequest('GET', '/users/1');
|
|
|
|
$response = $api->handle($request);
|
|
|
|
$body = json_decode($response->getBody(), true);
|
|
|
|
$this->assertArrayNotHasKey('relationships', $body['data']);
|
|
$this->assertArrayNotHasKey('included', $body);
|
|
}
|
|
|
|
public function testHasManyRelationshipInclusion()
|
|
{
|
|
$groupsAdapter = new MockAdapter([
|
|
'1' => $group1 = (object) ['id' => '1', 'name' => 'Admin'],
|
|
'2' => $group2 = (object) ['id' => '2', 'name' => 'Mod'],
|
|
'3' => $group3 = (object) ['id' => '3', 'name' => 'Member'],
|
|
'4' => $group4 = (object) ['id' => '4', 'name' => 'Guest']
|
|
]);
|
|
|
|
$usersAdapter = new MockAdapter([
|
|
'1' => $user = (object) [
|
|
'id' => '1',
|
|
'property1' => [$group1, $group2],
|
|
'property2' => [$group3, $group4]
|
|
]
|
|
]);
|
|
|
|
$api = new Api('http://example.com');
|
|
|
|
$relationships = [];
|
|
|
|
$api->resource('users', $usersAdapter, function (Builder $schema) use (&$relationships) {
|
|
$relationships[] = $schema->hasMany('groups1', 'groups', 'property1')
|
|
->included();
|
|
|
|
$relationships[] = $schema->hasMany('groups2', 'groups', 'property2')
|
|
->includable();
|
|
});
|
|
|
|
$api->resource('groups', $groupsAdapter, function (Builder $schema) {
|
|
$schema->attribute('name');
|
|
});
|
|
|
|
$request = $this->buildRequest('GET', '/users/1');
|
|
|
|
$response = $api->handle($request);
|
|
|
|
$this->assertEquals([[$relationships[0]]], $user->load);
|
|
|
|
$this->assertArraySubset(
|
|
[
|
|
'relationships' => [
|
|
'groups1' => [
|
|
'data' => [
|
|
['type' => 'groups', 'id' => '1'],
|
|
['type' => 'groups', 'id' => '2']
|
|
]
|
|
]
|
|
]
|
|
],
|
|
json_decode($response->getBody(), true)['data']
|
|
);
|
|
|
|
$this->assertEquals(
|
|
[
|
|
[
|
|
'type' => 'groups',
|
|
'id' => '1',
|
|
'attributes' => ['name' => 'Admin'],
|
|
'links' => [
|
|
'self' => 'http://example.com/groups/1'
|
|
]
|
|
],
|
|
[
|
|
'type' => 'groups',
|
|
'id' => '2',
|
|
'attributes' => ['name' => 'Mod'],
|
|
'links' => [
|
|
'self' => 'http://example.com/groups/2'
|
|
]
|
|
]
|
|
],
|
|
json_decode($response->getBody(), true)['included']
|
|
);
|
|
|
|
$user->load = [];
|
|
|
|
$response = $api->handle(
|
|
$request->withQueryParams(['include' => 'groups2'])
|
|
);
|
|
|
|
$this->assertEquals([[$relationships[1]]], $user->load);
|
|
|
|
$this->assertArraySubset(
|
|
[
|
|
'relationships' => [
|
|
'groups2' => [
|
|
'data' => [
|
|
['type' => 'groups', 'id' => '3'],
|
|
['type' => 'groups', 'id' => '4'],
|
|
]
|
|
]
|
|
]
|
|
],
|
|
json_decode($response->getBody(), true)['data']
|
|
);
|
|
|
|
$this->assertEquals(
|
|
[
|
|
[
|
|
'type' => 'groups',
|
|
'id' => '3',
|
|
'attributes' => ['name' => 'Member'],
|
|
'links' => [
|
|
'self' => 'http://example.com/groups/3'
|
|
]
|
|
],
|
|
[
|
|
'type' => 'groups',
|
|
'id' => '4',
|
|
'attributes' => ['name' => 'Guest'],
|
|
'links' => [
|
|
'self' => 'http://example.com/groups/4'
|
|
]
|
|
],
|
|
],
|
|
json_decode($response->getBody(), true)['included']
|
|
);
|
|
}
|
|
|
|
public function testNestedRelationshipInclusion()
|
|
{
|
|
$groupsAdapter = new MockAdapter([
|
|
'1' => $group1 = (object) ['id' => '1', 'name' => 'Admin'],
|
|
'2' => $group2 = (object) ['id' => '2', 'name' => 'Mod']
|
|
]);
|
|
|
|
$usersAdapter = new MockAdapter([
|
|
'1' => $user = (object) ['id' => '1', 'groups' => [$group1, $group2]]
|
|
]);
|
|
|
|
$postsAdapter = new MockAdapter([
|
|
'1' => $post = (object) ['id' => '1', 'user' => $user]
|
|
]);
|
|
|
|
$api = new Api('http://example.com');
|
|
|
|
$relationships = [];
|
|
|
|
$api->resource('posts', $postsAdapter, function (Builder $schema) use (&$relationships) {
|
|
$relationships[] = $schema->hasOne('user')->included();
|
|
});
|
|
|
|
$api->resource('users', $usersAdapter, function (Builder $schema) use (&$relationships) {
|
|
$relationships[] = $schema->hasMany('groups')->included();
|
|
});
|
|
|
|
$api->resource('groups', $groupsAdapter, function (Builder $schema) {
|
|
$schema->attribute('name');
|
|
});
|
|
|
|
$request = $this->buildRequest('GET', '/posts/1');
|
|
|
|
$response = $api->handle($request);
|
|
|
|
$this->assertEquals([$relationships[0]], $post->load[0]);
|
|
$this->assertEquals($relationships, $post->load[1]);
|
|
|
|
$this->assertArraySubset(
|
|
[
|
|
'relationships' => [
|
|
'user' => [
|
|
'data' => ['type' => 'users', 'id' => '1']
|
|
]
|
|
]
|
|
],
|
|
json_decode($response->getBody(), true)['data']
|
|
);
|
|
|
|
$included = json_decode($response->getBody(), true)['included'];
|
|
|
|
$this->assertContains(
|
|
[
|
|
'type' => 'users',
|
|
'id' => '1',
|
|
'relationships' => [
|
|
'groups' => [
|
|
'data' => [
|
|
['type' => 'groups', 'id' => '1'],
|
|
['type' => 'groups', 'id' => '2']
|
|
]
|
|
]
|
|
],
|
|
'links' => [
|
|
'self' => 'http://example.com/users/1'
|
|
]
|
|
],
|
|
$included
|
|
);
|
|
|
|
$this->assertContains(
|
|
[
|
|
'type' => 'groups',
|
|
'id' => '1',
|
|
'attributes' => ['name' => 'Admin'],
|
|
'links' => [
|
|
'self' => 'http://example.com/groups/1'
|
|
]
|
|
],
|
|
$included
|
|
);
|
|
|
|
$this->assertContains(
|
|
[
|
|
'type' => 'groups',
|
|
'id' => '2',
|
|
'attributes' => ['name' => 'Mod'],
|
|
'links' => [
|
|
'self' => 'http://example.com/groups/2'
|
|
]
|
|
],
|
|
$included
|
|
);
|
|
}
|
|
}
|