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 ( 44993f...7e5601 )
by Jérémiah
17:18
created

ArgumentsTransformer::populateObject()   B

Complexity

Conditions 9
Paths 9

Size

Total Lines 44
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 24
CRAP Score 9.0051

Importance

Changes 0
Metric Value
eloc 28
dl 0
loc 44
ccs 24
cts 25
cp 0.96
rs 8.0555
c 0
b 0
f 0
cc 9
nc 9
nop 4
crap 9.0051
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\ResolveInfo;
11
use GraphQL\Type\Definition\Type;
12
use Overblog\GraphQLBundle\Error\InvalidArgumentError;
13
use Overblog\GraphQLBundle\Error\InvalidArgumentsError;
14
use Symfony\Component\PropertyAccess\PropertyAccess;
15
use Symfony\Component\PropertyAccess\PropertyAccessor;
16
use Symfony\Component\Validator\Validator\ValidatorInterface;
17
18
class ArgumentsTransformer
19
{
20
    /**
21
     * @var ValidatorInterface
22
     */
23
    protected $validator;
24
25
    /**
26
     * @var array
27
     */
28
    protected $classesMap;
29
30
    /**
31
     * @var PropertyAccessor
32
     */
33
    protected $accessor;
34
35 2
    public function __construct(ValidatorInterface $validator = null, $classesMap = [])
36
    {
37 2
        $this->validator = $validator;
38 2
        $this->accessor = PropertyAccess::createPropertyAccessor();
39 2
        $this->classesMap = $classesMap;
40 2
    }
41
42
    /**
43
     * Get the PHP class for a given type.
44
     *
45
     * @param string $type
46
     *
47
     * @return object|false
48
     */
49 2
    private function getTypeClassInstance(string $type)
50
    {
51 2
        $classname = isset($this->classesMap[$type]) ? $this->classesMap[$type]['class'] : false;
52
53 2
        return $classname ? new $classname() : false;
54
    }
55
56
    /**
57
     * Extract given type from Resolve Info.
58
     *
59
     * @param string      $type
60
     * @param ResolveInfo $info
61
     *
62
     * @return Type
63
     */
64 2
    private function getType(string $type, ResolveInfo $info): Type
65
    {
66 2
        return $info->schema->getType($type);
0 ignored issues
show
Bug introduced by
The method getType() does not exist on null. ( Ignorable by Annotation )

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

66
        return $info->schema->/** @scrutinizer ignore-call */ getType($type);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
67
    }
68
69
    /**
70
     * Populate an object based on type with given data.
71
     *
72
     * @param Type        $type
73
     * @param mixed       $data
74
     * @param bool        $multiple
75
     * @param ResolveInfo $info
76
     *
77
     * @return mixed
78
     */
79 2
    private function populateObject(Type $type, $data, $multiple = false, ResolveInfo $info)
80
    {
81 2
        if (!$data) {
82 2
            return $data;
83
        }
84
85 2
        if ($multiple) {
86
            return \array_map(function ($data) use ($type, $info) {
87 2
                return $this->populateObject($type, $data, false, $info);
88 2
            }, $data);
89
        }
90
91 2
        if ($type instanceof EnumType) {
92 2
            $instance = $this->getTypeClassInstance($type->name);
93 2
            if ($instance) {
94 1
                $this->accessor->setValue($instance, 'value', $data);
95
96 1
                return $instance;
97
            } else {
98 2
                return $data;
99
            }
100 2
        } elseif ($type instanceof InputObjectType) {
101 2
            $instance = $this->getTypeClassInstance($type->name);
102 2
            if (!$instance) {
103
                return $data;
104
            }
105
106 2
            $fields = $type->getFields();
107
108 2
            foreach ($fields as $name => $field) {
109 2
                $fieldData = $this->accessor->getValue($data, \sprintf('[%s]', $name));
110
111 2
                if ($field->getType() instanceof ListOfType) {
112 2
                    $fieldValue = $this->populateObject($field->getType()->getWrappedType(), $fieldData, true, $info);
113
                } else {
114 2
                    $fieldValue = $this->populateObject($field->getType(), $fieldData, false, $info);
115
                }
116
117 2
                $this->accessor->setValue($instance, $name, $fieldValue);
118
            }
119
120 2
            return $instance;
121
        } else {
122 2
            return $data;
123
        }
124
    }
125
126
    /**
127
     * Given a GraphQL type and an array of data, populate corresponding object recursively
128
     * using annoted classes.
129
     *
130
     * @param string      $argType
131
     * @param mixed       $data
132
     * @param ResolveInfo $info
133
     *
134
     * @return mixed
135
     */
136 2
    public function getInstanceAndValidate(string $argType, $data, ResolveInfo $info, string $argName)
137
    {
138 2
        $isRequired = '!' === $argType[\strlen($argType) - 1];
139 2
        $isMultiple = '[' === $argType[0];
140 2
        $endIndex = ($isRequired ? 1 : 0) + ($isMultiple ? 1 : 0);
141 2
        $type = \substr($argType, $isMultiple ? 1 : 0, $endIndex > 0 ? -$endIndex : \strlen($argType));
142
143 2
        $result = $this->populateObject($this->getType($type, $info), $data, $isMultiple, $info);
144 2
        $errors = [];
145 2
        if (\is_object($result) && $this->validator) {
146 2
            $errors = $this->validator->validate($result);
147
        }
148
149 2
        if (\count($errors) > 0) {
150 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

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