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

Passed
Pull Request — master (#423)
by
unknown
20:29
created

Configuration::definitionsAutoMappingSection()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 21
ccs 18
cts 18
cp 1
rs 9.584
c 0
b 0
f 0
cc 1
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
    /**
27
     * Constructor.
28
     *
29
     * @param bool        $debug    Whether to use the debug mode
30
     * @param null|string $cacheDir
31
     */
32
    public function __construct($debug, $cacheDir = null)
33
    {
34 33
        $this->debug = (bool) $debug;
35
        $this->cacheDir = $cacheDir;
36 33
    }
37 33
38 33
    public function getConfigTreeBuilder()
39
    {
40 33
        $treeBuilder = new TreeBuilder();
41
        $rootNode = $treeBuilder->root(self::NAME);
42 33
43 33
        $rootNode
44
            ->children()
45
                ->append($this->batchingMethodSection())
46 33
                ->append($this->definitionsSection())
47 33
                ->append($this->errorsHandlerSection())
48 33
                ->append($this->servicesSection())
49 33
                ->append($this->securitySection())
50 33
            ->end();
51 33
52 33
        return $treeBuilder;
53
    }
54 33
55
    private function batchingMethodSection()
56
    {
57 33
        $builder = new TreeBuilder();
58
        /** @var EnumNodeDefinition $node */
59 33
        $node = $builder->root('batching_method', 'enum');
60
61 33
        $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
            ->values(['relay', 'apollo'])
63
            ->defaultValue('relay')
64 33
        ->end();
65 33
66 33
        return $node;
67
    }
68 33
69
    private function errorsHandlerSection()
70
    {
71 33
        $builder = new TreeBuilder();
72
        /** @var ArrayNodeDefinition $node */
73 33
        $node = $builder->root('errors_handler');
74
        $node
75 33
            ->treatFalseLike(['enabled' => false])
76
            ->treatTrueLike(['enabled' => true])
77 33
            ->treatNullLike(['enabled' => true])
78 33
            ->addDefaultsIfNotSet()
79 33
            ->children()
80 33
                ->booleanNode('enabled')->defaultTrue()->end()
81 33
                ->scalarNode('internal_error_message')->defaultValue(ErrorHandler::DEFAULT_ERROR_MESSAGE)->end()
82 33
                ->booleanNode('rethrow_internal_exceptions')->defaultFalse()->end()
83 33
                ->booleanNode('debug')->defaultValue($this->debug)->end()
84 33
                ->booleanNode('log')->defaultTrue()->end()
85 33
                ->scalarNode('logger_service')->defaultValue(ErrorLoggerListener::DEFAULT_LOGGER_SERVICE)->end()
86 33
                ->booleanNode('map_exceptions_to_parent')->defaultFalse()->end()
87 33
                ->arrayNode('exceptions')
88 33
                    ->addDefaultsIfNotSet()
89 33
                    ->children()
90 33
                        ->arrayNode('warnings')
91 33
                            ->treatNullLike([])
92 33
                            ->prototype('scalar')->end()
93 33
                        ->end()
94 33
                        ->arrayNode('errors')
95 33
                            ->treatNullLike([])
96 33
                            ->prototype('scalar')->end()
97 33
                    ->end()
98 33
                ->end()
99 33
            ->end();
100 33
101 33
        return $node;
102
    }
103 33
104
    private function definitionsSection()
105
    {
106 33
        $builder = new TreeBuilder();
107
        /** @var ArrayNodeDefinition $node */
108 33
        $node = $builder->root('definitions');
109
        $node
110 33
            ->addDefaultsIfNotSet()
111
            ->children()
112 33
                ->variableNode('default_resolver')->defaultValue([Resolver::class, 'defaultResolveFn'])->end()
113 33
                ->scalarNode('class_namespace')->defaultValue('Overblog\\GraphQLBundle\\__DEFINITIONS__')->end()
114 33
                ->scalarNode('cache_dir')->defaultNull()->end()
115 33
                ->booleanNode('use_classloader_listener')->defaultTrue()->end()
116 33
                ->booleanNode('auto_compile')->defaultTrue()->end()
117 33
                ->booleanNode('show_debug_info')->info('Show some performance stats in extensions')->defaultFalse()->end()
118 33
                ->booleanNode('config_validation')->defaultValue($this->debug)->end()
119 33
                ->append($this->definitionsSchemaSection())
120 33
                ->append($this->definitionsAutoMappingSection())
121 33
                ->append($this->definitionsMappingsSection())
122 33
                ->arrayNode('builders')
123 33
                    ->children()
124 33
                        ->append($this->builderSection('field'))
125 33
                        ->append($this->builderSection('args'))
126 33
                    ->end()
127 33
                ->end()
128 33
129
            ->end()
130 33
        ->end();
131 33
132
        return $node;
133 33
    }
134
135
    private function servicesSection()
136 33
    {
137
        $builder = new TreeBuilder();
138 33
        /** @var ArrayNodeDefinition $node */
139
        $node = $builder->root('services');
140 33
        $node
141
            ->addDefaultsIfNotSet()
142 33
            ->children()
143 33
                ->scalarNode('executor')
144 33
                    ->defaultValue(self::NAME.'.executor.default')
145 33
                ->end()
146 33
                ->scalarNode('promise_adapter')
147 33
                    ->defaultValue(self::NAME.'.promise_adapter.default')
148 33
                ->end()
149 33
                ->scalarNode('expression_language')
150 33
                    ->defaultValue(self::NAME.'.expression_language.default')
151 33
                ->end()
152 33
                ->scalarNode('cache_expression_language_parser')->end()
153 33
            ->end()
154 33
        ->end();
155 33
156
        return $node;
157 33
    }
158
159
    private function securitySection()
160 33
    {
161
        $builder = new TreeBuilder();
162 33
        /** @var ArrayNodeDefinition $node */
163
        $node = $builder->root('security');
164 33
        $node
165
            ->addDefaultsIfNotSet()
166 33
            ->children()
167 33
                ->append($this->securityQuerySection('query_max_depth', QueryDepth::DISABLED))
168 33
                ->append($this->securityQuerySection('query_max_complexity', QueryComplexity::DISABLED))
169 33
                ->booleanNode('enable_introspection')->defaultTrue()->end()
170 33
                ->booleanNode('handle_cors')->defaultFalse()->end()
171 33
            ->end()
172 33
        ->end();
173 33
174
        return $node;
175 33
    }
176
177
    private function definitionsSchemaSection()
178 33
    {
179
        $builder = new TreeBuilder();
180 33
        /** @var ArrayNodeDefinition $node */
181
        $node = $builder->root('schema');
182 33
        $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...
183
            ->beforeNormalization()
184 33
                ->ifTrue(function ($v) {
185
                    return isset($v['query']) && \is_string($v['query']) || isset($v['mutation']) && \is_string($v['mutation']);
186 29
                })
187 33
                ->then(function ($v) {
188
                    return ['default' => $v];
189 28
                })
190 33
            ->end()
191 33
            ->useAttributeAsKey('name')
192 33
            ->prototype('array')
193 33
                ->addDefaultsIfNotSet()
194 33
                ->children()
195 33
                    ->scalarNode('query')->defaultNull()->end()
196 33
                    ->scalarNode('mutation')->defaultNull()->end()
197 33
                    ->scalarNode('subscription')->defaultNull()->end()
198 33
                    ->arrayNode('resolver_maps')
199 33
                        ->defaultValue([])
200 33
                        ->prototype('scalar')->end()
201 33
                    ->end()
202 33
                    ->arrayNode('types')
203 33
                        ->defaultValue([])
204 33
                        ->prototype('scalar')->end()
205 33
                    ->end()
206 33
                ->end()
207 33
            ->end()
208 33
        ->end();
209 33
210
        return $node;
211 33
    }
212
213
    private function definitionsAutoMappingSection()
214 33
    {
215
        $builder = new TreeBuilder();
216 33
        /** @var ArrayNodeDefinition $node */
217 33
        $node = $builder->root('auto_mapping');
218
        $node
219 33
            ->treatFalseLike(['enabled' => false])
220 33
            ->treatTrueLike(['enabled' => true])
221 33
            ->treatNullLike(['enabled' => true])
222 33
            ->addDefaultsIfNotSet()
223 33
            ->children()
224 33
                ->booleanNode('enabled')->defaultTrue()->end()
225 33
                ->arrayNode('directories')
226 33
                    ->info('List of directories containing GraphQL classes.')
227 33
                    ->prototype('scalar')->end()
228 33
                ->end()
229 33
            ->end()
230 33
        ->end();
231 33
232 33
        return $node;
233 33
    }
234
235 29
    private function definitionsMappingsSection()
236 33
    {
237
        $builder = new TreeBuilder();
238 28
        $node = $builder->root('mappings');
239 7
        $node
240
            ->children()
241 21
                ->arrayNode('auto_discover')
242
                    ->treatFalseLike(['bundles' => false, 'root_dir' => false])
243 28
                    ->treatTrueLike(['bundles' => true, 'root_dir' => true])
244
                    ->treatNullLike(['bundles' => true, 'root_dir' => true])
245 28
                    ->addDefaultsIfNotSet()
246 33
                    ->children()
247 33
                        ->booleanNode('bundles')->defaultTrue()->end()
248 33
                        ->booleanNode('root_dir')->defaultTrue()->end()
249 33
                    ->end()
250 33
                ->end()
251 33
                ->arrayNode('types')
252 33
                    ->prototype('array')
253 33
                        ->addDefaultsIfNotSet()
254 33
                        ->beforeNormalization()
255 33
                            ->ifTrue(function ($v) {
256 33
                                return isset($v['type']) && \is_string($v['type']);
257 33
                            })
258
                            ->then(function ($v) {
259
                                if ('yml' === $v['type']) {
260 33
                                    $v['types'] = ['yaml'];
261
                                } else {
262
                                    $v['types'] = [$v['type']];
263
                                }
264
                                unset($v['type']);
265
266
                                return $v;
267
                            })
268 33
                        ->end()
269
                        ->children()
270 33
                            ->arrayNode('types')
271
                                ->prototype('enum')->values(\array_keys(OverblogGraphQLTypesExtension::SUPPORTED_TYPES_EXTENSIONS))->isRequired()->end()
272 33
                            ->end()
273 33
                            ->scalarNode('dir')->defaultNull()->end()
274
                            ->scalarNode('suffix')->defaultValue(OverblogGraphQLTypesExtension::DEFAULT_TYPES_SUFFIX)->end()
275 1
                        ->end()
276 33
                    ->end()
277
                ->end()
278 1
            ->end()
279 1
        ;
280
281 1
        return $node;
282 1
    }
283
284
    /**
285
     * @param string $name
286
     *
287 1
     * @return ArrayNodeDefinition
288 33
     */
289 33
    private function builderSection($name)
290
    {
291 33
        $builder = new TreeBuilder();
292 33
        /** @var ArrayNodeDefinition $node */
293 33
        $node = $builder->root($name);
294 33
        $node->beforeNormalization()
295 33
            ->ifTrue(function ($v) {
296 33
                return \is_array($v) && !empty($v);
297
            })
298
            ->then(function ($v) {
299 33
                foreach ($v as $key => &$config) {
300
                    if (\is_string($config)) {
301
                        $config = [
302
                            'alias' => $key,
303
                            'class' => $config,
304
                        ];
305
                    }
306
                }
307
308 33
                return $v;
309
            })
310 33
        ->end();
311
312 33
        $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...
313 33
            ->children()
314
                ->scalarNode('alias')->isRequired()->end()
315 31
                ->scalarNode('class')->isRequired()->end()
316 33
            ->end()
317
        ->end()
318 4
        ;
319 33
320 33
        return $node;
321
    }
322
323 33
    /**
324 33
     * @param string $name
325
     * @param bool   $disabledValue
326 31
     *
327 33
     * @return ScalarNodeDefinition
328
     */
329 31
    private function securityQuerySection($name, $disabledValue)
330 33
    {
331 33
        $builder = new TreeBuilder();
332 33
        /** @var ScalarNodeDefinition $node */
333 33
        $node = $builder->root($name, 'scalar');
334
        $node->beforeNormalization()
335 31
                ->ifTrue(function ($v) {
336 33
                    return \is_string($v) && \is_numeric($v);
337 33
                })
338 33
                ->then(function ($v) {
339
                    return (int) $v;
340
                })
341 33
            ->end();
342
343
        $node
344
            ->info('Disabled if equal to false.')
345
            ->beforeNormalization()
346
                ->ifTrue(function ($v) {
347
                    return false === $v;
348
                })
349
                ->then(function () use ($disabledValue) {
350
                    return $disabledValue;
351
                })
352
            ->end()
353
            ->defaultFalse()
354
            ->validate()
355
                ->ifTrue(function ($v) {
356
                    return \is_int($v) && $v < 0;
357
                })
358
                ->thenInvalid(\sprintf('"%s.security.%s" must be greater or equal to 0.', self::NAME, $name))
359
            ->end()
360
        ;
361
362
        return $node;
363
    }
364
}
365