Skip to content

Commit 4883a8b

Browse files
committed
Allow relationships to specify adapter-specific scope logic
1 parent 4a00155 commit 4883a8b

File tree

4 files changed

+43
-16
lines changed

4 files changed

+43
-16
lines changed

src/Adapter/AdapterInterface.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Tobyz\JsonApiServer\Adapter;
44

5+
use Closure;
56
use Tobyz\JsonApiServer\Schema\Attribute;
67
use Tobyz\JsonApiServer\Schema\HasMany;
78
use Tobyz\JsonApiServer\Schema\HasOne;
@@ -216,9 +217,11 @@ public function delete($model): void;
216217
*
217218
* @param array $models
218219
* @param array $relationships
220+
* @param Closure $scope Should be called to give the deepest relationship
221+
* an opportunity to scope the query that will fetch related resources
219222
* @return mixed
220223
*/
221-
public function load(array $models, array $relationships): void;
224+
public function load(array $models, array $relationships, Closure $scope): void;
222225

223226
/**
224227
* Load information about the IDs of related resources onto a collection

src/Adapter/EloquentAdapter.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Tobyz\JsonApiServer\Adapter;
44

5+
use Closure;
56
use Illuminate\Database\Eloquent\Collection;
67
use Illuminate\Database\Eloquent\Model;
78
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -188,9 +189,13 @@ public function paginate($query, int $limit, int $offset): void
188189
$query->take($limit)->skip($offset);
189190
}
190191

191-
public function load(array $models, array $relationships): void
192+
public function load(array $models, array $relationships, Closure $scope): void
192193
{
193-
(new Collection($models))->loadMissing($this->getRelationshipPath($relationships));
194+
$relationship = end($relationships);
195+
196+
(new Collection($models))->loadMissing([
197+
$this->getRelationshipPath($relationships) => $scope
198+
]);
194199
}
195200

196201
public function loadIds(array $models, Relationship $relationship): void

src/Handler/Concerns/IncludesData.php

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Tobyz\JsonApiServer\Exception\BadRequestException;
99
use Tobyz\JsonApiServer\ResourceType;
1010
use Tobyz\JsonApiServer\Schema\Relationship;
11+
use function Tobyz\JsonApiServer\run_callbacks;
1112

1213
trait IncludesData
1314
{
@@ -103,9 +104,27 @@ private function loadRelationships(array $models, array $include, Request $reque
103104
$adapter = $this->resource->getAdapter();
104105
$fields = $this->resource->getSchema()->getFields();
105106

106-
// TODO: don't load IDs for relationships which are included below
107+
$trails = $this->buildRelationshipTrails($this->resource, $include);
108+
$loaded = [];
109+
110+
foreach ($trails as $relationships) {
111+
$relationship = end($relationships);
112+
113+
if (($load = $relationship->getLoadable()) instanceof Closure) {
114+
$load($models, $relationships, false, $request);
115+
} else {
116+
$scope = function ($query) use ($request, $relationship) {
117+
run_callbacks($relationship->getScopes(), [$query, $request]);
118+
};
119+
120+
$adapter->load($models, $relationships, $scope);
121+
}
122+
123+
$loaded[] = $relationships[0];
124+
}
125+
107126
foreach ($fields as $name => $field) {
108-
if (! $field instanceof Relationship || ! evaluate($field->getLinkage(), [$request]) || ! $field->getLoadable()) {
127+
if (! $field instanceof Relationship || ! evaluate($field->getLinkage(), [$request]) || ! $field->getLoadable() || in_array($field, $loaded)) {
109128
continue;
110129
}
111130

@@ -115,16 +134,5 @@ private function loadRelationships(array $models, array $include, Request $reque
115134
$adapter->loadIds($models, $field);
116135
}
117136
}
118-
119-
$trails = $this->buildRelationshipTrails($this->resource, $include);
120-
121-
foreach ($trails as $relationships) {
122-
if (($load = end($relationships)->getLoadable()) instanceof Closure) {
123-
// TODO: probably need to loop through relationships here
124-
$load($models, false);
125-
} else {
126-
$adapter->load($models, $relationships);
127-
}
128-
}
129137
}
130138
}

src/Schema/Relationship.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ abstract class Relationship extends Field
1313
private $links = true;
1414
private $loadable = true;
1515
private $includable = false;
16+
private $scopes = [];
1617

1718
public function type($type)
1819
{
@@ -122,4 +123,14 @@ public function getLocation(): string
122123
{
123124
return 'relationships';
124125
}
126+
127+
public function scope(Closure $callback)
128+
{
129+
$this->scopes[] = $callback;
130+
}
131+
132+
public function getScopes(): array
133+
{
134+
return $this->scopes;
135+
}
125136
}

0 commit comments

Comments
 (0)