Passed
Pull Request — master (#1474)
by
unknown
03:25
created

Context::assertMutable()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 3
c 0
b 0
f 0
nc 2
nop 0
dl 0
loc 7
rs 10
ccs 0
cts 3
cp 0
crap 6
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
            $strategy = new GroupsExclusionStrategy($this->attributes['groups']);
76 2
77
            if (isset($this->attributes['inherited_groups'])) {
78
                $strategy->setInheritedGroups($this->attributes['inherited_groups']);
79 313
            }
80 313
81
            $this->addExclusionStrategy($strategy);
82 13
        }
83
84 13
        if (isset($this->attributes['version'])) {
85
            $this->addExclusionStrategy(new VersionExclusionStrategy($this->attributes['version']));
86
        }
87 2
88
        if (!empty($this->attributes['max_depth_checks'])) {
89 2
            $this->addExclusionStrategy(new DepthExclusionStrategy());
90
        }
91
92 2
        $this->initialized = true;
93
    }
94 2
95
    public function getMetadataFactory(): MetadataFactoryInterface
96
    {
97 316
        return $this->metadataFactory;
98
    }
99 316
100
    public function getVisitor(): VisitorInterface
101
    {
102 33
        return $this->visitor;
103
    }
104 33
105
    public function getNavigator(): GraphNavigatorInterface
106
    {
107 292
        return $this->navigator;
108
    }
109 292
110
    public function getExclusionStrategy(): ?ExclusionStrategyInterface
111
    {
112 11
        return $this->exclusionStrategy;
113
    }
114 11
115 11
    /**
116
     * @return mixed
117 11
     */
118
    public function getAttribute(string $key)
119
    {
120 37
        return $this->attributes[$key];
121
    }
122 37
123 37
    public function hasAttribute(string $key): bool
124
    {
125
        return isset($this->attributes[$key]);
126
    }
127
128
    /**
129 30
     * @param mixed $value
130
     *
131 30
     * @return $this
132
     */
133 30
    public function setAttribute(string $key, $value): self
134 30
    {
135 30
        $this->assertMutable();
136
        $this->attributes[$key] = $value;
137
138
        return $this;
139
    }
140
141
    final protected function assertMutable(): void
142
    {
143
        if (!$this->initialized) {
144
            return;
145
        }
146
147
        throw new LogicException('This context was already initialized and is immutable; you cannot modify it anymore.');
148
    }
149
150
    /**
151 3
     * @return $this
152
     */
153 3
    public function addExclusionStrategy(ExclusionStrategyInterface $strategy): self
154
    {
155 3
        $this->assertMutable();
156
157
        if (null === $this->exclusionStrategy) {
158
            $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...
159
160
            return $this;
161 15
        }
162
163 15
        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...
164
            $this->exclusionStrategy->addStrategy($strategy);
165
166
            return $this;
167 15
        }
168
169 15
        $this->exclusionStrategy = new DisjunctExclusionStrategy([
170
            $this->exclusionStrategy,
171
            $strategy,
172 2
        ]);
173
174 2
        return $this;
175
    }
176 2
177
    /**
178
     * @return $this
179
     */
180
    public function setVersion(string $version): self
181
    {
182 43
        $this->attributes['version'] = $version;
183
184 43
        return $this;
185
    }
186 43
187
    /**
188
     * @param array|string $groups
189
     *
190
     * @return $this
191
     */
192
    public function setGroups($groups): self
193
    {
194
        if (empty($groups)) {
195 288
            throw new LogicException('The groups must not be empty.');
196
        }
197 288
198
        $this->attributes['groups'] = (array) $groups;
199
200
        return $this;
201
    }
202
203 313
    /**
204
     * @return $this
205 313
     */
206
    public function enableMaxDepthChecks(): self
207
    {
208 185
        $this->attributes['max_depth_checks'] = true;
209
210 185
        return $this;
211 185
    }
212
213 180
    /**
214
     * @return $this
215 180
     */
216 180
    public function enableInheritGroups(): self
217
    {
218 179
        $this->attributes['inherited_groups'] = true;
219
220 179
        return $this;
221
    }
222 179
223
    public function getFormat(): string
224
    {
225 179
        return $this->format;
226
    }
227 180
228
    public function pushClassMetadata(ClassMetadata $metadata): void
229 180
    {
230
        $this->metadataStack->push($metadata);
231 180
    }
232
233
    public function pushPropertyMetadata(PropertyMetadata $metadata): void
234 180
    {
235
        $this->metadataStack->push($metadata);
236 7
    }
237
238 7
    public function popPropertyMetadata(): void
239
    {
240
        $metadata = $this->metadataStack->pop();
241
242
        if (!$metadata instanceof PropertyMetadata) {
243
            throw new RuntimeException('Context metadataStack not working well');
244 2
        }
245
    }
246 2
247
    public function popClassMetadata(): void
248
    {
249
        $metadata = $this->metadataStack->pop();
250 2
251 2
        if (!$metadata instanceof ClassMetadata) {
252 2
            throw new RuntimeException('Context metadataStack not working well');
253 2
        }
254
    }
255
256
    public function getMetadataStack(): \SplStack
257 2
    {
258
        return $this->metadataStack;
259
    }
260
261
    /**
262
     * @return array
263
     */
264
    public function getCurrentPath(): array
265
    {
266
        if (!$this->metadataStack) {
267
            return [];
268
        }
269
270
        $paths = [];
271
        foreach ($this->metadataStack as $metadata) {
272
            if ($metadata instanceof PropertyMetadata) {
273
                array_unshift($paths, $metadata->name);
274
            }
275
        }
276
277
        return $paths;
278
    }
279
280
    abstract public function getDepth(): int;
281
282
    abstract public function getDirection(): int;
283
}
284