Passed
Pull Request — master (#1473)
by Marcin
12:06
created

Context::close()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 0
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace JMS\Serializer;
6
7
use JMS\Serializer\Exception\LogicException;
8
use JMS\Serializer\Exception\RuntimeException;
9
use JMS\Serializer\Exclusion\DepthExclusionStrategy;
10
use JMS\Serializer\Exclusion\DisjunctExclusionStrategy;
11
use JMS\Serializer\Exclusion\ExclusionStrategyInterface;
12
use JMS\Serializer\Exclusion\GroupsExclusionStrategy;
13
use JMS\Serializer\Exclusion\VersionExclusionStrategy;
14
use JMS\Serializer\Metadata\ClassMetadata;
15
use JMS\Serializer\Metadata\PropertyMetadata;
16
use Metadata\MetadataFactory;
17
use Metadata\MetadataFactoryInterface;
18
19
abstract class Context
20
{
21
    /**
22
     * @var array
23
     */
24
    private $attributes = [];
25
26
    /**
27
     * @var string
28
     */
29
    private $format;
30
31
    /**
32
     * @var VisitorInterface
33
     */
34
    private $visitor;
35
36
    /**
37
     * @var GraphNavigatorInterface
38
     */
39
    private $navigator;
40
41
    /**
42
     * @var MetadataFactory
43
     */
44
    private $metadataFactory;
45
46
    /** @var DisjunctExclusionStrategy */
47
    private $exclusionStrategy;
48 387
49
    /**
50 387
     * @var bool
51
     */
52
    private $initialized = false;
53
54
    /** @var \SplStack */
55 313
    private $metadataStack;
56
57 313
    public function __construct()
58
    {
59
        $this->metadataStack = new \SplStack();
60
    }
61 313
62 313
    public function initialize(string $format, VisitorInterface $visitor, GraphNavigatorInterface $navigator, MetadataFactoryInterface $factory): void
63 313
    {
64 313
        if ($this->initialized) {
65 313
            throw new LogicException('This context was already initialized, and cannot be re-used.');
66
        }
67 313
68 15
        $this->format = $format;
69
        $this->visitor = $visitor;
70
        $this->navigator = $navigator;
71 313
        $this->metadataFactory = $factory;
0 ignored issues
show
Documentation Bug introduced by
$factory is of type Metadata\MetadataFactoryInterface, but the property $metadataFactory was declared to be of type Metadata\MetadataFactory. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof 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 given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
72 3
        $this->metadataStack = new \SplStack();
73
74
        if (isset($this->attributes['groups'])) {
75 313
            $this->addExclusionStrategy(new GroupsExclusionStrategy($this->attributes['groups']));
76 2
        }
77
78
        if (isset($this->attributes['version'])) {
79 313
            $this->addExclusionStrategy(new VersionExclusionStrategy($this->attributes['version']));
80 313
        }
81
82 13
        if (!empty($this->attributes['max_depth_checks'])) {
83
            $this->addExclusionStrategy(new DepthExclusionStrategy());
84 13
        }
85
86
        $this->initialized = true;
87 2
    }
88
89 2
    public function getMetadataFactory(): MetadataFactoryInterface
90
    {
91
        return $this->metadataFactory;
92 2
    }
93
94 2
    public function getVisitor(): VisitorInterface
95
    {
96
        return $this->visitor;
97 316
    }
98
99 316
    public function getNavigator(): GraphNavigatorInterface
100
    {
101
        return $this->navigator;
102 33
    }
103
104 33
    public function getExclusionStrategy(): ?ExclusionStrategyInterface
105
    {
106
        return $this->exclusionStrategy;
107 292
    }
108
109 292
    /**
110
     * @return mixed
111
     */
112 11
    public function getAttribute(string $key)
113
    {
114 11
        return $this->attributes[$key];
115 11
    }
116
117 11
    public function hasAttribute(string $key): bool
118
    {
119
        return isset($this->attributes[$key]);
120 37
    }
121
122 37
    /**
123 37
     * @param mixed $value
124
     *
125
     * @return $this
126
     */
127
    public function setAttribute(string $key, $value): self
128
    {
129 30
        $this->assertMutable();
130
        $this->attributes[$key] = $value;
131 30
132
        return $this;
133 30
    }
134 30
135 30
    final protected function assertMutable(): void
136
    {
137
        if (!$this->initialized) {
138
            return;
139
        }
140
141
        throw new LogicException('This context was already initialized and is immutable; you cannot modify it anymore.');
142
    }
143
144
    /**
145
     * @return $this
146
     */
147
    public function addExclusionStrategy(ExclusionStrategyInterface $strategy): self
148
    {
149
        $this->assertMutable();
150
151 3
        if (null === $this->exclusionStrategy) {
152
            $this->exclusionStrategy = $strategy;
0 ignored issues
show
Documentation Bug introduced by
$strategy is of type JMS\Serializer\Exclusion...lusionStrategyInterface, but the property $exclusionStrategy was declared to be of type JMS\Serializer\Exclusion\DisjunctExclusionStrategy. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof 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 given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
153 3
154
            return $this;
155 3
        }
156
157
        if ($this->exclusionStrategy instanceof DisjunctExclusionStrategy) {
0 ignored issues
show
introduced by
$this->exclusionStrategy is always a sub-type of JMS\Serializer\Exclusion\DisjunctExclusionStrategy.
Loading history...
158
            $this->exclusionStrategy->addStrategy($strategy);
159
160
            return $this;
161 15
        }
162
163 15
        $this->exclusionStrategy = new DisjunctExclusionStrategy([
164
            $this->exclusionStrategy,
165
            $strategy,
166
        ]);
167 15
168
        return $this;
169 15
    }
170
171
    /**
172 2
     * @return $this
173
     */
174 2
    public function setVersion(string $version): self
175
    {
176 2
        $this->attributes['version'] = $version;
177
178
        return $this;
179
    }
180
181
    /**
182 43
     * @param array|string $groups
183
     *
184 43
     * @return $this
185
     */
186 43
    public function setGroups($groups): self
187
    {
188
        if (empty($groups)) {
189
            throw new LogicException('The groups must not be empty.');
190
        }
191
192
        $this->attributes['groups'] = (array) $groups;
193
194
        return $this;
195 288
    }
196
197 288
    /**
198
     * @return $this
199
     */
200
    public function enableMaxDepthChecks(): self
201
    {
202
        $this->attributes['max_depth_checks'] = true;
203 313
204
        return $this;
205 313
    }
206
207
    public function getFormat(): string
208 185
    {
209
        return $this->format;
210 185
    }
211 185
212
    public function pushClassMetadata(ClassMetadata $metadata): void
213 180
    {
214
        $this->metadataStack->push($metadata);
215 180
    }
216 180
217
    public function pushPropertyMetadata(PropertyMetadata $metadata): void
218 179
    {
219
        $this->metadataStack->push($metadata);
220 179
    }
221
222 179
    public function popPropertyMetadata(): void
223
    {
224
        $metadata = $this->metadataStack->pop();
225 179
226
        if (!$metadata instanceof PropertyMetadata) {
227 180
            throw new RuntimeException('Context metadataStack not working well');
228
        }
229 180
    }
230
231 180
    public function popClassMetadata(): void
232
    {
233
        $metadata = $this->metadataStack->pop();
234 180
235
        if (!$metadata instanceof ClassMetadata) {
236 7
            throw new RuntimeException('Context metadataStack not working well');
237
        }
238 7
    }
239
240
    public function getMetadataStack(): \SplStack
241
    {
242
        return $this->metadataStack;
243
    }
244 2
245
    /**
246 2
     * @return array
247
     */
248
    public function getCurrentPath(): array
249
    {
250 2
        if (!$this->metadataStack) {
251 2
            return [];
252 2
        }
253 2
254
        $paths = [];
255
        foreach ($this->metadataStack as $metadata) {
256
            if ($metadata instanceof PropertyMetadata) {
257 2
                array_unshift($paths, $metadata->name);
258
            }
259
        }
260
261
        return $paths;
262
    }
263
264
    abstract public function getDepth(): int;
265
266
    abstract public function getDirection(): int;
267
268
    public function close(): void
269
    {
270
        unset($this->visitor, $this->navigator);
271
    }
272
}
273