GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 34dad4...932e75 )
by Cees-Jan
9s
created

Hydrator::getHydrator()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 18
ccs 11
cts 11
cp 1
rs 9.2
c 0
b 0
f 0
cc 4
eloc 11
nc 5
nop 1
crap 4
1
<?php declare(strict_types=1);
2
3
namespace ApiClients\Foundation\Hydrator;
4
5
use ApiClients\Foundation\Hydrator\Annotations\EmptyResource;
6
use ApiClients\Foundation\Resource\EmptyResourceInterface;
7
use ApiClients\Tools\CommandBus\CommandBus;
8
use Doctrine\Common\Annotations\AnnotationReader;
9
use Doctrine\Common\Annotations\CachedReader;
10
use Doctrine\Common\Annotations\Reader;
11
use Doctrine\Common\Cache\Cache;
12
use GeneratedHydrator\Configuration;
13
use Interop\Container\ContainerInterface;
14
use ReflectionClass;
15
use RecursiveDirectoryIterator;
16
use RecursiveIteratorIterator;
17
use ApiClients\Foundation\Resource\ResourceInterface;
18
use Zend\Hydrator\HydratorInterface;
19
20
class Hydrator
21
{
22
    /**
23
     * @var ContainerInterface
24
     */
25
    protected $container;
26
27
    /**
28
     * @var array
29
     */
30
    protected $options;
31
32
    /**
33
     * @var array
34
     */
35
    protected $hydrators = [];
36
37
    /**
38
     * @var array
39
     */
40
    protected $annotations = [];
41
42
    /**
43
     * @var HandlerInterface[]
44
     */
45
    protected $annotationHandlers = [];
46
47
    /**
48
     * @var Reader
49
     */
50
    protected $annotationReader;
51
52
    /**
53
     * @param ContainerInterface $container
54
     * @param array $options
55
     */
56 8
    public function __construct(ContainerInterface $container, array $options)
57
    {
58 8
        $this->container = $container;
59 8
        $this->options = $options;
60
61 8
        $reader = new AnnotationReader();
62 8
        if (isset($this->options[Options::ANNOTATION_CACHE]) &&
63 8
            $this->options[Options::ANNOTATION_CACHE] instanceof Cache
64
        ) {
65 1
            $reader = new CachedReader(
66
                $reader,
67 1
                $this->options[Options::ANNOTATION_CACHE]
68
            );
69
        }
70 8
        $this->annotationReader = $reader;
71
72 8
        $this->setUpAnnotations();
73 8
    }
74
75 8
    protected function setUpAnnotations()
76
    {
77 8
        if (!isset($this->options[Options::ANNOTATIONS])) {
78
            return;
79
        }
80
81 8
        foreach ($this->options[Options::ANNOTATIONS] as $annotationClass => $handler) {
82 8
            $this->annotationHandlers[$annotationClass] = new $handler($this);
83
        }
84 8
    }
85
86 2
    public function preheat(string $scanTarget, string $namespace)
87
    {
88 2
        $directory = new RecursiveDirectoryIterator($scanTarget);
89 2
        $directory = new RecursiveIteratorIterator($directory);
90
91 2
        foreach ($directory as $node) {
92 2
            if (!is_file($node->getPathname())) {
93 2
                continue;
94
            }
95
96 2
            $file = substr($node->getPathname(), strlen($scanTarget));
97 2
            $file = ltrim($file, DIRECTORY_SEPARATOR);
98 2
            $file = rtrim($file, '.php');
99
100 2
            $class = $namespace . '\\' . str_replace(DIRECTORY_SEPARATOR, '\\', $file);
101
102 2
            if (!class_exists($class)) {
103
                continue;
104
            }
105
106 2
            if (!is_subclass_of($class, ResourceInterface::class)) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if \ApiClients\Foundation\R...esourceInterface::class can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
107
                continue;
108
            }
109
110 2
            $this->getHydrator($class);
111 2
            $this->annotationReader->getClassAnnotations(new ReflectionClass($class));
112
        }
113 2
    }
114
115
    /**
116
     * @param string $class
117
     * @param array $json
118
     * @return ResourceInterface
119
     */
120 4 View Code Duplication
    public function hydrate(string $class, array $json): ResourceInterface
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
121
    {
122 4
        $fullClassName = implode(
123 4
            '\\',
124
            [
125
                $this->options[Options::NAMESPACE],
126 4
                $this->options[Options::NAMESPACE_SUFFIX],
127 4
                $class,
128
            ]
129
        );
130 4
        return $this->hydrateFQCN($fullClassName, $json);
131
    }
132
133
    /**
134
     * @param string $class
135
     * @param array $json
136
     * @return ResourceInterface
137
     */
138 4
    public function hydrateFQCN(string $class, array $json): ResourceInterface
139
    {
140 4
        $class = $this->getEmptyOrResource($class, $json);
141 4
        $hydrator = $this->getHydrator($class);
142 4
        $object = new $class($this->container->get(CommandBus::class));
143 4
        $json = $this->hydrateApplyAnnotations($json, $object);
144 4
        $resource = $hydrator->hydrate($json, $object);
145 4
        return $resource;
146
    }
147
148
    /**
149
     * @param array $json
150
     * @param ResourceInterface $object
151
     * @return array
152
     */
153 4 View Code Duplication
    protected function hydrateApplyAnnotations(array $json, ResourceInterface $object): array
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
154
    {
155 4
        foreach ($this->annotationHandlers as $annotationClass => $handler) {
156 4
            $annotation = $this->getAnnotation($object, $annotationClass);
157 4
            if ($annotation === null) {
158 4
                continue;
159
            }
160
161 4
            $json = $handler->hydrate($annotation, $json, $object);
162
        }
163
164 4
        return $json;
165
    }
166
167 4
    protected function getEmptyOrResource(string $class, array $json): string
168
    {
169 4
        if (count($json) > 0) {
170 4
            return $class;
171
        }
172
173 4
        $annotation = $this->getAnnotation(new $class($this->container->get(CommandBus::class)), EmptyResource::class);
174
175 4
        if (!($annotation instanceof EmptyResource)) {
176
            return $class;
177
        }
178
179
        $emptyClass = $this->options[Options::NAMESPACE] .
180 4
            '\\' .
181 4
            $this->options[Options::NAMESPACE_SUFFIX] .
182 4
            '\\' .
183
            $annotation->getEmptyReplacement();
184
185 4
        if (!class_exists($emptyClass)) {
186
            return $class;
187
        }
188
189 4
        return $emptyClass;
190
    }
191
192
    /**
193
     * @param string $class
194
     * @param ResourceInterface $object
195
     * @return array
196
     */
197 2 View Code Duplication
    public function extract(string $class, ResourceInterface $object): array
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
198
    {
199 2
        $fullClassName = implode(
200 2
            '\\',
201
            [
202
                $this->options[Options::NAMESPACE],
203 2
                $this->options[Options::NAMESPACE_SUFFIX],
204 2
                $class,
205
            ]
206
        );
207 2
        return $this->extractFQCN($fullClassName, $object);
208
    }
209
210
    /**
211
     * Takes a fully qualified class name and extracts the data for that class from the given $object
212
     * @param string $class
213
     * @param ResourceInterface $object
214
     * @return array
215
     */
216 2
    public function extractFQCN(string $class, ResourceInterface $object): array
217
    {
218 2
        if ($object instanceof EmptyResourceInterface) {
219 2
            return [];
220
        }
221
222 2
        $json = $this->getHydrator($class)->extract($object);
223 2
        $json = $this->extractApplyAnnotations($object, $json);
224 2
        return $json;
225
    }
226
227
    /**
228
     * @param array $json
229
     * @param ResourceInterface $object
230
     * @return array
231
     */
232 2 View Code Duplication
    protected function extractApplyAnnotations(ResourceInterface $object, array $json): array
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
233
    {
234 2
        foreach ($this->annotationHandlers as $annotationClass => $handler) {
235 2
            $annotation = $this->getAnnotation($object, $annotationClass);
236 2
            if ($annotation === null) {
237 2
                continue;
238
            }
239
240 2
            $json = $handler->extract($annotation, $object, $json);
241
        }
242
243 2
        return $json;
244
    }
245
246
    /**
247
     * @param ResourceInterface $object
248
     * @param string $annotationClass
249
     * @return null|AnnotationInterface
250
     */
251 4
    protected function getAnnotation(ResourceInterface $object, string $annotationClass)
252
    {
253 4
        $class = get_class($object);
254 4
        if (isset($this->annotations[$class][$annotationClass])) {
255 3
            return $this->annotations[$class][$annotationClass];
256
        }
257
258 4
        if (!isset($this->annotations[$class])) {
259 4
            $this->annotations[$class] = [];
260
        }
261
262 4
        $this->annotations[$class][$annotationClass] = $this->annotationReader
263 4
            ->getClassAnnotation(
264 4
                new ReflectionClass($object),
265
                $annotationClass
266
            )
267
        ;
268
269 4
        if ($this->annotations[$class][$annotationClass] !== null &&
270 4
            get_class($this->annotations[$class][$annotationClass]) === $annotationClass
271
        ) {
272
            return $this->annotations[$class][$annotationClass];
273
        }
274
275 4
        $this->annotations[$class][$annotationClass] = $this->annotationReader
276 4
            ->getClassAnnotation(
277 4
                new ReflectionClass(get_parent_class($object)),
278
                $annotationClass
279
            )
280
        ;
281
282 4
        return $this->annotations[$class][$annotationClass];
283
    }
284
285
    /**
286
     * @param string $resource
287
     * @param ResourceInterface $object
288
     * @return ResourceInterface
289
     */
290 1
    public function buildAsyncFromSync(string $resource, ResourceInterface $object): ResourceInterface
291
    {
292 1
        return $this->hydrateFQCN(
293
            $this->options[Options::NAMESPACE] . '\\Async\\' . $resource,
294 1
            $this->extractFQCN(
295
                $this->options[Options::NAMESPACE] . '\\Sync\\' . $resource,
296
                $object
297
            )
298
        );
299
    }
300
301
    /**
302
     * @param string $class
303
     * @return HydratorInterface
304
     */
305 6
    protected function getHydrator(string $class): HydratorInterface
306
    {
307 6
        if (isset($this->hydrators[$class])) {
308 4
            return $this->hydrators[$class];
309
        }
310
311 6
        $config = new Configuration($class);
312 6
        if (isset($this->options[Options::RESOURCE_CACHE_DIR])) {
313 6
            $config->setGeneratedClassesTargetDir($this->options[Options::RESOURCE_CACHE_DIR]);
314
        }
315 6
        if (isset($this->options[Options::RESOURCE_NAMESPACE])) {
316 6
            $config->setGeneratedClassesNamespace($this->options[Options::RESOURCE_NAMESPACE]);
317
        }
318 6
        $hydrator = $config->createFactory()->getHydratorClass();
319 6
        $this->hydrators[$class] = new $hydrator;
320
321 6
        return $this->hydrators[$class];
322
    }
323
}
324