14
14
namespace ApiPlatform \Bridge \Doctrine \Orm \State ;
15
15
16
16
use ApiPlatform \Core \Bridge \Doctrine \Orm \Util \QueryNameGenerator ;
17
- use ApiPlatform \Exception \RuntimeException ;
18
17
use ApiPlatform \Metadata \GraphQl \Operation as GraphQlOperation ;
19
18
use ApiPlatform \Metadata \Link ;
19
+ use ApiPlatform \Tests \Fixtures \TestBundle \Entity \DummyProduct ;
20
+ use Doctrine \ORM \Mapping \ClassMetadataInfo ;
20
21
use Doctrine \ORM \QueryBuilder ;
21
22
use Doctrine \Persistence \Mapping \ClassMetadata ;
22
23
@@ -31,81 +32,110 @@ private function handleLinks(QueryBuilder $queryBuilder, array $identifiers, Que
31
32
32
33
$ links = $ operation instanceof GraphQlOperation ? $ operation ->getLinks () : $ operation ->getUriVariables ();
33
34
34
- if ($ linkClass = $ context ['linkClass ' ] ?? false ) {
35
- foreach ($ links as $ link ) {
36
- if ($ linkClass === $ link ->getFromClass ()) {
37
- foreach ($ identifiers as $ identifier => $ value ) {
38
- $ this ->applyLink ($ queryBuilder , $ queryNameGenerator , $ doctrineClassMetadata , $ alias , $ link , $ identifier , $ value );
39
- }
35
+ // if ($linkClass = $context['linkClass'] ?? false) {
36
+ // foreach ($links as $link) {
37
+ // if ($linkClass === $link->getTargetClass()) {
38
+ // foreach ($identifiers as $identifier => $value) {
39
+ // $this->applyLink($queryBuilder, $queryNameGenerator, $doctrineClassMetadata, $alias, $link, $identifier, $value);
40
+ // }
41
+ //
42
+ // return;
43
+ // }
44
+ // }
45
+ // }
40
46
41
- return ;
42
- }
47
+ if (!$ links ) {
48
+ return ;
49
+ }
50
+
51
+ $ previousAlias = $ alias ;
52
+ $ previousIdentifier = end ($ links )->getIdentifiers ()[0 ] ?? 'id ' ;
53
+ $ expressions = [];
54
+ $ i = 0 ;
55
+
56
+ foreach (array_reverse ($ links ) as $ parameterName => $ link ) {
57
+ if ($ link ->getExpandedValue () || !$ link ->getFromClass ()) {
58
+ ++$ i ;
59
+ continue ;
43
60
}
44
61
45
- $ operation = $ this ->resourceMetadataCollectionFactory ->create ($ linkClass )->getOperation ($ operationName );
46
- $ links = $ operation instanceof GraphQlOperation ? $ operation ->getLinks () : $ operation ->getUriVariables ();
47
- foreach ($ links as $ link ) {
48
- if ($ resourceClass === $ link ->getFromClass ()) {
49
- $ link = $ link ->withFromProperty ($ link ->getToProperty ())->withFromClass ($ linkClass );
50
- foreach ($ identifiers as $ identifier => $ value ) {
51
- $ this ->applyLink ($ queryBuilder , $ queryNameGenerator , $ doctrineClassMetadata , $ alias , $ link , $ identifier , $ value );
52
- }
62
+ $ identifierProperty = $ link ->getIdentifiers ()[0 ] ?? 'id ' ;
63
+ $ currentAlias = $ i === 0 ? $ alias : $ queryNameGenerator ->generateJoinAlias ($ alias );
64
+ $ placeholder = $ queryNameGenerator ->generateParameterName ($ parameterName );
53
65
54
- return ;
55
- }
66
+ if (!$ link ->getFromProperty () && !$ link ->getToProperty ()) {
67
+ $ doctrineClassMetadata = $ manager ->getClassMetadata ($ link ->getFromClass ());
68
+
69
+ $ queryBuilder ->andWhere ("{$ currentAlias }. $ identifierProperty = : $ placeholder " );
70
+ $ queryBuilder ->setParameter ($ placeholder , $ identifiers [$ parameterName ], $ doctrineClassMetadata ->getTypeOfField ($ identifierProperty ));
71
+ $ previousAlias = $ currentAlias ;
72
+ $ previousIdentifier = $ identifierProperty ;
73
+ ++$ i ;
74
+ continue ;
56
75
}
57
76
58
- throw new RuntimeException (sprintf ('The class "%s" cannot be retrieved from "%s". ' , $ resourceClass , $ linkClass ));
59
- }
77
+ if ($ link ->getFromProperty ()) {
78
+ $ doctrineClassMetadata = $ manager ->getClassMetadata ($ link ->getFromClass ());
79
+ $ joinAlias = $ queryNameGenerator ->generateJoinAlias ('m ' );
80
+ $ assocationMapping = $ doctrineClassMetadata ->getAssociationMappings ()[$ link ->getFromProperty ()];
81
+ $ relationType = $ assocationMapping ['type ' ];
60
82
61
- if (!$ links ) {
62
- return ;
63
- }
83
+ if ($ relationType & ClassMetadataInfo::TO_MANY ) {
84
+ $ nextAlias = $ queryNameGenerator ->generateJoinAlias ($ alias );
64
85
65
- foreach ($ identifiers as $ identifier => $ value ) {
66
- $ link = $ links [$ identifier ] ?? $ links ['id ' ];
86
+ $ expressions ["$ previousAlias. $ previousIdentifier " ] = "SELECT $ joinAlias. {$ previousIdentifier } FROM {$ link ->getFromClass ()} $ nextAlias INNER JOIN $ nextAlias. {$ link ->getFromProperty ()} $ joinAlias WHERE $ nextAlias. {$ identifierProperty } = : $ placeholder " ;
67
87
68
- $ this ->applyLink ($ queryBuilder , $ queryNameGenerator , $ doctrineClassMetadata , $ alias , $ link , $ identifier , $ value );
88
+ $ queryBuilder ->setParameter ($ placeholder , $ identifiers [$ parameterName ], $ doctrineClassMetadata ->getTypeOfField ($ identifierProperty ));
89
+ $ previousAlias = $ nextAlias ;
90
+ ++$ i ;
91
+ continue ;
92
+ }
93
+
94
+
95
+ // A single-valued association path expression to an inverse side is not supported in DQL queries.
96
+ if ($ relationType & ClassMetadataInfo::TO_ONE && !$ assocationMapping ['isOwningSide ' ]) {
97
+ $ queryBuilder ->innerJoin ("$ previousAlias. " .$ assocationMapping ['mappedBy ' ], $ joinAlias );
98
+ } else {
99
+ $ queryBuilder ->join (
100
+ $ link ->getFromClass (),
101
+ $ joinAlias ,
102
+ 'with ' ,
103
+ "{$ previousAlias }. {$ previousIdentifier } = $ joinAlias. {$ link ->getFromProperty ()}"
104
+ );
105
+ }
106
+
107
+ $ queryBuilder ->andWhere ("$ joinAlias. $ identifierProperty = : $ placeholder " );
108
+ $ queryBuilder ->setParameter ($ placeholder , $ identifiers [$ parameterName ], $ doctrineClassMetadata ->getTypeOfField ($ identifierProperty ));
109
+ $ previousAlias = $ joinAlias ;
110
+ $ previousIdentifier = $ identifierProperty ;
111
+ ++$ i ;
112
+ continue ;
113
+ }
114
+
115
+ $ joinAlias = $ queryNameGenerator ->generateJoinAlias ($ alias );
116
+ $ queryBuilder ->join ("{$ previousAlias }. {$ link ->getToProperty ()}" , $ joinAlias );
117
+ $ queryBuilder ->andWhere ("$ joinAlias. $ identifierProperty = : $ placeholder " );
118
+ $ queryBuilder ->setParameter ($ placeholder , $ identifiers [$ parameterName ], $ doctrineClassMetadata ->getTypeOfField ($ identifierProperty ));
119
+ $ previousAlias = $ joinAlias ;
120
+ $ previousIdentifier = $ identifierProperty ;
121
+ ++$ i ;
69
122
}
70
- }
71
123
72
- private function applyLink (QueryBuilder $ queryBuilder , QueryNameGenerator $ queryNameGenerator , ClassMetadata $ doctrineClassMetadata , string $ alias , Link $ link , string $ identifier , $ value )
73
- {
74
- $ placeholder = ':id_ ' .$ identifier ;
75
- if ($ fromProperty = $ link ->getFromProperty ()) {
76
- $ propertyIdentifier = $ link ->getIdentifiers ()[0 ];
77
- $ joinAlias = $ queryNameGenerator ->generateJoinAlias ($ fromProperty );
78
-
79
- $ queryBuilder ->join (
80
- $ link ->getFromClass (),
81
- $ joinAlias ,
82
- 'with ' ,
83
- "$ alias. $ propertyIdentifier = $ joinAlias. $ fromProperty "
84
- );
85
-
86
- $ expression = $ queryBuilder ->expr ()->eq (
87
- "{$ joinAlias }. {$ propertyIdentifier }" ,
88
- $ placeholder
89
- );
90
- } elseif ($ property = $ link ->getToProperty ()) {
91
- $ propertyIdentifier = $ link ->getIdentifiers ()[0 ];
92
- $ joinAlias = $ queryNameGenerator ->generateJoinAlias ($ property );
93
-
94
- $ queryBuilder ->join (
95
- "$ alias. $ property " ,
96
- $ joinAlias ,
97
- );
98
-
99
- $ expression = $ queryBuilder ->expr ()->eq (
100
- "{$ joinAlias }. {$ propertyIdentifier }" ,
101
- $ placeholder
102
- );
103
- } else {
104
- $ expression = $ queryBuilder ->expr ()->eq (
105
- "{$ alias }. {$ identifier }" , $ placeholder
106
- );
124
+ if ($ expressions ) {
125
+ $ i = 0 ;
126
+ $ clause = '' ;
127
+ foreach ($ expressions as $ alias => $ expression ) {
128
+ if ($ i === 0 ) {
129
+ $ clause .= "$ alias IN ( " . $ expression ;
130
+ $ i ++;
131
+ continue ;
132
+ }
133
+
134
+ $ clause .= " AND $ alias IN ( " . $ expression ;
135
+ $ i ++;
136
+ }
137
+
138
+ $ queryBuilder ->andWhere ($ clause . str_repeat (') ' , $ i ));
107
139
}
108
- $ queryBuilder ->andWhere ($ expression );
109
- $ queryBuilder ->setParameter ($ placeholder , $ value , $ doctrineClassMetadata ->getTypeOfField ($ identifier ));
110
140
}
111
141
}
0 commit comments