Skip to content

Commit 1aa26e0

Browse files
committed
fix(laravel): graphql fix relationship loading
fix loading relationships by only loading those related to the model Signed-off-by: Tobias Oitzinger <[email protected]>
1 parent 1cf0a13 commit 1aa26e0

File tree

2 files changed

+55
-13
lines changed

2 files changed

+55
-13
lines changed

src/Laravel/ApiPlatformProvider.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -412,12 +412,12 @@ public function register(): void
412412
$this->app->singleton(ItemProvider::class, function (Application $app) {
413413
$tagged = iterator_to_array($app->tagged(LinksHandlerInterface::class));
414414

415-
return new ItemProvider(new LinksHandler($app), new ServiceLocator($tagged));
415+
return new ItemProvider(new LinksHandler($app, $app->make(ResourceMetadataCollectionFactoryInterface::class)), new ServiceLocator($tagged));
416416
});
417417
$this->app->singleton(CollectionProvider::class, function (Application $app) {
418418
$tagged = iterator_to_array($app->tagged(LinksHandlerInterface::class));
419419

420-
return new CollectionProvider($app->make(Pagination::class), new LinksHandler($app), $app->tagged(QueryExtensionInterface::class), new ServiceLocator($tagged));
420+
return new CollectionProvider($app->make(Pagination::class), new LinksHandler($app, $app->make(ResourceMetadataCollectionFactoryInterface::class)), $app->tagged(QueryExtensionInterface::class), new ServiceLocator($tagged));
421421
});
422422
$this->app->tag([ItemProvider::class, CollectionProvider::class], ProviderInterface::class);
423423

src/Laravel/Eloquent/State/LinksHandler.php

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@
1313

1414
namespace ApiPlatform\Laravel\Eloquent\State;
1515

16+
use ApiPlatform\Metadata\Exception\OperationNotFoundException;
17+
use ApiPlatform\Metadata\GraphQl\Query;
1618
use ApiPlatform\Metadata\HttpOperation;
19+
use ApiPlatform\Metadata\Link;
20+
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
1721
use Illuminate\Contracts\Foundation\Application;
1822
use Illuminate\Database\Eloquent\Builder;
1923
use Illuminate\Database\Eloquent\Model;
@@ -25,6 +29,7 @@ final class LinksHandler implements LinksHandlerInterface
2529
{
2630
public function __construct(
2731
private readonly Application $application,
32+
private readonly ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory,
2833
) {
2934
}
3035

@@ -34,27 +39,64 @@ public function handleLinks(Builder $builder, array $uriVariables, array $contex
3439

3540
if ($operation instanceof HttpOperation) {
3641
foreach (array_reverse($operation->getUriVariables() ?? []) as $uriVariable => $link) {
37-
$identifier = $uriVariables[$uriVariable];
42+
$builder = $this->buildQuery($builder, $link, $uriVariables[$uriVariable]);
43+
}
3844

39-
if ($to = $link->getToProperty()) {
40-
$builder = $builder->where($builder->getModel()->getTable().'.'.$builder->getModel()->{$to}()->getForeignKeyName(), $identifier);
45+
return $builder;
46+
}
4147

42-
continue;
43-
}
48+
if (!($linkClass = $context['linkClass'] ?? false)) {
49+
return $builder;
50+
}
4451

45-
if ($from = $link->getFromProperty()) {
46-
$relation = $this->application->make($link->getFromClass());
47-
$builder = $builder->getModel()->where($builder->getModel()->getTable().'.'.$relation->{$from}()->getForeignKeyName(), $identifier);
52+
$newLink = null;
53+
$linkedOperation = null;
54+
$linkProperty = $context['linkProperty'] ?? null;
4855

49-
continue;
56+
try {
57+
$resourceMetadataCollection = $this->resourceMetadataCollectionFactory->create($linkClass);
58+
$linkedOperation = $resourceMetadataCollection->getOperation($operation->getName());
59+
} catch (OperationNotFoundException) {
60+
// Instead, we'll look for the first Query available.
61+
foreach ($resourceMetadataCollection as $resourceMetadata) {
62+
foreach ($resourceMetadata->getGraphQlOperations() as $op) {
63+
if ($op instanceof Query) {
64+
$linkedOperation = $op;
65+
}
5066
}
67+
}
68+
}
5169

52-
$builder->where($builder->getModel()->getTable().'.'.$link->getIdentifiers()[0], $identifier);
70+
if (!$linkedOperation) {
71+
return $builder;
72+
}
73+
74+
$resourceClass = $builder->getModel()::class;
75+
foreach ($linkedOperation->getLinks() ?? [] as $link) {
76+
if ($resourceClass === $link->getToClass() && $linkProperty === $link->getFromProperty()) {
77+
$newLink = $link;
78+
break;
5379
}
80+
}
5481

82+
if (!$newLink) {
5583
return $builder;
5684
}
5785

58-
return $builder;
86+
return $this->buildQuery($builder, $newLink, $uriVariables[$newLink->getIdentifiers()[0]]);
87+
}
88+
89+
private function buildQuery(Builder $builder, Link $link, mixed $identifier): Builder
90+
{
91+
if ($to = $link->getToProperty()) {
92+
return $builder->where($builder->getModel()->{$to}()->getQualifiedForeignKeyName(), $identifier);
93+
}
94+
95+
if ($from = $link->getFromProperty()) {
96+
$relation = $this->application->make($link->getFromClass());
97+
return $builder->getModel()->where($relation->{$from}()->getQualifiedForeignKeyName(), $identifier);
98+
}
99+
100+
return $builder->where($builder->getModel()->qualifyColumn($link->getIdentifiers()[0]), $identifier);
59101
}
60102
}

0 commit comments

Comments
 (0)