Completed
Pull Request — master (#34)
by David
02:32 queued 55s
created

QueryField::getType()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 0
1
<?php
2
3
4
namespace TheCodingMachine\GraphQL\Controllers;
5
6
use GraphQL\Type\Definition\FieldDefinition;
7
use GraphQL\Type\Definition\InputObjectType;
8
use GraphQL\Type\Definition\ListOfType;
9
use GraphQL\Type\Definition\NonNull;
10
use GraphQL\Type\Definition\OutputType;
11
use GraphQL\Type\Definition\Type;
12
use TheCodingMachine\GraphQL\Controllers\Types\DateTimeType;
13
14
/**
15
 * A GraphQL field that maps to a PHP method automatically.
16
 */
17
class QueryField extends FieldDefinition
18
{
19
    /**
20
     * @var HydratorInterface
21
     */
22
    private $hydrator;
23
24
    /**
25
     * QueryField constructor.
26
     * @param string $name
27
     * @param OutputType&Type $type
28
     * @param array[] $arguments Indexed by argument name, value: ['type'=>InputType, 'default'=>val].
29
     * @param callable|null $resolve The method to execute
30
     * @param string|null $targetMethodOnSource The name of the method to execute on the source object. Mutually exclusive with $resolve parameter.
31
     * @param HydratorInterface $hydrator
32
     * @param null|string $comment
33
     * @param bool $injectSource Whether to inject the source object (for Fields), or null for Query and Mutations
34
     * @param array $additionalConfig
35
     */
36
    public function __construct(string $name, OutputType $type, array $arguments, ?callable $resolve, ?string $targetMethodOnSource, HydratorInterface $hydrator, ?string $comment, bool $injectSource, array $additionalConfig = [])
37
    {
38
        // FIXME: remove hydrator since not used!!!!
39
        $this->hydrator = $hydrator;
40
        $config = [
41
            'name' => $name,
42
            'type' => $type,
43
            'args' => array_map(function(array $item) { return $item['type']; }, $arguments)
44
        ];
45
        if ($comment) {
46
            $config['description'] = $comment;
47
        }
48
49
        $config['resolve'] = function ($source, array $args) use ($resolve, $targetMethodOnSource, $arguments, $injectSource) {
50
            $toPassArgs = [];
51
            if ($injectSource) {
52
                $toPassArgs[] = $source;
53
            }
54
            foreach ($arguments as $name => $arr) {
55
                $type = $arr['type'];
56
                if (isset($args[$name])) {
57
                    $val = $args[$name];
58
59
                    $type = $this->stripNonNullType($type);
60
                    if ($type instanceof ListOfType) {
61
                        $subtype = $this->stripNonNullType($type->getWrappedType());
62
                        $val = array_map(function ($item) use ($subtype) {
63
                            if ($subtype instanceof DateTimeType) {
64
                                return new \DateTimeImmutable($item);
65
                            } elseif ($subtype instanceof InputObjectType) {
66
                                return $this->hydrator->hydrate($item, $subtype);
67
                            };
68
                            return $item;
69
                        }, $val);
70
                    } elseif ($type instanceof DateTimeType) {
71
                        $val = new \DateTimeImmutable($val);
72
                    } elseif ($type instanceof InputObjectType) {
73
                        $val = $this->hydrator->hydrate($val, $type);
74
                    }
75
                } elseif (array_key_exists('default', $arr)) {
76
                    $val = $arr['default'];
77
                } else {
78
                    throw new GraphQLException("Expected argument '$name' was not provided.");
79
                }
80
81
                $toPassArgs[] = $val;
82
            }
83
84
            if ($resolve !== null) {
85
                return $resolve(...$toPassArgs);
86
            }
87
            if ($targetMethodOnSource !== null) {
88
                $method = [$source, $targetMethodOnSource];
89
                return $method(...$toPassArgs);
90
            }
91
            throw new \InvalidArgumentException('The QueryField constructor should be passed either a resolve method or a target method on source object.');
92
        };
93
94
        $config += $additionalConfig;
95
        parent::__construct($config);
96
    }
97
98
    private function stripNonNullType(Type $type): Type
99
    {
100
        if ($type instanceof NonNull) {
101
            return $this->stripNonNullType($type->getWrappedType());
102
        }
103
        return $type;
104
    }
105
}
106