PorpaginasTypeMapper::mapNameToType()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 7
dl 0
loc 15
rs 10
c 0
b 0
f 0
cc 3
nc 3
nop 2
1
<?php
2
3
4
namespace TheCodingMachine\GraphQL\Controllers\Mappers;
5
6
7
use function get_class;
8
use GraphQL\Type\Definition\InputObjectType;
9
use GraphQL\Type\Definition\InterfaceType;
10
use GraphQL\Type\Definition\ObjectType;
11
use GraphQL\Type\Definition\InputType;
12
use GraphQL\Type\Definition\OutputType;
13
use GraphQL\Type\Definition\Type;
14
use Porpaginas\Result;
15
use RuntimeException;
16
use function strpos;
17
use function substr;
18
use TheCodingMachine\GraphQL\Controllers\Types\MutableObjectType;
19
20
class PorpaginasTypeMapper implements TypeMapperInterface
21
{
22
    /**
23
     * @var array<string, MutableObjectType>
24
     */
25
    private $cache = [];
26
27
    /**
28
     * Returns true if this type mapper can map the $className FQCN to a GraphQL type.
29
     *
30
     * @param string $className The exact class name to look for (this function does not look into parent classes).
31
     * @return bool
32
     */
33
    public function canMapClassToType(string $className): bool
34
    {
35
        return is_a($className, Result::class, true);
36
    }
37
38
    /**
39
     * Maps a PHP fully qualified class name to a GraphQL type.
40
     *
41
     * @param string $className The exact class name to look for (this function does not look into parent classes).
42
     * @param OutputType|null $subType An optional sub-type if the main class is an iterator that needs to be typed.
43
     * @param RecursiveTypeMapperInterface $recursiveTypeMapper
44
     * @return MutableObjectType
45
     * @throws CannotMapTypeExceptionInterface
46
     */
47
    public function mapClassToType(string $className, ?OutputType $subType, RecursiveTypeMapperInterface $recursiveTypeMapper): MutableObjectType
48
    {
49
        if (!$this->canMapClassToType($className)) {
50
            throw CannotMapTypeException::createForType($className);
51
        }
52
        if ($subType === null) {
53
            throw PorpaginasMissingParameterException::noSubType();
54
        }
55
56
        return $this->getObjectType($subType);
57
    }
58
59
    private function getObjectType(OutputType $subType): MutableObjectType
60
    {
61
        if (!isset($subType->name)) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface GraphQL\Type\Definition\OutputType suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
62
            throw new RuntimeException('Cannot get name property from sub type '.get_class($subType));
63
        }
64
65
        $name = $subType->name;
66
67
        $typeName = 'PorpaginasResult_'.$name;
68
69
        if (!isset($this->cache[$typeName])) {
70
            $this->cache[$typeName] = new MutableObjectType([
71
                'name' => $typeName,
72
                'fields' => function() use ($subType) {
73
                    return [
74
                        'items' => [
75
                            'type' => Type::nonNull(Type::listOf(Type::nonNull($subType))),
76
                            'args' => [
77
                                'limit' => Type::int(),
78
                                'offset' => Type::int(),
79
                            ],
80
                            'resolve' => function (Result $root, $args) {
81
                                if (!isset($args['limit']) && isset($args['offset'])) {
82
                                    throw PorpaginasMissingParameterException::missingLimit();
83
                                }
84
                                if (isset($args['limit'])) {
85
                                    return $root->take($args['offset'] ?? 0, $args['limit']);
86
                                }
87
                                return $root;
88
                            }
89
                        ],
90
                        'count' => [
91
                            'type' => Type::int(),
92
                            'description' => 'The total count of items.',
93
                            'resolve' => function (Result $root) {
94
                                return $root->count();
95
                            }
96
                        ]
97
                    ];
98
                }
99
            ]);
100
        }
101
102
        return $this->cache[$typeName];
103
    }
104
105
    /**
106
     * Returns true if this type mapper can map the $typeName GraphQL name to a GraphQL type.
107
     *
108
     * @param string $typeName The name of the GraphQL type
109
     * @return bool
110
     */
111
    public function canMapNameToType(string $typeName): bool
112
    {
113
        return strpos($typeName, 'PorpaginasResult_') === 0;
114
    }
115
116
    /**
117
     * Returns a GraphQL type by name (can be either an input or output type)
118
     *
119
     * @param string $typeName The name of the GraphQL type
120
     * @param RecursiveTypeMapperInterface $recursiveTypeMapper
121
     * @return Type&(InputType|OutputType)
122
     * @throws CannotMapTypeExceptionInterface
123
     */
124
    public function mapNameToType(string $typeName, RecursiveTypeMapperInterface $recursiveTypeMapper): Type
125
    {
126
        if (!$this->canMapNameToType($typeName)) {
127
            throw CannotMapTypeException::createForName($typeName);
128
        }
129
130
        $subTypeName = substr($typeName, 17);
131
132
        $subType = $recursiveTypeMapper->mapNameToType($subTypeName);
133
134
        if (!$subType instanceof OutputType) {
135
            throw CannotMapTypeException::mustBeOutputType($subTypeName);
136
        }
137
138
        return $this->getObjectType($subType);
139
    }
140
141
    /**
142
     * Returns the list of classes that have matching input GraphQL types.
143
     *
144
     * @return string[]
145
     */
146
    public function getSupportedClasses(): array
147
    {
148
        // We cannot get the list of all possible porpaginas results but this is not an issue.
149
        // getSupportedClasses is only useful to get classes that can be hidden behind interfaces
150
        // and Porpaginas results are not part of those.
151
        return [];
152
    }
153
154
    /**
155
     * Returns true if this type mapper can map the $className FQCN to a GraphQL input type.
156
     *
157
     * @param string $className
158
     * @return bool
159
     */
160
    public function canMapClassToInputType(string $className): bool
161
    {
162
        return false;
163
    }
164
165
    /**
166
     * Maps a PHP fully qualified class name to a GraphQL input type.
167
     *
168
     * @param string $className
169
     * @param RecursiveTypeMapperInterface $recursiveTypeMapper
170
     * @return InputObjectType
171
     */
172
    public function mapClassToInputType(string $className, RecursiveTypeMapperInterface $recursiveTypeMapper): InputObjectType
173
    {
174
        throw CannotMapTypeException::createForInputType($className);
175
    }
176
177
    /**
178
     * Returns true if this type mapper can extend an existing type for the $className FQCN
179
     *
180
     * @param string $className
181
     * @param MutableObjectType $type
182
     * @param RecursiveTypeMapperInterface $recursiveTypeMapper
183
     * @return bool
184
     */
185
    public function canExtendTypeForClass(string $className, MutableObjectType $type, RecursiveTypeMapperInterface $recursiveTypeMapper): bool
186
    {
187
        return false;
188
    }
189
190
    /**
191
     * Extends the existing GraphQL type that is mapped to $className.
192
     *
193
     * @param string $className
194
     * @param MutableObjectType $type
195
     * @param RecursiveTypeMapperInterface $recursiveTypeMapper
196
     * @throws CannotMapTypeExceptionInterface
197
     */
198
    public function extendTypeForClass(string $className, MutableObjectType $type, RecursiveTypeMapperInterface $recursiveTypeMapper): void
199
    {
200
        throw CannotMapTypeException::createForExtendType($className, $type);
201
    }
202
203
    /**
204
     * Returns true if this type mapper can extend an existing type for the $typeName GraphQL type
205
     *
206
     * @param string $typeName
207
     * @param MutableObjectType $type
208
     * @param RecursiveTypeMapperInterface $recursiveTypeMapper
209
     * @return bool
210
     */
211
    public function canExtendTypeForName(string $typeName, MutableObjectType $type, RecursiveTypeMapperInterface $recursiveTypeMapper): bool
212
    {
213
        return false;
214
    }
215
216
    /**
217
     * Extends the existing GraphQL type that is mapped to the $typeName GraphQL type.
218
     *
219
     * @param string $typeName
220
     * @param MutableObjectType $type
221
     * @param RecursiveTypeMapperInterface $recursiveTypeMapper
222
     * @throws CannotMapTypeExceptionInterface
223
     */
224
    public function extendTypeForName(string $typeName, MutableObjectType $type, RecursiveTypeMapperInterface $recursiveTypeMapper): void
225
    {
226
        throw CannotMapTypeException::createForExtendName($typeName, $type);
227
    }
228
}
229