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 (#23)
by Jérémiah
12:42
created

FieldsConfigSolution::checkAccessCallback()   A

Complexity

Conditions 4
Paths 1

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 19
ccs 11
cts 11
cp 1
rs 9.2
cc 4
eloc 11
nc 1
nop 2
crap 4
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\Resolver\Config;
13
14
use Overblog\GraphQLBundle\Definition\Argument;
15
use Overblog\GraphQLBundle\Definition\Builder\MappingInterface;
16
use Overblog\GraphQLBundle\Error\UserError;
17
use Overblog\GraphQLBundle\Relay\Connection\Output\Connection;
18
use Overblog\GraphQLBundle\Relay\Connection\Output\Edge;
19
use Overblog\GraphQLBundle\Resolver\ResolverInterface;
20
21
class FieldsConfigSolution extends AbstractConfigSolution
22
{
23
    /**
24
     * @var TypeConfigSolution
25
     */
26
    private $typeConfigSolution;
27
28
    /**
29
     * @var ResolveCallbackConfigSolution
30
     */
31
    private $resolveCallbackConfigSolution;
32
33 41
    public function __construct(
34
        TypeConfigSolution $typeConfigSolution,
35
        ResolveCallbackConfigSolution $resolveCallbackConfigSolution
36
    ) {
37 41
        $this->typeConfigSolution = $typeConfigSolution;
38 41
        $this->resolveCallbackConfigSolution = $resolveCallbackConfigSolution;
39 41
    }
40
41 36
    public function solve($values, array &$config = null)
42
    {
43
        // builder must be last
44 36
        $fieldsTreated = ['complexity', 'type', 'args', 'argsBuilder', 'deprecationReason', 'builder'];
45
46 36
        $fieldsDefaultAccess = isset($config['fieldsDefaultAccess']) ? $config['fieldsDefaultAccess'] : null;
47 36
        unset($config['fieldsDefaultAccess']);
48
49 36
        foreach ($values as $field => &$options) {
50
            //init access with fields default access if needed
51 36
            $options['access'] = isset($options['access']) ? $options['access'] : $fieldsDefaultAccess;
52
53 36
            foreach ($fieldsTreated as $fieldTreated) {
54 36
                if (isset($options[$fieldTreated])) {
55 36
                    $method = 'solve'.ucfirst($fieldTreated);
56 36
                    $options = $this->$method($options, $field, $config);
57 36
                }
58 36
            }
59 36
            $options = $this->resolveResolveAndAccessIfNeeded($options);
60 36
        }
61
62 36
        return $values;
63
    }
64
65 2
    private function solveComplexity($options, $field)
0 ignored issues
show
Unused Code introduced by
The parameter $field is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
66
    {
67 2
        $treatedOptions = $options;
68
69 2
        $value = $treatedOptions['complexity'];
70
71
        $treatedOptions['complexity'] = function () use ($value) {
72 2
            $args = func_get_args();
73 2
            $complexity = $this->solveUsingExpressionLanguageIfNeeded(
74 2
                $value,
75
                [
76 2
                    'childrenComplexity' => $args[0],
77 2
                    'args' => new Argument($args[1]),
78
                ]
79 2
            );
80
81 2
            return (int) $complexity;
82
        };
83
84 2
        return $treatedOptions;
85
    }
86
87 19
    private function solveBuilder($options, $field)
88
    {
89 19
        $builderConfig = isset($options['builderConfig']) ? $options['builderConfig'] : [];
90
91 19
        $access = isset($options['access']) ? $options['access'] : null;
92 19
        $options = $this->builderToMappingDefinition($options['builder'], $builderConfig, $this->fieldResolver, $field);
93 19
        $options['access'] = $access;
94 19
        $options = $this->resolveResolveAndAccessIfNeeded($options);
95
96 19
        unset($options['builderConfig'], $options['builder']);
97
98 19
        return $options;
99
    }
100
101 36
    private function solveType($options)
102
    {
103 36
        $options['type'] = $this->typeConfigSolution->solveTypeCallback($options['type']);
104
105 36
        return $options;
106
    }
107
108
    private function solveArgs($options)
109
    {
110
        foreach ($options['args'] as &$argsOptions) {
111
            $argsOptions['type'] = $this->typeConfigSolution->solveTypeCallback($argsOptions['type']);
112
            if (isset($argsOptions['defaultValue'])) {
113
                $argsOptions['defaultValue'] = $this->solveUsingExpressionLanguageIfNeeded($argsOptions['defaultValue']);
114
            }
115
        }
116
117
        return $options;
118
    }
119
120 17
    private function solveArgsBuilder($options)
121
    {
122 17
        $argsBuilderConfig = isset($options['argsBuilder']['config']) ? $options['argsBuilder']['config'] : [];
123
124 17
        $options['args'] = array_merge(
125 17
            $this->builderToMappingDefinition($options['argsBuilder']['builder'], $argsBuilderConfig, $this->argResolver),
126 17
            isset($options['args']) ? $options['args'] : []
127 17
        );
128
129 17
        unset($options['argsBuilder']);
130
131 17
        return $options;
132
    }
133
134
    private function solveDeprecationReason($options)
135
    {
136
        $options['deprecationReason'] = $this->solveUsingExpressionLanguageIfNeeded($options['deprecationReason']);
137
138
        return $options;
139
    }
140
141 36
    private function builderToMappingDefinition($rawBuilder, array $rawBuilderConfig, ResolverInterface $builderResolver, $name = null)
142
    {
143
        /** @var MappingInterface $builder */
144 36
        $builder = $builderResolver->resolve($rawBuilder);
145 36
        $builderConfig = [];
146 36
        if (!empty($rawBuilderConfig)) {
147 19
            $builderConfig = $rawBuilderConfig;
148 19
            $builderConfig = $this->configResolver->resolve($builderConfig);
149 19
        }
150
151 36
        if (null !== $name) {
152 19
            $builderConfig['name'] = $name;
153 19
        }
154
155 36
        return $builder->toMappingDefinition($builderConfig);
156
    }
157
158 36
    private function resolveResolveAndAccessIfNeeded(array $options)
159
    {
160 36
        $treatedOptions = $options;
161
162 36
        if (isset($treatedOptions['resolve'])) {
163 36
            $treatedOptions['resolve'] = $this->resolveCallbackConfigSolution->solve($treatedOptions['resolve']);
164 36
        }
165
166 36
        if (isset($treatedOptions['access'])) {
167 7
            $resolveCallback = $this->configResolver->getDefaultResolveFn();
168
169 7
            if (isset($treatedOptions['resolve'])) {
170 7
                $resolveCallback = $treatedOptions['resolve'];
171 7
            }
172
173 7
            $treatedOptions['resolve'] = $this->resolveAccessAndWrapResolveCallback($treatedOptions['access'], $resolveCallback);
174 7
        }
175 36
        unset($treatedOptions['access']);
176
177 36
        return $treatedOptions;
178
    }
179
180 12
    private function resolveAccessAndWrapResolveCallback($expression, callable $resolveCallback = null)
181
    {
182
        return function () use ($expression, $resolveCallback) {
183 12
            $args = func_get_args();
184
185 12
            $result = null !== $resolveCallback  ? call_user_func_array($resolveCallback, $args) : null;
186
187 12
            $values = call_user_func_array([$this, 'solveResolveCallbackArgs'], $args);
188
189 12
            return $this->filterResultUsingAccess($result, $expression, $values);
190 12
        };
191
    }
192
193 12
    private function filterResultUsingAccess($result, $expression, $values)
194
    {
195 12
        $checkAccess = $this->checkAccessCallback($expression, $values);
196
197 12
        switch (true) {
198 12
            case is_array($result) || $result instanceof \ArrayAccess:
199 4
                $result = array_filter(
200 4
                    array_map(
201
                        function ($object) use ($checkAccess) {
202 4
                            return $checkAccess($object) ? $object : null;
203 4
                        },
204
                        $result
205 4
                    )
206 4
                );
207 4
                break;
208
209 8
            case $result instanceof Connection:
210 2
                $result->edges = array_map(
211
                    function (Edge $edge) use ($checkAccess) {
212 2
                        $edge->node = $checkAccess($edge->node) ? $edge->node : null;
213
214 2
                        return $edge;
215 2
                    },
216 2
                    $result->edges
217 2
                );
218 2
                break;
219
220 7
            default:
221 7
                $checkAccess($result, true);
222 3
                break;
223 7
        }
224
225 8
        return $result;
226
    }
227
228
    private function checkAccessCallback($expression, $values)
229
    {
230 12
        return function ($object, $throwException = false) use ($expression, $values) {
231
            try {
232 12
                $access = $this->solveUsingExpressionLanguageIfNeeded(
233 12
                    $expression,
234 12
                    array_merge($values, ['object' => $object])
235 12
                );
236 12
            } catch (\Exception $e) {
237 2
                $access = false;
238
            }
239
240 12
            if ($throwException && !$access) {
241 4
                throw new UserError('Access denied to this field.');
242
            }
243
244 8
            return $access;
245 12
        };
246
    }
247
}
248