1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the API Platform project. |
5
|
|
|
* |
6
|
|
|
* (c) Kévin Dunglas <[email protected]> |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace ApiPlatform\Core\Bridge\Symfony\Bundle\DependencyInjection; |
13
|
|
|
|
14
|
|
|
use Doctrine\ORM\Version; |
15
|
|
|
use phpDocumentor\Reflection\DocBlockFactoryInterface; |
16
|
|
|
use Symfony\Component\Cache\Adapter\ArrayAdapter; |
17
|
|
|
use Symfony\Component\Config\FileLocator; |
18
|
|
|
use Symfony\Component\Config\Resource\DirectoryResource; |
19
|
|
|
use Symfony\Component\DependencyInjection\ContainerBuilder; |
20
|
|
|
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; |
21
|
|
|
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; |
22
|
|
|
use Symfony\Component\Finder\Finder; |
23
|
|
|
use Symfony\Component\HttpKernel\DependencyInjection\Extension; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* The extension of this bundle. |
27
|
|
|
* |
28
|
|
|
* @author Kévin Dunglas <[email protected]> |
29
|
|
|
*/ |
30
|
|
|
final class ApiPlatformExtension extends Extension implements PrependExtensionInterface |
31
|
|
|
{ |
32
|
|
|
/** |
33
|
|
|
* {@inheritdoc} |
34
|
|
|
*/ |
35
|
|
|
public function prepend(ContainerBuilder $container) |
36
|
|
|
{ |
37
|
|
|
if (empty($frameworkConfiguration = $container->getExtensionConfig('framework'))) { |
38
|
|
|
return; |
39
|
|
|
} |
40
|
|
|
|
41
|
|
|
foreach ($frameworkConfiguration as $frameworkParameters) { |
42
|
|
|
if (isset($frameworkParameters['serializer'])) { |
43
|
|
|
$serializerConfig = $serializerConfig ?? $frameworkParameters['serializer']; |
44
|
|
|
} |
45
|
|
|
|
46
|
|
|
if (isset($frameworkParameters['property_info'])) { |
47
|
|
|
$propertyInfoConfig = $propertyInfoConfig ?? $frameworkParameters['property_info']; |
48
|
|
|
} |
49
|
|
|
} |
50
|
|
|
|
51
|
|
View Code Duplication |
if (!isset($serializerConfig['enabled'])) { |
|
|
|
|
52
|
|
|
$container->prependExtensionConfig('framework', ['serializer' => ['enabled' => true]]); |
53
|
|
|
} |
54
|
|
|
|
55
|
|
View Code Duplication |
if (!isset($propertyInfoConfig['enabled'])) { |
|
|
|
|
56
|
|
|
$container->prependExtensionConfig('framework', ['property_info' => ['enabled' => true]]); |
57
|
|
|
} |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* {@inheritdoc} |
62
|
|
|
*/ |
63
|
|
|
public function load(array $configs, ContainerBuilder $container) |
64
|
|
|
{ |
65
|
|
|
$configuration = new Configuration(); |
66
|
|
|
$config = $this->processConfiguration($configuration, $configs); |
67
|
|
|
$formats = $this->getFormats($config['formats']); |
68
|
|
|
$errorFormats = $this->getFormats($config['error_formats']); |
69
|
|
|
$this->handleConfig($container, $config, $formats, $errorFormats); |
70
|
|
|
|
71
|
|
|
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); |
72
|
|
|
$loader->load('api.xml'); |
73
|
|
|
$loader->load('data_provider.xml'); |
74
|
|
|
|
75
|
|
|
$bundles = $container->getParameter('kernel.bundles'); |
76
|
|
|
|
77
|
|
|
$this->registerMetadataConfiguration($container, $loader); |
78
|
|
|
$this->registerSwaggerConfiguration($container, $config, $loader); |
79
|
|
|
$this->registerJsonLdConfiguration($formats, $loader); |
80
|
|
|
$this->registerJsonHalConfiguration($formats, $loader); |
81
|
|
|
$this->registerJsonProblemConfiguration($errorFormats, $loader); |
82
|
|
|
$this->registerLoaders($container, $bundles, $config['loader_paths']); |
83
|
|
|
$this->registerBundlesConfiguration($bundles, $config, $loader); |
84
|
|
|
$this->registerCacheConfiguration($container); |
85
|
|
|
$this->registerDoctrineExtensionConfiguration($container, $config); |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* Handles configuration. |
90
|
|
|
* |
91
|
|
|
* @param ContainerBuilder $container |
92
|
|
|
* @param array $config |
93
|
|
|
* @param array $formats |
94
|
|
|
* @param array $errorFormats |
95
|
|
|
*/ |
96
|
|
|
private function handleConfig(ContainerBuilder $container, array $config, array $formats, array $errorFormats) |
97
|
|
|
{ |
98
|
|
|
$container->setParameter('api_platform.title', $config['title']); |
99
|
|
|
$container->setParameter('api_platform.description', $config['description']); |
100
|
|
|
$container->setParameter('api_platform.version', $config['version']); |
101
|
|
|
$container->setParameter('api_platform.exception_to_status', $config['exception_to_status']); |
102
|
|
|
$container->setParameter('api_platform.formats', $formats); |
103
|
|
|
$container->setParameter('api_platform.error_formats', $errorFormats); |
104
|
|
|
$container->setParameter('api_platform.eager_loading.enabled', $config['eager_loading']['enabled']); |
105
|
|
|
$container->setParameter('api_platform.eager_loading.max_joins', $config['eager_loading']['max_joins']); |
106
|
|
|
$container->setParameter('api_platform.eager_loading.force_eager', $config['eager_loading']['force_eager']); |
107
|
|
|
$container->setParameter('api_platform.collection.order', $config['collection']['order']); |
108
|
|
|
$container->setParameter('api_platform.collection.order_parameter_name', $config['collection']['order_parameter_name']); |
109
|
|
|
$container->setParameter('api_platform.collection.pagination.enabled', $config['collection']['pagination']['enabled']); |
110
|
|
|
$container->setParameter('api_platform.collection.pagination.client_enabled', $config['collection']['pagination']['client_enabled']); |
111
|
|
|
$container->setParameter('api_platform.collection.pagination.client_items_per_page', $config['collection']['pagination']['client_items_per_page']); |
112
|
|
|
$container->setParameter('api_platform.collection.pagination.items_per_page', $config['collection']['pagination']['items_per_page']); |
113
|
|
|
$container->setParameter('api_platform.collection.pagination.maximum_items_per_page', $config['collection']['pagination']['maximum_items_per_page']); |
114
|
|
|
$container->setParameter('api_platform.collection.pagination.page_parameter_name', $config['collection']['pagination']['page_parameter_name']); |
115
|
|
|
$container->setParameter('api_platform.collection.pagination.enabled_parameter_name', $config['collection']['pagination']['enabled_parameter_name']); |
116
|
|
|
$container->setParameter('api_platform.collection.pagination.items_per_page_parameter_name', $config['collection']['pagination']['items_per_page_parameter_name']); |
117
|
|
|
|
118
|
|
|
$container->setAlias('api_platform.operation_path_resolver.default', $config['default_operation_path_resolver']); |
119
|
|
|
|
120
|
|
|
if ($config['name_converter']) { |
121
|
|
|
$container->setAlias('api_platform.name_converter', $config['name_converter']); |
122
|
|
|
} |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* Registers metadata configuration. |
127
|
|
|
* |
128
|
|
|
* @param ContainerBuilder $container |
129
|
|
|
* @param XmlFileLoader $loader |
130
|
|
|
*/ |
131
|
|
|
private function registerMetadataConfiguration(ContainerBuilder $container, XmlFileLoader $loader) |
132
|
|
|
{ |
133
|
|
|
$loader->load('metadata.xml'); |
134
|
|
|
|
135
|
|
|
if (!interface_exists(DocBlockFactoryInterface::class)) { |
136
|
|
|
$container->removeDefinition('api_platform.metadata.resource.metadata_factory.php_doc'); |
137
|
|
|
} |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
/** |
141
|
|
|
* Registers the Swagger and Swagger UI configuration. |
142
|
|
|
* |
143
|
|
|
* @param ContainerBuilder $container |
144
|
|
|
* @param array $config |
145
|
|
|
* @param XmlFileLoader $loader |
146
|
|
|
*/ |
147
|
|
|
private function registerSwaggerConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader) |
148
|
|
|
{ |
149
|
|
|
if (!$config['enable_swagger']) { |
150
|
|
|
return; |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
$loader->load('swagger.xml'); |
154
|
|
|
|
155
|
|
|
if ($config['enable_swagger_ui']) { |
156
|
|
|
$loader->load('swagger-ui.xml'); |
157
|
|
|
$container->setParameter('api_platform.enable_swagger_ui', $config['enable_swagger_ui']); |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
$container->setParameter('api_platform.enable_swagger', $config['enable_swagger']); |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* Registers the JSON-LD and Hydra configuration. |
165
|
|
|
* |
166
|
|
|
* @param array $formats |
167
|
|
|
* @param XmlFileLoader $loader |
168
|
|
|
*/ |
169
|
|
|
private function registerJsonLdConfiguration(array $formats, XmlFileLoader $loader) |
170
|
|
|
{ |
171
|
|
|
if (!isset($formats['jsonld'])) { |
172
|
|
|
return; |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
$loader->load('jsonld.xml'); |
176
|
|
|
$loader->load('hydra.xml'); |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
/** |
180
|
|
|
* Registers the HAL configuration. |
181
|
|
|
* |
182
|
|
|
* @param array $formats |
183
|
|
|
* @param XmlFileLoader $loader |
184
|
|
|
*/ |
185
|
|
|
private function registerJsonHalConfiguration(array $formats, XmlFileLoader $loader) |
186
|
|
|
{ |
187
|
|
|
if (!isset($formats['jsonhal'])) { |
188
|
|
|
return; |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
$loader->load('hal.xml'); |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
/** |
195
|
|
|
* Registers the JSON Problem configuration. |
196
|
|
|
* |
197
|
|
|
* @param array $errorFormats |
198
|
|
|
* @param XmlFileLoader $loader |
199
|
|
|
*/ |
200
|
|
|
private function registerJsonProblemConfiguration(array $errorFormats, XmlFileLoader $loader) |
201
|
|
|
{ |
202
|
|
|
if (!isset($errorFormats['jsonproblem'])) { |
203
|
|
|
return; |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
$loader->load('problem.xml'); |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
/** |
210
|
|
|
* Registers configuration for integration with third-party bundles. |
211
|
|
|
* |
212
|
|
|
* @param string[] $bundles |
213
|
|
|
* @param array $config |
214
|
|
|
* @param XmlFileLoader $loader |
215
|
|
|
*/ |
216
|
|
|
private function registerBundlesConfiguration(array $bundles, array $config, XmlFileLoader $loader) |
217
|
|
|
{ |
218
|
|
|
// Doctrine ORM support |
219
|
|
|
if (isset($bundles['DoctrineBundle']) && class_exists(Version::class)) { |
220
|
|
|
$loader->load('doctrine_orm.xml'); |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
// FOSUser support |
224
|
|
|
if (isset($bundles['FOSUserBundle']) && $config['enable_fos_user']) { |
225
|
|
|
$loader->load('fos_user.xml'); |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
// NelmioApiDoc support |
229
|
|
|
if (isset($bundles['NelmioApiDocBundle']) && $config['enable_nelmio_api_doc']) { |
230
|
|
|
$loader->load('nelmio_api_doc.xml'); |
231
|
|
|
} |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
/** |
235
|
|
|
* Registers the cache configuration. |
236
|
|
|
* |
237
|
|
|
* @param ContainerBuilder $container |
238
|
|
|
*/ |
239
|
|
|
private function registerCacheConfiguration(ContainerBuilder $container) |
240
|
|
|
{ |
241
|
|
|
// Don't use system cache pool in dev |
242
|
|
|
if (!$container->getParameter('kernel.debug')) { |
243
|
|
|
return; |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
$container->register('api_platform.cache.metadata.property', ArrayAdapter::class); |
247
|
|
|
$container->register('api_platform.cache.metadata.resource', ArrayAdapter::class); |
248
|
|
|
$container->register('api_platform.cache.route_name_resolver', ArrayAdapter::class); |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
/** |
252
|
|
|
* Registers configuration file loaders. |
253
|
|
|
* |
254
|
|
|
* @param ContainerBuilder $container |
255
|
|
|
* @param string[] $bundles |
256
|
|
|
*/ |
257
|
|
|
private function registerLoaders(ContainerBuilder $container, array $bundles, array $loaderPaths) |
258
|
|
|
{ |
259
|
|
|
$annotationPaths = $loaderPaths['annotation']; |
260
|
|
|
$yamlResources = $loaderPaths['yaml']; |
261
|
|
|
$xmlResources = $loaderPaths['xml']; |
262
|
|
|
|
263
|
|
|
foreach ($bundles as $bundle) { |
264
|
|
|
$bundleDirectory = dirname((new \ReflectionClass($bundle))->getFileName()); |
265
|
|
|
$this->addFileResources($bundleDirectory, $xmlResources, $yamlResources); |
266
|
|
|
|
267
|
|
|
if (file_exists($entityDirectory = $bundleDirectory.'/Entity')) { |
268
|
|
|
$annotationPaths[] = $entityDirectory; |
269
|
|
|
$container->addResource(new DirectoryResource($entityDirectory, '/\.php$/')); |
270
|
|
|
} |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
$container->getDefinition('api_platform.metadata.resource.name_collection_factory.annotation')->addArgument($annotationPaths); |
274
|
|
|
$container->getDefinition('api_platform.metadata.extractor.yaml')->addArgument($yamlResources); |
275
|
|
|
$container->getDefinition('api_platform.metadata.extractor.xml')->addArgument($xmlResources); |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
/** |
279
|
|
|
* Manipulate doctrine extension services according to the configuration. |
280
|
|
|
* |
281
|
|
|
* @param ContainerBuilder $container |
282
|
|
|
* @param array $config |
283
|
|
|
*/ |
284
|
|
|
private function registerDoctrineExtensionConfiguration(ContainerBuilder $container, array $config) |
285
|
|
|
{ |
286
|
|
|
if (false === $config['eager_loading']['enabled']) { |
287
|
|
|
$container->removeDefinition('api_platform.doctrine.orm.query_extension.eager_loading'); |
288
|
|
|
} |
289
|
|
|
} |
290
|
|
|
|
291
|
|
|
/** |
292
|
|
|
* Populates file resources lists. |
293
|
|
|
* |
294
|
|
|
* @param string $bundleDirectory |
295
|
|
|
* @param string[] $xmlResources |
296
|
|
|
* @param string[] $yamlResources |
297
|
|
|
*/ |
298
|
|
|
private function addFileResources(string $bundleDirectory, array &$xmlResources, array &$yamlResources) |
299
|
|
|
{ |
300
|
|
|
try { |
301
|
|
|
foreach (Finder::create()->files()->in($bundleDirectory.'/Resources/config/')->path('api_resources')->name('*.{yml,yaml,xml}') as $file) { |
302
|
|
|
if ('xml' === $file->getExtension()) { |
303
|
|
|
$xmlResources[] = $file->getRealPath(); |
304
|
|
|
} else { |
305
|
|
|
$yamlResources[] = $file->getRealPath(); |
306
|
|
|
} |
307
|
|
|
} |
308
|
|
|
} catch (\InvalidArgumentException $e) { |
309
|
|
|
// Ignore invalid paths |
310
|
|
|
} |
311
|
|
|
} |
312
|
|
|
|
313
|
|
|
/** |
314
|
|
|
* Normalizes the format from config to the one accepted by Symfony HttpFoundation. |
315
|
|
|
* |
316
|
|
|
* @param array $configFormats |
317
|
|
|
* |
318
|
|
|
* @return array |
319
|
|
|
*/ |
320
|
|
|
private function getFormats(array $configFormats): array |
321
|
|
|
{ |
322
|
|
|
$formats = []; |
323
|
|
|
foreach ($configFormats as $format => $value) { |
324
|
|
|
foreach ($value['mime_types'] as $mimeType) { |
325
|
|
|
$formats[$format][] = $mimeType; |
326
|
|
|
} |
327
|
|
|
} |
328
|
|
|
|
329
|
|
|
return $formats; |
330
|
|
|
} |
331
|
|
|
} |
332
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.