EventGenerator::onEvent()   A
last analyzed

Complexity

Conditions 5
Paths 5

Size

Total Lines 23
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 18
nc 5
nop 1
dl 0
loc 23
rs 9.3554
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Remorhaz\JSON\Data\Walker;
6
7
use Generator;
8
use Remorhaz\JSON\Data\Event\AfterArrayEvent;
9
use Remorhaz\JSON\Data\Event\AfterElementEvent;
10
use Remorhaz\JSON\Data\Event\AfterElementEventInterface;
11
use Remorhaz\JSON\Data\Event\AfterObjectEvent;
12
use Remorhaz\JSON\Data\Event\AfterPropertyEvent;
13
use Remorhaz\JSON\Data\Event\AfterPropertyEventInterface;
14
use Remorhaz\JSON\Data\Event\BeforeArrayEvent;
15
use Remorhaz\JSON\Data\Event\BeforeElementEvent;
16
use Remorhaz\JSON\Data\Event\BeforeElementEventInterface;
17
use Remorhaz\JSON\Data\Event\BeforeObjectEvent;
18
use Remorhaz\JSON\Data\Event\BeforePropertyEvent;
19
use Remorhaz\JSON\Data\Event\BeforePropertyEventInterface;
20
use Remorhaz\JSON\Data\Event\EventInterface;
21
use Remorhaz\JSON\Data\Event\ScalarEvent;
22
use Remorhaz\JSON\Data\Path\PathInterface;
23
use Remorhaz\JSON\Data\Value\ArrayValueInterface;
24
use Remorhaz\JSON\Data\Value\NodeValueInterface;
25
use Remorhaz\JSON\Data\Value\ObjectValueInterface;
26
use Remorhaz\JSON\Data\Value\ScalarValueInterface;
27
28
final class EventGenerator
29
{
30
31
    private $stack;
32
33
    private $path;
34
35
    public function __construct(NodeValueInterface $value, PathInterface $path)
36
    {
37
        $this->stack = [$value];
38
        $this->path = $path;
39
    }
40
41
    public function __invoke(): Generator
42
    {
43
        while (true) {
44
            if (empty($this->stack)) {
45
                return;
46
            }
47
            $entity = array_pop($this->stack);
48
            switch (true) {
49
                case $entity instanceof EventInterface:
50
                    yield from $this->onEvent($entity);
51
                    break;
52
53
                case $entity instanceof ScalarValueInterface:
54
                    yield from $this->onScalarValue($entity);
55
                    break;
56
57
                case $entity instanceof ArrayValueInterface:
58
                    yield from $this->onArrayValue($entity);
59
                    break;
60
61
                case $entity instanceof ObjectValueInterface:
62
                    yield from $this->onObjectValue($entity);
63
                    break;
64
65
                default:
66
                    throw new Exception\UnexpectedEntityException($entity);
67
            }
68
        }
69
    }
70
71
    private function onEvent(EventInterface $event): Generator
72
    {
73
        switch (true) {
74
            case $event instanceof BeforeElementEventInterface:
75
                $this->path = $this
76
                    ->path
77
                    ->copyWithElement($event->getIndex());
78
                break;
79
80
            case $event instanceof BeforePropertyEventInterface:
81
                $this->path = $this
82
                    ->path
83
                    ->copyWithProperty($event->getName());
84
                break;
85
86
            case $event instanceof AfterElementEventInterface:
87
            case $event instanceof AfterPropertyEventInterface:
88
                $this->path = $this
89
                    ->path
90
                    ->copyParent();
91
                break;
92
        }
93
        yield $event;
94
    }
95
96
    private function onScalarValue(ScalarValueInterface $value): Generator
97
    {
98
        yield new ScalarEvent($value->getData(), $this->path);
99
    }
100
101
    private function onArrayValue(ArrayValueInterface $value): Generator
102
    {
103
        $localStack = [];
104
        foreach ($value->createChildIterator() as $index => $child) {
105
            $elementPath = $this
106
                ->path
107
                ->copyWithElement($index);
0 ignored issues
show
Bug introduced by
It seems like $index can also be of type double and null and string and true; however, parameter $index of Remorhaz\JSON\Data\Path\...face::copyWithElement() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

107
                ->copyWithElement(/** @scrutinizer ignore-type */ $index);
Loading history...
108
            array_push(
109
                $localStack,
110
                new BeforeElementEvent($index, $elementPath),
0 ignored issues
show
Bug introduced by
It seems like $index can also be of type double and null and string and true; however, parameter $index of Remorhaz\JSON\Data\Event...entEvent::__construct() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

110
                new BeforeElementEvent(/** @scrutinizer ignore-type */ $index, $elementPath),
Loading history...
111
                $child,
112
                new AfterElementEvent($index, $elementPath)
0 ignored issues
show
Bug introduced by
It seems like $index can also be of type double and null and string and true; however, parameter $index of Remorhaz\JSON\Data\Event...entEvent::__construct() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

112
                new AfterElementEvent(/** @scrutinizer ignore-type */ $index, $elementPath)
Loading history...
113
            );
114
        }
115
        array_push(
116
            $this->stack,
117
            new AfterArrayEvent($this->path),
118
            ...array_reverse($localStack)
119
        );
120
        yield new BeforeArrayEvent($this->path);
121
    }
122
123
    private function onObjectValue(ObjectValueInterface $value): Generator
124
    {
125
        $localStack = [];
126
        foreach ($value->createChildIterator() as $name => $child) {
127
            $elementPath = $this
128
                ->path
129
                ->copyWithProperty($name);
0 ignored issues
show
Bug introduced by
It seems like $name can also be of type null and true; however, parameter $name of Remorhaz\JSON\Data\Path\...ace::copyWithProperty() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

129
                ->copyWithProperty(/** @scrutinizer ignore-type */ $name);
Loading history...
130
            array_push(
131
                $localStack,
132
                new BeforePropertyEvent($name, $elementPath),
0 ignored issues
show
Bug introduced by
It seems like $name can also be of type null and true; however, parameter $name of Remorhaz\JSON\Data\Event...rtyEvent::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

132
                new BeforePropertyEvent(/** @scrutinizer ignore-type */ $name, $elementPath),
Loading history...
133
                $child,
134
                new AfterPropertyEvent($name, $elementPath)
0 ignored issues
show
Bug introduced by
It seems like $name can also be of type null and true; however, parameter $name of Remorhaz\JSON\Data\Event...rtyEvent::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

134
                new AfterPropertyEvent(/** @scrutinizer ignore-type */ $name, $elementPath)
Loading history...
135
            );
136
        }
137
        array_push(
138
            $this->stack,
139
            new AfterObjectEvent($this->path),
140
            ...array_reverse($localStack)
141
        );
142
        yield new BeforeObjectEvent($this->path);
143
    }
144
}
145