Context   A
last analyzed

Complexity

Total Complexity 35

Size/Duplication

Total Lines 252
Duplicated Lines 0 %

Test Coverage

Coverage 86.17%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 73
dl 0
loc 252
ccs 81
cts 94
cp 0.8617
rs 9.6
c 1
b 0
f 0
wmc 35

22 Methods

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