49
49
use ApiPlatform \OpenApi \Model \Response ;
50
50
use ApiPlatform \OpenApi \Model \SecurityScheme ;
51
51
use ApiPlatform \OpenApi \Model \Server ;
52
+ use ApiPlatform \OpenApi \Model \Tag ;
52
53
use ApiPlatform \OpenApi \OpenApi ;
53
54
use ApiPlatform \OpenApi \Options ;
54
55
use ApiPlatform \OpenApi \Serializer \NormalizeOperationNameTrait ;
@@ -69,6 +70,7 @@ final class OpenApiFactory implements OpenApiFactoryInterface
69
70
use TypeFactoryTrait;
70
71
71
72
public const BASE_URL = 'base_url ' ;
73
+ public const API_PLATFORM_TAG = 'x-apiplatform-tag ' ;
72
74
public const OVERRIDE_OPENAPI_RESPONSES = 'open_api_override_responses ' ;
73
75
private readonly Options $ openApiOptions ;
74
76
private readonly PaginationOptions $ paginationOptions ;
@@ -101,6 +103,10 @@ public function __construct(
101
103
102
104
/**
103
105
* {@inheritdoc}
106
+ *
107
+ * You can filter openapi operations with the `x-apiplatform-tag` on an OpenApi Operation using the `filter_tags`.
108
+ *
109
+ * @param array{base_url?: string, filter_tags?: string[]}&array<string, mixed> $context
104
110
*/
105
111
public function __invoke (array $ context = []): OpenApi
106
112
{
@@ -112,12 +118,13 @@ public function __invoke(array $context = []): OpenApi
112
118
$ paths = new Paths ();
113
119
$ schemas = new \ArrayObject ();
114
120
$ webhooks = new \ArrayObject ();
121
+ $ tags = [];
115
122
116
123
foreach ($ this ->resourceNameCollectionFactory ->create () as $ resourceClass ) {
117
124
$ resourceMetadataCollection = $ this ->resourceMetadataFactory ->create ($ resourceClass );
118
125
119
126
foreach ($ resourceMetadataCollection as $ resourceMetadata ) {
120
- $ this ->collectPaths ($ resourceMetadata , $ resourceMetadataCollection , $ paths , $ schemas , $ webhooks , $ context );
127
+ $ this ->collectPaths ($ resourceMetadata , $ resourceMetadataCollection , $ paths , $ schemas , $ webhooks , $ tags , $ context );
121
128
}
122
129
}
123
130
@@ -128,6 +135,8 @@ public function __invoke(array $context = []): OpenApi
128
135
$ securityRequirements [] = [$ key => []];
129
136
}
130
137
138
+ $ globalTags = $ this ->openApiOptions ->getTags () ?: array_values ($ tags ) ?: [];
139
+
131
140
return new OpenApi (
132
141
$ info ,
133
142
$ servers ,
@@ -142,19 +151,25 @@ public function __invoke(array $context = []): OpenApi
142
151
new \ArrayObject ($ securitySchemes )
143
152
),
144
153
$ securityRequirements ,
145
- [] ,
154
+ $ globalTags ,
146
155
null ,
147
156
null ,
148
157
$ webhooks
149
158
);
150
159
}
151
160
152
- private function collectPaths (ApiResource $ resource , ResourceMetadataCollection $ resourceMetadataCollection , Paths $ paths , \ArrayObject $ schemas , \ArrayObject $ webhooks , array $ context = []): void
161
+ private function collectPaths (ApiResource $ resource , ResourceMetadataCollection $ resourceMetadataCollection , Paths $ paths , \ArrayObject $ schemas , \ArrayObject $ webhooks , array & $ tags , array $ context = []): void
153
162
{
154
163
if (0 === $ resource ->getOperations ()->count ()) {
155
164
return ;
156
165
}
157
166
167
+ // This filters on our extension x-apiplatform-tag as the openapi operation tag is used for ordering operations
168
+ $ filteredTags = $ context ['filter_tags ' ] ?? [];
169
+ if (!\is_array ($ filteredTags )) {
170
+ $ filteredTags = [$ filteredTags ];
171
+ }
172
+
158
173
foreach ($ resource ->getOperations () as $ operationName => $ operation ) {
159
174
$ resourceShortName = $ operation ->getShortName ();
160
175
// No path to return
@@ -169,6 +184,15 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection
169
184
continue ;
170
185
}
171
186
187
+ $ operationTag = ($ openapiAttribute ?->getExtensionProperties()[self ::API_PLATFORM_TAG ] ?? []);
188
+ if (!\is_array ($ operationTag )) {
189
+ $ operationTag = [$ operationTag ];
190
+ }
191
+
192
+ if ($ filteredTags && $ filteredTags !== array_intersect ($ filteredTags , $ operationTag )) {
193
+ continue ;
194
+ }
195
+
172
196
$ resourceClass = $ operation ->getClass () ?? $ resource ->getClass ();
173
197
$ routeName = $ operation ->getRouteName () ?? $ operation ->getName ();
174
198
@@ -217,6 +241,10 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection
217
241
extensionProperties: $ openapiOperation ->getExtensionProperties (),
218
242
);
219
243
244
+ foreach ($ openapiOperation ->getTags () as $ v ) {
245
+ $ tags [$ v ] = new Tag (name: $ v , description: $ resource ->getDescription ());
246
+ }
247
+
220
248
[$ requestMimeTypes , $ responseMimeTypes ] = $ this ->getMimeTypes ($ operation );
221
249
222
250
if ($ path ) {
0 commit comments