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
Push — annotations ( 21fbfb...bee78b )
by Jérémiah
14:55
created

Configuration::definitionsMappingsSection()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 48

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 38
CRAP Score 3

Importance

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