fab2s /
NodalFlow
| 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 ReflectionException; |
||
| 17 | use ReflectionMethod; |
||
| 18 | use Symfony\Component\EventDispatcher\EventDispatcher; |
||
| 19 | use Symfony\Component\EventDispatcher\EventDispatcherInterface; |
||
| 20 | |||
| 21 | /** |
||
| 22 | * Abstract Class FlowEventAbstract |
||
| 23 | */ |
||
| 24 | abstract class FlowEventAbstract extends FlowAncestryAbstract |
||
| 25 | { |
||
| 26 | /** |
||
| 27 | * Progress modulo to apply |
||
| 28 | * Set to x if you want to trigger |
||
| 29 | * progress every x iterations in flow |
||
| 30 | * |
||
| 31 | * @var int |
||
| 32 | */ |
||
| 33 | protected $progressMod = 1024; |
||
| 34 | |||
| 35 | /** |
||
| 36 | * @var EventDispatcherInterface |
||
| 37 | */ |
||
| 38 | protected $dispatcher; |
||
| 39 | |||
| 40 | /** |
||
| 41 | * @var array |
||
| 42 | */ |
||
| 43 | protected $activeEvents; |
||
| 44 | |||
| 45 | /** |
||
| 46 | * @var array |
||
| 47 | */ |
||
| 48 | protected $dispatchArgs = []; |
||
| 49 | |||
| 50 | /** |
||
| 51 | * @var int |
||
| 52 | */ |
||
| 53 | protected $eventInstanceKey = 0; |
||
| 54 | |||
| 55 | /** |
||
| 56 | * @var int |
||
| 57 | */ |
||
| 58 | protected $eventNameKey = 1; |
||
| 59 | |||
| 60 | /** |
||
| 61 | * Get current $progressMod |
||
| 62 | * |
||
| 63 | * @return int |
||
| 64 | */ |
||
| 65 | public function getProgressMod(): int |
||
| 66 | { |
||
| 67 | return $this->progressMod; |
||
| 68 | } |
||
| 69 | |||
| 70 | /** |
||
| 71 | * Define the progress modulo, Progress Callback will be |
||
| 72 | * triggered upon each iteration in the flow modulo $progressMod |
||
| 73 | * |
||
| 74 | * @param int $progressMod |
||
| 75 | * |
||
| 76 | * @return $this |
||
| 77 | */ |
||
| 78 | public function setProgressMod(int $progressMod): self |
||
| 79 | { |
||
| 80 | $this->progressMod = max(1, $progressMod); |
||
| 81 | |||
| 82 | return $this; |
||
| 83 | } |
||
| 84 | |||
| 85 | /** |
||
| 86 | * @throws ReflectionException |
||
| 87 | * |
||
| 88 | * @return EventDispatcherInterface |
||
| 89 | */ |
||
| 90 | public function getDispatcher(): EventDispatcherInterface |
||
| 91 | { |
||
| 92 | if ($this->dispatcher === null) { |
||
| 93 | $this->dispatcher = new EventDispatcher; |
||
| 94 | $this->initDispatchArgs(EventDispatcher::class); |
||
| 95 | } |
||
| 96 | |||
| 97 | return $this->dispatcher; |
||
| 98 | } |
||
| 99 | |||
| 100 | /** |
||
| 101 | * @param EventDispatcherInterface $dispatcher |
||
| 102 | * |
||
| 103 | * @throws ReflectionException |
||
| 104 | * |
||
| 105 | * @return $this |
||
| 106 | */ |
||
| 107 | public function setDispatcher(EventDispatcherInterface $dispatcher): self |
||
| 108 | { |
||
| 109 | $this->dispatcher = $dispatcher; |
||
| 110 | |||
| 111 | return $this->initDispatchArgs(\get_class($dispatcher)); |
||
| 112 | } |
||
| 113 | |||
| 114 | /** |
||
| 115 | * Register callback class |
||
| 116 | * |
||
| 117 | * @param CallbackInterface $callBack |
||
| 118 | * |
||
| 119 | * @throws ReflectionException |
||
| 120 | * |
||
| 121 | * @return $this |
||
| 122 | * |
||
| 123 | * @deprecated Use Flow events & dispatcher instead |
||
| 124 | */ |
||
| 125 | public function setCallBack(CallbackInterface $callBack): self |
||
| 126 | { |
||
| 127 | $this->getDispatcher()->addSubscriber(new CallbackWrapper($callBack)); |
||
| 128 | |||
| 129 | return $this; |
||
| 130 | } |
||
| 131 | |||
| 132 | /** |
||
| 133 | * @param string $eventName |
||
| 134 | * @param NodeInterface|null $node |
||
| 135 | * |
||
| 136 | * @return $this |
||
| 137 | */ |
||
| 138 | protected function triggerEvent(string $eventName, NodeInterface $node = null): self |
||
| 139 | { |
||
| 140 | if (isset($this->activeEvents[$eventName])) { |
||
| 141 | $this->dispatchArgs[$this->eventNameKey] = $eventName; |
||
| 142 | $this->dispatchArgs[$this->eventInstanceKey]->setNode($node); |
||
| 143 | $this->dispatcher->dispatch(/* @scrutinizer ignore-type */ ...$this->dispatchArgs); |
||
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
| 144 | } |
||
| 145 | |||
| 146 | return $this; |
||
| 147 | } |
||
| 148 | |||
| 149 | /** |
||
| 150 | * @param bool $reload |
||
| 151 | * |
||
| 152 | * @return $this |
||
| 153 | */ |
||
| 154 | protected function listActiveEvent(bool $reload = false): self |
||
| 155 | { |
||
| 156 | if (!isset($this->dispatcher) || (isset($this->activeEvents) && !$reload)) { |
||
| 157 | return $this; |
||
| 158 | } |
||
| 159 | |||
| 160 | $this->activeEvents = []; |
||
| 161 | $eventList = FlowEvent::getEventList(); |
||
| 162 | $sortedListeners = $this->dispatcher->getListeners(); |
||
| 163 | foreach ($sortedListeners as $eventName => $listeners) { |
||
| 164 | if (isset($eventList[$eventName]) && !empty($listeners)) { |
||
| 165 | $this->activeEvents[$eventName] = 1; |
||
| 166 | } |
||
| 167 | } |
||
| 168 | |||
| 169 | return $this; |
||
| 170 | } |
||
| 171 | |||
| 172 | /** |
||
| 173 | * I am really wondering wtf happening in their mind when |
||
| 174 | * they decided to flip argument order on such a low level |
||
| 175 | * foundation. |
||
| 176 | * |
||
| 177 | * This is just one of those cases where usability should win |
||
| 178 | * over academic principles. Setting name upon event instance is |
||
| 179 | * just not more convenient than setting it at call time, it's |
||
| 180 | * just a useless mutation in most IRL cases where the event is |
||
| 181 | * the same throughout many event slots (you know, practice). |
||
| 182 | * It's not even so obvious that coupling event with their |
||
| 183 | * usage is such a good idea, academically speaking. |
||
| 184 | * |
||
| 185 | * Now if you add that this results in: |
||
| 186 | * - duplicated code in symfony itself |
||
| 187 | * - hackish tricks to maintain BC |
||
| 188 | * - loss of argument type hinting |
||
| 189 | * - making it harder to support multiple version |
||
| 190 | * while this is supposed to achieve better compatibility |
||
| 191 | * AND no actual feature was added for so long ... |
||
| 192 | * |
||
| 193 | * This is pretty close to achieving the opposite of the |
||
| 194 | * original purpose IMHO |
||
| 195 | * |
||
| 196 | * PS: |
||
| 197 | * Okay, this is also a tribute to Linus memorable rants, but ... |
||
| 198 | * |
||
| 199 | * @param string $class |
||
| 200 | * |
||
| 201 | * @throws ReflectionException |
||
| 202 | * |
||
| 203 | * @return FlowEventAbstract |
||
| 204 | */ |
||
| 205 | protected function initDispatchArgs(string $class): self |
||
| 206 | { |
||
| 207 | $reflection = new ReflectionMethod($class, 'dispatch'); |
||
| 208 | $firstParam = $reflection->getParameters()[0]; |
||
| 209 | $this->dispatchArgs = [ |
||
| 210 | new FlowEvent($this), |
||
| 211 | null, |
||
| 212 | ]; |
||
| 213 | |||
| 214 | if ($firstParam->getName() !== 'event') { |
||
| 215 | $this->eventInstanceKey = 1; |
||
| 216 | $this->eventNameKey = 0; |
||
| 217 | $this->dispatchArgs = array_reverse($this->dispatchArgs); |
||
| 218 | } |
||
| 219 | |||
| 220 | return $this; |
||
| 221 | } |
||
| 222 | } |
||
| 223 |