This commit is contained in:
Toby Zerner 2019-07-04 15:40:45 +09:30
parent 9ee46b3ee0
commit bb415b0486
13 changed files with 69 additions and 21 deletions

View File

@ -6,8 +6,7 @@
"json-api-php/json-api": "^2.0", "json-api-php/json-api": "^2.0",
"psr/http-message": "^1.0", "psr/http-message": "^1.0",
"psr/http-server-handler": "^1.0", "psr/http-server-handler": "^1.0",
"spatie/macroable": "^1.0", "zendframework/zend-diactoros": "^2.1"
"zendframework/zend-diactoros": "^2.0"
}, },
"license": "MIT", "license": "MIT",
"authors": [ "authors": [

View File

@ -119,7 +119,28 @@ class EloquentAdapter implements AdapterInterface
public function filterByAttribute($query, Attribute $field, $value) public function filterByAttribute($query, Attribute $field, $value)
{ {
$query->where($this->getAttributeProperty($field), $value); $property = $this->getAttributeProperty($field);
if (preg_match('/(.+)\.\.(.+)/', $value, $matches)) {
if ($matches[1] !== '*') {
$query->where($property, '>=', $matches[1]);
}
if ($matches[2] !== '*') {
$query->where($property, '<=', $matches[2]);
}
return;
}
foreach (['>=', '>', '<=', '<'] as $operator) {
if (strpos($value, $operator) === 0) {
$query->where($property, $operator, substr($value, strlen($operator)));
return;
}
}
$query->where($property, $value);
} }
public function filterByHasOne($query, HasOne $field, array $ids) public function filterByHasOne($query, HasOne $field, array $ids)

View File

@ -123,12 +123,13 @@ class Api implements RequestHandlerInterface
} }
$errors = $e->getJsonApiErrors(); $errors = $e->getJsonApiErrors();
$status = $e->getJsonApiStatus();
$data = new JsonApi\ErrorDocument( $data = new JsonApi\ErrorDocument(
...$errors ...$errors
); );
return new JsonApiResponse($data); return new JsonApiResponse($data, $status);
} }
public function getBaseUrl(): string public function getBaseUrl(): string

View File

@ -5,4 +5,6 @@ namespace Tobscure\JsonApiServer;
interface ErrorProviderInterface interface ErrorProviderInterface
{ {
public function getJsonApiErrors(): array; public function getJsonApiErrors(): array;
public function getJsonApiStatus(): string;
} }

View File

@ -34,9 +34,14 @@ class BadRequestException extends \DomainException implements ErrorProviderInter
return [ return [
new Error( new Error(
new Error\Title('Bad Request'), new Error\Title('Bad Request'),
new Error\Status('400'), new Error\Status($this->getJsonApiStatus()),
...$members ...$members
) )
]; ];
} }
public function getJsonApiStatus(): string
{
return '400';
}
} }

View File

@ -5,15 +5,20 @@ namespace Tobscure\JsonApiServer\Exception;
use JsonApiPhp\JsonApi\Error; use JsonApiPhp\JsonApi\Error;
use Tobscure\JsonApiServer\ErrorProviderInterface; use Tobscure\JsonApiServer\ErrorProviderInterface;
class BadRequestException extends \DomainException implements ErrorProviderInterface class ForbiddenException extends \DomainException implements ErrorProviderInterface
{ {
public function getJsonApiErrors(): array public function getJsonApiErrors(): array
{ {
return [ return [
new Error( new Error(
new Error\Title('Forbidden'), new Error\Title('Forbidden'),
new Error\Status('403') new Error\Status($this->getJsonApiStatus())
) )
]; ];
} }
public function getJsonApiStatus(): string
{
return '403';
}
} }

View File

@ -16,4 +16,9 @@ class InternalServerErrorException extends \RuntimeException implements ErrorPro
) )
]; ];
} }
public function getJsonApiStatus(): string
{
return '500';
}
} }

View File

@ -5,7 +5,7 @@ namespace Tobscure\JsonApiServer\Exception;
use JsonApiPhp\JsonApi\Error; use JsonApiPhp\JsonApi\Error;
use Tobscure\JsonApiServer\ErrorProviderInterface; use Tobscure\JsonApiServer\ErrorProviderInterface;
class BadRequestException extends \DomainException implements ErrorProviderInterface class MethodNotAllowedException extends \DomainException implements ErrorProviderInterface
{ {
public function getJsonApiErrors(): array public function getJsonApiErrors(): array
{ {

View File

@ -48,15 +48,15 @@ trait SavesData
$body = (array) $body; $body = (array) $body;
if (! isset($body['data'])) { if (! isset($body['data'])) {
throw new BadRequestException; throw new BadRequestException('Root data attribute missing');
} }
if (isset($body['data']['attributes']) && ! is_array($body['data']['attributes'])) { if (isset($body['data']['attributes']) && ! is_array($body['data']['attributes'])) {
throw new BadRequestException; throw new BadRequestException('data.attributes must be an object');
} }
if (isset($body['data']['relationships']) && ! is_array($body['data']['relationships'])) { if (isset($body['data']['relationships']) && ! is_array($body['data']['relationships'])) {
throw new BadRequestException; throw new BadRequestException('data.relationships must be an object');
} }
return array_merge( return array_merge(

View File

@ -127,6 +127,14 @@ class Index implements RequestHandlerInterface
unset($queryParams['page']['offset']); unset($queryParams['page']['offset']);
} }
if (isset($queryParams['filter'])) {
foreach ($queryParams['filter'] as $k => &$v) {
if ($v === null) {
$v = '';
}
}
}
$queryString = http_build_query($queryParams); $queryString = http_build_query($queryParams);
return $selfUrl.($queryString ? '?'.$queryString : ''); return $selfUrl.($queryString ? '?'.$queryString : '');

View File

@ -3,12 +3,9 @@
namespace Tobscure\JsonApiServer\Schema; namespace Tobscure\JsonApiServer\Schema;
use Closure; use Closure;
use Spatie\Macroable\Macroable;
class Attribute extends Field class Attribute extends Field
{ {
use Macroable;
public $location = 'attributes'; public $location = 'attributes';
public $sortable = false; public $sortable = false;
public $sorter; public $sorter;

View File

@ -3,13 +3,10 @@
namespace Tobscure\JsonApiServer\Schema; namespace Tobscure\JsonApiServer\Schema;
use Closure; use Closure;
use Spatie\Macroable\Macroable;
use Tobscure\JsonApiServer\Handler\Show; use Tobscure\JsonApiServer\Handler\Show;
abstract class Relationship extends Field abstract class Relationship extends Field
{ {
use Macroable;
public $location = 'relationships'; public $location = 'relationships';
public $linkage; public $linkage;
public $hasLinks = true; public $hasLinks = true;

View File

@ -34,7 +34,7 @@ class Serializer
$schema = $resource->getSchema(); $schema = $resource->getSchema();
$data = [ $data = [
'type' => $resource->getType(), 'type' => $type = $resource->getType(),
'id' => $adapter->getId($model), 'id' => $adapter->getId($model),
'fields' => [], 'fields' => [],
'links' => [], 'links' => [],
@ -43,9 +43,17 @@ class Serializer
$resourceUrl = $this->api->getBaseUrl().'/'.$data['type'].'/'.$data['id']; $resourceUrl = $this->api->getBaseUrl().'/'.$data['type'].'/'.$data['id'];
ksort($schema->fields); $fields = $schema->fields;
foreach ($schema->fields as $name => $field) { $queryParams = $this->request->getQueryParams();
if (isset($queryParams['fields'][$type])) {
$fields = array_intersect_key($fields, array_flip(explode(',', $queryParams['fields'][$type])));
}
ksort($fields);
foreach ($fields as $name => $field) {
if (! ($field->isVisible)($this->request, $model)) { if (! ($field->isVisible)($this->request, $model)) {
continue; continue;
} }
@ -132,7 +140,7 @@ class Serializer
if ($field->getter) { if ($field->getter) {
$value = ($field->getter)($this->request, $model); $value = ($field->getter)($this->request, $model);
} else { } else {
$value = $isLinkage ? $adapter->getHasMany($model, $field) : null; $value = ($isLinkage || $isIncluded) ? $adapter->getHasMany($model, $field) : null;
} }
$identifiers = []; $identifiers = [];