Passed
Push — main ( 1d3d49...043de0 )
by Mark
02:14
created

AbstractEnvironment::getRuntimeDataset()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 9
ccs 5
cts 5
cp 1
crap 2
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace League\Emoji\Environment;
6
7
use League\Configuration\Configuration;
8
use League\Configuration\ConfigurationInterface;
9
use League\Emoji\Dataset\RuntimeDataset;
10
use League\Emoji\Event\ListenerData;
11
use League\Emoji\Extension\ExtensionInterface;
12
use League\Emoji\Renderer\NodeRendererInterface;
13
use League\Emoji\Util\PrioritizedList;
14
use Psr\EventDispatcher\EventDispatcherInterface;
15
use Psr\EventDispatcher\StoppableEventInterface;
16
17
abstract class AbstractEnvironment implements EnvironmentInterface
18
{
19
    /** @var Configuration */
20
    protected $config;
21
22
    /** @var ?RuntimeDataset */
23
    protected $dataset;
24
25
    /**
26
     * @var ExtensionInterface[]
27
     *
28
     * @psalm-readonly-allow-private-mutation
29
     */
30
    protected $extensions = [];
31
32
    /** @var ?EventDispatcherInterface */
33
    protected $eventDispatcher;
34
35
    /**
36
     * @var bool
37
     *
38
     * @psalm-readonly-allow-private-mutation
39
     */
40
    protected $initialized = false;
41
42
    /**
43
     * @var ?PrioritizedList<ListenerData>
44
     *
45
     * @psalm-readonly-allow-private-mutation
46
     */
47
    protected $listenerData;
48
49
    /**
50
     * @var array<string, PrioritizedList<NodeRendererInterface>>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<string, Prioritize...NodeRendererInterface>> at position 4 could not be parsed: Expected '>' at position 4, but found 'PrioritizedList'.
Loading history...
51
     *
52
     * @psalm-readonly-allow-private-mutation
53
     */
54
    protected $renderersByClass = [];
55
56
    /**
57
     * @var ExtensionInterface[]
58
     *
59
     * @psalm-readonly-allow-private-mutation
60
     */
61
    protected $uninitializedExtensions = [];
62
63
    /**
64
     * @throws \RuntimeException
65
     */
66 696
    protected function assertUninitialized(string $message): void
67
    {
68 696
        if ($this->initialized) {
69 9
            throw new \RuntimeException(\sprintf('%s The Environment has already been initialized.', $message));
70
        }
71 687
    }
72
73
    /**
74
     * {@inheritDoc}
75
     */
76 255
    public function dispatch(object $event)
77
    {
78 255
        $this->initialize();
79
80 255
        if ($this->eventDispatcher !== null) {
81 3
            return $this->eventDispatcher->dispatch($event);
82
        }
83
84 252
        foreach ($this->getListenersForEvent($event) as $listener) {
85 246
            if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) {
86 3
                return $event;
87
            }
88
89 246
            $listener($event);
90
        }
91
92 249
        return $event;
93
    }
94
95 672
    public function getConfiguration(): ConfigurationInterface
96
    {
97 672
        $this->initializeConfiguration();
98
99 672
        return $this->config->reader();
100
    }
101
102
    /**
103
     * {@inheritDoc}
104
     *
105
     * @return ExtensionInterface[]
106
     */
107 6
    public function getExtensions(): iterable
108
    {
109 6
        return $this->extensions;
110
    }
111
112
    /**
113
     * {@inheritDoc}
114
     *
115
     * @return iterable<callable>
116
     */
117 252
    public function getListenersForEvent(object $event): iterable
118
    {
119 252
        if ($this->listenerData === null) {
120
            /** @var PrioritizedList<ListenerData> $listenerData */
121 3
            $listenerData       = new PrioritizedList();
122 3
            $this->listenerData = $listenerData;
123
        }
124
125
        /** @var ListenerData $listenerData */
126 252
        foreach ($this->listenerData as $listenerData) {
127 249
            if (! \is_a($event, $listenerData->getEvent())) {
128 246
                continue;
129
            }
130
131
            yield function (object $event) use ($listenerData): void {
132 246
                $this->initialize();
133
134 246
                \call_user_func($listenerData->getListener(), $event);
135 246
            };
136
        }
137 249
    }
138
139
    /**
140
     * {@inheritDoc}
141
     */
142 249
    public function getRenderersForClass(string $nodeClass): iterable
143
    {
144 249
        $this->initialize();
145
146
        // If renderers are defined for this specific class, return them immediately
147 249
        if (isset($this->renderersByClass[$nodeClass])) {
148 237
            return $this->renderersByClass[$nodeClass];
149
        }
150
151 15
        while (\class_exists($parent = $parent ?? $nodeClass) && ($parent = \get_parent_class($parent))) {
152 9
            if (! isset($this->renderersByClass[$parent])) {
153 9
                continue;
154
            }
155
156
            // "Cache" this result to avoid future loops
157 3
            return $this->renderersByClass[$nodeClass] = $this->renderersByClass[$parent];
158
        }
159
160 12
        return [];
161
    }
162
163 651
    public function getRuntimeDataset(string $index = 'hexcode'): RuntimeDataset
164
    {
165 651
        $this->initialize();
166
167 651
        if ($this->dataset === null) {
168 651
            $this->dataset = new RuntimeDataset($this->getConfiguration());
169
        }
170
171 651
        return $this->dataset->indexBy($index);
172
    }
173
174 687
    protected function initialize(): void
175
    {
176 687
        if ($this->initialized) {
177 249
            return;
178
        }
179
180 687
        $this->initializeConfiguration();
181
182 687
        $this->initializeExtensions();
183
184 687
        $this->initialized = true;
185 687
    }
186
187
    abstract protected function initializeConfiguration(): void;
188
189
    abstract protected function initializeExtensions(): void;
190
191 3
    public function setEventDispatcher(EventDispatcherInterface $dispatcher): void
192
    {
193 3
        $this->eventDispatcher = $dispatcher;
194 3
    }
195
}
196