Passed
Push — master ( 21a5dc...1ca6d2 )
by Nate
40s
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 Psr\SimpleCache\CacheInterface;
12
use ReflectionClass;
13
use ReflectionProperty;
14
use Tebru\AnnotationReader\AnnotationReaderAdapter;
15
use Tebru\Gson\Annotation\VirtualProperty;
16
use Tebru\Gson\ClassMetadata;
17
use Tebru\Gson\Internal\AccessorMethodProvider;
18
use Tebru\Gson\Internal\AccessorStrategy\GetByMethod;
19
use Tebru\Gson\Internal\AccessorStrategy\SetByNull;
20
use Tebru\Gson\Internal\AccessorStrategyFactory;
21
use Tebru\Gson\Internal\DefaultClassMetadata;
22
use Tebru\Gson\Internal\Excluder;
23
use Tebru\Gson\Internal\Naming\PropertyNamer;
24
use Tebru\Gson\Internal\PhpTypeFactory;
25
use Tebru\PhpType\TypeToken;
26
27
/**
28
 * Class PropertyCollectionFactory
29
 *
30
 * Aggregates information about class properties to be used during
31
 * future parsing.
32
 *
33
 * @author Nate Brunette <[email protected]>
34
 */
35
final class ClassMetadataFactory
36
{
37
    /**
38
     * @var ReflectionPropertySetFactory
39
     */
40
    private $reflectionPropertySetFactory;
41
42
    /**
43
     * @var AnnotationReaderAdapter
44
     */
45
    private $annotationReader;
46
47
    /**
48
     * @var PropertyNamer
49
     */
50
    private $propertyNamer;
51
52
    /**
53
     * @var AccessorMethodProvider
54
     */
55
    private $accessorMethodProvider;
56
57
    /**
58
     * @var AccessorStrategyFactory
59
     */
60
    private $accessorStrategyFactory;
61
62
    /**
63
     * @var PhpTypeFactory
64
     */
65
    private $phpTypeFactory;
66
67
    /**
68
     * @var Excluder
69
     */
70
    private $excluder;
71
72
    /**
73
     * @var CacheInterface
74
     */
75
    private $cache;
76
77
    /**
78
     * Constructor
79
     *
80
     * @param ReflectionPropertySetFactory $reflectionPropertySetFactory
81
     * @param AnnotationReaderAdapter $annotationReader
82
     * @param PropertyNamer $propertyNamer
83
     * @param AccessorMethodProvider $accessorMethodProvider
84
     * @param AccessorStrategyFactory $accessorStrategyFactory
85
     * @param PhpTypeFactory $phpTypeFactory
86
     * @param Excluder $excluder
87
     * @param CacheInterface $cache
88
     */
89 6
    public function __construct(
90
        ReflectionPropertySetFactory $reflectionPropertySetFactory,
91
        AnnotationReaderAdapter $annotationReader,
92
        PropertyNamer $propertyNamer,
93
        AccessorMethodProvider $accessorMethodProvider,
94
        AccessorStrategyFactory $accessorStrategyFactory,
95
        PhpTypeFactory $phpTypeFactory,
96
        Excluder $excluder,
97
        CacheInterface $cache
98
    ) {
99 6
        $this->reflectionPropertySetFactory = $reflectionPropertySetFactory;
100 6
        $this->annotationReader = $annotationReader;
101 6
        $this->propertyNamer = $propertyNamer;
102 6
        $this->accessorMethodProvider = $accessorMethodProvider;
103 6
        $this->accessorStrategyFactory = $accessorStrategyFactory;
104 6
        $this->phpTypeFactory = $phpTypeFactory;
105 6
        $this->excluder = $excluder;
106 6
        $this->cache = $cache;
107 6
    }
108
109
    /**
110
     * Create a new [@see ClassMetadata] with properties of the provided type
111
     *
112
     * @param TypeToken $phpType
113
     * @return DefaultClassMetadata
114
     */
115 5
    public function create(TypeToken $phpType): DefaultClassMetadata
116
    {
117 5
        $class = $phpType->getRawType();
118 5
        $key = 'gson.classmetadata.'.\str_replace('\\', '', $class);
119
120 5
        $data = $this->cache->get($key);
121 5
        if ($data !== null) {
122 1
            return $data;
123
        }
124
125 5
        $properties = new PropertyCollection();
126 5
        $classMetadata = new DefaultClassMetadata($class, $this->annotationReader->readClass($class, true), $properties);
127
128 5
        $reflectionClass = new ReflectionClass($class);
129 5
        $reflectionProperties = $this->reflectionPropertySetFactory->create($reflectionClass);
130
131
        /** @var ReflectionProperty $reflectionProperty */
132 5
        foreach ($reflectionProperties as $reflectionProperty) {
133 4
            $annotations = $this->annotationReader->readProperty(
134 4
                $reflectionProperty->getName(),
135 4
                $reflectionProperty->getDeclaringClass()->getName(),
136 4
                false,
137 4
                true
138
            );
139
140 4
            $serializedName = $this->propertyNamer->serializedName($reflectionProperty->getName(), $annotations);
141 4
            $getterMethod = $this->accessorMethodProvider->getterMethod($reflectionClass, $reflectionProperty, $annotations);
142 4
            $setterMethod = $this->accessorMethodProvider->setterMethod($reflectionClass, $reflectionProperty, $annotations);
143 4
            $getterStrategy = $this->accessorStrategyFactory->getterStrategy($reflectionProperty, $getterMethod);
144 4
            $setterStrategy = $this->accessorStrategyFactory->setterStrategy($reflectionProperty, $setterMethod);
145 4
            $type = $this->phpTypeFactory->create($annotations, $getterMethod, $setterMethod, $reflectionProperty);
146
147 4
            $property = new Property(
148 4
                $reflectionProperty->getName(),
149 4
                $serializedName,
150 4
                $type,
151 4
                $getterStrategy,
152 4
                $setterStrategy,
153 4
                $annotations,
154 4
                $reflectionProperty->getModifiers(),
155 4
                false,
156 4
                $classMetadata
157
            );
158
159 4
            $skipSerialize = $this->excluder->excludePropertySerialize($property);
160 4
            $skipDeserialize = $this->excluder->excludePropertyDeserialize($property);
161
162
            // if we're skipping serialization and deserialization, we don't need
163
            // to add the property to the collection
164 4
            if ($skipSerialize && $skipDeserialize) {
165 2
                continue;
166
            }
167
168 4
            $property->setSkipSerialize($skipSerialize);
169 4
            $property->setSkipDeserialize($skipDeserialize);
170
171 4
            $properties->add($property);
172
        }
173
174
        // add virtual properties
175 5
        foreach ($reflectionClass->getMethods() as $reflectionMethod) {
176 4
            $annotations = $this->annotationReader->readMethod(
177 4
                $reflectionMethod->getName(),
178 4
                $reflectionMethod->getDeclaringClass()->getName(),
179 4
                false,
180 4
                true
181
            );
182 4
            if (null === $annotations->get(VirtualProperty::class)) {
183 4
                continue;
184
            }
185
186 2
            $serializedName = $this->propertyNamer->serializedName($reflectionMethod->getName(), $annotations);
187 2
            $type = $this->phpTypeFactory->create($annotations, $reflectionMethod);
188 2
            $getterStrategy = new GetByMethod($reflectionMethod->getName());
189 2
            $setterStrategy = new SetByNull();
190
191 2
            $property = new Property(
192 2
                $reflectionMethod->getName(),
193 2
                $serializedName,
194 2
                $type,
195 2
                $getterStrategy,
196 2
                $setterStrategy,
197 2
                $annotations,
198 2
                $reflectionMethod->getModifiers(),
199 2
                true,
200 2
                $classMetadata
201
            );
202
203 2
            $skipSerialize = $this->excluder->excludePropertySerialize($property);
204 2
            $skipDeserialize = $this->excluder->excludePropertyDeserialize($property);
205
206
            // if we're skipping serialization and deserialization, we don't need
207
            // to add the property to the collection
208 2
            if ($skipSerialize && $skipDeserialize) {
209 2
                continue;
210
            }
211
212 2
            $property->setSkipSerialize($skipSerialize);
213 2
            $property->setSkipDeserialize($skipDeserialize);
214
215 2
            $properties->add($property);
216
        }
217
218 5
        $classMetadata->setSkipSerialize($this->excluder->excludeClassSerialize($classMetadata));
219 5
        $classMetadata->setSkipDeserialize($this->excluder->excludeClassDeserialize($classMetadata));
220
221 5
        $this->cache->set($key, $classMetadata);
222
223 5
        return $classMetadata;
224
    }
225
}
226