ResolvableInputObjectType::__construct()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 13
dl 0
loc 21
rs 9.8333
c 0
b 0
f 0
cc 2
nc 2
nop 8

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
4
namespace TheCodingMachine\GraphQL\Controllers\Types;
5
6
use function get_class;
7
use GraphQL\Type\Definition\FieldDefinition;
8
use GraphQL\Type\Definition\InputObjectType;
9
use GraphQL\Type\Definition\ListOfType;
10
use GraphQL\Type\Definition\NonNull;
11
use GraphQL\Type\Definition\OutputType;
12
use GraphQL\Type\Definition\Type;
13
use ReflectionMethod;
14
use TheCodingMachine\GraphQL\Controllers\FieldsBuilderFactory;
15
use TheCodingMachine\GraphQL\Controllers\GraphQLException;
16
use TheCodingMachine\GraphQL\Controllers\Hydrators\HydratorInterface;
17
use TheCodingMachine\GraphQL\Controllers\Mappers\RecursiveTypeMapperInterface;
18
use TheCodingMachine\GraphQL\Controllers\Types\DateTimeType;
19
20
/**
21
 * A GraphQL input object that can be resolved using a factory
22
 */
23
class ResolvableInputObjectType extends InputObjectType implements ResolvableInputInterface
24
{
25
    /**
26
     * @var HydratorInterface
27
     */
28
    private $hydrator;
29
30
    /**
31
     * @var callable&array<int, object|string>
32
     */
33
    private $resolve;
34
35
    /**
36
     * QueryField constructor.
37
     * @param string $name
38
     * @param FieldsBuilderFactory $controllerQueryProviderFactory
39
     * @param RecursiveTypeMapperInterface $recursiveTypeMapper
40
     * @param object $factory
41
     * @param string $methodName
42
     * @param HydratorInterface $hydrator
43
     * @param null|string $comment
44
     * @param array $additionalConfig
45
     */
46
    public function __construct(string $name, FieldsBuilderFactory $controllerQueryProviderFactory, RecursiveTypeMapperInterface $recursiveTypeMapper, $factory, string $methodName, HydratorInterface $hydrator, ?string $comment, array $additionalConfig = [])
47
    {
48
        $this->hydrator = $hydrator;
49
        $this->resolve = [ $factory, $methodName ];
50
51
        $fields = function() use ($controllerQueryProviderFactory, $factory, $methodName, $recursiveTypeMapper) {
52
            $method = new ReflectionMethod($factory, $methodName);
53
            $fieldProvider = $controllerQueryProviderFactory->buildFieldsBuilder($recursiveTypeMapper);
54
            return $fieldProvider->getInputFields($method);
55
        };
56
57
        $config = [
58
            'name' => $name,
59
            'fields' => $fields,
60
        ];
61
        if ($comment) {
62
            $config['description'] = $comment;
63
        }
64
65
        $config += $additionalConfig;
66
        parent::__construct($config);
67
    }
68
69
    /**
70
     * @param array $args
71
     * @return object
72
     */
73
    public function resolve(array $args)
74
    {
75
        $toPassArgs = [];
76
        foreach ($this->getFields() as $name => $field) {
77
            $type = $field->getType();
78
            if (isset($args[$name])) {
79
                $val = $args[$name];
80
81
                $type = $this->stripNonNullType($type);
82
                if ($type instanceof ListOfType) {
83
                    $subtype = $this->stripNonNullType($type->getWrappedType());
84
                    $val = array_map(function ($item) use ($subtype) {
85
                        if ($subtype instanceof DateTimeType) {
86
                            return new \DateTimeImmutable($item);
87
                        } elseif ($subtype instanceof InputObjectType) {
88
                            return $this->hydrator->hydrate($item, $subtype);
89
                        }
90
                        return $item;
91
                    }, $val);
92
                } elseif ($type instanceof DateTimeType) {
93
                    $val = new \DateTimeImmutable($val);
94
                } elseif ($type instanceof InputObjectType) {
95
                    $val = $this->hydrator->hydrate($val, $type);
96
                }
97
            } elseif ($field->defaultValueExists()) {
98
                $val = $field->defaultValue;
99
            } else {
100
                throw new GraphQLException("Expected argument '$name' was not provided in GraphQL input type '".$this->name."' used in factory '".get_class($this->resolve[0]).'::'.$this->resolve[1]."()'");
0 ignored issues
show
Bug introduced by
Are you sure $this->resolve[1] of type object|string can be used in concatenation? ( Ignorable by Annotation )

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

100
                throw new GraphQLException("Expected argument '$name' was not provided in GraphQL input type '".$this->name."' used in factory '".get_class($this->resolve[0]).'::'./** @scrutinizer ignore-type */ $this->resolve[1]."()'");
Loading history...
Bug introduced by
It seems like $this->resolve[0] can also be of type string; however, parameter $object of get_class() does only seem to accept object, 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

100
                throw new GraphQLException("Expected argument '$name' was not provided in GraphQL input type '".$this->name."' used in factory '".get_class(/** @scrutinizer ignore-type */ $this->resolve[0]).'::'.$this->resolve[1]."()'");
Loading history...
101
            }
102
103
            $toPassArgs[] = $val;
104
        }
105
106
        $resolve = $this->resolve;
107
108
        return $resolve(...$toPassArgs);
109
    }
110
    
111
    private function stripNonNullType(Type $type): Type
112
    {
113
        if ($type instanceof NonNull) {
114
            return $this->stripNonNullType($type->getWrappedType());
115
        }
116
        return $type;
117
    }
118
}
119