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 ( d99cb6...ae5fa7 )
by Cees-Jan
7s
created

Hydrator   B

Complexity

Total Complexity 40

Size/Duplication

Total Lines 323
Duplicated Lines 31.58 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 94.07%

Importance

Changes 0
Metric Value
dl 102
loc 323
ccs 111
cts 118
cp 0.9407
rs 8.2608
c 0
b 0
f 0
wmc 40
lcom 1
cbo 7

15 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A hydrateFQCN() 0 9 1
A hydrateNestedResources() 18 18 4
B hydrateCollectionResources() 22 22 5
A hydrateRenameResourceProperties() 15 15 3
A hydrate() 0 5 1
A extractFQCN() 0 8 1
A extractNestedResources() 14 14 3
A extractCollectionResources() 18 18 4
A extractRenameResourceProperties() 15 15 3
B getAnnotation() 0 31 4
A extract() 0 5 1
A buildAsyncFromSync() 0 10 1
A getHydrator() 0 18 4
A createObject() 0 14 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Hydrator often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Hydrator, and based on these observations, apply Extract Interface, too.

1
<?php
2
declare(strict_types=1);
3
4
namespace WyriHaximus\ApiClient\Transport;
5
6
use Doctrine\Common\Annotations\AnnotationReader;
7
use GeneratedHydrator\Configuration;
8
use ReflectionClass;
9
use WyriHaximus\ApiClient\Annotations\Collection;
10
use WyriHaximus\ApiClient\Annotations\Nested;
11
use WyriHaximus\ApiClient\Annotations\Rename;
12
use WyriHaximus\ApiClient\Resource\ResourceInterface;
13
use Zend\Hydrator\HydratorInterface;
14
15
class Hydrator
16
{
17
    /**
18
     * @var array
19
     */
20
    protected $options;
21
22
    /**
23
     * @var Client
24
     */
25
    protected $transport;
26
27
    /**
28
     * @var array
29
     */
30
    protected $hydrators = [];
31
32
    /**
33
     * @var array
34
     */
35
    protected $annotations = [];
36
37
    /**
38
     * @var AnnotationReader
39
     */
40
    protected $annotationReader;
41
42
    /**
43
     * @param Client $transport
44
     * @param array $options
45
     */
46 17
    public function __construct(Client $transport, array $options)
47
    {
48 17
        $this->transport = $transport;
49 17
        $this->options = $options;
50 17
        $this->annotationReader = new AnnotationReader();
51 17
    }
52
53
    /**
54
     * @param string $class
55
     * @param array $json
56
     * @return ResourceInterface
57
     */
58 5
    public function hydrateFQCN(string $class, array $json): ResourceInterface
59
    {
60 5
        $hydrator = $this->getHydrator($class);
61 5
        $object = $this->createObject($class);
62 5
        $json = $this->hydrateNestedResources($object, $json);
63 5
        $json = $this->hydrateCollectionResources($object, $json);
64 5
        $json = $this->hydrateRenameResourceProperties($object, $json);
65 5
        return $hydrator->hydrate($json, $object);
66
    }
67
68
    /**
69
     * @param ResourceInterface $object
70
     * @param array $json
71
     * @return array
72
     */
73 5 View Code Duplication
    protected function hydrateNestedResources(ResourceInterface $object, array $json)
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...
74
    {
75 5
        $annotation = $this->getAnnotation($object, Nested::class);
76
77 5
        if (!($annotation instanceof Nested)) {
78 5
            return $json;
79
        }
80
81 5
        foreach ($annotation->properties() as $property) {
82 5
            if ($json[$property] === null) {
83
                continue;
84
            }
85
86 5
            $json[$property] = $this->hydrate($annotation->get($property), $json[$property]);
87
        }
88
89 5
        return $json;
90
    }
91
92
    /**
93
     * @param ResourceInterface $object
94
     * @param array $json
95
     * @return array
96
     */
97 5 View Code Duplication
    protected function hydrateCollectionResources(ResourceInterface $object, array $json)
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...
98
    {
99 5
        $annotation = $this->getAnnotation($object, Collection::class);
100
101 5
        if (!($annotation instanceof Collection)) {
102 5
            return $json;
103
        }
104
105 5
        foreach ($annotation->properties() as $property) {
106 5
            $array = $json[$property];
107 5
            $json[$property] = [];
108 5
            foreach ($array as $resource) {
109 5
                if ($resource === null) {
110
                    continue;
111
                }
112
113 5
                $json[$property][] = $this->hydrate($annotation->get($property), $resource);
114
            }
115
        }
116
117 5
        return $json;
118
    }
119
120
    /**
121
     * @param ResourceInterface $object
122
     * @param array $json
123
     * @return array
124
     */
125 5 View Code Duplication
    protected function hydrateRenameResourceProperties(ResourceInterface $object, array $json)
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...
126
    {
127 5
        $annotation = $this->getAnnotation($object, Rename::class);
128
129 5
        if (!($annotation instanceof Rename)) {
130 5
            return $json;
131
        }
132
133 5
        foreach ($annotation->properties() as $property) {
134 5
            $json[$property] = $json[$annotation->get($property)];
135 5
            unset($json[$annotation->get($property)]);
136
        }
137
138 5
        return $json;
139
    }
140
141
    /**
142
     * @param string $class
143
     * @param array $json
144
     * @return ResourceInterface
145
     */
146 5
    public function hydrate(string $class, array $json): ResourceInterface
147
    {
148 5
        $fullClassName = $this->options['namespace'] . '\\' . $this->options['resource_namespace'] . '\\' . $class;
149 5
        return $this->hydrateFQCN($fullClassName, $json);
150
    }
151
152
    /**
153
     * Takes a fully qualified class name and extracts the data for that class from the given $object
154
     * @param string $class
155
     * @param ResourceInterface $object
156
     * @return array
157
     */
158 2
    public function extractFQCN(string $class, ResourceInterface $object): array
159
    {
160 2
        $json = $this->getHydrator($class)->extract($object);
161 2
        $json = $this->extractNestedResources($json, $object);
162 2
        $json = $this->extractCollectionResources($json, $object);
163 2
        $json = $this->extractRenameResourceProperties($json, $object);
164 2
        return $json;
165
    }
166
167
    /**
168
     * @param array $json
169
     * @param ResourceInterface $object
170
     * @return array
171
     */
172 2 View Code Duplication
    protected function extractNestedResources(array $json, ResourceInterface $object)
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...
173
    {
174 2
        $annotation = $this->getAnnotation($object, Nested::class);
175
176 2
        if (!($annotation instanceof Nested)) {
177 2
            return $json;
178
        }
179
180 2
        foreach ($annotation->properties() as $property) {
181 2
            $json[$property] = $this->extract($annotation->get($property), $json[$property]);
182
        }
183
184 2
        return $json;
185
    }
186
187
    /**
188
     * @param array $json
189
     * @param ResourceInterface $object
190
     * @return array
191
     */
192 2 View Code Duplication
    protected function extractCollectionResources(array $json, ResourceInterface $object)
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...
193
    {
194 2
        $annotation = $this->getAnnotation($object, Collection::class);
195
196 2
        if (!($annotation instanceof Collection)) {
197 2
            return $json;
198
        }
199
200 2
        foreach ($annotation->properties() as $property) {
201 2
            $array = $json[$property];
202 2
            $json[$property] = [];
203 2
            foreach ($array as $resource) {
204 2
                $json[$property][] = $this->extract($annotation->get($property), $resource);
205
            }
206
        }
207
208 2
        return $json;
209
    }
210
211
    /**
212
     * @param array $json
213
     * @param ResourceInterface $object
214
     * @return array
215
     */
216 2 View Code Duplication
    protected function extractRenameResourceProperties(array $json, ResourceInterface $object)
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...
217
    {
218 2
        $annotation = $this->getAnnotation($object, Rename::class);
219
220 2
        if (!($annotation instanceof Rename)) {
221 2
            return $json;
222
        }
223
224 2
        foreach ($annotation->properties() as $property) {
225 2
            $json[$annotation->get($property)] = $json[$property];
226 2
            unset($json[$property]);
227
        }
228
229 2
        return $json;
230
    }
231
232
    /**
233
     * @param ResourceInterface $object
234
     * @param string $annotationClass
235
     * @return null|object
236
     */
237 5
    protected function getAnnotation(ResourceInterface $object, string $annotationClass)
238
    {
239 5
        $class = get_class($object);
240 5
        if (isset($this->annotations[$class][$annotationClass])) {
241 1
            return $this->annotations[$class][$annotationClass];
242
        }
243
244 5
        if (!isset($this->annotations[$class])) {
245 5
            $this->annotations[$class] = [];
246
        }
247
248 5
        $this->annotations[$class][$annotationClass] = $this->annotationReader
249 5
            ->getClassAnnotation(
250 5
                new ReflectionClass($object),
251
                $annotationClass
252
            )
253
        ;
254
255 5
        if (get_class($this->annotations[$class][$annotationClass]) === $annotationClass) {
256
            return $this->annotations[$class][$annotationClass];
257
        }
258
259 5
        $this->annotations[$class][$annotationClass] = $this->annotationReader
260 5
            ->getClassAnnotation(
261 5
                new ReflectionClass(get_parent_class($object)),
262
                $annotationClass
263
            )
264
        ;
265
266 5
        return $this->annotations[$class][$annotationClass];
267
    }
268
269
    /**
270
     * @param string $class
271
     * @param ResourceInterface $object
272
     * @return array
273
     */
274 2
    public function extract(string $class, ResourceInterface $object): array
275
    {
276 2
        $fullClassName = $this->options['namespace'] . '\\' . $this->options['resource_namespace'] . '\\' . $class;
277 2
        return $this->extractFQCN($fullClassName, $object);
278
    }
279
280
    /**
281
     * @param string $resource
282
     * @param ResourceInterface $object
283
     * @return ResourceInterface
284
     */
285 1
    public function buildAsyncFromSync(string $resource, ResourceInterface $object): ResourceInterface
286
    {
287 1
        return $this->hydrateFQCN(
288 1
            $this->options['namespace'] . '\\Async\\' . $resource,
289 1
            $this->extractFQCN(
290 1
                $this->options['namespace'] . '\\Sync\\' . $resource,
291
                $object
292
            )
293
        );
294
    }
295
296
    /**
297
     * @param string $class
298
     * @return HydratorInterface
299
     */
300 5
    protected function getHydrator(string $class): HydratorInterface
301
    {
302 5
        if (isset($this->hydrators[$class])) {
303 5
            return $this->hydrators[$class];
304
        }
305
306 5
        $config = new Configuration($class);
307 5
        if (isset($this->options['resource_hydrator_cache_dir'])) {
308 5
            $config->setGeneratedClassesTargetDir($this->options['resource_hydrator_cache_dir']);
309
        }
310 5
        if (isset($this->options['resource_hydrator_namespace'])) {
311 5
            $config->setGeneratedClassesNamespace($this->options['resource_hydrator_namespace']);
312
        }
313 5
        $hydrator = $config->createFactory()->getHydratorClass();
314 5
        $this->hydrators[$class] = new $hydrator;
315
316 5
        return $this->hydrators[$class];
317
    }
318
319
    /**
320
     * @param string $class
321
     * @return ResourceInterface
322
     */
323 5
    protected function createObject(string $class): ResourceInterface
324
    {
325 5
        $object = new $class();
326 5
        $object->setTransport($this->transport);
327 5
        if (isset($this->options['setters'])) {
328
            foreach ($this->options['setters'] as $method => $argument) {
329
                if (!method_exists($object, $method)) {
330
                    continue;
331
                }
332
                $object->$method($argument);
333
            }
334
        }
335 5
        return $object;
336
    }
337
}
338