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 (#473)
by
unknown
15:25
created

BuilderProcessor::getFieldBuilderMapping()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 42
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 7.4937

Importance

Changes 0
Metric Value
eloc 28
dl 0
loc 42
ccs 17
cts 26
cp 0.6538
rs 8.8497
c 0
b 0
f 0
cc 6
nc 7
nop 4
crap 7.4937
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Overblog\GraphQLBundle\Config\Processor;
6
7
use Overblog\GraphQLBundle\Definition\Builder\MappingInterface;
8
use Overblog\GraphQLBundle\Relay\Connection\BackwardConnectionArgsDefinition;
9
use Overblog\GraphQLBundle\Relay\Connection\ConnectionArgsDefinition;
10
use Overblog\GraphQLBundle\Relay\Connection\ForwardConnectionArgsDefinition;
11
use Overblog\GraphQLBundle\Relay\Mutation\MutationFieldDefinition;
12
use Overblog\GraphQLBundle\Relay\Node\GlobalIdFieldDefinition;
13
use Overblog\GraphQLBundle\Relay\Node\NodeFieldDefinition;
14
use Overblog\GraphQLBundle\Relay\Node\PluralIdentifyingRootFieldDefinition;
15
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
16
17
final class BuilderProcessor implements ProcessorInterface
18
{
19
    public const BUILDER_FIELD_TYPE = 'field';
20
    public const BUILDER_FIELDS_TYPE = 'fields';
21
    public const BUILDER_ARGS_TYPE = 'args';
22
23
    public const BUILDER_TYPES = [
24
        self::BUILDER_FIELD_TYPE,
25
        self::BUILDER_FIELDS_TYPE,
26
        self::BUILDER_ARGS_TYPE,
27
    ];
28
29
    /** @var MappingInterface[] */
30
    private static $builderClassMap = [
31
        self::BUILDER_ARGS_TYPE => [
32
            'Relay::ForwardConnection' => ForwardConnectionArgsDefinition::class,
33
            'Relay::BackwardConnection' => BackwardConnectionArgsDefinition::class,
34
            'Relay::Connection' => ConnectionArgsDefinition::class,
35
        ],
36
        self::BUILDER_FIELD_TYPE => [
37
            'Relay::Mutation' => MutationFieldDefinition::class,
38
            'Relay::GlobalId' => GlobalIdFieldDefinition::class,
39
            'Relay::Node' => NodeFieldDefinition::class,
40
            'Relay::PluralIdentifyingRoot' => PluralIdentifyingRootFieldDefinition::class,
41
        ],
42
        self::BUILDER_FIELDS_TYPE => [],
43
    ];
44
45
    /**
46
     * {@inheritdoc}
47
     */
48 39
    public static function process(array $configs): array
49
    {
50 39
        $addedTypes = [];
51
        // map: "type name" => "provided by" for better DX, while debugging accidental type overrides in builders
52 39
        $reservedTypesMap = array_combine(
53 39
            array_keys($configs),
54 39
            array_fill(0, count($configs), 'configs')
55
        );
56
57 39
        foreach ($configs as &$config) {
58 39
            if (isset($config['config']['builders']) && \is_array($config['config']['builders'])) {
59 1
                ['fields' => $buildersFields, 'types' => $buildersTypes] = self::processFieldsBuilders(
60 1
                    $config['config']['builders'],
61 1
                    $reservedTypesMap
0 ignored issues
show
Bug introduced by
It seems like $reservedTypesMap can also be of type false; however, parameter $reservedTypesMap of Overblog\GraphQLBundle\C...processFieldsBuilders() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

61
                    /** @scrutinizer ignore-type */ $reservedTypesMap
Loading history...
62
                );
63
64 1
                $config['config']['fields'] = isset($config['config']['fields'])
65 1
                    ? \array_merge($buildersFields, $config['config']['fields'])
66
                    : $buildersFields;
67
68 1
                $addedTypes = \array_merge($addedTypes, $buildersTypes);
69
70 1
                unset($config['config']['builders']);
71
            }
72
73 39
            if (isset($config['config']['fields']) && \is_array($config['config']['fields'])) {
74 34
                ['fields' => $buildersFields, 'types' => $buildersTypes] = self::processFieldBuilders(
75 34
                    $config['config']['fields'],
76 34
                    $reservedTypesMap
77
                );
78
79 32
                $config['config']['fields'] = $buildersFields;
80
81 32
                $addedTypes = \array_merge($addedTypes, $buildersTypes);
82
            }
83
        }
84
85 37
        return \array_merge($configs, $addedTypes);
86
    }
87
88 11
    public static function addBuilderClass($name, $type, $builderClass): void
89
    {
90 11
        self::checkBuilderClass($builderClass, $type);
91 1
        self::$builderClassMap[$type][$name] = $builderClass;
92 1
    }
93
94
    /**
95
     * @param string $builderClass
96
     * @param string $type
97
     */
98 11
    private static function checkBuilderClass($builderClass, $type): void
99
    {
100 11
        $interface = MappingInterface::class;
101
102 11
        if (!\is_string($builderClass)) {
0 ignored issues
show
introduced by
The condition is_string($builderClass) is always true.
Loading history...
103 5
            throw new \InvalidArgumentException(
104 5
                \sprintf('%s builder class should be string, but %s given.', \ucfirst($type), \gettype($builderClass))
105
            );
106
        }
107
108 6
        if (!\class_exists($builderClass)) {
109 2
            throw new \InvalidArgumentException(
110 2
                \sprintf('%s builder class "%s" not found.', \ucfirst($type), $builderClass)
111
            );
112
        }
113
114 4
        if (!\is_subclass_of($builderClass, $interface)) {
115 3
            throw new \InvalidArgumentException(
116 3
                \sprintf(
117 3
                    '%s builder class should implement "%s", but "%s" given.',
118 3
                    \ucfirst($type),
119 3
                    $interface,
120 3
                    $builderClass
121
                )
122
            );
123
        }
124 1
    }
125
126 34
    private static function processFieldBuilders(array $fields, array &$reservedTypesMap)
127
    {
128 34
        $newTypes = [];
129
130 34
        foreach ($fields as &$field) {
131 34
            $fieldBuilderName = null;
132
133 34
            if (isset($field['builder']) && \is_string($field['builder'])) {
134 9
                $fieldBuilderName = $field['builder'];
135 9
                unset($field['builder']);
136 33
            } elseif (\is_string($field)) {
137 2
                @\trigger_error(
138
                    'The builder short syntax (Field: Builder => Field: {builder: Builder}) is deprecated as of 0.7 and will be removed in 0.12. '.
139 2
                    'It will be replaced by the field type short syntax (Field: Type => Field: {type: Type})',
140 2
                    \E_USER_DEPRECATED
141
                );
142 2
                $fieldBuilderName = $field;
143
            }
144
145 34
            $builderConfig = [];
146 34
            if (isset($field['builderConfig'])) {
147 8
                if (\is_array($field['builderConfig'])) {
148 8
                    $builderConfig = $field['builderConfig'];
149
                }
150 8
                unset($field['builderConfig']);
151
            }
152
153 34
            if ($fieldBuilderName) {
154 9
                $mapping = self::getFieldBuilderMapping($fieldBuilderName, self::BUILDER_FIELD_TYPE, $builderConfig, $reservedTypesMap);
155
156 8
                $fieldMapping = $mapping['field'];
157 8
                $field = \is_array($field) ? \array_merge($fieldMapping, $field) : $fieldMapping;
158 8
                $newTypes = \array_merge($newTypes, $mapping['types']);
159
            }
160 33
            if (isset($field['argsBuilder'])) {
161 15
                $field = self::processFieldArgumentsBuilders($field);
162
            }
163
        }
164
165
        return [
166 32
            'fields' => $fields,
167 32
            'types' => $newTypes,
168
        ];
169
    }
170
171 1
    private static function processFieldsBuilders(array $builders, array &$reservedTypesMap)
172
    {
173 1
        $fields = [];
174 1
        $newTypes = [];
175
176 1
        foreach ($builders as $builder) {
177 1
            $builderName = $builder['builder'];
178 1
            $builderConfig = $builder['builderConfig'] ?? null;
179
180 1
            $mapping = self::getFieldBuilderMapping($builderName, self::BUILDER_FIELDS_TYPE, $builderConfig, $reservedTypesMap);
0 ignored issues
show
Bug introduced by
It seems like $builderConfig can also be of type null; however, parameter $builderConfig of Overblog\GraphQLBundle\C...etFieldBuilderMapping() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

180
            $mapping = self::getFieldBuilderMapping($builderName, self::BUILDER_FIELDS_TYPE, /** @scrutinizer ignore-type */ $builderConfig, $reservedTypesMap);
Loading history...
181
182 1
            $fields = \array_merge($fields, $mapping['fields']);
183 1
            $newTypes = \array_merge($newTypes, $mapping['types']);
184
        }
185
186
        return [
187 1
            'fields' => $fields,
188 1
            'types' => $newTypes,
189
        ];
190
    }
191
192
    /**
193
     * @param string $builderName
194
     * @param string $builderType
195
     * @param array $builderConfig
196
     * @param array $reservedTypesMap
197
     * @return array
198
     * @throws InvalidConfigurationException
199
     * @throws \LogicException
200
     */
201 9
    private static function getFieldBuilderMapping(string $builderName, string $builderType, array $builderConfig, array &$reservedTypesMap)
202
    {
203 9
        $builder = self::getBuilder($builderName, $builderType);
204 8
        $mapping = $builder->toMappingDefinition($builderConfig);
205
206 8
        if (self::BUILDER_FIELD_TYPE === $builderType) {
207 8
            $fieldMappingKey = 'field';
208 1
        } else if (self::BUILDER_FIELDS_TYPE === $builderType) {
209 1
            $fieldMappingKey = 'fields';
210
        } else {
211
            throw new \LogicException(sprintf(
212
                'Expected any of builder types "%s". Received "%s"',
213
                implode(', ', [self::BUILDER_FIELD_TYPE, self::BUILDER_FIELDS_TYPE]),
214
                $builderType
215
            ));
216
        }
217
218 8
        $fieldMapping = $mapping[$fieldMappingKey] ?? $mapping;
219 8
        $typesMapping = [];
220
221 8
        if (isset($mapping[$fieldMappingKey], $mapping['types'])) {
222 1
            $builderClass = get_class($builder);
223
224 1
            foreach ($mapping['types'] as $typeName => $typeConfig) {
225 1
                if (isset($reservedTypesMap[$typeName])) {
226
                    throw new InvalidConfigurationException(sprintf(
227
                        'Type "%s" emitted by builder "%s" already exists. Type was provided by "%s".' .
228
                        'Builder may only emit new types. Overriding is not allowed.',
229
                        $typeName,
230
                        $builderClass,
231
                        $reservedTypesMap[$typeName]
232
                    ));
233
                }
234
235 1
                $reservedTypesMap[$typeName] = sprintf('builder %s (%s) ', $builderName, $builderClass);
236 1
                $typesMapping[$typeName] = $typeConfig;
237
            }
238
        }
239
240
        return [
241 8
            $fieldMappingKey => $fieldMapping,
242 8
            'types' => $typesMapping,
243
        ];
244
    }
245
246
    /**
247
     * @param string $name
248
     * @param string $type
249
     *
250
     * @return MappingInterface
251
     *
252
     * @throws InvalidConfigurationException if builder class not define
253
     */
254 22
    private static function getBuilder($name, $type)
255
    {
256 22
        static $builders = [];
257 22
        if (isset($builders[$type][$name])) {
258 19
            return $builders[$type][$name];
259
        }
260
261 8
        $builderClassMap = self::$builderClassMap[$type];
262
263 8
        if (isset($builderClassMap[$name])) {
264 5
            return $builders[$type][$name] = new $builderClassMap[$name]();
265
        }
266
        // deprecated relay builder name ?
267 3
        $newName = 'Relay::'.\rtrim($name, 'Args');
268 3
        if (isset($builderClassMap[$newName])) {
269 1
            @\trigger_error(
270 1
                \sprintf('The "%s" %s builder is deprecated as of 0.7 and will be removed in 0.12. Use "%s" instead.', $name, $type, $newName),
271 1
                \E_USER_DEPRECATED
272
            );
273
274 1
            return $builders[$type][$newName] = new $builderClassMap[$newName]();
275
        }
276
277 2
        throw new InvalidConfigurationException(\sprintf('%s builder "%s" not found.', \ucfirst($type), $name));
278
    }
279
280 15
    private static function processFieldArgumentsBuilders(array $field)
281
    {
282 15
        $argsBuilderName = null;
283
284 15
        if (\is_string($field['argsBuilder'])) {
285 15
            $argsBuilderName = $field['argsBuilder'];
286 1
        } elseif (isset($field['argsBuilder']['builder']) && \is_string($field['argsBuilder']['builder'])) {
287 1
            $argsBuilderName = $field['argsBuilder']['builder'];
288
        }
289
290 15
        $builderConfig = [];
291 15
        if (isset($field['argsBuilder']['config']) && \is_array($field['argsBuilder']['config'])) {
292 1
            $builderConfig = $field['argsBuilder']['config'];
293
        }
294
295 15
        if ($argsBuilderName) {
296 15
            $args = self::getBuilder($argsBuilderName, self::BUILDER_ARGS_TYPE)->toMappingDefinition($builderConfig);
297 14
            $field['args'] = isset($field['args']) && \is_array($field['args']) ? \array_merge($args, $field['args']) : $args;
298
        }
299
300 14
        unset($field['argsBuilder']);
301
302 14
        return $field;
303
    }
304
}
305