1313
1414namespace ApiPlatform \Laravel \Eloquent \State ;
1515
16+ use ApiPlatform \Metadata \Exception \OperationNotFoundException ;
17+ use ApiPlatform \Metadata \GraphQl \Operation ;
18+ use ApiPlatform \Metadata \GraphQl \Query ;
1619use ApiPlatform \Metadata \HttpOperation ;
20+ use ApiPlatform \Metadata \Link ;
21+ use ApiPlatform \Metadata \Resource \Factory \ResourceMetadataCollectionFactoryInterface ;
1722use Illuminate \Contracts \Foundation \Application ;
1823use Illuminate \Database \Eloquent \Builder ;
1924use 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