Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Completed
Pull Request — master (#264)
by Jérémiah
22:49
created

Configuration::definitionsSection()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 30
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 29
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 30
ccs 29
cts 29
cp 1
rs 8.8571
c 0
b 0
f 0
cc 1
eloc 25
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Overblog\GraphQLBundle\DependencyInjection;
4
5
use GraphQL\Validator\Rules\QueryComplexity;
6
use GraphQL\Validator\Rules\QueryDepth;
7
use Overblog\GraphQLBundle\Error\ErrorHandler;
8
use Overblog\GraphQLBundle\EventListener\ErrorLoggerListener;
9
use Overblog\GraphQLBundle\Resolver\Resolver;
10
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
11
use Symfony\Component\Config\Definition\Builder\EnumNodeDefinition;
12
use Symfony\Component\Config\Definition\Builder\ScalarNodeDefinition;
13
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
14
use Symfony\Component\Config\Definition\ConfigurationInterface;
15
16
class Configuration implements ConfigurationInterface
17
{
18
    const NAME = 'overblog_graphql';
19
20
    /** bool */
21
    private $debug;
22
23
    /** null|string */
24
    private $cacheDir;
25
26 25
    /**
27
     * Constructor.
28 25
     *
29 25
     * @param bool        $debug    Whether to use the debug mode
30 25
     * @param null|string $cacheDir
31
     */
32 25
    public function __construct($debug, $cacheDir = null)
33
    {
34 25
        $this->debug = (bool) $debug;
35 25
        $this->cacheDir = $cacheDir;
36
    }
37
38 25
    public function getConfigTreeBuilder()
39 25
    {
40 25
        $treeBuilder = new TreeBuilder();
41 25
        $rootNode = $treeBuilder->root(self::NAME);
42 25
43 25
        $rootNode
44 25
            ->children()
45 25
                ->append($this->batchingMethodSection())
46 25
                ->append($this->definitionsSection())
47 25
                ->append($this->errorsHandlerSection())
48 25
                ->append($this->servicesSection())
49 25
                ->append($this->securitySection())
50 25
            ->end();
51 25
52 25
        return $treeBuilder;
53 25
    }
54 25
55 25
    private function batchingMethodSection()
56 25
    {
57 21
        $builder = new TreeBuilder();
58 25
        /** @var EnumNodeDefinition $node */
59 25
        $node = $builder->root('batching_method', 'enum');
60 21
61 25
        $node
0 ignored issues
show
Unused Code introduced by
The call to the method Symfony\Component\Config...umNodeDefinition::end() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
62 25
            ->values(['relay', 'apollo'])
63 25
            ->defaultValue('relay')
64 25
        ->end();
65 25
66 25
        return $node;
67 25
    }
68 25
69 25
    private function errorsHandlerSection()
70 25
    {
71 25
        $builder = new TreeBuilder();
72 25
        /** @var ArrayNodeDefinition $node */
73 25
        $node = $builder->root('errors_handler');
74 25
        $node
75 25
            ->treatFalseLike(['enabled' => false])
76 25
            ->treatTrueLike(['enabled' => true])
77 25
            ->treatNullLike(['enabled' => true])
78 25
            ->addDefaultsIfNotSet()
79 25
            ->children()
80 25
                ->booleanNode('enabled')->defaultTrue()->end()
81 25
                ->scalarNode('internal_error_message')->defaultValue(ErrorHandler::DEFAULT_ERROR_MESSAGE)->end()
82 25
                ->booleanNode('rethrow_internal_exceptions')->defaultFalse()->end()
83 25
                ->booleanNode('debug')->defaultValue($this->debug)->end()
84 25
                ->booleanNode('log')->defaultTrue()->end()
85 25
                ->scalarNode('logger_service')->defaultValue(ErrorLoggerListener::DEFAULT_LOGGER_SERVICE)->end()
86 25
                ->booleanNode('map_exceptions_to_parent')->defaultFalse()->end()
87 25
                ->arrayNode('exceptions')
88 25
                    ->addDefaultsIfNotSet()
89 25
                    ->children()
90 25
                        ->arrayNode('warnings')
91 25
                            ->treatNullLike([])
92 25
                            ->prototype('scalar')->end()
93 25
                        ->end()
94 25
                        ->arrayNode('errors')
95 25
                            ->treatNullLike([])
96 25
                            ->prototype('scalar')->end()
97 25
                        ->end()
98 25
                        ->arrayNode('types')
99 25
                            ->addDefaultsIfNotSet()
100 25
                            ->children()
101 25
                                ->scalarNode('warnings')
102 25
                                    ->defaultValue(ErrorHandler::DEFAULT_USER_WARNING_CLASS)
103 20
                                ->end()
104 25
                                ->scalarNode('errors')
105 25
                                    ->defaultValue(ErrorHandler::DEFAULT_USER_ERROR_CLASS)
106 5
                                ->end()
107
                            ->end()
108 5
                        ->end()
109 25
                    ->end()
110 25
                ->end()
111 25
            ->end();
112 25
113 25
        return $node;
114 25
    }
115 25
116 25
    private function definitionsSection()
117 25
    {
118 25
        $builder = new TreeBuilder();
119 25
        /** @var ArrayNodeDefinition $node */
120 25
        $node = $builder->root('definitions');
121 25
        $node
122 25
            ->addDefaultsIfNotSet()
123 25
            ->children()
124 25
                ->variableNode('default_resolver')->defaultValue([Resolver::class, 'defaultResolveFn'])->end()
125 25
                ->scalarNode('class_namespace')->defaultValue('Overblog\\GraphQLBundle\\__DEFINITIONS__')->end()
126 25
                ->scalarNode('cache_dir')->defaultValue($this->cacheDir.'/overblog/graphql-bundle/__definitions__')->end()
127 25
                ->booleanNode('use_classloader_listener')->defaultTrue()->end()
128 25
                ->booleanNode('auto_compile')->defaultTrue()->end()
129 25
                ->booleanNode('show_debug_info')->info('Show some performance stats in extensions')->defaultFalse()->end()
130 25
                ->booleanNode('config_validation')->defaultValue($this->debug)->end()
131 25
                ->append($this->definitionsSchemaSection())
132 25
                ->append($this->definitionsAutoMappingSection())
133 25
                ->append($this->definitionsMappingsSection())
134 25
                ->arrayNode('builders')
135 25
                    ->children()
136 25
                        ->append($this->builderSection('field'))
137 25
                        ->append($this->builderSection('args'))
138 25
                    ->end()
139 25
                ->end()
140 25
141 25
            ->end()
142 25
        ->end();
143 25
144 25
        return $node;
145
    }
146 25
147 25
    private function servicesSection()
148 25
    {
149 25
        $builder = new TreeBuilder();
150 25
        /** @var ArrayNodeDefinition $node */
151 25
        $node = $builder->root('services');
152
        $node
153 25
            ->addDefaultsIfNotSet()
154 25
            ->children()
155 25
                ->scalarNode('executor')
156 25
                    ->defaultValue(self::NAME.'.executor.default')
157 25
                ->end()
158 25
                ->scalarNode('promise_adapter')
159 25
                    ->defaultValue(self::NAME.'.promise_adapter.default')
160 25
                ->end()
161 25
                ->scalarNode('expression_language')
162 25
                    ->defaultValue(self::NAME.'.expression_language.default')
163 25
                ->end()
164 25
                ->scalarNode('cache_expression_language_parser')
165 25
                    ->defaultValue(self::NAME.'.cache_expression_language_parser.default')
166 25
                ->end()
167 25
            ->end()
168 25
        ->end();
169 25
170 25
        return $node;
171 25
    }
172 25
173 25
    private function securitySection()
174 25
    {
175 25
        $builder = new TreeBuilder();
176 25
        /** @var ArrayNodeDefinition $node */
177 25
        $node = $builder->root('security');
178 25
        $node
179 25
            ->addDefaultsIfNotSet()
180 25
            ->children()
181
                ->append($this->securityQuerySection('query_max_depth', QueryDepth::DISABLED))
182 25
                ->append($this->securityQuerySection('query_max_complexity', QueryComplexity::DISABLED))
183
                ->booleanNode('handle_cors')->defaultFalse()->end()
184
            ->end()
185
        ->end();
186
187
        return $node;
188 25
    }
189
190 25
    private function definitionsSchemaSection()
191 25
    {
192 25
        $builder = new TreeBuilder();
193 25
        /** @var ArrayNodeDefinition $node */
194 1
        $node = $builder->root('schema');
195 25
        $node
0 ignored issues
show
Bug introduced by
The method useAttributeAsKey() does not exist on Symfony\Component\Config...\Builder\NodeDefinition. Did you maybe mean attribute()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
196 25
            ->beforeNormalization()
197 1
                ->ifTrue(function ($v) {
198 1
                    return isset($v['query']) && is_string($v['query']) || isset($v['mutation']) && is_string($v['mutation']);
199
                })
200 1
                ->then(function ($v) {
201 1
                    return ['default' => $v];
202
                })
203
            ->end()
204
            ->useAttributeAsKey('name')
205
            ->prototype('array')
206 1
                ->addDefaultsIfNotSet()
207 25
                ->children()
208 25
                    ->scalarNode('query')->defaultNull()->end()
209
                    ->scalarNode('mutation')->defaultNull()->end()
210 25
                    ->scalarNode('subscription')->defaultNull()->end()
211 25
                ->end()
212 25
            ->end()
213 25
        ->end();
214 25
215 25
        return $node;
216
    }
217
218 25
    private function definitionsAutoMappingSection()
219
    {
220
        $builder = new TreeBuilder();
221
        /** @var ArrayNodeDefinition $node */
222
        $node = $builder->root('auto_mapping');
223
        $node
224 25
            ->treatFalseLike(['enabled' => false])
225
            ->treatTrueLike(['enabled' => true])
226 25
            ->treatNullLike(['enabled' => true])
227 25
            ->addDefaultsIfNotSet()
228 25
            ->children()
229 25
                ->booleanNode('enabled')->defaultTrue()->end()
230 23
                ->arrayNode('directories')
231 25
                    ->info('List of directories containing GraphQL classes.')
232 25
                    ->prototype('scalar')->end()
233 2
                ->end()
234 25
            ->end()
235 25
        ->end();
236
237
        return $node;
238 25
    }
239 25
240 25
    private function definitionsMappingsSection()
241 23
    {
242 25
        $builder = new TreeBuilder();
243 25
        /** @var ArrayNodeDefinition $node */
244 23
        $node = $builder->root('mappings');
245 25
        $node
246 25
            ->children()
247 25
                ->arrayNode('auto_discover')
248 25
                    ->treatFalseLike(['bundles' => false, 'root_dir' => false])
249 25
                    ->treatTrueLike(['bundles' => true, 'root_dir' => true])
250 23
                    ->treatNullLike(['bundles' => true, 'root_dir' => true])
251 25
                    ->addDefaultsIfNotSet()
252 25
                    ->children()
253 25
                        ->booleanNode('bundles')->defaultTrue()->end()
254
                        ->booleanNode('root_dir')->defaultTrue()->end()
255
                    ->end()
256 25
                ->end()
257
                ->arrayNode('types')
258
                    ->prototype('array')
259
                        ->addDefaultsIfNotSet()
260
                        ->beforeNormalization()
261
                            ->ifTrue(function ($v) {
262
                                return isset($v['type']) && 'yml' === $v['type'];
263
                            })
264
                            ->then(function ($v) {
265
                                $v['type'] = 'yaml';
266
267
                                return $v;
268
                            })
269
                        ->end()
270
                        ->children()
271
                            ->enumNode('type')->values(['yaml', 'xml'])->defaultNull()->end()
272
                            ->scalarNode('dir')->defaultNull()->end()
273
                            ->scalarNode('suffix')->defaultValue(OverblogGraphQLTypesExtension::DEFAULT_TYPES_SUFFIX)->end()
274
                        ->end()
275
                    ->end()
276
                ->end()
277
            ->end()
278
        ->end();
279
280
        return $node;
281
    }
282
283
    /**
284
     * @param string $name
285
     *
286
     * @return ArrayNodeDefinition
287
     */
288
    private function builderSection($name)
289
    {
290
        $builder = new TreeBuilder();
291
        /** @var ArrayNodeDefinition $node */
292
        $node = $builder->root($name);
293
        $node->beforeNormalization()
294
            ->ifTrue(function ($v) {
295
                return is_array($v) && !empty($v);
296
            })
297
            ->then(function ($v) {
298
                foreach ($v as $key => &$config) {
299
                    if (is_string($config)) {
300
                        $config = [
301
                            'alias' => $key,
302
                            'class' => $config,
303
                        ];
304
                    }
305
                }
306
307
                return $v;
308
            })
309
        ->end();
310
311
        $node->prototype('array')
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Symfony\Component\Config...\Builder\NodeDefinition as the method children() does only exist in the following sub-classes of Symfony\Component\Config...\Builder\NodeDefinition: Symfony\Component\Config...der\ArrayNodeDefinition. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
312
            ->children()
313
                ->scalarNode('alias')->isRequired()->end()
314
                ->scalarNode('class')->isRequired()->end()
315
            ->end()
316
        ->end()
317
        ;
318
319
        return $node;
320
    }
321
322
    /**
323
     * @param string $name
324
     * @param bool   $disabledValue
325
     *
326
     * @return ScalarNodeDefinition
327
     */
328
    private function securityQuerySection($name, $disabledValue)
329
    {
330
        $builder = new TreeBuilder();
331
        /** @var ScalarNodeDefinition $node */
332
        $node = $builder->root($name, 'scalar');
333
        $node->beforeNormalization()
334
                ->ifTrue(function ($v) {
335
                    return is_string($v) && is_numeric($v);
336
                })
337
                ->then(function ($v) {
338
                    return (int) $v;
339
                })
340
            ->end();
341
342
        $node
343
            ->info('Disabled if equal to false.')
344
            ->beforeNormalization()
345
                ->ifTrue(function ($v) {
346
                    return false === $v;
347
                })
348
                ->then(function () use ($disabledValue) {
349
                    return $disabledValue;
350
                })
351
            ->end()
352
            ->defaultFalse()
353
            ->validate()
354
                ->ifTrue(function ($v) {
355
                    return is_int($v) && $v < 0;
356
                })
357
                ->thenInvalid(sprintf('"%s.security.%s" must be greater or equal to 0.', self::NAME, $name))
358
            ->end()
359
        ;
360
361
        return $node;
362
    }
363
}
364