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

Registry::isGraphqlType()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 10
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
3
4
namespace TheCodingMachine\GraphQL\Controllers\Registry;
5
6
use function class_exists;
7
use Doctrine\Common\Annotations\Reader;
8
use Psr\Container\ContainerExceptionInterface;
9
use Psr\Container\ContainerInterface;
10
use Psr\Container\NotFoundExceptionInterface;
11
use TheCodingMachine\GraphQL\Controllers\HydratorInterface;
12
use TheCodingMachine\GraphQL\Controllers\Security\AuthenticationServiceInterface;
13
use TheCodingMachine\GraphQL\Controllers\Security\AuthorizationServiceInterface;
14
use TheCodingMachine\GraphQL\Controllers\Mappers\TypeMapperInterface;
15
use GraphQL\Type\Definition\ObjectType;
16
use TheCodingMachine\GraphQL\Controllers\TypeGenerator;
17
18
/**
19
 * The role of the registry is to provide access to all GraphQL types.
20
 * If the type is not found, it can be queried from the container, or if not in the container, it can be created from the Registry itself.
21
 */
22
class Registry implements RegistryInterface
23
{
24
25
    /**
26
     * @var ContainerInterface
27
     */
28
    private $container;
29
30
    /**
31
     * @var ObjectType[]
32
     */
33
    private $values = [];
34
    /**
35
     * @var null|AuthorizationServiceInterface
36
     */
37
    private $authorizationService;
38
    /**
39
     * @var AuthenticationServiceInterface
40
     */
41
    private $authenticationService;
42
    /**
43
     * @var Reader
44
     */
45
    private $annotationReader;
46
    /**
47
     * @var TypeMapperInterface
48
     */
49
    private $typeMapper;
50
    /**
51
     * @var HydratorInterface
52
     */
53
    private $hydrator;
54
55
    /**
56
     * @param ContainerInterface $container The proxied container.
57
     */
58
    public function __construct(ContainerInterface $container, AuthorizationServiceInterface $authorizationService, AuthenticationServiceInterface $authenticationService, Reader $annotationReader, TypeMapperInterface $typeMapper, HydratorInterface $hydrator)
59
    {
60
        $this->container = $container;
61
        $this->authorizationService = $authorizationService;
62
        $this->authenticationService = $authenticationService;
63
        $this->annotationReader = $annotationReader;
64
        $this->typeMapper = $typeMapper;
65
        $this->hydrator = $hydrator;
66
    }
67
68
    /**
69
     * Finds an entry of the container by its identifier and returns it.
70
     *
71
     * @param string $id Identifier of the entry to look for.
72
     *
73
     * @throws NotFoundExceptionInterface  No entry was found for **this** identifier.
74
     * @throws ContainerExceptionInterface Error while retrieving the entry.
75
     *
76
     * @return mixed Entry.
77
     */
78
    public function get($id)
79
    {
80
        if (isset($this->values[$id])) {
81
            return $this->values[$id];
82
        }
83
        if ($this->container->has($id)) {
84
            return $this->container->get($id);
85
        }
86
87
        // The registry will try to instantiate the type if the class exists and has an annotation.
88
89
90
        /*if (is_a($id, ObjectType::class, true)) {
91
            $this->values[$id] = new $id($this);
92
            return $this->values[$id];
93
        }*/
94
        if ($this->isGraphqlType($id)) {
95
            $refTypeClass = new \ReflectionClass($id);
96
            if ($refTypeClass->hasMethod('__construct') && $refTypeClass->getMethod('__construct')->getNumberOfRequiredParameters() > 0) {
97
                throw NotFoundException::notFoundInContainer($id);
98
            }
99
            // FIXME: TypeGenerator is hard coded here
100
            $typeGenerator = new TypeGenerator($this);
101
            $this->values[$id] = $typeGenerator->mapAnnotatedObject(new $id());
102
            return $this->values[$id];
103
        }
104
105
106
        throw NotFoundException::notFound($id);
107
    }
108
109
    private function isGraphqlType(string $className) : bool
110
    {
111
        if (!class_exists($className))  {
112
            return false;
113
        }
114
        $refTypeClass = new \ReflectionClass($className);
115
116
        /** @var \TheCodingMachine\GraphQL\Controllers\Annotations\Type|null $typeField */
117
        $typeField = $this->getAnnotationReader()->getClassAnnotation($refTypeClass, \TheCodingMachine\GraphQL\Controllers\Annotations\Type::class);
118
        return $typeField !== null;
119
    }
120
121
    /**
122
     * Returns true if the container can return an entry for the given identifier.
123
     * Returns false otherwise.
124
     *
125
     * `has($id)` returning true does not mean that `get($id)` will not throw an exception.
126
     * It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface`.
127
     *
128
     * @param string $id Identifier of the entry to look for.
129
     *
130
     * @return bool
131
     */
132
    public function has($id)
133
    {
134
        if (isset($this->values[$id])) {
135
            return true;
136
        }
137
        if ($this->container->has($id)) {
138
            return true;
139
        }
140
141
        /*if (is_a($id, ObjectType::class, true)) {
142
            return true;
143
        }*/
144
        return $this->isGraphqlType($id);
145
    }
146
147
    /**
148
     * Returns the authorization service.
149
     *
150
     * @return AuthorizationServiceInterface
151
     */
152
    public function getAuthorizationService(): AuthorizationServiceInterface
153
    {
154
        return $this->authorizationService;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->authorizationService could return the type null which is incompatible with the type-hinted return TheCodingMachine\GraphQL...izationServiceInterface. Consider adding an additional type-check to rule them out.
Loading history...
155
    }
156
157
    /**
158
     * @return AuthenticationServiceInterface
159
     */
160
    public function getAuthenticationService(): AuthenticationServiceInterface
161
    {
162
        return $this->authenticationService;
163
    }
164
165
    /**
166
     * @return Reader
167
     */
168
    public function getAnnotationReader(): Reader
169
    {
170
        return $this->annotationReader;
171
    }
172
173
    /**
174
     * @return TypeMapperInterface
175
     */
176
    public function getTypeMapper(): TypeMapperInterface
177
    {
178
        return $this->typeMapper;
179
    }
180
181
    /**
182
     * @return HydratorInterface
183
     */
184
    public function getHydrator(): HydratorInterface
185
    {
186
        return $this->hydrator;
187
    }
188
}
189