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

ClassMetadataFactory::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 8
nc 1
nop 8
dl 0
loc 18
ccs 9
cts 9
cp 1
crap 1
rs 10
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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