Completed
Pull Request — master (#60)
by David
02:24
created

AbstractQueryProviderTest.php$0 ➔ mapNameToType()   A

Complexity

Conditions 3

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.9666
c 0
b 0
f 0
cc 3
1
<?php
2
3
4
namespace TheCodingMachine\GraphQL\Controllers;
5
6
use Doctrine\Common\Annotations\Annotation;
7
use Doctrine\Common\Annotations\AnnotationReader as DoctrineAnnotationReader;
8
use GraphQL\Type\Definition\InputObjectType;
9
use GraphQL\Type\Definition\InputType;
10
use GraphQL\Type\Definition\ObjectType;
11
use GraphQL\Type\Definition\OutputType;
12
use GraphQL\Type\Definition\StringType;
13
use GraphQL\Type\Definition\Type;
14
use Mouf\Picotainer\Picotainer;
15
use PHPUnit\Framework\TestCase;
16
use Psr\Container\ContainerInterface;
17
use Symfony\Component\Cache\Simple\ArrayCache;
18
use TheCodingMachine\GraphQL\Controllers\Fixtures\TestObject;
19
use TheCodingMachine\GraphQL\Controllers\Fixtures\TestObject2;
20
use TheCodingMachine\GraphQL\Controllers\Mappers\CannotMapTypeException;
21
use TheCodingMachine\GraphQL\Controllers\Mappers\RecursiveTypeMapper;
22
use TheCodingMachine\GraphQL\Controllers\Mappers\RecursiveTypeMapperInterface;
23
use TheCodingMachine\GraphQL\Controllers\Mappers\TypeMapperInterface;
24
use TheCodingMachine\GraphQL\Controllers\Containers\EmptyContainer;
25
use TheCodingMachine\GraphQL\Controllers\Containers\BasicAutoWiringContainer;
26
use TheCodingMachine\GraphQL\Controllers\Reflection\CachedDocBlockFactory;
27
use TheCodingMachine\GraphQL\Controllers\Security\VoidAuthenticationService;
28
use TheCodingMachine\GraphQL\Controllers\Security\VoidAuthorizationService;
29
30
abstract class AbstractQueryProviderTest extends TestCase
31
{
32
    private $testObjectType;
33
    private $testObjectType2;
34
    private $inputTestObjectType;
35
    private $typeMapper;
36
    private $hydrator;
37
    private $registry;
38
    private $typeGenerator;
39
    private $controllerQueryProviderFactory;
40
    private $annotationReader;
41
42
    protected function getTestObjectType()
43
    {
44
        if ($this->testObjectType === null) {
45
            $this->testObjectType = new ObjectType([
46
                'name'    => 'TestObject',
47
                'fields'  => [
48
                    'test'   => Type::string(),
49
                ],
50
            ]);
51
        }
52
        return $this->testObjectType;
53
    }
54
55
    protected function getTestObjectType2()
56
    {
57
        if ($this->testObjectType2 === null) {
58
            $this->testObjectType2 = new ObjectType([
59
                'name'    => 'TestObject2',
60
                'fields'  => [
61
                    'test'   => Type::string(),
62
                ],
63
            ]);
64
        }
65
        return $this->testObjectType2;
66
    }
67
68
    protected function getInputTestObjectType()
69
    {
70
        if ($this->inputTestObjectType === null) {
71
            $this->inputTestObjectType = new InputObjectType([
72
                'name'    => 'TestObject',
73
                'fields'  => [
74
                    'test'   => Type::string(),
75
                ],
76
            ]);
77
        }
78
        return $this->inputTestObjectType;
79
    }
80
81
    protected function getTypeMapper()
82
    {
83
        if ($this->typeMapper === null) {
84
            $this->typeMapper = new RecursiveTypeMapper(new class($this->getTestObjectType(), $this->getTestObjectType2(), $this->getInputTestObjectType()) implements TypeMapperInterface {
85
                /**
86
                 * @var ObjectType
87
                 */
88
                private $testObjectType;
89
                /**
90
                 * @var ObjectType
91
                 */
92
                private $testObjectType2;
93
                /**
94
                 * @var InputObjectType
95
                 */
96
                private $inputTestObjectType;
97
98
                public function __construct(ObjectType $testObjectType, ObjectType $testObjectType2, InputObjectType $inputTestObjectType)
99
                {
100
                    $this->testObjectType = $testObjectType;
101
                    $this->testObjectType2 = $testObjectType2;
102
                    $this->inputTestObjectType = $inputTestObjectType;
103
                }
104
105
                public function mapClassToType(string $className, RecursiveTypeMapperInterface $recursiveTypeMapper): ObjectType
106
                {
107
                    if ($className === TestObject::class) {
108
                        return $this->testObjectType;
109
                    } elseif ($className === TestObject2::class) {
110
                        return $this->testObjectType2;
111
                    } else {
112
                        throw CannotMapTypeException::createForType($className);
113
                    }
114
                }
115
116
                public function mapClassToInputType(string $className): InputType
117
                {
118
                    if ($className === TestObject::class) {
119
                        return $this->inputTestObjectType;
120
                    } else {
121
                        throw CannotMapTypeException::createForInputType($className);
122
                    }
123
                }
124
125
                public function canMapClassToType(string $className): bool
126
                {
127
                    return $className === TestObject::class || $className === TestObject2::class;
128
                }
129
130
                /**
131
                 * Returns true if this type mapper can map the $className FQCN to a GraphQL input type.
132
                 *
133
                 * @param string $className
134
                 * @return bool
135
                 */
136
                public function canMapClassToInputType(string $className): bool
137
                {
138
                    return $className === TestObject::class || $className === TestObject2::class;
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
                    return [TestObject::class, TestObject2::class];
149
                }
150
151
                /**
152
                 * Returns a GraphQL type by name (can be either an input or output type)
153
                 *
154
                 * @param string $typeName The name of the GraphQL type
155
                 * @return Type&(InputType|OutputType)
156
                 * @throws CannotMapTypeException
157
                 */
158
                public function mapNameToType(string $typeName, RecursiveTypeMapperInterface $recursiveTypeMapper): Type
159
                {
160
                    switch ($typeName) {
161
                        case 'TestObject':
162
                            return $this->testObjectType;
163
                        case 'TestObject2':
164
                            return $this->testObjectType2;
165
                        default:
166
                            throw CannotMapTypeException::createForName($typeName);
167
                    }
168
                }
169
170
                /**
171
                 * Returns true if this type mapper can map the $typeName GraphQL name to a GraphQL type.
172
                 *
173
                 * @param string $typeName The name of the GraphQL type
174
                 * @return bool
175
                 */
176
                public function canMapNameToType(string $typeName): bool
177
                {
178
                    return $typeName === 'TestObject' || $typeName === 'TestObject2';
179
                }
180
            }, new NamingStrategy(), new ArrayCache());
181
        }
182
        return $this->typeMapper;
183
    }
184
185
    protected function getHydrator()
186
    {
187
        if ($this->hydrator === null) {
188
            $this->hydrator = new class implements HydratorInterface {
189
                public function hydrate(array $data, InputType $type)
190
                {
191
                    return new TestObject($data['test']);
192
                }
193
            };
194
        }
195
        return $this->hydrator;
196
    }
197
198
    protected function getRegistry()
199
    {
200
        if ($this->registry === null) {
201
            $this->registry = $this->buildAutoWiringContainer(new Picotainer([
202
                'customOutput' => function() {
203
                    return new StringType();
204
                }
205
            ]));
206
        }
207
        return $this->registry;
208
    }
209
210
    protected function buildAutoWiringContainer(ContainerInterface $container): BasicAutoWiringContainer
211
    {
212
        return new BasicAutoWiringContainer($container);
213
    }
214
215
    protected function getAnnotationReader(): AnnotationReader
216
    {
217
        if ($this->annotationReader === null) {
218
            $this->annotationReader = new AnnotationReader(new DoctrineAnnotationReader());
219
        }
220
        return $this->annotationReader;
221
    }
222
223
    protected function buildControllerQueryProvider($controller)
224
    {
225
        return new ControllerQueryProvider(
226
            $controller,
227
            $this->getAnnotationReader(),
228
            $this->getTypeMapper(),
229
            $this->getHydrator(),
230
            new VoidAuthenticationService(),
231
            new VoidAuthorizationService(),
232
            $this->getRegistry(),
233
            new CachedDocBlockFactory(new ArrayCache())
234
        );
235
    }
236
237
    protected function getTypeGenerator(): TypeGenerator
238
    {
239
        if ($this->typeGenerator === null) {
240
            $this->typeGenerator = new TypeGenerator($this->getAnnotationReader(), $this->getControllerQueryProviderFactory());
241
        }
242
        return $this->typeGenerator;
243
    }
244
245
    protected function getControllerQueryProviderFactory(): ControllerQueryProviderFactory
246
    {
247
        if ($this->controllerQueryProviderFactory === null) {
248
            $this->controllerQueryProviderFactory = new ControllerQueryProviderFactory($this->getAnnotationReader(),
249
                $this->getHydrator(),
250
                new VoidAuthenticationService(),
251
                new VoidAuthorizationService(),
252
                $this->getRegistry(),
253
                new CachedDocBlockFactory(new ArrayCache()));
254
        }
255
        return $this->controllerQueryProviderFactory;
256
    }
257
}
258