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
Push — master ( 024700...341ac6 )
by Jérémiah
04:30
created

TypesConfiguration::addFieldsSelection()   B

Complexity

Conditions 6
Paths 2

Size

Total Lines 79
Code Lines 67

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 65
CRAP Score 6.0001

Importance

Changes 6
Bugs 2 Features 0
Metric Value
c 6
b 2
f 0
dl 0
loc 79
ccs 65
cts 66
cp 0.9848
rs 8.4178
cc 6
eloc 67
nc 2
nop 2
crap 6.0001

2 Methods

Rating   Name   Duplication   Size   Complexity  
B TypesConfiguration::relayNormalizer() 0 20 7
A TypesConfiguration::normalizedConfigTypeKey() 0 4 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the OverblogGraphQLBundle package.
5
 *
6
 * (c) Overblog <http://github.com/overblog/>
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 Overblog\GraphQLBundle\DependencyInjection;
13
14
use Overblog\GraphQLBundle\Config;
15
use Overblog\GraphQLBundle\Definition\Builder\MappingInterface;
16
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
17
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
18
use Symfony\Component\Config\Definition\ConfigurationInterface;
19
20
/**
21
 * @todo fix xml
22
 */
23
class TypesConfiguration implements ConfigurationInterface
24
{
25
    private static $types = [
26
        'object',
27
        'enum',
28
        'interface',
29
        'union',
30
        'input-object',
31
    ];
32
33 15
    public function getConfigTreeBuilder()
34
    {
35 15
        $treeBuilder = new TreeBuilder();
36 15
        $rootNode = $treeBuilder->root('overblog_graphql_types');
37
38 15
        $configTypeKeys = array_map(
39
            function ($type) {
40 15
                return $this->normalizedConfigTypeKey($type);
41 15
            },
42
            self::$types
43 15
        );
44
45 15
        $this->addBeforeNormalization($rootNode);
46
47
        $rootNode
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...
48 15
            ->useAttributeAsKey('name')
49 15
            ->prototype('array')
50
                // config is the unique config entry allowed
51 15
                ->beforeNormalization()
52
                    ->ifTrue(function ($v) use ($configTypeKeys) {
53 15
                        if (!empty($v) && is_array($v)) {
54 15
                            $keys = array_keys($v);
55 15
                            foreach ($configTypeKeys as $configTypeKey) {
56 15
                                if (in_array($configTypeKey, $keys)) {
57 5
                                    return true;
58
                                }
59 14
                            }
60 10
                        }
61
62 10
                        return  false;
63 15
                    })
64 15
                        ->thenInvalid(
65 15
                            sprintf(
66 15
                                'Don\'t use internal config keys %s, replace it by "config" instead.',
67 15
                                implode(', ',  $configTypeKeys)
68 15
                            )
69 15
                        )
70 15
                ->end()
71
                // config is renamed _{TYPE}_config
72 15
                ->beforeNormalization()
73
                    ->ifTrue(function ($v) {
74 10
                        return isset($v['type']) && is_string($v['type']);
75 15
                    })
76
                    ->then(function ($v) {
77 9
                        $key = $this->normalizedConfigTypeKey($v['type']);
78
79 9
                        if (empty($v[$key])) {
80 9
                            $v[$key] = isset($v['config']) ? $v['config'] : [];
81 9
                        }
82 9
                        unset($v['config']);
83
84 9
                        return $v;
85 15
                    })
86 15
                ->end()
87 15
                ->cannotBeOverwritten()
88 15
                ->children()
89 15
                    ->enumNode('type')->values(self::$types)->isRequired()->end()
90 15
                    ->append(Config\ObjectTypeDefinition::create()->getDefinition())
91 15
                    ->append(Config\EnumTypeDefinition::create()->getDefinition())
92 15
                    ->append(Config\InterfaceTypeDefinition::create()->getDefinition())
93 15
                    ->append(Config\UnionTypeDefinition::create()->getDefinition())
94 15
                    ->append(Config\InputObjectTypeDefinition::create()->getDefinition())
95 15
                    ->variableNode('config')->end()
96 15
                ->end()
97
                // _{TYPE}_config is renamed config
98 15
                ->validate()
99
                    ->ifTrue(function ($v) {
100 9
                        return isset($v[$this->normalizedConfigTypeKey($v['type'])]);
101 15
                    })
102
                    ->then(function ($v) {
103 9
                        $key = $this->normalizedConfigTypeKey($v['type']);
104 9
                        $v['config'] = $v[$key];
105 9
                        unset($v[$key]);
106
107 9
                        return $v;
108 15
                    })
109 15
                ->end()
110
111 15
            ->end();
112
113 15
        return $treeBuilder;
114
    }
115
116 15
    private function addBeforeNormalization(ArrayNodeDefinition $node)
117
    {
118
        $typeKeyExists = function ($types) { return !empty($types) && is_array($types); };
119
120
        $node
121
            // set type config.name
122 15
            ->beforeNormalization()
123 15
                ->ifTrue($typeKeyExists)
124
                ->then(function ($types) {
125 15
                    foreach ($types as $name => &$type) {
126 15
                        $type['config'] = isset($type['config']) && is_array($type['config']) ? $type['config'] : [];
127 15
                        $type['config']['name'] = $name;
128 15
                    }
129
130 15
                    return $types;
131 15
                })
132 15
            ->end()
133
            // normalized relay-connection
134 15
            ->beforeNormalization()
135 15
                ->ifTrue($typeKeyExists)
136 15
                ->then($this->relayNormalizer('relay-connection', 'Overblog\GraphQLBundle\Relay\Connection\ConnectionDefinition'))
137 15
            ->end()
138
            // normalized relay-node
139 15
            ->beforeNormalization()
140 15
                ->ifTrue($typeKeyExists)
141 15
                ->then($this->relayNormalizer('relay-node', 'Overblog\GraphQLBundle\Relay\Node\NodeDefinition'))
142 15
            ->end()
143
            // normalized relay-mutation-input
144 15
            ->beforeNormalization()
145 15
                ->ifTrue($typeKeyExists)
146 15
                ->then($this->relayNormalizer('relay-mutation-input', 'Overblog\GraphQLBundle\Relay\Mutation\InputDefinition'))
147 15
            ->end()
148
            // normalized relay-mutation-payload
149 15
            ->beforeNormalization()
150
                ->ifTrue(function ($types) { return !empty($types) && is_array($types); })
151 15
                ->then($this->relayNormalizer('relay-mutation-payload', 'Overblog\GraphQLBundle\Relay\Mutation\PayloadDefinition'))
152 15
            ->end();
153 15
    }
154
155
    private function relayNormalizer($typeToTreat, $definitionBuilderClass)
156
    {
157 15
        return function ($types) use ($typeToTreat, $definitionBuilderClass) {
158 15
            foreach ($types as $name => $type) {
159 15
                if (isset($type['type']) && is_string($type['type']) && $typeToTreat === $type['type']) {
160 6
                    $config = isset($type['config']) && is_array($type['config']) ? $type['config'] : [];
161 6
                    $config['name'] = $name;
162
163
                    /** @var MappingInterface $builder */
164 6
                    $builder = new $definitionBuilderClass();
165
166 6
                    $connectionDefinition = $builder->toMappingDefinition($config);
167
168 6
                    $types = array_replace($types, $connectionDefinition);
169 6
                }
170 15
            }
171
172 15
            return $types;
173 15
        };
174
    }
175
176 15
    private function normalizedConfigTypeKey($type)
177
    {
178 15
        return '_'.str_replace('-', '_', $type).'_config';
179
    }
180
}
181