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 ( 06b165...ec107c )
by Cees-Jan
03:40
created

Hydrator::getAnnotation()   B

Complexity

Conditions 4
Paths 5

Size

Total Lines 31
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 4.0047

Importance

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