Test Failed
Push — caching ( fd9061...49ea6a )
by Nate
02:41
created

ClassMetadataFactory::create()   C

Complexity

Conditions 11
Paths 13

Size

Total Lines 100
Code Lines 70

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 69
CRAP Score 11

Importance

Changes 0
Metric Value
eloc 70
dl 0
loc 100
ccs 69
cts 69
cp 1
rs 6.5077
c 0
b 0
f 0
cc 11
nc 13
nop 2
crap 11

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/*
3
 * Copyright (c) Nate Brunette.
4
 * Distributed under the MIT License (http://opensource.org/licenses/MIT)
5
 */
6
7
declare(strict_types=1);
8
9
namespace Tebru\Gson\Internal\Data;
10
11
use InvalidArgumentException;
12
use Psr\SimpleCache\CacheInterface;
13
use ReflectionClass;
14
use ReflectionProperty;
15
use Tebru\AnnotationReader\AnnotationReaderAdapter;
16
use Tebru\Gson\Annotation\Accessor;
17
use Tebru\Gson\Annotation\JsonAdapter;
18
use Tebru\Gson\Annotation\VirtualProperty;
19
use Tebru\Gson\Internal\AccessorMethodProvider;
20
use Tebru\Gson\Internal\AccessorStrategy\GetByMethod;
21
use Tebru\Gson\Internal\AccessorStrategy\SetByNull;
22
use Tebru\Gson\Internal\AccessorStrategyFactory;
23
use Tebru\Gson\Internal\DefaultClassMetadata;
24
use Tebru\Gson\Internal\Excluder;
25
use Tebru\Gson\Internal\Naming\PropertyNamer;
26
use Tebru\Gson\Internal\TypeAdapterProvider;
27
use Tebru\Gson\Internal\TypeTokenFactory;
28
use Tebru\PhpType\TypeToken;
29
30
/**
31
 * Class PropertyCollectionFactory
32
 *
33
 * Aggregates information about class properties to be used during
34
 * future parsing.
35
 *
36
 * @author Nate Brunette <[email protected]>
37
 */
38
final class ClassMetadataFactory
39
{
40
    /**
41
     * @var ReflectionPropertySetFactory
42
     */
43
    private $reflectionPropertySetFactory;
44
45
    /**
46
     * @var AnnotationReaderAdapter
47
     */
48
    private $annotationReader;
49
50
    /**
51
     * @var PropertyNamer
52
     */
53
    private $propertyNamer;
54
55
    /**
56
     * @var AccessorMethodProvider
57
     */
58
    private $accessorMethodProvider;
59
60
    /**
61
     * @var AccessorStrategyFactory
62
     */
63
    private $accessorStrategyFactory;
64
65
    /**
66
     * @var TypeTokenFactory
67
     */
68
    private $phpTypeFactory;
69
70
    /**
71
     * @var Excluder
72
     */
73
    private $excluder;
74
75
    /**
76
     * @var CacheInterface
77
     */
78
    private $cache;
79
80
    /**
81
     * Constructor
82
     *
83
     * @param ReflectionPropertySetFactory $reflectionPropertySetFactory
84
     * @param AnnotationReaderAdapter $annotationReader
85
     * @param PropertyNamer $propertyNamer
86
     * @param AccessorMethodProvider $accessorMethodProvider
87
     * @param AccessorStrategyFactory $accessorStrategyFactory
88
     * @param TypeTokenFactory $phpTypeFactory
89
     * @param Excluder $excluder
90
     * @param CacheInterface $cache
91 10
     */
92
    public function __construct(
93
        ReflectionPropertySetFactory $reflectionPropertySetFactory,
94
        AnnotationReaderAdapter $annotationReader,
95
        PropertyNamer $propertyNamer,
96
        AccessorMethodProvider $accessorMethodProvider,
97
        AccessorStrategyFactory $accessorStrategyFactory,
98
        TypeTokenFactory $phpTypeFactory,
99
        Excluder $excluder,
100
        CacheInterface $cache
101 10
    ) {
102 10
        $this->reflectionPropertySetFactory = $reflectionPropertySetFactory;
103 10
        $this->annotationReader = $annotationReader;
104 10
        $this->propertyNamer = $propertyNamer;
105 10
        $this->accessorMethodProvider = $accessorMethodProvider;
106 10
        $this->accessorStrategyFactory = $accessorStrategyFactory;
107 10
        $this->phpTypeFactory = $phpTypeFactory;
108 10
        $this->excluder = $excluder;
109 10
        $this->cache = $cache;
110
    }
111
112
    /**
113
     * Create a new [@param TypeToken $phpType
114
     *
115
     * @param TypeAdapterProvider $typeAdapterProvider
116
     * @return DefaultClassMetadata
117 5
     */
118
    public function create(TypeToken $phpType, TypeAdapterProvider $typeAdapterProvider): DefaultClassMetadata
119 5
    {
120 5
        $class = $phpType->rawType;
121
        $key = 'gson.classmetadata.'.str_replace('\\', '', $class);
122 5
123 5
        $data = $this->cache->get($key);
124 1
        if ($data !== null) {
125
            return $data;
126
        }
127 5
128 5
        $properties = new PropertyCollection();
129
        $classMetadata = new DefaultClassMetadata($class, $this->annotationReader->readClass($class, true), $properties);
130 5
131 5
        $reflectionClass = new ReflectionClass($class);
132
        $reflectionProperties = $this->reflectionPropertySetFactory->create($reflectionClass);
133
134 5
        /** @var ReflectionProperty $reflectionProperty */
135 4
        foreach ($reflectionProperties as $reflectionProperty) {
136 4
            $annotations = $this->annotationReader->readProperty(
137 4
                $reflectionProperty->getName(),
138 4
                $reflectionProperty->getDeclaringClass()->getName(),
139 4
                false,
140
                true
141
            );
142 4
143 4
            $accessor = $annotations->get(Accessor::class);
144 4
            $serializedName = $this->propertyNamer->serializedName($reflectionProperty->getName(), $annotations);
145 4
            $getterMethod = $this->accessorMethodProvider->getterMethod($reflectionClass, $reflectionProperty, $annotations);
146 4
            $setterMethod = $this->accessorMethodProvider->setterMethod($reflectionClass, $reflectionProperty, $annotations);
147 4
            $getterStrategy = $this->accessorStrategyFactory->getterStrategy($reflectionProperty, $getterMethod);
148
            $setterStrategy = $this->accessorStrategyFactory->setterStrategy($reflectionProperty, $setterMethod);
149 4
            $type = $this->phpTypeFactory->create($annotations, $getterMethod, $setterMethod, $reflectionProperty);
150 4
151 4
            $property = new Property(
152 4
                $reflectionProperty->getName(),
153 4
                $serializedName,
154 4
                $type,
155 4
                $accessor && $accessor->getter() ? $getterStrategy : null,
0 ignored issues
show
Bug introduced by
The method getter() does not exist on Tebru\AnnotationReader\AbstractAnnotation. It seems like you code against a sub-type of Tebru\AnnotationReader\AbstractAnnotation such as Tebru\Gson\Annotation\Accessor. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

155
                $accessor && $accessor->/** @scrutinizer ignore-call */ getter() ? $getterStrategy : null,
Loading history...
156 4
                $setterStrategy,
157 4
                $annotations,
158 4
                $reflectionProperty->getModifiers(),
159 4
                false,
160
                $classMetadata,
161
                $annotations->get(JsonAdapter::class)
162 4
            );
163 4
164 2
            $this->applyExcludes($property);
165
            if ($property->skipSerialize && $property->skipDeserialize) {
166
                continue;
167 4
            }
168 4
169
            $this->applyAdapter($typeAdapterProvider, $property);
170
            $properties->add($property);
171
        }
172 5
173 4
        // add virtual properties
174 4
        foreach ($reflectionClass->getMethods() as $reflectionMethod) {
175 4
            $annotations = $this->annotationReader->readMethod(
176 4
                $reflectionMethod->getName(),
177 4
                $reflectionMethod->getDeclaringClass()->getName(),
178
                false,
179 4
                true
180 4
            );
181
            if (null === $annotations->get(VirtualProperty::class)) {
182
                continue;
183 2
            }
184 2
185 2
            $serializedName = $this->propertyNamer->serializedName($reflectionMethod->getName(), $annotations);
186 2
            $type = $this->phpTypeFactory->create($annotations, $reflectionMethod);
187
            $getterStrategy = new GetByMethod($reflectionMethod->getName());
188 2
            $setterStrategy = new SetByNull();
189 2
190 2
            $property = new Property(
191 2
                $reflectionMethod->getName(),
192 2
                $serializedName,
193 2
                $type,
194 2
                $getterStrategy,
195 2
                $setterStrategy,
196 2
                $annotations,
197 2
                $reflectionMethod->getModifiers(),
198 2
                true,
199
                $classMetadata,
200
                $annotations->get(JsonAdapter::class)
201 2
            );
202 2
203 2
            $this->applyExcludes($property);
204
            if ($property->skipSerialize && $property->skipDeserialize) {
205
                continue;
206 2
            }
207 2
208
            $this->applyAdapter($typeAdapterProvider, $property);
209
            $properties->add($property);
210 5
        }
211 5
212
        $classMetadata->setSkipSerialize($this->excluder->excludeClassSerialize($classMetadata));
213 5
        $classMetadata->setSkipDeserialize($this->excluder->excludeClassDeserialize($classMetadata));
214
215 5
        $this->cache->set($key, $classMetadata);
216
217
        return $classMetadata;
218 4
    }
219
220 4
    private function applyExcludes(Property $property)
221 4
    {
222
        $skipSerialize = $this->excluder->excludePropertySerialize($property);
223 4
        $skipDeserialize = $this->excluder->excludePropertyDeserialize($property);
224 4
225 4
        $property->setSkipSerialize($skipSerialize);
226
        $property->setSkipDeserialize($skipDeserialize);
227
    }
228
229
    /**
230
     * @param TypeAdapterProvider $typeAdapterProvider
231 4
     * @param Property $property
232
     */
233 4
    private function applyAdapter(TypeAdapterProvider $typeAdapterProvider, Property $property): void
234
    {
235 4
        $adapter = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $adapter is dead and can be removed.
Loading history...
236
        try {
237
            $adapter = $typeAdapterProvider->getAdapterFromProperty($property);
238 4
        } catch (InvalidArgumentException $exception) { }
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
239 4
240
        if ($adapter && $adapter->canCache() === true) {
0 ignored issues
show
introduced by
The condition $adapter->canCache() === true is always false.
Loading history...
241 4
            $property->adapter = $adapter;
242
        }
243
    }
244
}
245