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
Pull Request — master (#3)
by Cees-Jan
09:10 queued 06:06
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 Doctrine\Common\Annotations\AnnotationReader;
6
use Doctrine\Common\Annotations\CachedReader;
7
use Doctrine\Common\Cache\Cache;
8
use GeneratedHydrator\Configuration;
9
use ReflectionClass;
10
use ApiClients\Foundation\Resource\ResourceInterface;
11
use ApiClients\Foundation\Resource\AbstractResource;
12
use Zend\Hydrator\HydratorInterface;
13
14
class Hydrator
15
{
16
    /**
17
     * @var array
18
     */
19
    protected $options;
20
21
    /**
22
     * @var array
23
     */
24
    protected $hydrators = [];
25
26
    /**
27
     * @var array
28
     */
29
    protected $annotations = [];
30
31
    /**
32
     * @var HandlerInterface[]
33
     */
34
    protected $annotationHandlers = [];
35
36
    /**
37
     * @var AnnotationReader
38
     */
39
    protected $annotationReader;
40
41
    /**
42
     * @param array $options
43
     */
44 4
    public function __construct(array $options)
45
    {
46 4
        $this->options = $options;
47
48 4
        $reader = new AnnotationReader();
49 4
        if (isset($this->options[Options::ANNOTATION_CACHE]) &&
50 4
            $this->options[Options::ANNOTATION_CACHE] instanceof Cache
51
        ) {
52 1
            $reader = new CachedReader(
53
                $reader,
54 1
                $this->options[Options::ANNOTATION_CACHE]
55
            );
56
        }
57 4
        $this->annotationReader = $reader;
0 ignored issues
show
Documentation Bug introduced by
It seems like $reader can also be of type object<Doctrine\Common\Annotations\CachedReader>. However, the property $annotationReader is declared as type object<Doctrine\Common\A...tions\AnnotationReader>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
58
59 4
        $this->setUpAnnotations();
60 4
        $this->addSelfToExtraProperties();
61 4
    }
62
63 4
    protected function setUpAnnotations()
64
    {
65 4
        if (!isset($this->options[Options::ANNOTATIONS])) {
66
            return;
67
        }
68
69 4
        foreach ($this->options[Options::ANNOTATIONS] as $annotationClass => $handler) {
70 4
            $this->annotationHandlers[$annotationClass] = new $handler($this);
71
        }
72 4
    }
73
74 4
    protected function addSelfToExtraProperties()
75
    {
76 4
        $this->options[Options::EXTRA_PROPERTIES]['hydrator'] = $this;
77 4
    }
78
79
    /**
80
     * @param string $class
81
     * @param array $json
82
     * @return ResourceInterface
83
     */
84 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...
85
    {
86 4
        $fullClassName = implode(
87 4
            '\\',
88
            [
89
                $this->options[Options::NAMESPACE],
90 4
                $this->options[Options::NAMESPACE_SUFFIX],
91 4
                $class,
92
            ]
93
        );
94 4
        return $this->hydrateFQCN($fullClassName, $json);
95
    }
96
97
    /**
98
     * @param string $class
99
     * @param array $json
100
     * @return ResourceInterface
101
     */
102 4
    public function hydrateFQCN(string $class, array $json): ResourceInterface
103
    {
104 4
        $hydrator = $this->getHydrator($class);
105 4
        $object = new $class();
106 4
        $json = $this->hydrateApplyAnnotations($json, $object);
107 4
        $resource = $hydrator->hydrate($json, $object);
108 4
        if ($resource instanceof AbstractResource) {
109
            $resource->setExtraProperties($this->options[Options::EXTRA_PROPERTIES]);
110
        }
111 4
        return $resource;
112
    }
113
114
    /**
115
     * @param array $json
116
     * @param ResourceInterface $object
117
     * @return array
118
     */
119 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...
120
    {
121 4
        foreach ($this->annotationHandlers as $annotationClass => $handler) {
122 4
            $annotation = $this->getAnnotation($object, $annotationClass);
123 4
            if ($annotation === null) {
124 4
                continue;
125
            }
126
127 4
            $json = $handler->hydrate($annotation, $json, $object);
128
        }
129
130 4
        return $json;
131
    }
132
133
    /**
134
     * @param string $class
135
     * @param ResourceInterface $object
136
     * @return array
137
     */
138 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...
139
    {
140 2
        $fullClassName = implode(
141 2
            '\\',
142
            [
143
                $this->options[Options::NAMESPACE],
144 2
                $this->options[Options::NAMESPACE_SUFFIX],
145 2
                $class,
146
            ]
147
        );
148 2
        return $this->extractFQCN($fullClassName, $object);
149
    }
150
151
    /**
152
     * Takes a fully qualified class name and extracts the data for that class from the given $object
153
     * @param string $class
154
     * @param ResourceInterface $object
155
     * @return array
156
     */
157 2
    public function extractFQCN(string $class, ResourceInterface $object): array
158
    {
159 2
        $json = $this->getHydrator($class)->extract($object);
160 2
        $json = $this->extractApplyAnnotations($object, $json);
161 2
        return $json;
162
    }
163
164
    /**
165
     * @param array $json
166
     * @param ResourceInterface $object
167
     * @return array
168
     */
169 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...
170
    {
171 2
        foreach ($this->annotationHandlers as $annotationClass => $handler) {
172 2
            $annotation = $this->getAnnotation($object, $annotationClass);
173 2
            if ($annotation === null) {
174 2
                continue;
175
            }
176
177 2
            $json = $handler->extract($annotation, $object, $json);
178
        }
179
180 2
        return $json;
181
    }
182
183
    /**
184
     * @param ResourceInterface $object
185
     * @param string $annotationClass
186
     * @return null|AnnotationInterface
187
     */
188 4
    protected function getAnnotation(ResourceInterface $object, string $annotationClass)
189
    {
190 4
        $class = get_class($object);
191 4
        if (isset($this->annotations[$class][$annotationClass])) {
192 2
            return $this->annotations[$class][$annotationClass];
193
        }
194
195 4
        if (!isset($this->annotations[$class])) {
196 4
            $this->annotations[$class] = [];
197
        }
198
199 4
        $this->annotations[$class][$annotationClass] = $this->annotationReader
200 4
            ->getClassAnnotation(
201 4
                new ReflectionClass($object),
202
                $annotationClass
203
            )
204
        ;
205
206 4
        if (get_class($this->annotations[$class][$annotationClass]) === $annotationClass) {
207
            return $this->annotations[$class][$annotationClass];
208
        }
209
210 4
        $this->annotations[$class][$annotationClass] = $this->annotationReader
211 4
            ->getClassAnnotation(
212 4
                new ReflectionClass(get_parent_class($object)),
213
                $annotationClass
214
            )
215
        ;
216
217 4
        return $this->annotations[$class][$annotationClass];
218
    }
219
220
    /**
221
     * @param string $resource
222
     * @param ResourceInterface $object
223
     * @return ResourceInterface
224
     */
225 1
    public function buildAsyncFromSync(string $resource, ResourceInterface $object): ResourceInterface
226
    {
227 1
        return $this->hydrateFQCN(
228
            $this->options[Options::NAMESPACE] . '\\Async\\' . $resource,
229 1
            $this->extractFQCN(
230
                $this->options[Options::NAMESPACE] . '\\Sync\\' . $resource,
231
                $object
232
            )
233
        );
234
    }
235
236
    /**
237
     * @param string $class
238
     * @return HydratorInterface
239
     */
240 4
    protected function getHydrator(string $class): HydratorInterface
241
    {
242 4
        if (isset($this->hydrators[$class])) {
243 4
            return $this->hydrators[$class];
244
        }
245
246 4
        $config = new Configuration($class);
247 4
        if (isset($this->options[Options::RESOURCE_CACHE_DIR])) {
248 3
            $config->setGeneratedClassesTargetDir($this->options[Options::RESOURCE_CACHE_DIR]);
249
        }
250 4
        if (isset($this->options[Options::RESOURCE_NAMESPACE])) {
251 4
            $config->setGeneratedClassesNamespace($this->options[Options::RESOURCE_NAMESPACE]);
252
        }
253 4
        $hydrator = $config->createFactory()->getHydratorClass();
254 4
        $this->hydrators[$class] = new $hydrator;
255
256 4
        return $this->hydrators[$class];
257
    }
258
}
259