This commit is contained in:
Toby Zerner 2019-08-02 16:35:59 +00:00
parent adc388e149
commit 0d43544adc
6 changed files with 89 additions and 18 deletions

View File

@ -57,11 +57,13 @@ trait IncludesData
throw new BadRequestException("Invalid include [{$path}{$name}]", 'include');
}
if (is_string($schema->fields[$name]->resource)) {
$relatedResource = $this->api->getResource($schema->fields[$name]->resource);
$this->validateInclude($relatedResource, $nested, $name.'.');
}
}
}
private function buildRelationshipTrails(ResourceType $resource, array $include): array
{
@ -75,6 +77,7 @@ trait IncludesData
$trails[] = [$relationship];
}
if (is_string($schema->fields[$name]->resource)) {
$relatedResource = $this->api->getResource($relationship->resource);
$trails = array_merge(
@ -87,6 +90,7 @@ trait IncludesData
)
);
}
}
return $trails;
}
@ -101,13 +105,21 @@ trait IncludesData
continue;
}
if ($field->loader) {
($field->loader)($models, true);
} else {
$adapter->loadIds($models, $field);
}
}
$trails = $this->buildRelationshipTrails($this->resource, $include);
foreach ($trails as $relationships) {
if ($loader = end($relationships)->loader) {
($loader)($models, false);
} else {
$adapter->load($models, $relationships);
}
}
}
}

View File

@ -10,6 +10,7 @@ use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface;
use Tobscure\JsonApiServer\Api;
use Tobscure\JsonApiServer\Exception\BadRequestException;
use Tobscure\JsonApiServer\Exception\ForbiddenException;
use Tobscure\JsonApiServer\JsonApiResponse;
use Tobscure\JsonApiServer\ResourceType;
use Tobscure\JsonApiServer\Schema;
@ -37,6 +38,10 @@ class Index implements RequestHandlerInterface
$adapter = $this->resource->getAdapter();
$schema = $this->resource->getSchema();
if (! ($schema->isVisible)($request)) {
throw new ForbiddenException('You cannot view this resource');
}
$query = $adapter->query();
foreach ($schema->scopes as $scope) {
@ -219,7 +224,7 @@ class Index implements RequestHandlerInterface
$attribute = $schema->fields[$name];
if ($attribute->sorter) {
($attribute->sorter)($query, $direction, $request);
($attribute->sorter)($request, $query, $direction);
} else {
$adapter->sortByAttribute($query, $attribute, $direction);
}

View File

@ -7,6 +7,7 @@ use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface;
use Tobscure\JsonApiServer\Api;
use Tobscure\JsonApiServer\Exception\ForbiddenException;
use Tobscure\JsonApiServer\JsonApiResponse;
use Tobscure\JsonApiServer\ResourceType;
use Tobscure\JsonApiServer\Serializer;
@ -28,6 +29,12 @@ class Show implements RequestHandlerInterface
public function handle(Request $request): Response
{
$schema = $this->resource->getSchema();
if (! ($schema->isVisible)($request)) {
throw new ForbiddenException('You cannot view this resource');
}
$include = $this->getInclude($request);
$this->loadRelationships([$this->model], $include, $request);

View File

@ -30,6 +30,7 @@ class Builder
public function __construct()
{
$this->visible();
$this->notCreatable();
$this->notUpdatable();
$this->notDeletable();
@ -40,7 +41,7 @@ class Builder
return $this->field(Attribute::class, $name, $property);
}
public function hasOne(string $name, string $resource = null, string $property = null): HasOne
public function hasOne(string $name, $resource = null, string $property = null): HasOne
{
$field = $this->field(HasOne::class, $name, $property);
@ -51,7 +52,7 @@ class Builder
return $field;
}
public function hasMany(string $name, string $resource = null, string $property = null): HasMany
public function hasMany(string $name, $resource = null, string $property = null): HasMany
{
$field = $this->field(HasMany::class, $name, $property);
@ -107,6 +108,34 @@ class Builder
$this->singleScopes[] = $callback;
}
public function visibleIf(Closure $condition)
{
$this->isVisible = $condition;
return $this;
}
public function visible()
{
return $this->visibleIf(function () {
return true;
});
}
public function notVisibleIf(Closure $condition)
{
return $this->visibleIf(function (...$args) use ($condition) {
return ! $condition(...$args);
});
}
public function notVisible()
{
return $this->notVisibleIf(function () {
return true;
});
}
public function creatableIf(Closure $condition)
{
$this->isCreatable = $condition;

View File

@ -11,6 +11,7 @@ abstract class Relationship extends Field
public $linkage;
public $hasLinks = true;
public $loadable = true;
public $loader;
public $included = false;
public $resource;
@ -70,6 +71,13 @@ abstract class Relationship extends Field
return $this;
}
public function load(Closure $callback)
{
$this->loader = $callback;
return $this;
}
public function included()
{
$this->included = true;

View File

@ -184,7 +184,17 @@ class Serializer
private function addRelated(Schema\Relationship $field, $model, array $include): JsonApi\ResourceIdentifier
{
$relatedResource = $this->api->getResource($field->resource);
if (is_array($field->resource)) {
foreach ($field->resource as $class => $resource) {
if ($model instanceof $class) {
break;
}
}
} else {
$resource = $field->resource;
}
$relatedResource = $this->api->getResource($resource);
return $this->resourceIdentifier(
$this->addToMap($relatedResource, $model, $include)