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 ( bc8140...045964 )
by Cees-Jan
02:08
created

Hydrator::hydrateFQCN()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 7
cts 7
cp 1
rs 9.6666
c 0
b 0
f 0
cc 1
eloc 7
nc 1
nop 2
crap 1
1
<?php declare(strict_types=1);
2
3
namespace ApiClients\Foundation\Hydrator;
4
5
use ApiClients\Foundation\Hydrator\Annotations\EmptyResource;
6
use ApiClients\Foundation\Hydrator\CommandBus\Command\BuildAsyncFromSyncCommand;
7
use ApiClients\Foundation\Hydrator\CommandBus\Command\ExtractCommand;
8
use ApiClients\Foundation\Hydrator\CommandBus\Command\ExtractFQCNCommand;
9
use ApiClients\Foundation\Hydrator\CommandBus\Command\HydrateCommand;
10
use ApiClients\Foundation\Hydrator\CommandBus\Command\HydrateFQCNCommand;
11
use ApiClients\Foundation\Hydrator\CommandBus\Handler\BuildAsyncFromSyncHandler;
12
use ApiClients\Foundation\Hydrator\CommandBus\Handler\ExtractFQCNHandler;
13
use ApiClients\Foundation\Hydrator\CommandBus\Handler\ExtractHandler;
14
use ApiClients\Foundation\Hydrator\CommandBus\Handler\HydrateFQCNHandler;
15
use ApiClients\Foundation\Hydrator\CommandBus\Handler\HydrateHandler;
16
use ApiClients\Foundation\Resource\EmptyResourceInterface;
17
use Doctrine\Common\Annotations\AnnotationReader;
18
use Doctrine\Common\Annotations\CachedReader;
19
use Doctrine\Common\Annotations\Reader;
20
use Doctrine\Common\Cache\Cache;
21
use GeneratedHydrator\Configuration;
22
use League\Tactician\CommandBus;
23
use League\Tactician\Setup\QuickStart;
24
use ReflectionClass;
25
use RecursiveDirectoryIterator;
26
use RecursiveIteratorIterator;
27
use ApiClients\Foundation\Resource\ResourceInterface;
28
use ApiClients\Foundation\Resource\AbstractResource;
29
use Zend\Hydrator\HydratorInterface;
30
31
class Hydrator
32
{
33
    /**
34
     * @var array
35
     */
36
    protected $options;
37
38
    /**
39
     * @var array
40
     */
41
    protected $hydrators = [];
42
43
    /**
44
     * @var array
45
     */
46
    protected $annotations = [];
47
48
    /**
49
     * @var HandlerInterface[]
50
     */
51
    protected $annotationHandlers = [];
52
53
    /**
54
     * @var CommandBus
55
     */
56
    protected $commandBus;
57
58
    /**
59
     * @var Reader
60
     */
61
    protected $annotationReader;
62
63
    /**
64
     * @param array $options
65
     */
66 6
    public function __construct(array $options)
67
    {
68 6
        $this->options = $options;
69
70 6
        $reader = new AnnotationReader();
71 6
        if (isset($this->options[Options::ANNOTATION_CACHE]) &&
72 6
            $this->options[Options::ANNOTATION_CACHE] instanceof Cache
73
        ) {
74 1
            $reader = new CachedReader(
75
                $reader,
76 1
                $this->options[Options::ANNOTATION_CACHE]
77
            );
78
        }
79 6
        $this->annotationReader = $reader;
80
81 6
        $this->setUpAnnotations();
82 6
        $this->createCommandBus();
83 6
    }
84
85 6
    protected function setUpAnnotations()
86
    {
87 6
        if (!isset($this->options[Options::ANNOTATIONS])) {
88
            return;
89
        }
90
91 6
        foreach ($this->options[Options::ANNOTATIONS] as $annotationClass => $handler) {
92 6
            $this->annotationHandlers[$annotationClass] = new $handler($this);
93
        }
94 6
    }
95
96 6
    protected function createCommandBus()
97
    {
98 6
        $this->options[Options::COMMAND_BUS][BuildAsyncFromSyncCommand::class] =
99 6
            new BuildAsyncFromSyncHandler($this);
100 6
        $this->options[Options::COMMAND_BUS][ExtractCommand::class] = new ExtractHandler($this);
101 6
        $this->options[Options::COMMAND_BUS][ExtractFQCNCommand::class] = new ExtractFQCNHandler($this);
102 6
        $this->options[Options::COMMAND_BUS][HydrateCommand::class] = new HydrateHandler($this);
103 6
        $this->options[Options::COMMAND_BUS][HydrateFQCNCommand::class] = new HydrateFQCNHandler($this);
104 6
        $this->commandBus = QuickStart::create($this->options[Options::COMMAND_BUS]);
105 6
    }
106
107 2
    public function preheat(string $scanTarget, string $namespace)
108
    {
109 2
        $directory = new RecursiveDirectoryIterator($scanTarget);
110 2
        $directory = new RecursiveIteratorIterator($directory);
111
112 2
        foreach ($directory as $node) {
113 2
            if (!is_file($node->getPathname())) {
114 2
                continue;
115
            }
116
117 2
            $file = substr($node->getPathname(), strlen($scanTarget));
118 2
            $file = ltrim($file, DIRECTORY_SEPARATOR);
119 2
            $file = rtrim($file, '.php');
120
121 2
            $class = $namespace . '\\' . str_replace(DIRECTORY_SEPARATOR, '\\', $file);
122
123 2
            if (!class_exists($class)) {
124
                continue;
125
            }
126
127 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...
128
                continue;
129
            }
130
131 2
            $this->getHydrator($class);
132 2
            $this->annotationReader->getClassAnnotations(new ReflectionClass($class));
133
        }
134 2
    }
135
136
    /**
137
     * @param string $class
138
     * @param array $json
139
     * @return ResourceInterface
140
     */
141 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...
142
    {
143 4
        $fullClassName = implode(
144 4
            '\\',
145
            [
146
                $this->options[Options::NAMESPACE],
147 4
                $this->options[Options::NAMESPACE_SUFFIX],
148 4
                $class,
149
            ]
150
        );
151 4
        return $this->hydrateFQCN($fullClassName, $json);
152
    }
153
154
    /**
155
     * @param string $class
156
     * @param array $json
157
     * @return ResourceInterface
158
     */
159 4
    public function hydrateFQCN(string $class, array $json): ResourceInterface
160
    {
161 4
        $class = $this->getEmptyOrResource($class, $json);
162 4
        $hydrator = $this->getHydrator($class);
163 4
        $object = new $class($this->commandBus);
164 4
        $json = $this->hydrateApplyAnnotations($json, $object);
165 4
        $resource = $hydrator->hydrate($json, $object);
166 4
        return $resource;
167
    }
168
169
    /**
170
     * @param array $json
171
     * @param ResourceInterface $object
172
     * @return array
173
     */
174 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...
175
    {
176 4
        foreach ($this->annotationHandlers as $annotationClass => $handler) {
177 4
            $annotation = $this->getAnnotation($object, $annotationClass);
178 4
            if ($annotation === null) {
179 4
                continue;
180
            }
181
182 4
            $json = $handler->hydrate($annotation, $json, $object);
183
        }
184
185 4
        return $json;
186
    }
187
188 4
    protected function getEmptyOrResource(string $class, array $json): string
189
    {
190 4
        if (count($json) > 0) {
191 4
            return $class;
192
        }
193
194 4
        $annotation = $this->getAnnotation(new $class($this->commandBus), EmptyResource::class);
195
196 4
        if (!($annotation instanceof EmptyResource)) {
197
            return $class;
198
        }
199
200
        $emptyClass = $this->options[Options::NAMESPACE] .
201 4
            '\\' .
202 4
            $this->options[Options::NAMESPACE_SUFFIX] .
203 4
            '\\' .
204
            $annotation->getEmptyReplacement();
205
206 4
        if (!class_exists($emptyClass)) {
207
            return $class;
208
        }
209
210 4
        return $emptyClass;
211
    }
212
213
    /**
214
     * @param string $class
215
     * @param ResourceInterface $object
216
     * @return array
217
     */
218 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...
219
    {
220 2
        $fullClassName = implode(
221 2
            '\\',
222
            [
223
                $this->options[Options::NAMESPACE],
224 2
                $this->options[Options::NAMESPACE_SUFFIX],
225 2
                $class,
226
            ]
227
        );
228 2
        return $this->extractFQCN($fullClassName, $object);
229
    }
230
231
    /**
232
     * Takes a fully qualified class name and extracts the data for that class from the given $object
233
     * @param string $class
234
     * @param ResourceInterface $object
235
     * @return array
236
     */
237 2
    public function extractFQCN(string $class, ResourceInterface $object): array
238
    {
239 2
        if ($object instanceof EmptyResourceInterface) {
240 2
            return [];
241
        }
242
243 2
        $json = $this->getHydrator($class)->extract($object);
244 2
        $json = $this->extractApplyAnnotations($object, $json);
245 2
        return $json;
246
    }
247
248
    /**
249
     * @param array $json
250
     * @param ResourceInterface $object
251
     * @return array
252
     */
253 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...
254
    {
255 2
        foreach ($this->annotationHandlers as $annotationClass => $handler) {
256 2
            $annotation = $this->getAnnotation($object, $annotationClass);
257 2
            if ($annotation === null) {
258 2
                continue;
259
            }
260
261 2
            $json = $handler->extract($annotation, $object, $json);
262
        }
263
264 2
        return $json;
265
    }
266
267
    /**
268
     * @param ResourceInterface $object
269
     * @param string $annotationClass
270
     * @return null|AnnotationInterface
271
     */
272 4
    protected function getAnnotation(ResourceInterface $object, string $annotationClass)
273
    {
274 4
        $class = get_class($object);
275 4
        if (isset($this->annotations[$class][$annotationClass])) {
276 2
            return $this->annotations[$class][$annotationClass];
277
        }
278
279 4
        if (!isset($this->annotations[$class])) {
280 4
            $this->annotations[$class] = [];
281
        }
282
283 4
        $this->annotations[$class][$annotationClass] = $this->annotationReader
284 4
            ->getClassAnnotation(
285 4
                new ReflectionClass($object),
286
                $annotationClass
287
            )
288
        ;
289
290 4
        if (get_class($this->annotations[$class][$annotationClass]) === $annotationClass) {
291
            return $this->annotations[$class][$annotationClass];
292
        }
293
294 4
        $this->annotations[$class][$annotationClass] = $this->annotationReader
295 4
            ->getClassAnnotation(
296 4
                new ReflectionClass(get_parent_class($object)),
297
                $annotationClass
298
            )
299
        ;
300
301 4
        return $this->annotations[$class][$annotationClass];
302
    }
303
304
    /**
305
     * @param string $resource
306
     * @param ResourceInterface $object
307
     * @return ResourceInterface
308
     */
309 1
    public function buildAsyncFromSync(string $resource, ResourceInterface $object): ResourceInterface
310
    {
311 1
        return $this->hydrateFQCN(
312
            $this->options[Options::NAMESPACE] . '\\Async\\' . $resource,
313 1
            $this->extractFQCN(
314
                $this->options[Options::NAMESPACE] . '\\Sync\\' . $resource,
315
                $object
316
            )
317
        );
318
    }
319
320
    /**
321
     * @param string $class
322
     * @return HydratorInterface
323
     */
324 6
    protected function getHydrator(string $class): HydratorInterface
325
    {
326 6
        if (isset($this->hydrators[$class])) {
327 4
            return $this->hydrators[$class];
328
        }
329
330 6
        $config = new Configuration($class);
331 6
        if (isset($this->options[Options::RESOURCE_CACHE_DIR])) {
332 6
            $config->setGeneratedClassesTargetDir($this->options[Options::RESOURCE_CACHE_DIR]);
333
        }
334 6
        if (isset($this->options[Options::RESOURCE_NAMESPACE])) {
335 6
            $config->setGeneratedClassesNamespace($this->options[Options::RESOURCE_NAMESPACE]);
336
        }
337 6
        $hydrator = $config->createFactory()->getHydratorClass();
338 6
        $this->hydrators[$class] = new $hydrator;
339
340 6
        return $this->hydrators[$class];
341
    }
342
343
    /**
344
     * @return CommandBus
345
     */
346
    public function getCommandBus(): CommandBus
347
    {
348
        return $this->commandBus;
349
    }
350
}
351