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 — 0.12 ( 89e3ca...d0b971 )
by Jérémiah
21:45 queued 18:29
created

ArgumentsTransformer   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 175
Duplicated Lines 0 %

Test Coverage

Coverage 98.41%

Importance

Changes 0
Metric Value
wmc 29
eloc 66
dl 0
loc 175
ccs 62
cts 63
cp 0.9841
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A getType() 0 3 1
A getTypeClassInstance() 0 5 3
A __construct() 0 5 1
B populateObject() 0 48 10
A getArguments() 0 19 4
B getInstanceAndValidate() 0 22 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Overblog\GraphQLBundle\Transformer;
6
7
use GraphQL\Type\Definition\EnumType;
8
use GraphQL\Type\Definition\InputObjectType;
9
use GraphQL\Type\Definition\ListOfType;
10
use GraphQL\Type\Definition\NonNull;
11
use GraphQL\Type\Definition\ResolveInfo;
12
use GraphQL\Type\Definition\Type;
13
use Overblog\GraphQLBundle\Error\InvalidArgumentError;
14
use Overblog\GraphQLBundle\Error\InvalidArgumentsError;
15
use Symfony\Component\PropertyAccess\PropertyAccess;
16
use Symfony\Component\PropertyAccess\PropertyAccessor;
17
use Symfony\Component\Validator\Validator\ValidatorInterface;
18
19
class ArgumentsTransformer
20
{
21
    /**
22
     * @var ValidatorInterface
23
     */
24
    protected $validator;
25
26
    /**
27
     * @var array
28
     */
29
    protected $classesMap;
30
31
    /**
32
     * @var PropertyAccessor
33
     */
34
    protected $accessor;
35
36 8
    public function __construct(ValidatorInterface $validator = null, $classesMap = [])
37
    {
38 8
        $this->validator = $validator;
39 8
        $this->accessor = PropertyAccess::createPropertyAccessor();
40 8
        $this->classesMap = $classesMap;
41 8
    }
42
43
    /**
44
     * Get the PHP class for a given type.
45
     *
46
     * @param string $type
47
     *
48
     * @return object|false
49
     */
50 8
    private function getTypeClassInstance(string $type)
51
    {
52 8
        $classname = isset($this->classesMap[$type]) ? $this->classesMap[$type]['class'] : false;
53
54 8
        return $classname ? new $classname() : false;
55
    }
56
57
    /**
58
     * Extract given type from Resolve Info.
59
     *
60
     * @param string      $type
61
     * @param ResolveInfo $info
62
     *
63
     * @return Type
64
     */
65 8
    private function getType(string $type, ResolveInfo $info): Type
66
    {
67 8
        return $info->schema->getType($type);
68
    }
69
70
    /**
71
     * Populate an object based on type with given data.
72
     *
73
     * @param Type        $type
74
     * @param mixed       $data
75
     * @param bool        $multiple
76
     * @param ResolveInfo $info
77
     *
78
     * @return mixed
79
     */
80 8
    private function populateObject(Type $type, $data, bool $multiple, ResolveInfo $info)
81
    {
82 8
        if (null === $data) {
83 2
            return $data;
84
        }
85
86 8
        if ($type instanceof NonNull) {
87 1
            $type = $type->getWrappedType();
88
        }
89
90 8
        if ($multiple) {
91
            return \array_map(function ($data) use ($type, $info) {
92 6
                return $this->populateObject($type, $data, false, $info);
93 6
            }, $data);
94
        }
95
96 8
        if ($type instanceof EnumType) {
97 2
            $instance = $this->getTypeClassInstance($type->name);
98 2
            if ($instance) {
99 1
                $this->accessor->setValue($instance, 'value', $data);
100
101 1
                return $instance;
102
            } else {
103 2
                return $data;
104
            }
105 8
        } elseif ($type instanceof InputObjectType) {
106 8
            $instance = $this->getTypeClassInstance($type->name);
107 8
            if (!$instance) {
108
                return $data;
109
            }
110
111 8
            $fields = $type->getFields();
112
113 8
            foreach ($fields as $name => $field) {
114 8
                $fieldData = $this->accessor->getValue($data, \sprintf('[%s]', $name));
115
116 8
                if ($field->getType() instanceof ListOfType) {
117 2
                    $fieldValue = $this->populateObject($field->getType()->getWrappedType(), $fieldData, true, $info);
118
                } else {
119 8
                    $fieldValue = $this->populateObject($field->getType(), $fieldData, false, $info);
120
                }
121
122 8
                $this->accessor->setValue($instance, $name, $fieldValue);
123
            }
124
125 8
            return $instance;
126
        } else {
127 8
            return $data;
128
        }
129
    }
130
131
    /**
132
     * Given a GraphQL type and an array of data, populate corresponding object recursively
133
     * using annoted classes.
134
     *
135
     * @param string      $argType
136
     * @param mixed       $data
137
     * @param ResolveInfo $info
138
     *
139
     * @return mixed
140
     */
141 8
    public function getInstanceAndValidate(string $argType, $data, ResolveInfo $info, string $argName)
142
    {
143 8
        $isRequired = '!' === $argType[\strlen($argType) - 1];
144 8
        $isMultiple = '[' === $argType[0];
145 8
        $isStrictMultiple = false;
146 8
        if ($isMultiple) {
147 4
            $isStrictMultiple = '!' === $argType[\strpos($argType, ']') - 1];
148
        }
149
150 8
        $endIndex = ($isRequired ? 1 : 0) + ($isMultiple ? 1 : 0) + ($isStrictMultiple ? 1 : 0);
151 8
        $type = \substr($argType, $isMultiple ? 1 : 0, $endIndex > 0 ? -$endIndex : \strlen($argType));
152
153 8
        $result = $this->populateObject($this->getType($type, $info), $data, $isMultiple, $info);
154 8
        $errors = [];
155 8
        if (\is_object($result) && $this->validator) {
156 4
            $errors = $this->validator->validate($result);
157
        }
158
159 8
        if (\count($errors) > 0) {
160 1
            throw new InvalidArgumentError($argName, $errors);
0 ignored issues
show
Bug introduced by
It seems like $errors can also be of type array; however, parameter $errors of Overblog\GraphQLBundle\E...entError::__construct() does only seem to accept Symfony\Component\Valida...tViolationListInterface, 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

160
            throw new InvalidArgumentError($argName, /** @scrutinizer ignore-type */ $errors);
Loading history...
161
        } else {
162 7
            return $result;
163
        }
164
    }
165
166
    /**
167
     * Transform a list of arguments into their corresponding php class and validate them.
168
     *
169
     * @param array       $mapping
170
     * @param mixed       $data
171
     * @param ResolveInfo $info
172
     *
173
     * @return array
174
     */
175 2
    public function getArguments(array $mapping, $data, ResolveInfo $info)
176
    {
177 2
        $args = [];
178 2
        $exceptions = [];
179
180 2
        foreach ($mapping as $name => $type) {
181
            try {
182 2
                $value = $this->getInstanceAndValidate($type, $data[$name], $info, $name);
183 1
                $args[] = $value;
184 1
            } catch (InvalidArgumentError $exception) {
185 1
                $exceptions[] = $exception;
186
            }
187
        }
188
189 2
        if (!empty($exceptions)) {
190 1
            throw new InvalidArgumentsError($exceptions);
191
        }
192
193 1
        return $args;
194
    }
195
}
196