Completed
Push — master ( cb0ced...7754cf )
by Edward
04:45
created

ValueIteratorFactory::fetchValue()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
cc 4
eloc 10
c 0
b 0
f 0
nc 4
nop 1
dl 0
loc 17
ccs 0
cts 11
cp 0
crap 20
rs 9.9332
1
<?php
2
declare(strict_types=1);
3
4
namespace Remorhaz\JSON\Data\Iterator;
5
6
use Generator;
7
use Iterator;
8
use Remorhaz\JSON\Data\Event\AfterArrayEventInterface;
9
use Remorhaz\JSON\Data\Event\AfterObjectEventInterface;
10
use Remorhaz\JSON\Data\Event\BeforeArrayEventInterface;
11
use Remorhaz\JSON\Data\Event\BeforeObjectEventInterface;
12
use Remorhaz\JSON\Data\Event\DataEventInterface;
13
use Remorhaz\JSON\Data\Event\ElementEventInterface;
14
use Remorhaz\JSON\Data\Event\PropertyEventInterface;
15
use Remorhaz\JSON\Data\Event\ScalarEventInterface;
16
use Remorhaz\JSON\Data\Value\ValueInterface;
17
18
final class ValueIteratorFactory implements ValueIteratorFactoryInterface
19
{
20
21
    /**
22
     * @param Iterator $eventIterator
23
     * @return Iterator|ValueInterface[]
24
     */
25
    public function createArrayIterator(Iterator $eventIterator): Iterator
26
    {
27
        return $this->createArrayGenerator($eventIterator);
28
    }
29
30
    /**
31
     * @param Iterator $eventIterator
32
     * @return Generator|ValueInterface[]
33
     */
34
    private function createArrayGenerator(Iterator $eventIterator): Generator
35
    {
36
        $event = $this->fetchEvent($eventIterator);
37
        if (!$event instanceof BeforeArrayEventInterface) {
38
            throw new Exception\UnexpectedDataEventException($event, BeforeArrayEventInterface::class);
39
        }
40
41
        do {
42
            $event = $this->fetchEvent($eventIterator);
43
            if ($event instanceof AfterArrayEventInterface) {
44
                return;
45
            }
46
47
            if (!$event instanceof ElementEventInterface) {
48
                throw new Exception\UnexpectedDataEventException($event, ElementEventInterface::class);
49
            }
50
            $index = $event->getIndex();
51
52
            yield $index => $this->fetchValue($eventIterator);
53
        } while (true);
54
    }
55
56
    /**
57
     * @param Iterator $eventIterator
58
     * @return Iterator|ValueInterface[]
59
     */
60
    public function createObjectIterator(Iterator $eventIterator): Iterator
61
    {
62
        return $this->createObjectGenerator($eventIterator);
63
    }
64
65
    /**
66
     * @param Iterator $eventIterator
67
     * @return Generator|ValueInterface[]
68
     */
69
    public function createObjectGenerator(Iterator $eventIterator): Generator
70
    {
71
        $event = $this->fetchEvent($eventIterator);
72
        if (!$event instanceof BeforeObjectEventInterface) {
73
            throw new Exception\UnexpectedDataEventException($event, BeforeObjectEventInterface::class);
74
        }
75
76
        do {
77
            $event = $this->fetchEvent($eventIterator);
78
            if ($event instanceof AfterObjectEventInterface) {
79
                return;
80
            }
81
82
            if (!$event instanceof PropertyEventInterface) {
83
                throw new Exception\UnexpectedDataEventException($event, PropertyEventInterface::class);
84
            }
85
            $property = $event->getName();
86
87
            yield $property => $this->fetchValue($eventIterator);
88
        } while (true);
89
    }
90
91
    private function fetchEvent(Iterator $eventIterator): DataEventInterface
92
    {
93
        if (!$eventIterator->valid()) {
94
            throw new Exception\UnexpectedEndOfDataEventsException;
95
        }
96
        $event = $eventIterator->current();
97
        $eventIterator->next();
98
99
        if (!$event instanceof DataEventInterface) {
100
            throw new Exception\InvalidDataEventException($event);
101
        }
102
103
        return $event;
104
    }
105
106
    private function skipValue(Iterator $eventIterator): void
107
    {
108
        $event = $this->fetchEvent($eventIterator);
109
        if ($event instanceof ScalarEventInterface) {
110
            return;
111
        }
112
113
        if ($event instanceof BeforeArrayEventInterface) {
114
            $this->skipArrayValue($eventIterator);
115
            return;
116
        }
117
118
        if ($event instanceof BeforeObjectEventInterface) {
119
            $this->skipObjectValue($eventIterator);
120
            return;
121
        }
122
123
        throw new Exception\InvalidDataEventException($event);
124
    }
125
126
    private function fetchValue(Iterator $eventIterator): ValueInterface
127
    {
128
        $event = $this->fetchEvent($eventIterator);
129
        if ($event instanceof ScalarEventInterface) {
130
            return $event->getValue();
131
        }
132
        if ($event instanceof BeforeArrayEventInterface) {
133
            $this->skipArrayValue($eventIterator);
134
            return $event->getValue();
135
        }
136
137
        if ($event instanceof BeforeObjectEventInterface) {
138
            $this->skipObjectValue($eventIterator);
139
            return $event->getValue();
140
        }
141
142
        throw new Exception\InvalidDataEventException($event);
143
    }
144
145
    private function skipArrayValue(Iterator $eventIterator): void
146
    {
147
        do {
148
            $event = $this->fetchEvent($eventIterator);
149
            if ($event instanceof ElementEventInterface) {
150
                $this->skipValue($eventIterator);
151
                continue;
152
            }
153
            if ($event instanceof AfterArrayEventInterface) {
154
                return;
155
            }
156
            throw new Exception\InvalidDataEventException($event);
157
        } while (true);
158
    }
159
160
    private function skipObjectValue(Iterator $eventIterator): void
161
    {
162
        do {
163
            $event = $this->fetchEvent($eventIterator);
164
            if ($event instanceof PropertyEventInterface) {
165
                $this->skipValue($eventIterator);
166
                continue;
167
            }
168
            if ($event instanceof AfterObjectEventInterface) {
169
                return;
170
            }
171
            throw new Exception\InvalidDataEventException($event);
172
        } while (true);
173
    }
174
}
175