Completed
Pull Request — master (#60)
by David
03:41
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
        return $this->typeMapper;
172
    }
173
174
    protected function getHydrator()
175
    {
176
        if ($this->hydrator === null) {
177
            $this->hydrator = new class implements HydratorInterface {
178
                public function hydrate(array $data, InputType $type)
179
                {
180
                    return new TestObject($data['test']);
181
                }
182
            };
183
        }
184
        return $this->hydrator;
185
    }
186
187
    protected function getRegistry()
188
    {
189
        if ($this->registry === null) {
190
            $this->registry = $this->buildAutoWiringContainer(new Picotainer([
191
                'customOutput' => function() {
192
                    return new StringType();
193
                }
194
            ]));
195
        }
196
        return $this->registry;
197
    }
198
199
    protected function buildAutoWiringContainer(ContainerInterface $container): BasicAutoWiringContainer
200
    {
201
        return new BasicAutoWiringContainer($container);
202
    }
203
204
    protected function getAnnotationReader(): AnnotationReader
205
    {
206
        if ($this->annotationReader === null) {
207
            $this->annotationReader = new AnnotationReader(new DoctrineAnnotationReader());
208
        }
209
        return $this->annotationReader;
210
    }
211
212
    protected function buildControllerQueryProvider($controller)
213
    {
214
        return new ControllerQueryProvider(
215
            $controller,
216
            $this->getAnnotationReader(),
217
            $this->getTypeMapper(),
218
            $this->getHydrator(),
219
            new VoidAuthenticationService(),
220
            new VoidAuthorizationService(),
221
            $this->getRegistry(),
222
            new CachedDocBlockFactory(new ArrayCache())
223
        );
224
    }
225
226
    protected function getTypeGenerator(): TypeGenerator
227
    {
228
        if ($this->typeGenerator === null) {
229
            $this->typeGenerator = new TypeGenerator($this->getAnnotationReader(), $this->getControllerQueryProviderFactory());
230
        }
231
        return $this->typeGenerator;
232
    }
233
234
    protected function getControllerQueryProviderFactory(): ControllerQueryProviderFactory
235
    {
236
        if ($this->controllerQueryProviderFactory === null) {
237
            $this->controllerQueryProviderFactory = new ControllerQueryProviderFactory($this->getAnnotationReader(),
238
                $this->getHydrator(),
239
                new VoidAuthenticationService(),
240
                new VoidAuthorizationService(),
241
                $this->getRegistry(),
242
                new CachedDocBlockFactory(new ArrayCache()));
243
        }
244
        return $this->controllerQueryProviderFactory;
245
    }
246
}
247