ResolvableInputObjectType   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 94
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 13
eloc 44
dl 0
loc 94
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
B resolve() 0 36 9
A __construct() 0 21 2
A stripNonNullType() 0 6 2
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