Passed
Pull Request — master (#1434)
by Marcin
20:07 queued 08:20
created

Context::getNavigator()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 1
cts 1
cp 1
crap 1
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 MetadataFactory
38
     */
39
    private $metadataFactory;
40
41
    /** @var DisjunctExclusionStrategy */
42
    private $exclusionStrategy;
43
44
    /**
45
     * @var bool
46
     */
47
    private $initialized = false;
48 387
49
    /** @var \SplStack */
50 387
    private $metadataStack;
51
52
    public function __construct()
53
    {
54
        $this->metadataStack = new \SplStack();
55 313
    }
56
57 313
    public function initialize(string $format, VisitorInterface $visitor, MetadataFactoryInterface $factory): void
58
    {
59
        if ($this->initialized) {
60
            throw new LogicException('This context was already initialized, and cannot be re-used.');
61 313
        }
62 313
63 313
        $this->format = $format;
64 313
        $this->visitor = $visitor;
65 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...
66
        $this->metadataStack = new \SplStack();
67 313
68 15
        if (isset($this->attributes['groups'])) {
69
            $this->addExclusionStrategy(new GroupsExclusionStrategy($this->attributes['groups']));
70
        }
71 313
72 3
        if (isset($this->attributes['version'])) {
73
            $this->addExclusionStrategy(new VersionExclusionStrategy($this->attributes['version']));
74
        }
75 313
76 2
        if (!empty($this->attributes['max_depth_checks'])) {
77
            $this->addExclusionStrategy(new DepthExclusionStrategy());
78
        }
79 313
80 313
        $this->initialized = true;
81
    }
82 13
83
    public function getMetadataFactory(): MetadataFactoryInterface
84 13
    {
85
        return $this->metadataFactory;
86
    }
87 2
88
    public function getVisitor(): VisitorInterface
89 2
    {
90
        return $this->visitor;
91
    }
92 2
93
    public function getExclusionStrategy(): ?ExclusionStrategyInterface
94 2
    {
95
        return $this->exclusionStrategy;
96
    }
97 316
98
    /**
99 316
     * @return mixed
100
     */
101
    public function getAttribute(string $key)
102 33
    {
103
        return $this->attributes[$key];
104 33
    }
105
106
    public function hasAttribute(string $key): bool
107 292
    {
108
        return isset($this->attributes[$key]);
109 292
    }
110
111
    /**
112 11
     * @param mixed $value
113
     *
114 11
     * @return $this
115 11
     */
116
    public function setAttribute(string $key, $value): self
117 11
    {
118
        $this->assertMutable();
119
        $this->attributes[$key] = $value;
120 37
121
        return $this;
122 37
    }
123 37
124
    final protected function assertMutable(): void
125
    {
126
        if (!$this->initialized) {
127
            return;
128
        }
129 30
130
        throw new LogicException('This context was already initialized and is immutable; you cannot modify it anymore.');
131 30
    }
132
133 30
    /**
134 30
     * @return $this
135 30
     */
136
    public function addExclusionStrategy(ExclusionStrategyInterface $strategy): self
137
    {
138
        $this->assertMutable();
139
140
        if (null === $this->exclusionStrategy) {
141
            $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...
142
143
            return $this;
144
        }
145
146
        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...
147
            $this->exclusionStrategy->addStrategy($strategy);
148
149
            return $this;
150
        }
151 3
152
        $this->exclusionStrategy = new DisjunctExclusionStrategy([
153 3
            $this->exclusionStrategy,
154
            $strategy,
155 3
        ]);
156
157
        return $this;
158
    }
159
160
    /**
161 15
     * @return $this
162
     */
163 15
    public function setVersion(string $version): self
164
    {
165
        $this->attributes['version'] = $version;
166
167 15
        return $this;
168
    }
169 15
170
    /**
171
     * @param array|string $groups
172 2
     *
173
     * @return $this
174 2
     */
175
    public function setGroups($groups): self
176 2
    {
177
        if (empty($groups)) {
178
            throw new LogicException('The groups must not be empty.');
179
        }
180
181
        $this->attributes['groups'] = (array) $groups;
182 43
183
        return $this;
184 43
    }
185
186 43
    /**
187
     * @return $this
188
     */
189
    public function enableMaxDepthChecks(): self
190
    {
191
        $this->attributes['max_depth_checks'] = true;
192
193
        return $this;
194
    }
195 288
196
    public function getFormat(): string
197 288
    {
198
        return $this->format;
199
    }
200
201
    public function pushClassMetadata(ClassMetadata $metadata): void
202
    {
203 313
        $this->metadataStack->push($metadata);
204
    }
205 313
206
    public function pushPropertyMetadata(PropertyMetadata $metadata): void
207
    {
208 185
        $this->metadataStack->push($metadata);
209
    }
210 185
211 185
    public function popPropertyMetadata(): void
212
    {
213 180
        $metadata = $this->metadataStack->pop();
214
215 180
        if (!$metadata instanceof PropertyMetadata) {
216 180
            throw new RuntimeException('Context metadataStack not working well');
217
        }
218 179
    }
219
220 179
    public function popClassMetadata(): void
221
    {
222 179
        $metadata = $this->metadataStack->pop();
223
224
        if (!$metadata instanceof ClassMetadata) {
225 179
            throw new RuntimeException('Context metadataStack not working well');
226
        }
227 180
    }
228
229 180
    public function getMetadataStack(): \SplStack
230
    {
231 180
        return $this->metadataStack;
232
    }
233
234 180
    /**
235
     * @return array
236 7
     */
237
    public function getCurrentPath(): array
238 7
    {
239
        if (!$this->metadataStack) {
240
            return [];
241
        }
242
243
        $paths = [];
244 2
        foreach ($this->metadataStack as $metadata) {
245
            if ($metadata instanceof PropertyMetadata) {
246 2
                array_unshift($paths, $metadata->name);
247
            }
248
        }
249
250 2
        return $paths;
251 2
    }
252 2
253 2
    abstract public function getDepth(): int;
254
255
    abstract public function getDirection(): int;
256
}
257