Completed
Pull Request — 2.0 (#1065)
by Pierre
04:11
created

Configuration   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 192
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 6

Importance

Changes 0
Metric Value
wmc 11
lcom 0
cbo 6
dl 0
loc 192
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
B getConfigTreeBuilder() 0 95 1
C addExceptionToStatusSection() 0 44 7
B addFormatSection() 0 31 3
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
declare(strict_types=1);
13
14
namespace ApiPlatform\Core\Bridge\Symfony\Bundle\DependencyInjection;
15
16
use ApiPlatform\Core\Exception\InvalidArgumentException;
17
use Symfony\Bundle\TwigBundle\TwigBundle;
18
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
19
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
20
use Symfony\Component\Config\Definition\ConfigurationInterface;
21
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
22
use Symfony\Component\HttpFoundation\Response;
23
use Symfony\Component\Serializer\Exception\ExceptionInterface;
24
25
/**
26
 * The configuration of the bundle.
27
 *
28
 * @author Kévin Dunglas <[email protected]>
29
 * @author Baptiste Meyer <[email protected]>
30
 */
31
final class Configuration implements ConfigurationInterface
32
{
33
    /**
34
     * {@inheritdoc}
35
     */
36
    public function getConfigTreeBuilder()
37
    {
38
        $treeBuilder = new TreeBuilder();
39
        $rootNode = $treeBuilder->root('api_platform');
40
41
        $rootNode
42
            ->children()
43
                ->scalarNode('title')->defaultValue('')->info('The title of the API.')->end()
44
                ->scalarNode('description')->defaultValue('')->info('The description of the API.')->end()
45
                ->scalarNode('version')->defaultValue('0.0.0')->info('The version of the API.')->end()
46
                ->scalarNode('default_operation_path_resolver')->defaultValue('api_platform.operation_path_resolver.underscore')->info('Specify the default operation path resolver to use for generating resources operations path.')->end()
47
                ->scalarNode('name_converter')->defaultNull()->info('Specify a name converter to use.')->end()
48
                ->arrayNode('eager_loading')
49
                    ->canBeDisabled()
50
                    ->addDefaultsIfNotSet()
51
                    ->children()
52
                        ->booleanNode('enabled')->defaultTrue()->info('To enable or disable eager loading')->end()
53
                        ->integerNode('max_joins')->defaultValue(30)->info('Max number of joined relations before EagerLoading throws a RuntimeException')->end()
54
                        ->booleanNode('force_eager')->defaultTrue()->info('Force join on every relation. If disabled, it will only join relations having the EAGER fetch mode.')->end()
55
                    ->end()
56
                ->end()
57
                ->booleanNode('enable_fos_user')->defaultValue(false)->info('Enable the FOSUserBundle integration.')->end()
58
                ->booleanNode('enable_nelmio_api_doc')->defaultValue(false)->info('Enable the Nelmio Api doc integration.')->end()
59
                ->booleanNode('enable_swagger')->defaultValue(true)->info('Enable the Swagger documentation and export.')->end()
60
                ->booleanNode('enable_swagger_ui')->defaultValue(class_exists(TwigBundle::class))->info('Enable Swagger ui.')->end()
61
62
                ->arrayNode('oauth')
63
                    ->canBeEnabled()
64
                    ->addDefaultsIfNotSet()
65
                    ->children()
66
                        ->booleanNode('enabled')->defaultFalse()->info('To enable or disable oauth')->end()
67
                        ->scalarNode('clientId')->defaultValue('')->info('The oauth client id.')->end()
68
                        ->scalarNode('clientSecret')->defaultValue('')->info('The oauth client secret.')->end()
69
                        ->scalarNode('type')->defaultValue('oauth2')->info('The oauth client secret.')->end()
70
                        ->scalarNode('flow')->defaultValue('application')->info('The oauth flow grant type.')->end()
71
                        ->scalarNode('tokenUrl')->defaultValue('/oauth/v2/token')->info('The oauth token url.')->end()
72
                        ->scalarNode('authorizationUrl')->defaultValue('/oauth/v2/auth')->info('The oauth authentication url.')->end()
73
                        ->arrayNode('scopes')
74
                            ->prototype('scalar')->end()
75
                        ->end()
76
                    ->end()
77
                ->end()
78
79
                ->arrayNode('collection')
80
                    ->addDefaultsIfNotSet()
81
                    ->children()
82
                        ->scalarNode('order')->defaultValue('ASC')->info('The default order of results.')->end() // Default ORDER is required for postgresql and mysql >= 5.7 when using LIMIT/OFFSET request
83
                        ->scalarNode('order_parameter_name')->defaultValue('order')->cannotBeEmpty()->info('The name of the query parameter to order results.')->end()
84
                        ->arrayNode('pagination')
85
                            ->canBeDisabled()
86
                            ->addDefaultsIfNotSet()
87
                            ->children()
88
                                ->booleanNode('enabled')->defaultTrue()->info('To enable or disable pagination for all resource collections by default.')->end()
89
                                ->booleanNode('client_enabled')->defaultFalse()->info('To allow the client to enable or disable the pagination.')->end()
90
                                ->booleanNode('client_items_per_page')->defaultFalse()->info('To allow the client to set the number of items per page.')->end()
91
                                ->integerNode('items_per_page')->defaultValue(30)->info('The default number of items per page.')->end()
92
                                ->integerNode('maximum_items_per_page')->defaultNull()->info('The maximum number of items per page.')->end()
93
                                ->scalarNode('page_parameter_name')->defaultValue('page')->cannotBeEmpty()->info('The default name of the parameter handling the page number.')->end()
94
                                ->scalarNode('enabled_parameter_name')->defaultValue('pagination')->cannotBeEmpty()->info('The name of the query parameter to enable or disable pagination.')->end()
95
                                ->scalarNode('items_per_page_parameter_name')->defaultValue('itemsPerPage')->cannotBeEmpty()->info('The name of the query parameter to set the number of items per page.')->end()
96
                            ->end()
97
                        ->end()
98
                    ->end()
99
                ->end()
100
101
                ->arrayNode('loader_paths')
102
                    ->addDefaultsIfNotSet()
103
                    ->children()
104
                        ->arrayNode('annotation')
105
                            ->prototype('scalar')->end()
106
                        ->end()
107
                        ->arrayNode('yaml')
108
                            ->prototype('scalar')->end()
109
                        ->end()
110
                        ->arrayNode('xml')
111
                            ->prototype('scalar')->end()
112
                        ->end()
113
                    ->end()
114
                ->end()
115
            ->end();
116
117
        $this->addExceptionToStatusSection($rootNode);
118
119
        $this->addFormatSection($rootNode, 'formats', [
120
            'jsonld' => ['mime_types' => ['application/ld+json']],
121
            'json' => ['mime_types' => ['application/json']], // Swagger support
122
            'html' => ['mime_types' => ['text/html']], // Swagger UI support
123
        ]);
124
        $this->addFormatSection($rootNode, 'error_formats', [
125
            'jsonproblem' => ['mime_types' => ['application/problem+json']],
126
            'jsonld' => ['mime_types' => ['application/ld+json']],
127
        ]);
128
129
        return $treeBuilder;
130
    }
131
132
    /**
133
     * Adds an exception to status section.
134
     *
135
     * @param ArrayNodeDefinition $rootNode
136
     *
137
     * @throws InvalidConfigurationException
138
     */
139
    private function addExceptionToStatusSection(ArrayNodeDefinition $rootNode)
140
    {
141
        $rootNode
142
            ->children()
143
                ->arrayNode('exception_to_status')
144
                    ->defaultValue([
145
                        ExceptionInterface::class => Response::HTTP_BAD_REQUEST,
146
                        InvalidArgumentException::class => Response::HTTP_BAD_REQUEST,
147
                    ])
148
                    ->info('The list of exceptions mapped to their HTTP status code.')
149
                    ->normalizeKeys(false)
150
                    ->useAttributeAsKey('exception_class')
151
                    ->beforeNormalization()
152
                        ->ifArray()
153
                        ->then(function (array $exceptionToStatus) {
154
                            foreach ($exceptionToStatus as &$httpStatusCode) {
155
                                if (is_int($httpStatusCode)) {
156
                                    continue;
157
                                }
158
159
                                if (defined($httpStatusCodeConstant = sprintf('%s::%s', Response::class, $httpStatusCode))) {
160
                                    $httpStatusCode = constant($httpStatusCodeConstant);
161
                                }
162
                            }
163
164
                            return $exceptionToStatus;
165
                        })
166
                    ->end()
167
                    ->prototype('integer')->end()
168
                    ->validate()
169
                        ->ifArray()
170
                        ->then(function (array $exceptionToStatus) {
171
                            foreach ($exceptionToStatus as $httpStatusCode) {
172
                                if ($httpStatusCode < 100 || $httpStatusCode >= 600) {
173
                                    throw new InvalidConfigurationException(sprintf('The HTTP status code "%s" is not valid.', $httpStatusCode));
174
                                }
175
                            }
176
177
                            return $exceptionToStatus;
178
                        })
179
                    ->end()
180
                ->end()
181
            ->end();
182
    }
183
184
    /**
185
     * Adds a format section.
186
     *
187
     * @param ArrayNodeDefinition $rootNode
188
     * @param string              $key
189
     * @param array               $defaultValue
190
     */
191
    private function addFormatSection(ArrayNodeDefinition $rootNode, string $key, array $defaultValue)
192
    {
193
        $rootNode
194
            ->children()
195
                ->arrayNode($key)
196
                    ->defaultValue($defaultValue)
197
                    ->info('The list of enabled formats. The first one will be the default.')
198
                    ->normalizeKeys(false)
199
                    ->useAttributeAsKey('format')
200
                    ->beforeNormalization()
201
                        ->ifArray()
202
                        ->then(function ($v) {
203
                            foreach ($v as $format => $value) {
204
                                if (isset($value['mime_types'])) {
205
                                    continue;
206
                                }
207
208
                                $v[$format] = ['mime_types' => $value];
209
                            }
210
211
                            return $v;
212
                        })
213
                    ->end()
214
                    ->prototype('array')
215
                        ->children()
216
                            ->arrayNode('mime_types')->prototype('scalar')->end()->end()
217
                        ->end()
218
                    ->end()
219
                ->end()
220
            ->end();
221
    }
222
}
223