Skip to content

Commit dc8c09b

Browse files
authoredNov 15, 2024··
fix(laravel) graphQl Relationship loading (#6792)
Co-authored-by: Antoine Bluchet <soyuka@users.noreply.github.com> Closes: #6791 fixes api-platform/api-platform#2795, #6791
1 parent 8109906 commit dc8c09b

File tree

2 files changed

+64
-13
lines changed

2 files changed

+64
-13
lines changed
 

‎src/Laravel/ApiPlatformProvider.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -432,12 +432,12 @@ public function register(): void
432432
$this->app->singleton(ItemProvider::class, function (Application $app) {
433433
$tagged = iterator_to_array($app->tagged(LinksHandlerInterface::class));
434434

435-
return new ItemProvider(new LinksHandler($app), new ServiceLocator($tagged));
435+
return new ItemProvider(new LinksHandler($app, $app->make(ResourceMetadataCollectionFactoryInterface::class)), new ServiceLocator($tagged));
436436
});
437437
$this->app->singleton(CollectionProvider::class, function (Application $app) {
438438
$tagged = iterator_to_array($app->tagged(LinksHandlerInterface::class));
439439

440-
return new CollectionProvider($app->make(Pagination::class), new LinksHandler($app), $app->tagged(QueryExtensionInterface::class), new ServiceLocator($tagged));
440+
return new CollectionProvider($app->make(Pagination::class), new LinksHandler($app, $app->make(ResourceMetadataCollectionFactoryInterface::class)), $app->tagged(QueryExtensionInterface::class), new ServiceLocator($tagged));
441441
});
442442
$this->app->tag([ItemProvider::class, CollectionProvider::class], ProviderInterface::class);
443443

‎src/Laravel/Eloquent/State/LinksHandler.php

+62-11
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@
1313

1414
namespace ApiPlatform\Laravel\Eloquent\State;
1515

16+
use ApiPlatform\Metadata\Exception\OperationNotFoundException;
17+
use ApiPlatform\Metadata\GraphQl\Operation;
18+
use ApiPlatform\Metadata\GraphQl\Query;
1619
use ApiPlatform\Metadata\HttpOperation;
20+
use ApiPlatform\Metadata\Link;
21+
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
1722
use Illuminate\Contracts\Foundation\Application;
1823
use Illuminate\Database\Eloquent\Builder;
1924
use Illuminate\Database\Eloquent\Model;
@@ -25,6 +30,7 @@ final class LinksHandler implements LinksHandlerInterface
2530
{
2631
public function __construct(
2732
private readonly Application $application,
33+
private readonly ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory,
2834
) {
2935
}
3036

@@ -34,27 +40,72 @@ public function handleLinks(Builder $builder, array $uriVariables, array $contex
3440

3541
if ($operation instanceof HttpOperation) {
3642
foreach (array_reverse($operation->getUriVariables() ?? []) as $uriVariable => $link) {
37-
$identifier = $uriVariables[$uriVariable];
43+
$builder = $this->buildQuery($builder, $link, $uriVariables[$uriVariable]);
44+
}
3845

39-
if ($to = $link->getToProperty()) {
40-
$builder = $builder->where($builder->getModel()->{$to}()->getQualifiedForeignKeyName(), $identifier);
46+
return $builder;
47+
}
4148

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

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

49-
continue;
57+
try {
58+
$resourceMetadataCollection = $this->resourceMetadataCollectionFactory->create($linkClass);
59+
$linkedOperation = $resourceMetadataCollection->getOperation($operation->getName());
60+
} catch (OperationNotFoundException) {
61+
// Instead, we'll look for the first Query available.
62+
foreach ($resourceMetadataCollection as $resourceMetadata) {
63+
foreach ($resourceMetadata->getGraphQlOperations() as $op) {
64+
if ($op instanceof Query) {
65+
$linkedOperation = $op;
66+
}
5067
}
68+
}
69+
}
70+
71+
if (!$linkedOperation instanceof Operation) {
72+
return $builder;
73+
}
5174

52-
$builder->where($builder->getModel()->qualifyColumn($link->getIdentifiers()[0]), $identifier);
75+
$resourceClass = $builder->getModel()::class;
76+
foreach ($linkedOperation->getLinks() ?? [] as $link) {
77+
if ($resourceClass === $link->getToClass() && $linkProperty === $link->getFromProperty()) {
78+
$newLink = $link;
79+
break;
5380
}
81+
}
5482

83+
if (!$newLink) {
5584
return $builder;
5685
}
5786

58-
return $builder;
87+
return $this->buildQuery($builder, $newLink, $uriVariables[$newLink->getIdentifiers()[0]]);
88+
}
89+
90+
/**
91+
* @param Builder<Model> $builder
92+
*
93+
* @throws \Illuminate\Contracts\Container\BindingResolutionException
94+
*
95+
* @return Builder<Model> $builder
96+
*/
97+
private function buildQuery(Builder $builder, Link $link, mixed $identifier): Builder
98+
{
99+
if ($to = $link->getToProperty()) {
100+
return $builder->where($builder->getModel()->{$to}()->getQualifiedForeignKeyName(), $identifier);
101+
}
102+
103+
if ($from = $link->getFromProperty()) {
104+
$relation = $this->application->make($link->getFromClass());
105+
106+
return $builder->getModel()->where($relation->{$from}()->getQualifiedForeignKeyName(), $identifier);
107+
}
108+
109+
return $builder->where($builder->getModel()->qualifyColumn($link->getIdentifiers()[0]), $identifier);
59110
}
60111
}

0 commit comments

Comments
 (0)
Please sign in to comment.