Passed
Pull Request — master (#1257)
by
unknown
02:36
created

Context::getVisitor()   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\SkipWhenEmptyExclusionStrategy;
14
use JMS\Serializer\Exclusion\ValueExclusionStrategyInterface;
15
use JMS\Serializer\Exclusion\VersionExclusionStrategy;
16
use JMS\Serializer\Metadata\ClassMetadata;
17
use JMS\Serializer\Metadata\PropertyMetadata;
18
use Metadata\MetadataFactory;
19
use Metadata\MetadataFactoryInterface;
20
21
abstract class Context
22
{
23
    public const ATTR_SKIP_WHEN_EMPTY = 'default_skip_when_empty';
24
    /**
25
     * @var array
26
     */
27
    private $attributes = [];
28
29
    /**
30
     * @var string
31
     */
32
    private $format;
33
34
    /**
35
     * @var VisitorInterface
36
     */
37
    private $visitor;
38
39
    /**
40
     * @var GraphNavigatorInterface
41
     */
42
    private $navigator;
43
44
    /**
45
     * @var MetadataFactory
46
     */
47
    private $metadataFactory;
48 387
49
    /** @var DisjunctExclusionStrategy */
50 387
    private $exclusionStrategy;
51
52
    /**
53
     * @var bool
54
     */
55 313
    private $initialized = false;
56
57 313
    /** @var \SplStack */
58
    private $metadataStack;
59
60
    public function __construct()
61 313
    {
62 313
        $this->metadataStack = new \SplStack();
63 313
    }
64 313
65 313
    public function initialize(string $format, VisitorInterface $visitor, GraphNavigatorInterface $navigator, MetadataFactoryInterface $factory): void
66
    {
67 313
        if ($this->initialized) {
68 15
            throw new LogicException('This context was already initialized, and cannot be re-used.');
69
        }
70
71 313
        $this->format = $format;
72 3
        $this->visitor = $visitor;
73
        $this->navigator = $navigator;
74
        $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...
75 313
        $this->metadataStack = new \SplStack();
76 2
77
        if (isset($this->attributes['groups'])) {
78
            $this->addExclusionStrategy(new GroupsExclusionStrategy($this->attributes['groups']));
79 313
        }
80 313
81
        if (isset($this->attributes['version'])) {
82 13
            $this->addExclusionStrategy(new VersionExclusionStrategy($this->attributes['version']));
83
        }
84 13
85
        if (!empty($this->attributes['max_depth_checks'])) {
86
            $this->addExclusionStrategy(new DepthExclusionStrategy());
87 2
        }
88
89 2
        if (!empty($this->attributes[self::ATTR_SKIP_WHEN_EMPTY])) {
90
            $this->addExclusionStrategy(new SkipWhenEmptyExclusionStrategy());
91
        }
92 2
93
        $this->initialized = true;
94 2
    }
95
96
    public function getMetadataFactory(): MetadataFactoryInterface
97 316
    {
98
        return $this->metadataFactory;
99 316
    }
100
101
    public function getVisitor(): VisitorInterface
102 33
    {
103
        return $this->visitor;
104 33
    }
105
106
    public function getNavigator(): GraphNavigatorInterface
107 292
    {
108
        return $this->navigator;
109 292
    }
110
111
    public function getExclusionStrategy(): ?DisjunctExclusionStrategy
112 11
    {
113
        return $this->exclusionStrategy;
114 11
    }
115 11
116
    /**
117 11
     * @return mixed
118
     */
119
    public function getAttribute(string $key)
120 37
    {
121
        return $this->attributes[$key];
122 37
    }
123 37
124
    public function hasAttribute(string $key): bool
125
    {
126
        return isset($this->attributes[$key]);
127
    }
128
129 30
    /**
130
     * @param mixed $value
131 30
     *
132
     * @return $this
133 30
     */
134 30
    public function setAttribute(string $key, $value): self
135 30
    {
136
        $this->assertMutable();
137
        $this->attributes[$key] = $value;
138
139
        return $this;
140
    }
141
142
    final protected function assertMutable(): void
143
    {
144
        if (!$this->initialized) {
145
            return;
146
        }
147
148
        throw new LogicException('This context was already initialized and is immutable; you cannot modify it anymore.');
149
    }
150
151 3
    /**
152
     * @param ExclusionStrategyInterface|ValueExclusionStrategyInterface $strategy
153 3
     *
154
     * @return $this
155 3
     */
156
    public function addExclusionStrategy($strategy): self
157
    {
158
        $this->assertMutable();
159
160
        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...
161 15
            $this->exclusionStrategy->addStrategy($strategy);
162
163 15
            return $this;
164
        }
165
166
        $this->exclusionStrategy = new DisjunctExclusionStrategy([$strategy]);
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
    /**
208 185
     * @return $this
209
     */
210 185
    public function enableSkipWhenEmpty(): self
211 185
    {
212
        $this->attributes[self::ATTR_SKIP_WHEN_EMPTY] = true;
213 180
214
        return $this;
215 180
    }
216 180
217
    public function getFormat(): string
218 179
    {
219
        return $this->format;
220 179
    }
221
222 179
    public function pushClassMetadata(ClassMetadata $metadata): void
223
    {
224
        $this->metadataStack->push($metadata);
225 179
    }
226
227 180
    public function pushPropertyMetadata(PropertyMetadata $metadata): void
228
    {
229 180
        $this->metadataStack->push($metadata);
230
    }
231 180
232
    public function popPropertyMetadata(): void
233
    {
234 180
        $metadata = $this->metadataStack->pop();
235
236 7
        if (!$metadata instanceof PropertyMetadata) {
237
            throw new RuntimeException('Context metadataStack not working well');
238 7
        }
239
    }
240
241
    public function popClassMetadata(): void
242
    {
243
        $metadata = $this->metadataStack->pop();
244 2
245
        if (!$metadata instanceof ClassMetadata) {
246 2
            throw new RuntimeException('Context metadataStack not working well');
247
        }
248
    }
249
250 2
    public function getMetadataStack(): \SplStack
251 2
    {
252 2
        return $this->metadataStack;
253 2
    }
254
255
    /**
256
     * @return array
257 2
     */
258
    public function getCurrentPath(): array
259
    {
260
        if (!$this->metadataStack) {
261
            return [];
262
        }
263
264
        $paths = [];
265
        foreach ($this->metadataStack as $metadata) {
266
            if ($metadata instanceof PropertyMetadata) {
267
                array_unshift($paths, $metadata->name);
268
            }
269
        }
270
271
        return $paths;
272
    }
273
274
    abstract public function getDepth(): int;
275
276
    abstract public function getDirection(): int;
277
}
278