Test Setup Failed
Push — 2.x ( d5e498 )
by Fabrice
04:04
created

FlowEventAbstract::initDispatchArgs()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 10
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 16
rs 9.9332
1
<?php
2
3
/*
4
 * This file is part of NodalFlow.
5
 *     (c) Fabrice de Stefanis / https://github.com/fab2s/NodalFlow
6
 * This source file is licensed under the MIT license which you will
7
 * find in the LICENSE file or at https://opensource.org/licenses/MIT
8
 */
9
10
namespace fab2s\NodalFlow\Flows;
11
12
use fab2s\NodalFlow\Callbacks\CallbackInterface;
13
use fab2s\NodalFlow\Events\CallbackWrapper;
14
use fab2s\NodalFlow\Events\FlowEvent;
15
use fab2s\NodalFlow\Nodes\NodeInterface;
16
use Symfony\Component\EventDispatcher\EventDispatcher;
17
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
18
19
/**
20
 * Abstract Class FlowEventAbstract
21
 */
22
abstract class FlowEventAbstract extends FlowAncestryAbstract
23
{
24
    /**
25
     * Progress modulo to apply
26
     * Set to x if you want to trigger
27
     * progress every x iterations in flow
28
     *
29
     * @var int
30
     */
31
    protected $progressMod = 1024;
32
33
    /**
34
     * @var EventDispatcherInterface
35
     */
36
    protected $dispatcher;
37
38
    /**
39
     * @var array
40
     */
41
    protected $activeEvents;
42
43
    /**
44
     * @var array
45
     */
46
    protected $dispatchArgs = [];
47
48
    /**
49
     * @var int
50
     */
51
    protected $eventInstanceKey = 0;
52
53
    /**
54
     * @var int
55
     */
56
    protected $eventNameKey = 1;
57
58
    /**
59
     * Get current $progressMod
60
     *
61
     * @return int
62
     */
63
    public function getProgressMod(): int
64
    {
65
        return $this->progressMod;
66
    }
67
68
    /**
69
     * Define the progress modulo, Progress Callback will be
70
     * triggered upon each iteration in the flow modulo $progressMod
71
     *
72
     * @param int $progressMod
73
     *
74
     * @return $this
75
     */
76
    public function setProgressMod(int $progressMod): self
77
    {
78
        $this->progressMod = max(1, $progressMod);
79
80
        return $this;
81
    }
82
83
    /**
84
     * @throws \ReflectionException
85
     *
86
     * @return EventDispatcherInterface
87
     */
88
    public function getDispatcher(): EventDispatcherInterface
89
    {
90
        if ($this->dispatcher === null) {
91
            $this->dispatcher = new EventDispatcher;
92
            $this->initDispatchArgs(EventDispatcher::class);
93
        }
94
95
        return $this->dispatcher;
96
    }
97
98
    /**
99
     * @param EventDispatcherInterface $dispatcher
100
     *
101
     * @throws \ReflectionException
102
     *
103
     * @return $this
104
     */
105
    public function setDispatcher(EventDispatcherInterface $dispatcher): self
106
    {
107
        $this->dispatcher = $dispatcher;
108
109
        return $this->initDispatchArgs(\get_class($dispatcher));
110
    }
111
112
    /**
113
     * Register callback class
114
     *
115
     * @param CallbackInterface $callBack
116
     *
117
     * @throws \ReflectionException
118
     *
119
     * @return $this
120
     *
121
     * @deprecated Use Flow events & dispatcher instead
122
     */
123
    public function setCallBack(CallbackInterface $callBack): self
124
    {
125
        $this->getDispatcher()->addSubscriber(new CallbackWrapper($callBack));
126
127
        return $this;
128
    }
129
130
    /**
131
     * @param string             $eventName
132
     * @param NodeInterface|null $node
133
     *
134
     * @return $this
135
     */
136
    protected function triggerEvent(string $eventName, NodeInterface $node = null): self
137
    {
138
        if (isset($this->activeEvents[$eventName])) {
139
            $this->dispatchArgs[$this->eventNameKey] = $eventName;
140
            $this->dispatchArgs[$this->eventInstanceKey]->setNode($node);
141
            $this->dispatcher->dispatch(...$this->dispatchArgs);
0 ignored issues
show
Bug introduced by
$this->dispatchArgs is expanded, but the parameter $event of Symfony\Contracts\EventD...erInterface::dispatch() does not expect variable arguments. ( Ignorable by Annotation )

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

141
            $this->dispatcher->dispatch(/** @scrutinizer ignore-type */ ...$this->dispatchArgs);
Loading history...
142
        }
143
144
        return $this;
145
    }
146
147
    /**
148
     * @param bool $reload
149
     *
150
     * @return $this
151
     */
152
    protected function listActiveEvent(bool $reload = false): self
153
    {
154
        if (!isset($this->dispatcher) || (isset($this->activeEvents) && !$reload)) {
155
            return $this;
156
        }
157
158
        $this->activeEvents = [];
159
        $eventList          = FlowEvent::getEventList();
160
        $sortedListeners    = $this->dispatcher->getListeners();
161
        foreach ($sortedListeners as $eventName => $listeners) {
162
            if (isset($eventList[$eventName]) && !empty($listeners)) {
163
                $this->activeEvents[$eventName] = 1;
164
            }
165
        }
166
167
        return $this;
168
    }
169
170
    /**
171
     * I am really wondering wtf happening in their mind when
172
     * they decided to flip argument order on such a low level
173
     * foundation.
174
     *
175
     * This is just one of those cases where usability should win
176
     * over academic principles. Setting name upon event instance is
177
     * just not more convenient than setting it at call time, it's
178
     * just a useless mutation in most IRL cases where the event is
179
     * the same throughout many event slots (you know, practice).
180
     * It's not even so obvious that coupling event with their
181
     * usage is such a good idea, academically speaking.
182
     *
183
     * Now if you add that this results in:
184
     *  - duplicated code in symfony itself
185
     *  - hackish tricks to maintain BC
186
     *  - loss of argument type hinting
187
     *  - making it harder to support multiple version
188
     *    while this is supposed to achieve better compatibility
189
     *    AND no actual feature was added for so long ...
190
     *
191
     * This is pretty close to achieving the opposite of the
192
     * original purpose IMHO
193
     *
194
     * PS:
195
     * Okay, this is also a tribute to Linus memorable rants, but ...
196
     *
197
     * @param string $class
198
     *
199
     * @throws \ReflectionException
200
     *
201
     * @return FlowEventAbstract
202
     */
203
    protected function initDispatchArgs(string $class): self
204
    {
205
        $reflection         = new \ReflectionMethod($class, 'dispatch');
206
        $firstParam         = $reflection->getParameters()[0];
207
        $this->dispatchArgs = [
208
            new FlowEvent($this),
209
            null,
210
        ];
211
212
        if ($firstParam->getName() !== 'event') {
213
            $this->eventInstanceKey = 1;
214
            $this->eventNameKey     = 0;
215
            $this->dispatchArgs     = array_reverse($this->dispatchArgs);
216
        }
217
218
        return $this;
219
    }
220
}
221