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 — 0.12 (#567)
by Jérémiah
19:11
created

InheritanceProcessor::process()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 7
ccs 5
cts 5
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Overblog\GraphQLBundle\Config\Processor;
6
7
final class InheritanceProcessor implements ProcessorInterface
8
{
9
    public const HEIRS_KEY = 'heirs';
10
    public const INHERITS_KEY = 'inherits';
11
12
    /**
13
     * {@inheritdoc}
14
     */
15 43
    public static function process(array $configs): array
16
    {
17 43
        $configs = self::processConfigsHeirs($configs);
18 42
        $configs = self::processConfigsInherits($configs);
19 39
        $configs = self::removedDecorators($configs);
20
21 39
        return $configs;
22
    }
23
24 39
    private static function removedDecorators(array $configs)
25
    {
26
        return \array_filter($configs, function ($config) {
27 39
            return !isset($config['decorator']) || true !== $config['decorator'];
28 39
        });
29
    }
30
31 43
    private static function processConfigsHeirs(array $configs)
32
    {
33 43
        foreach ($configs as $parentName => &$config) {
34 43
            if (!empty($config[self::HEIRS_KEY])) {
35
                // allows shorthand configuration `heirs: QueryFooDecorator` is equivalent to `heirs: [QueryFooDecorator]`
36 5
                if (!\is_array($config[self::HEIRS_KEY])) {
37 1
                    $config[self::HEIRS_KEY] = [$config[self::HEIRS_KEY]];
38
                }
39 5
                foreach ($config[self::HEIRS_KEY] as $heirs) {
40 5
                    if (!isset($configs[$heirs])) {
41 1
                        throw new \InvalidArgumentException(\sprintf(
42 1
                            'Type %s child of %s not found.',
43 1
                            \json_encode($heirs),
44 1
                            \json_encode($parentName)
45
                        ));
46
                    }
47
48 4
                    if (!isset($configs[$heirs][self::INHERITS_KEY])) {
49 1
                        $configs[$heirs][self::INHERITS_KEY] = [];
50
                    }
51
52 4
                    $configs[$heirs][self::INHERITS_KEY][] = $parentName;
53
                }
54
            }
55 43
            unset($config[self::HEIRS_KEY]);
56
        }
57
58 42
        return $configs;
59
    }
60
61 42
    private static function processConfigsInherits(array $configs)
62
    {
63 42
        foreach ($configs as $name => &$config) {
64 42
            if (!isset($config['type'])) {
65 6
                continue;
66
            }
67
68 37
            $allowedTypes = [$config['type']];
69 37
            if ('object' === $config['type']) {
70 37
                $allowedTypes[] = 'interface';
71
            }
72 37
            $flattenInherits = self::flattenInherits($name, $configs, $allowedTypes);
73 34
            if (empty($flattenInherits)) {
74 34
                continue;
75
            }
76 2
            $config = self::inheritsTypeConfig($name, $flattenInherits, $configs);
77
        }
78
79 39
        return $configs;
80
    }
81
82 2
    private static function inheritsTypeConfig($child, array $parents, array $configs)
83
    {
84 2
        $parentTypes = \array_intersect_key($configs, \array_flip($parents));
85
86
        // Restore initial order
87
        \uksort($parentTypes, function ($a, $b) use ($parents) {
88 1
            return \array_search($a, $parents, true) > \array_search($b, $parents, true);
89 2
        });
90
91 2
        $mergedParentsConfig = self::mergeConfigs(...\array_column($parentTypes, 'config'));
92 2
        $childType = $configs[$child];
93
        // unset resolveType field resulting from the merge of a "interface" type
94 2
        if ('object' === $childType['type']) {
95 2
            unset($mergedParentsConfig['resolveType']);
96
        }
97
98 2
        if (isset($mergedParentsConfig['interfaces'], $childType['config']['interfaces'])) {
99 1
            $childType['config']['interfaces'] = \array_merge($mergedParentsConfig['interfaces'], $childType['config']['interfaces']);
100
        }
101
102 2
        $configs = \array_replace_recursive(['config' => $mergedParentsConfig], $childType);
103
104 2
        return $configs;
105
    }
106
107 37
    private static function flattenInherits($name, array $configs, array $allowedTypes, $child = null, array $typesTreated = [])
108
    {
109 37
        self::checkTypeExists($name, $configs, $child);
110 37
        self::checkCircularReferenceInheritsTypes($name, $typesTreated);
111 37
        self::checkAllowedInheritsTypes($name, $configs[$name], $allowedTypes, $child);
112
113
        // flatten
114 37
        $config = $configs[$name];
115 37
        if (empty($config[self::INHERITS_KEY]) || !\is_array($config[self::INHERITS_KEY])) {
116 34
            return [];
117
        }
118 5
        $typesTreated[$name] = true;
119 5
        $flattenInheritsTypes = [];
120 5
        foreach ($config[self::INHERITS_KEY] as $typeToInherit) {
121 5
            $flattenInheritsTypes = \array_merge(
122 5
                $flattenInheritsTypes,
123 5
                self::flattenInherits($typeToInherit, $configs, $allowedTypes, $name, $typesTreated)
124
            );
125 2
            $flattenInheritsTypes[] = $typeToInherit;
126
        }
127
128 2
        return $flattenInheritsTypes;
129
    }
130
131 37
    private static function checkTypeExists($name, array $configs, $child): void
132
    {
133 37
        if (!isset($configs[$name])) {
134 1
            throw new \InvalidArgumentException(\sprintf(
135 1
                'Type %s inherited by %s not found.',
136 1
                \json_encode($name),
137 1
                \json_encode($child)
138
            ));
139
        }
140 37
    }
141
142 37
    private static function checkCircularReferenceInheritsTypes($name, array $typesTreated): void
143
    {
144 37
        if (isset($typesTreated[$name])) {
145 1
            throw new \InvalidArgumentException(\sprintf(
146 1
                'Type circular inheritance detected (%s).',
147 1
                \implode('->', \array_merge(\array_keys($typesTreated), [$name]))
148
            ));
149
        }
150 37
    }
151
152 37
    private static function checkAllowedInheritsTypes($name, array $config, array $allowedTypes, $child): void
153
    {
154 37
        if (empty($config['decorator']) && isset($config['type']) && !\in_array($config['type'], $allowedTypes)) {
155 1
            throw new \InvalidArgumentException(\sprintf(
156 1
                'Type %s can\'t inherit %s because its type (%s) is not allowed type (%s).',
157 1
                \json_encode($child),
158 1
                \json_encode($name),
159 1
                \json_encode($config['type']),
160 1
                \json_encode($allowedTypes)
161
            ));
162
        }
163 37
    }
164
165 2
    private static function mergeConfigs(...$configs): array
166
    {
167 2
        $result = [];
168
169 2
        foreach ($configs as $config) {
170 2
            $interfaces = $result['interfaces'] ?? null;
171 2
            $result = \array_replace_recursive($result, $config);
172
173 2
            if (!empty($interfaces) && !empty($config['interfaces'])) {
174 1
                $result['interfaces'] = \array_values(\array_unique(\array_merge($interfaces, $config['interfaces'])));
175
            }
176
        }
177
178 2
        return $result;
179
    }
180
}
181