Completed
Pull Request — 2.0 (#1078)
by Claudio
03:09
created

Configuration   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 193
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 5

Importance

Changes 0
Metric Value
wmc 11
lcom 0
cbo 5
dl 0
loc 193
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
C addExceptionToStatusSection() 0 44 7
B addFormatSection() 0 31 3
B getConfigTreeBuilder() 0 96 1
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
                ->scalarNode('api_resources_directory')->defaultValue('Entity')->info('The name of the directory within the bundles that contains the api resources.')->end()
49
                ->arrayNode('eager_loading')
50
                    ->canBeDisabled()
51
                    ->addDefaultsIfNotSet()
52
                    ->children()
53
                        ->booleanNode('enabled')->defaultTrue()->info('To enable or disable eager loading')->end()
54
                        ->integerNode('max_joins')->defaultValue(30)->info('Max number of joined relations before EagerLoading throws a RuntimeException')->end()
55
                        ->booleanNode('force_eager')->defaultTrue()->info('Force join on every relation. If disabled, it will only join relations having the EAGER fetch mode.')->end()
56
                    ->end()
57
                ->end()
58
                ->booleanNode('enable_fos_user')->defaultValue(false)->info('Enable the FOSUserBundle integration.')->end()
59
                ->booleanNode('enable_nelmio_api_doc')->defaultValue(false)->info('Enable the Nelmio Api doc integration.')->end()
60
                ->booleanNode('enable_swagger')->defaultValue(true)->info('Enable the Swagger documentation and export.')->end()
61
                ->booleanNode('enable_swagger_ui')->defaultValue(class_exists(TwigBundle::class))->info('Enable Swagger ui.')->end()
62
63
                ->arrayNode('oauth')
64
                    ->canBeEnabled()
65
                    ->addDefaultsIfNotSet()
66
                    ->children()
67
                        ->booleanNode('enabled')->defaultFalse()->info('To enable or disable oauth')->end()
68
                        ->scalarNode('clientId')->defaultValue('')->info('The oauth client id.')->end()
69
                        ->scalarNode('clientSecret')->defaultValue('')->info('The oauth client secret.')->end()
70
                        ->scalarNode('type')->defaultValue('oauth2')->info('The oauth client secret.')->end()
71
                        ->scalarNode('flow')->defaultValue('application')->info('The oauth flow grant type.')->end()
72
                        ->scalarNode('tokenUrl')->defaultValue('/oauth/v2/token')->info('The oauth token url.')->end()
73
                        ->scalarNode('authorizationUrl')->defaultValue('/oauth/v2/auth')->info('The oauth authentication url.')->end()
74
                        ->arrayNode('scopes')
75
                            ->prototype('scalar')->end()
76
                        ->end()
77
                    ->end()
78
                ->end()
79
80
                ->arrayNode('collection')
81
                    ->addDefaultsIfNotSet()
82
                    ->children()
83
                        ->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
84
                        ->scalarNode('order_parameter_name')->defaultValue('order')->cannotBeEmpty()->info('The name of the query parameter to order results.')->end()
85
                        ->arrayNode('pagination')
86
                            ->canBeDisabled()
87
                            ->addDefaultsIfNotSet()
88
                            ->children()
89
                                ->booleanNode('enabled')->defaultTrue()->info('To enable or disable pagination for all resource collections by default.')->end()
90
                                ->booleanNode('client_enabled')->defaultFalse()->info('To allow the client to enable or disable the pagination.')->end()
91
                                ->booleanNode('client_items_per_page')->defaultFalse()->info('To allow the client to set the number of items per page.')->end()
92
                                ->integerNode('items_per_page')->defaultValue(30)->info('The default number of items per page.')->end()
93
                                ->integerNode('maximum_items_per_page')->defaultNull()->info('The maximum number of items per page.')->end()
94
                                ->scalarNode('page_parameter_name')->defaultValue('page')->cannotBeEmpty()->info('The default name of the parameter handling the page number.')->end()
95
                                ->scalarNode('enabled_parameter_name')->defaultValue('pagination')->cannotBeEmpty()->info('The name of the query parameter to enable or disable pagination.')->end()
96
                                ->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()
97
                            ->end()
98
                        ->end()
99
                    ->end()
100
                ->end()
101
102
                ->arrayNode('loader_paths')
103
                    ->addDefaultsIfNotSet()
104
                    ->children()
105
                        ->arrayNode('annotation')
106
                            ->prototype('scalar')->end()
107
                        ->end()
108
                        ->arrayNode('yaml')
109
                            ->prototype('scalar')->end()
110
                        ->end()
111
                        ->arrayNode('xml')
112
                            ->prototype('scalar')->end()
113
                        ->end()
114
                    ->end()
115
                ->end()
116
            ->end();
117
118
        $this->addExceptionToStatusSection($rootNode);
119
120
        $this->addFormatSection($rootNode, 'formats', [
121
            'jsonld' => ['mime_types' => ['application/ld+json']],
122
            'json' => ['mime_types' => ['application/json']], // Swagger support
123
            'html' => ['mime_types' => ['text/html']], // Swagger UI support
124
        ]);
125
        $this->addFormatSection($rootNode, 'error_formats', [
126
            'jsonproblem' => ['mime_types' => ['application/problem+json']],
127
            'jsonld' => ['mime_types' => ['application/ld+json']],
128
        ]);
129
130
        return $treeBuilder;
131
    }
132
133
    /**
134
     * Adds an exception to status section.
135
     *
136
     * @param ArrayNodeDefinition $rootNode
137
     *
138
     * @throws InvalidConfigurationException
139
     */
140
    private function addExceptionToStatusSection(ArrayNodeDefinition $rootNode)
141
    {
142
        $rootNode
143
            ->children()
144
                ->arrayNode('exception_to_status')
145
                    ->defaultValue([
146
                        ExceptionInterface::class => Response::HTTP_BAD_REQUEST,
147
                        InvalidArgumentException::class => Response::HTTP_BAD_REQUEST,
148
                    ])
149
                    ->info('The list of exceptions mapped to their HTTP status code.')
150
                    ->normalizeKeys(false)
151
                    ->useAttributeAsKey('exception_class')
152
                    ->beforeNormalization()
153
                        ->ifArray()
154
                        ->then(function (array $exceptionToStatus) {
155
                            foreach ($exceptionToStatus as &$httpStatusCode) {
156
                                if (is_int($httpStatusCode)) {
157
                                    continue;
158
                                }
159
160
                                if (defined($httpStatusCodeConstant = sprintf('%s::%s', Response::class, $httpStatusCode))) {
161
                                    $httpStatusCode = constant($httpStatusCodeConstant);
162
                                }
163
                            }
164
165
                            return $exceptionToStatus;
166
                        })
167
                    ->end()
168
                    ->prototype('integer')->end()
169
                    ->validate()
170
                        ->ifArray()
171
                        ->then(function (array $exceptionToStatus) {
172
                            foreach ($exceptionToStatus as $httpStatusCode) {
173
                                if ($httpStatusCode < 100 || $httpStatusCode >= 600) {
174
                                    throw new InvalidConfigurationException(sprintf('The HTTP status code "%s" is not valid.', $httpStatusCode));
175
                                }
176
                            }
177
178
                            return $exceptionToStatus;
179
                        })
180
                    ->end()
181
                ->end()
182
            ->end();
183
    }
184
185
    /**
186
     * Adds a format section.
187
     *
188
     * @param ArrayNodeDefinition $rootNode
189
     * @param string              $key
190
     * @param array               $defaultValue
191
     */
192
    private function addFormatSection(ArrayNodeDefinition $rootNode, string $key, array $defaultValue)
193
    {
194
        $rootNode
195
            ->children()
196
                ->arrayNode($key)
197
                    ->defaultValue($defaultValue)
198
                    ->info('The list of enabled formats. The first one will be the default.')
199
                    ->normalizeKeys(false)
200
                    ->useAttributeAsKey('format')
201
                    ->beforeNormalization()
202
                        ->ifArray()
203
                        ->then(function ($v) {
204
                            foreach ($v as $format => $value) {
205
                                if (isset($value['mime_types'])) {
206
                                    continue;
207
                                }
208
209
                                $v[$format] = ['mime_types' => $value];
210
                            }
211
212
                            return $v;
213
                        })
214
                    ->end()
215
                    ->prototype('array')
216
                        ->children()
217
                            ->arrayNode('mime_types')->prototype('scalar')->end()->end()
218
                        ->end()
219
                    ->end()
220
                ->end()
221
            ->end();
222
    }
223
}
224