Skip to content

Commit f0c7ed5

Browse files
committed
Eloquent: apply scopes when including polymorphic relationships
1 parent 71dcdad commit f0c7ed5

File tree

2 files changed

+45
-24
lines changed

2 files changed

+45
-24
lines changed

src/Adapter/EloquentAdapter.php

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -211,13 +211,19 @@ public function load(array $models, array $relationships, $scope, bool $linkage)
211211
// to load anything as the related ID is store directly on the model.
212212

213213
(new Collection($models))->loadMissing([
214-
$this->getRelationshipPath($relationships) => function ($relation) use ($relationships, $scope) {
214+
$this->getRelationshipPath($relationships) => function ($relation) use ($scope) {
215215
$query = $relation->getQuery();
216216

217217
if (is_array($scope)) {
218-
// TODO: since https://github.com/laravel/framework/pull/35190
219-
// was merged, we can now apply loading constraints to
220-
// polymorphic relationships.
218+
// Requires Laravel 8.15+
219+
foreach ($scope as $v) {
220+
$adapter = $v['resource']->getAdapter();
221+
if ($adapter instanceof self) {
222+
$relation->constrain([
223+
get_class($adapter->newModel()) => $v['scope']
224+
]);
225+
}
226+
}
221227
} else {
222228
$scope($query);
223229
}

src/Endpoint/Concerns/IncludesData.php

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ private function getInclude(Context $context): array
3131
if (! empty($queryParams['include'])) {
3232
$include = $this->parseInclude($queryParams['include']);
3333

34-
$this->validateInclude($this->resource, $include);
34+
$this->validateInclude([$this->resource], $include);
3535

3636
return $include;
3737
}
@@ -58,26 +58,38 @@ private function parseInclude(string $include): array
5858
return $tree;
5959
}
6060

61-
private function validateInclude(ResourceType $resource, array $include, string $path = '')
61+
private function validateInclude(array $resources, array $include, string $path = '')
6262
{
63-
$fields = $resource->getSchema()->getFields();
64-
6563
foreach ($include as $name => $nested) {
66-
if (
67-
! isset($fields[$name])
68-
|| ! $fields[$name] instanceof Relationship
69-
|| ! $fields[$name]->isIncludable()
70-
) {
71-
throw new BadRequestException("Invalid include [{$path}{$name}]", 'include');
72-
}
64+
foreach ($resources as $resource) {
65+
$fields = $resource->getSchema()->getFields();
66+
67+
if (
68+
! isset($fields[$name])
69+
|| ! $fields[$name] instanceof Relationship
70+
|| ! $fields[$name]->isIncludable()
71+
) {
72+
continue;
73+
}
74+
75+
$type = $fields[$name]->getType();
7376

74-
if (($type = $fields[$name]->getType()) && is_string($type)) {
75-
$relatedResource = $this->api->getResource($type);
77+
if (is_string($type)) {
78+
$relatedResource = $this->api->getResource($type);
7679

77-
$this->validateInclude($relatedResource, $nested, $name.'.');
78-
} elseif ($nested) {
79-
throw new BadRequestException("Invalid include [{$path}{$name}.*]", 'include');
80+
$this->validateInclude([$relatedResource], $nested, $name.'.');
81+
} else {
82+
$relatedResources = is_array($type) ? array_map(function ($type) {
83+
return $this->api->getResource($type);
84+
}, $type) : array_values($this->api->getResources());
85+
86+
$this->validateInclude($relatedResources, $nested, $name.'.');
87+
}
88+
89+
continue 2;
8090
}
91+
92+
throw new BadRequestException("Invalid include [{$path}{$name}]", 'include');
8193
}
8294
}
8395

@@ -123,10 +135,13 @@ private function loadRelationshipsAtLevel(array $models, array $relationshipPath
123135
}, $relatedResources),
124136

125137
array_map(function ($relatedResource) use ($context, $field) {
126-
return function ($query) use ($context, $field, $relatedResource) {
127-
run_callbacks($relatedResource->getSchema()->getListeners('scope'), [$query, $context]);
128-
run_callbacks($field->getListeners('scope'), [$query, $context]);
129-
};
138+
return [
139+
'resource' => $relatedResource,
140+
'scope' => function ($query) use ($context, $field, $relatedResource) {
141+
run_callbacks($relatedResource->getSchema()->getListeners('scope'), [$query, $context]);
142+
run_callbacks($field->getListeners('scope'), [$query, $context]);
143+
}
144+
];
130145
}, $relatedResources)
131146
);
132147
}

0 commit comments

Comments
 (0)