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 ( e42a09...f71048 )
by Cees-Jan
8s
created

Hydrator::extractFQCN()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

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