Allow relationships to specify adapter-specific scope logic
This commit is contained in:
parent
4a001556d8
commit
4883a8b595
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Tobyz\JsonApiServer\Adapter;
|
||||
|
||||
use Closure;
|
||||
use Tobyz\JsonApiServer\Schema\Attribute;
|
||||
use Tobyz\JsonApiServer\Schema\HasMany;
|
||||
use Tobyz\JsonApiServer\Schema\HasOne;
|
||||
|
|
@ -216,9 +217,11 @@ interface AdapterInterface
|
|||
*
|
||||
* @param array $models
|
||||
* @param array $relationships
|
||||
* @param Closure $scope Should be called to give the deepest relationship
|
||||
* an opportunity to scope the query that will fetch related resources
|
||||
* @return mixed
|
||||
*/
|
||||
public function load(array $models, array $relationships): void;
|
||||
public function load(array $models, array $relationships, Closure $scope): void;
|
||||
|
||||
/**
|
||||
* Load information about the IDs of related resources onto a collection
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Tobyz\JsonApiServer\Adapter;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
|
@ -188,9 +189,13 @@ class EloquentAdapter implements AdapterInterface
|
|||
$query->take($limit)->skip($offset);
|
||||
}
|
||||
|
||||
public function load(array $models, array $relationships): void
|
||||
public function load(array $models, array $relationships, Closure $scope): void
|
||||
{
|
||||
(new Collection($models))->loadMissing($this->getRelationshipPath($relationships));
|
||||
$relationship = end($relationships);
|
||||
|
||||
(new Collection($models))->loadMissing([
|
||||
$this->getRelationshipPath($relationships) => $scope
|
||||
]);
|
||||
}
|
||||
|
||||
public function loadIds(array $models, Relationship $relationship): void
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use function Tobyz\JsonApiServer\evaluate;
|
|||
use Tobyz\JsonApiServer\Exception\BadRequestException;
|
||||
use Tobyz\JsonApiServer\ResourceType;
|
||||
use Tobyz\JsonApiServer\Schema\Relationship;
|
||||
use function Tobyz\JsonApiServer\run_callbacks;
|
||||
|
||||
trait IncludesData
|
||||
{
|
||||
|
|
@ -103,9 +104,27 @@ trait IncludesData
|
|||
$adapter = $this->resource->getAdapter();
|
||||
$fields = $this->resource->getSchema()->getFields();
|
||||
|
||||
// TODO: don't load IDs for relationships which are included below
|
||||
$trails = $this->buildRelationshipTrails($this->resource, $include);
|
||||
$loaded = [];
|
||||
|
||||
foreach ($trails as $relationships) {
|
||||
$relationship = end($relationships);
|
||||
|
||||
if (($load = $relationship->getLoadable()) instanceof Closure) {
|
||||
$load($models, $relationships, false, $request);
|
||||
} else {
|
||||
$scope = function ($query) use ($request, $relationship) {
|
||||
run_callbacks($relationship->getScopes(), [$query, $request]);
|
||||
};
|
||||
|
||||
$adapter->load($models, $relationships, $scope);
|
||||
}
|
||||
|
||||
$loaded[] = $relationships[0];
|
||||
}
|
||||
|
||||
foreach ($fields as $name => $field) {
|
||||
if (! $field instanceof Relationship || ! evaluate($field->getLinkage(), [$request]) || ! $field->getLoadable()) {
|
||||
if (! $field instanceof Relationship || ! evaluate($field->getLinkage(), [$request]) || ! $field->getLoadable() || in_array($field, $loaded)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -115,16 +134,5 @@ trait IncludesData
|
|||
$adapter->loadIds($models, $field);
|
||||
}
|
||||
}
|
||||
|
||||
$trails = $this->buildRelationshipTrails($this->resource, $include);
|
||||
|
||||
foreach ($trails as $relationships) {
|
||||
if (($load = end($relationships)->getLoadable()) instanceof Closure) {
|
||||
// TODO: probably need to loop through relationships here
|
||||
$load($models, false);
|
||||
} else {
|
||||
$adapter->load($models, $relationships);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ abstract class Relationship extends Field
|
|||
private $links = true;
|
||||
private $loadable = true;
|
||||
private $includable = false;
|
||||
private $scopes = [];
|
||||
|
||||
public function type($type)
|
||||
{
|
||||
|
|
@ -122,4 +123,14 @@ abstract class Relationship extends Field
|
|||
{
|
||||
return 'relationships';
|
||||
}
|
||||
|
||||
public function scope(Closure $callback)
|
||||
{
|
||||
$this->scopes[] = $callback;
|
||||
}
|
||||
|
||||
public function getScopes(): array
|
||||
{
|
||||
return $this->scopes;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue