Passed
Push — master ( 5cd32c...1a1aa9 )
by Rafael
05:46
created

configurePluginPaginationGlobalConfig()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 5
c 0
b 0
f 0
ccs 4
cts 4
cp 1
rs 9.4285
cc 1
eloc 3
nc 1
nop 1
crap 1
1
<?php
2
3
/*******************************************************************************
4
 *  This file is part of the GraphQL Bundle package.
5
 *
6
 *  (c) YnloUltratech <[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 Ynlo\GraphQLBundle\DependencyInjection;
13
14
use GraphQL\Validator\Rules\QueryComplexity;
15
use GraphQL\Validator\Rules\QueryDepth;
16
use Symfony\Component\Config\Definition\Builder\NodeBuilder;
17
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
18
use Symfony\Component\Config\Definition\ConfigurationInterface;
19
use Ynlo\GraphQLBundle\Encoder\SecureIDEncoder;
20
21
/**
22
 * Class Configuration
23
 */
24
class Configuration implements ConfigurationInterface
25
{
26
    /**
27
     * {@inheritdoc}
28
     */
29 1
    public function getConfigTreeBuilder()
30
    {
31 1
        $treeBuilder = new TreeBuilder();
32
        /** @var NodeBuilder $rootNode */
33 1
        $rootNode = $treeBuilder->root('graphql')->addDefaultsIfNotSet()->children();
0 ignored issues
show
Bug introduced by
The method addDefaultsIfNotSet() does not exist on Symfony\Component\Config...\Builder\NodeDefinition. It seems like you code against a sub-type of Symfony\Component\Config...\Builder\NodeDefinition such as Symfony\Component\Config...der\ArrayNodeDefinition. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

33
        $rootNode = $treeBuilder->root('graphql')->/** @scrutinizer ignore-call */ addDefaultsIfNotSet()->children();
Loading history...
34 1
        $this->configureEndpoints($rootNode);
35 1
        $this->configureCORS($rootNode);
36 1
        $this->configureGraphiQL($rootNode);
37 1
        $this->configureDefinition($rootNode);
38 1
        $this->configureSecurity($rootNode);
39 1
        $this->configureOthers($rootNode);
40
41 1
        return $treeBuilder;
42
    }
43
44 1
    protected function configureEndpoints(NodeBuilder $root)
45
    {
46 1
        $endpoints = $root->arrayNode('endpoints')
47 1
                          ->useAttributeAsKey('name')
48 1
                          ->validate()
49 1
                          ->ifTrue(
50 1
                              function ($v) {
51 1
                                  return array_key_exists('default', $v);
52 1
                              }
53 1
                          )->thenInvalid('"default" can\'t be used as endpoint name, the system internally use this endpoint name to store the entire schema.')
54 1
                          ->end()
55 1
                          ->arrayPrototype()
0 ignored issues
show
Bug introduced by
The method arrayPrototype() does not exist on Symfony\Component\Config...\Builder\NodeDefinition. It seems like you code against a sub-type of Symfony\Component\Config...\Builder\NodeDefinition such as Symfony\Component\Config...der\ArrayNodeDefinition. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

55
                          ->/** @scrutinizer ignore-call */ arrayPrototype()
Loading history...
56 1
                          ->children();
57
58 1
        $endpoints->arrayNode('roles')
59 1
                  ->beforeNormalization()
60 1
                  ->ifString()
61 1
                  ->then(
62 1
                      function ($v) {
63 1
                          return preg_split('/\s*,\s*/', $v);
64 1
                      }
65
                  )
66 1
                  ->end()
67 1
                  ->prototype('scalar')
68 1
                  ->end();
69
70 1
        $endpoints->scalarNode('host')->example('^api\.backend\.');
71 1
        $endpoints->scalarNode('path')->example('/backend');
72
73 1
        $root->arrayNode('endpoint_alias')
74 1
             ->info('Use alias to refer to multiple endpoints using only one name')
75 1
             ->useAttributeAsKey('name')
76 1
             ->beforeNormalization()
77 1
             ->ifString()
78 1
             ->then(
79 1
                 function ($v) {
80
                     return preg_split('/\s*,\s*/', $v);
81 1
                 }
82
             )
83 1
             ->end()
84 1
             ->variablePrototype();
0 ignored issues
show
Bug introduced by
The method variablePrototype() does not exist on Symfony\Component\Config...\Builder\NodeDefinition. It seems like you code against a sub-type of Symfony\Component\Config...\Builder\NodeDefinition such as Symfony\Component\Config...der\ArrayNodeDefinition. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

84
             ->/** @scrutinizer ignore-call */ variablePrototype();
Loading history...
85
86 1
        $root->scalarNode('endpoint_default')->info('Endpoint to apply to all definitions without explicit endpoint.');
87
88 1
    }
89
90 1
    protected function configureGraphiQL(NodeBuilder $root)
91
    {
92 1
        $graphiql = $root->arrayNode('graphiql')->addDefaultsIfNotSet()->children();
93
94 1
        $graphiql->scalarNode('title')
95 1
                 ->defaultValue('GraphQL API Explorer');
96
97
        $graphiql
98 1
            ->scalarNode('data_warning_message')
99 1
            ->defaultValue('Heads up! GraphQL Explorer makes use of your <strong>real</strong>, <strong>live</strong>, <strong>production</strong> data.');
100 1
        $graphiql->booleanNode('data_warning_dismissible')->defaultTrue();
101 1
        $graphiql->enumNode('data_warning_style')->values(['info', 'warning', 'danger'])->defaultValue('danger');
102
103 1
        $graphiql->scalarNode('template')
104 1
                 ->defaultValue('@YnloGraphQL/explorer.html.twig');
105
106 1
        $authentication = $graphiql->arrayNode('authentication')->addDefaultsIfNotSet()->children();
107
        $authentication
108 1
            ->booleanNode('required')
109 1
            ->info(
110 1
                'The API require credentials to make any requests, 
111
if this value is FALSE and a provider is specified the authentication is optional.'
112
            )
113 1
            ->defaultFalse();
114
115 1
        $authentication->scalarNode('login_message')
116 1
                       ->defaultValue('Start exploring GraphQL API queries using your account’s data now.');
117
118 1
        $authenticationProvider = $authentication->arrayNode('provider')->children();
119
120 1
        $jwt = $authenticationProvider->arrayNode('jwt')->canBeEnabled()->children();
121
122 1
        $jwtLogin = $jwt->arrayNode('login')->children();
123
124 1
        $jwtLogin->scalarNode('url')
125 1
                 ->info('Route name or URI to make the login process to retrieve the token.')
126 1
                 ->isRequired();
127
128 1
        $jwtLogin->scalarNode('username_parameter')
129 1
                 ->defaultValue('username');
130
131 1
        $jwtLogin->scalarNode('username_label')
132 1
                 ->defaultValue('Username');
133
134 1
        $jwtLogin->scalarNode('password_parameter')
135 1
                 ->defaultValue('password');
136
137 1
        $jwtLogin->scalarNode('password_label')
138 1
                 ->defaultValue('Password');
139
140 1
        $jwtLogin->enumNode('parameters_in')
141 1
                 ->values(['form', 'query', 'header'])
142 1
                 ->info('How pass parameters to request the token')
143 1
                 ->defaultValue('form');
144
145 1
        $jwtLogin->scalarNode('response_token_path')
146 1
                 ->defaultValue('token')
147 1
                 ->info('Where the token should be located in the response in case of JSON, set null if the response is the token.');
148
149 1
        $jwtRequests = $jwt->arrayNode('requests')->addDefaultsIfNotSet()->children();
150
151 1
        $jwtRequests->enumNode('token_in')
152 1
                    ->values(['query', 'header'])
153 1
                    ->info('Where should be located the token on every request')
154 1
                    ->defaultValue('header');
155
156 1
        $jwtRequests->scalarNode('token_name')
157 1
                    ->defaultValue('Authorization')
158 1
                    ->info('Name of the token in query or header name');
159
160 1
        $jwtRequests->scalarNode('token_template')
161 1
                    ->defaultValue('Bearer {token}')
162 1
                    ->info('Customize how the token should be send,  use the place holder {token} to replace for current token');
163
164 1
        $authenticationProvider->scalarNode('custom')
165 1
                               ->defaultNull()
166 1
                               ->info('Configure custom service to use as authentication provider');
167 1
    }
168
169 1
    protected function configureCORS(NodeBuilder $root)
170
    {
171 1
        $cors = $root->arrayNode('cors')->canBeEnabled()->children();
172 1
        $cors->booleanNode('allow_credentials')->defaultTrue();
173 1
        $cors->variableNode('allow_headers')->defaultValue(['Origin', 'Content-Type', 'Accept', 'Authorization']);
174 1
        $cors->integerNode('max_age')->defaultValue(3600);
175 1
        $cors->variableNode('allow_methods')->defaultValue(['POST', 'GET', 'OPTIONS']);
176 1
        $cors->variableNode('allow_origins')->defaultValue(['*']);
177 1
    }
178
179 1
    protected function configureDefinition(NodeBuilder $root)
180
    {
181 1
        $definitions = $root->arrayNode('definitions')->addDefaultsIfNotSet()->children();
182
183 1
        $plugins = $definitions->arrayNode('plugins')->addDefaultsIfNotSet();
184 1
        $this->configurePluginPaginationGlobalConfig($plugins->children());
185 1
        $this->configurePluginNamespaceGlobalConfig($plugins->children());
186 1
    }
187
188 1
    protected function configurePluginPaginationGlobalConfig(NodeBuilder $root)
189
    {
190 1
        $pagination = $root->arrayNode('pagination')->addDefaultsIfNotSet()->children();
191 1
        $pagination->integerNode('limit')
192 1
                   ->defaultValue(100)->info('Maximum limit allowed for all paginations');
193 1
    }
194
195 1
    protected function configurePluginNamespaceGlobalConfig(NodeBuilder $root)
196
    {
197 1
        $namespaces = $root->arrayNode('namespaces')
198 1
                           ->info(
199 1
                               'Group GraphQL schema using namespaced schemas. 
200
On large schemas is  helpful to keep schemas grouped by bundle and node'
201
                           )
202 1
                           ->canBeEnabled()
203 1
                           ->addDefaultsIfNotSet()
204 1
                           ->children();
205
206 1
        $bundles = $namespaces->arrayNode('bundles')
207 1
                              ->info('Group each bundle into a separate schema definition')
208 1
                              ->canBeDisabled()
209 1
                              ->addDefaultsIfNotSet()
210 1
                              ->children();
211
212 1
        $bundles->scalarNode('query_suffix')
213 1
                ->info('The following suffix will be used for bundle query groups')
214 1
                ->defaultValue('BundleQuery');
215
216 1
        $bundles->scalarNode('mutation_suffix')
217 1
                ->info('The following suffix will be used for bundle mutation groups')
218 1
                ->defaultValue('BundleMutation');
219
220 1
        $bundles->variableNode('ignore')
221 1
                ->info('The following bundles will be ignore for grouping, all definitions will be placed in the root query or mutation')
222 1
                ->defaultValue(['AppBundle']);
223
224 1
        $bundles->arrayNode('aliases')
225 1
                ->info(
226 1
                    'Define aliases for bundles to set definitions inside other desired bundle name. 
227
Can be used to group multiple bundles or publish a bundle with a different name'
228
                )
229 1
                ->example('SecurityBundle: AppBundle')
230 1
                ->useAttributeAsKey('name')
231 1
                ->prototype('scalar');
232
233
234 1
        $nodes = $namespaces->arrayNode('nodes')
235 1
                            ->info('Group queries and mutations of the same node into a node specific schema definition.')
236 1
                            ->addDefaultsIfNotSet()
237 1
                            ->canBeDisabled()
238 1
                            ->children();
239
240 1
        $nodes->scalarNode('query_suffix')
241 1
              ->info('The following suffix will be used to create the name for queries to the same node')
242 1
              ->defaultValue('Query');
243
244 1
        $nodes->scalarNode('mutation_suffix')
245 1
              ->info('The following suffix will be used to create the name for mutations to the same node')
246 1
              ->defaultValue('Mutation');
247
248 1
        $nodes->variableNode('ignore')
249 1
              ->info('The following nodes will be ignore for grouping, all definitions will be placed in the root query or mutation')
250 1
              ->defaultValue(['Node']);
251
252 1
        $nodes->arrayNode('aliases')
253 1
              ->info(
254 1
                  'Define aliases for nodes to set definitions inside other desired node name. 
255
Can be used to group multiple nodes or publish a node with a different group name'
256
              )
257 1
              ->example('InvoiceItem: Invoice')
258 1
              ->useAttributeAsKey('name')
259 1
              ->prototype('scalar');
260 1
    }
261
262 1
    private function configureSecurity(NodeBuilder $rootNode)
263
    {
264
        $securityNode = $rootNode
265 1
            ->arrayNode('security')
266 1
            ->canBeEnabled()
267 1
            ->children();
268
269
        $validationRulesNode = $securityNode
270 1
            ->arrayNode('validation_rules')
271 1
            ->addDefaultsIfNotSet()
272 1
            ->children();
273
        $validationRulesNode
274 1
            ->integerNode('query_complexity')
275 1
            ->info('Query complexity score before execution. (Recommended >= 200)')
276 1
            ->min(0)
277 1
            ->defaultValue(QueryComplexity::DISABLED);
278
        $validationRulesNode
279 1
            ->integerNode('query_depth')
280 1
            ->info('Max depth of the query. (Recommended >= 11)')
281 1
            ->min(0)
282 1
            ->defaultValue(QueryDepth::DISABLED);
283
        $validationRulesNode
284 1
            ->booleanNode('disable_introspection')
285 1
            ->defaultFalse();
286 1
    }
287
288 1
    private function configureOthers(NodeBuilder $rootNode)
289
    {
290
        $rootNode
291 1
            ->scalarNode('id_encoder')
292 1
            ->defaultValue(SecureIDEncoder::class)
293 1
            ->info('Service used to encode nodes identifiers, must implements IDEncoderInterface');
294 1
    }
295
}
296