This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
                                via PHP's auto-loading mechanism.
                                                    These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php | ||
| 2 | |||
| 3 | namespace Spatie\EventSourcing; | ||
| 4 | |||
| 5 | use Exception; | ||
| 6 | use Illuminate\Support\Arr; | ||
| 7 | use Illuminate\Support\Collection; | ||
| 8 | use Spatie\EventSourcing\EventHandlers\EventHandler; | ||
| 9 | use Spatie\EventSourcing\EventHandlers\EventHandlerCollection; | ||
| 10 | use Spatie\EventSourcing\Events\EventHandlerFailedHandlingEvent; | ||
| 11 | use Spatie\EventSourcing\Events\FinishedEventReplay; | ||
| 12 | use Spatie\EventSourcing\Events\StartingEventReplay; | ||
| 13 | use Spatie\EventSourcing\Exceptions\InvalidEventHandler; | ||
| 14 | use Spatie\EventSourcing\Projectors\Projector; | ||
| 15 | use Spatie\EventSourcing\Projectors\QueuedProjector; | ||
| 16 | |||
| 17 | class Projectionist | ||
| 18 | { | ||
| 19 | private EventHandlerCollection $projectors; | ||
| 0 ignored issues–
                            show             Bug
    
    
    
        introduced 
                            by  
  Loading history... | |||
| 20 | |||
| 21 | private EventHandlerCollection $reactors; | ||
| 22 | |||
| 23 | private bool $catchExceptions; | ||
| 24 | |||
| 25 | private bool $replayChunkSize; | ||
| 26 | |||
| 27 | private bool $isProjecting = false; | ||
| 28 | |||
| 29 | private bool $isReplaying = false; | ||
| 30 | |||
| 31 | public function __construct(array $config) | ||
| 32 |     { | ||
| 33 | $this->projectors = new EventHandlerCollection(); | ||
| 34 | $this->reactors = new EventHandlerCollection(); | ||
| 35 | |||
| 36 | $this->catchExceptions = $config['catch_exceptions']; | ||
| 37 | $this->replayChunkSize = $config['replay_chunk_size']; | ||
| 38 | } | ||
| 39 | |||
| 40 | public function addProjector($projector): Projectionist | ||
| 41 |     { | ||
| 42 |         if (is_string($projector)) { | ||
| 43 | $projector = app($projector); | ||
| 44 | } | ||
| 45 | |||
| 46 |         if (! $projector instanceof Projector) { | ||
| 47 | throw InvalidEventHandler::notAProjector($projector); | ||
| 48 | } | ||
| 49 | |||
| 50 | $this->projectors->add($projector); | ||
| 51 | |||
| 52 | return $this; | ||
| 53 | } | ||
| 54 | |||
| 55 | public function withoutEventHandlers(array $eventHandlers = null): Projectionist | ||
| 56 |     { | ||
| 57 |         if (is_null($eventHandlers)) { | ||
| 58 | $this->projectors = new EventHandlerCollection(); | ||
| 59 | $this->reactors = new EventHandlerCollection(); | ||
| 60 | |||
| 61 | return $this; | ||
| 62 | } | ||
| 63 | |||
| 64 | $eventHandlers = Arr::wrap($eventHandlers); | ||
| 65 | |||
| 66 | $this->projectors->remove($eventHandlers); | ||
| 67 | |||
| 68 | $this->reactors->remove($eventHandlers); | ||
| 69 | |||
| 70 | return $this; | ||
| 71 | } | ||
| 72 | |||
| 73 | public function withoutEventHandler(string $eventHandler): Projectionist | ||
| 74 |     { | ||
| 75 | return $this->withoutEventHandlers([$eventHandler]); | ||
| 76 | } | ||
| 77 | |||
| 78 | public function addProjectors(array $projectors): Projectionist | ||
| 79 |     { | ||
| 80 |         foreach ($projectors as $projector) { | ||
| 81 | $this->addProjector($projector); | ||
| 82 | } | ||
| 83 | |||
| 84 | return $this; | ||
| 85 | } | ||
| 86 | |||
| 87 | public function getProjectors(): Collection | ||
| 88 |     { | ||
| 89 | return $this->projectors->all(); | ||
| 90 | } | ||
| 91 | |||
| 92 | public function getProjector(string $name): ?Projector | ||
| 93 |     { | ||
| 94 | return $this->projectors->all()->first(fn (Projector $projector) => $projector->getName() === $name); | ||
| 95 | } | ||
| 96 | |||
| 97 | public function getAsyncProjectorsFor(StoredEvent $storedEvent): Collection | ||
| 98 |     { | ||
| 99 | return $this->projectors | ||
| 100 | ->forEvent($storedEvent) | ||
| 101 | ->reject(fn (Projector $projector) => $projector->shouldBeCalledImmediately()) | ||
| 102 | ->values(); | ||
| 103 | } | ||
| 104 | |||
| 105 | public function addReactor($reactor): Projectionist | ||
| 106 |     { | ||
| 107 |         if (is_string($reactor)) { | ||
| 108 | $reactor = app($reactor); | ||
| 109 | } | ||
| 110 | |||
| 111 |         if (! $reactor instanceof EventHandler) { | ||
| 112 | throw InvalidEventHandler::notAnEventHandler($reactor); | ||
| 113 | } | ||
| 114 | |||
| 115 | $this->reactors->add($reactor); | ||
| 116 | |||
| 117 | return $this; | ||
| 118 | } | ||
| 119 | |||
| 120 | public function addReactors(array $reactors): Projectionist | ||
| 121 |     { | ||
| 122 |         foreach ($reactors as $reactor) { | ||
| 123 | $this->addReactor($reactor); | ||
| 124 | } | ||
| 125 | |||
| 126 | return $this; | ||
| 127 | } | ||
| 128 | |||
| 129 | public function getReactors(): Collection | ||
| 130 |     { | ||
| 131 | return $this->reactors->all(); | ||
| 132 | } | ||
| 133 | |||
| 134 | public function getReactorsFor(StoredEvent $storedEvent): Collection | ||
| 135 |     { | ||
| 136 | return $this->reactors->forEvent($storedEvent)->values(); | ||
| 137 | } | ||
| 138 | |||
| 139 | public function addEventHandler($eventHandlerClass) | ||
| 140 |     { | ||
| 141 |         if (! is_string($eventHandlerClass)) { | ||
| 142 | $eventHandlerClass = get_class($eventHandlerClass); | ||
| 143 | } | ||
| 144 | |||
| 145 |         if (is_subclass_of($eventHandlerClass, Projector::class)) { | ||
| 146 | $this->addProjector($eventHandlerClass); | ||
| 147 | |||
| 148 | return; | ||
| 149 | } | ||
| 150 | |||
| 151 |         if (is_subclass_of($eventHandlerClass, QueuedProjector::class)) { | ||
| 152 | $this->addProjector($eventHandlerClass); | ||
| 153 | |||
| 154 | return; | ||
| 155 | } | ||
| 156 | |||
| 157 |         if (is_subclass_of($eventHandlerClass, EventHandler::class)) { | ||
| 158 | $this->addReactor($eventHandlerClass); | ||
| 159 | |||
| 160 | return; | ||
| 161 | } | ||
| 162 | |||
| 163 | throw InvalidEventHandler::notAnEventHandlingClassName($eventHandlerClass); | ||
| 164 | } | ||
| 165 | |||
| 166 | public function addEventHandlers(array $eventHandlers) | ||
| 167 |     { | ||
| 168 |         foreach ($eventHandlers as $eventHandler) { | ||
| 169 | $this->addEventHandler($eventHandler); | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | public function handle(StoredEvent $storedEvent): void | ||
| 174 |     { | ||
| 175 | $projectors = $this->projectors | ||
| 176 | ->forEvent($storedEvent) | ||
| 177 | ->reject(fn (Projector $projector) => $projector->shouldBeCalledImmediately()); | ||
| 178 | |||
| 179 | $this->applyStoredEventToProjectors( | ||
| 180 | $storedEvent, | ||
| 181 | $projectors | ||
| 182 | ); | ||
| 183 | |||
| 184 | $this->applyStoredEventToReactors( | ||
| 185 | $storedEvent, | ||
| 186 | $this->reactors->forEvent($storedEvent) | ||
| 187 | ); | ||
| 188 | } | ||
| 189 | |||
| 190 | public function handleWithSyncProjectors(StoredEvent $storedEvent): void | ||
| 191 |     { | ||
| 192 | $projectors = $this->projectors | ||
| 193 | ->forEvent($storedEvent) | ||
| 194 | ->filter(fn (Projector $projector) => $projector->shouldBeCalledImmediately()); | ||
| 195 | |||
| 196 | $this->applyStoredEventToProjectors($storedEvent, $projectors); | ||
| 197 | } | ||
| 198 | |||
| 199 | public function isProjecting(): bool | ||
| 200 |     { | ||
| 201 | return $this->isProjecting; | ||
| 202 | } | ||
| 203 | |||
| 204 | private function applyStoredEventToProjectors(StoredEvent $storedEvent, Collection $projectors): void | ||
| 205 |     { | ||
| 206 | $this->isProjecting = true; | ||
| 207 | |||
| 208 |         foreach ($projectors as $projector) { | ||
| 209 | $this->callEventHandler($projector, $storedEvent); | ||
| 210 | } | ||
| 211 | |||
| 212 | $this->isProjecting = false; | ||
| 213 | } | ||
| 214 | |||
| 215 | private function applyStoredEventToReactors(StoredEvent $storedEvent, Collection $reactors): void | ||
| 216 |     { | ||
| 217 |         foreach ($reactors as $reactor) { | ||
| 218 | $this->callEventHandler($reactor, $storedEvent); | ||
| 219 | } | ||
| 220 | } | ||
| 221 | |||
| 222 | private function callEventHandler(EventHandler $eventHandler, StoredEvent $storedEvent): bool | ||
| 223 |     { | ||
| 224 |         try { | ||
| 225 | $eventHandler->handle($storedEvent); | ||
| 226 |         } catch (Exception $exception) { | ||
| 227 |             if (! $this->catchExceptions) { | ||
| 228 | throw $exception; | ||
| 229 | } | ||
| 230 | |||
| 231 | $eventHandler->handleException($exception); | ||
| 232 | |||
| 233 | event(new EventHandlerFailedHandlingEvent($eventHandler, $storedEvent, $exception)); | ||
| 234 | |||
| 235 | return false; | ||
| 236 | } | ||
| 237 | |||
| 238 | return true; | ||
| 239 | } | ||
| 240 | |||
| 241 | public function isReplaying(): bool | ||
| 242 |     { | ||
| 243 | return $this->isReplaying; | ||
| 244 | } | ||
| 245 | |||
| 246 | public function replay( | ||
| 247 | Collection $projectors, | ||
| 248 | int $startingFromEventId = 0, | ||
| 249 | callable $onEventReplayed = null | ||
| 250 |     ): void { | ||
| 251 | $projectors = new EventHandlerCollection($projectors); | ||
| 252 | |||
| 253 | $this->isReplaying = true; | ||
| 254 | |||
| 255 |         if ($startingFromEventId === 0) { | ||
| 256 |             $projectors->all()->each(function (Projector $projector) { | ||
| 257 |                 if (method_exists($projector, 'resetState')) { | ||
| 258 | $projector->resetState(); | ||
| 259 | } | ||
| 260 | }); | ||
| 261 | } | ||
| 262 | |||
| 263 | event(new StartingEventReplay($projectors->all())); | ||
| 264 | |||
| 265 |         $projectors->call('onStartingEventReplay'); | ||
| 266 | |||
| 267 |         app(StoredEventRepository::class)->retrieveAllStartingFrom($startingFromEventId)->each(function (StoredEvent $storedEvent) use ($projectors, $onEventReplayed) { | ||
| 268 | $this->applyStoredEventToProjectors( | ||
| 269 | $storedEvent, | ||
| 270 | $projectors->forEvent($storedEvent) | ||
| 271 | ); | ||
| 272 | |||
| 273 |             if ($onEventReplayed) { | ||
| 274 | $onEventReplayed($storedEvent); | ||
| 275 | } | ||
| 276 | }); | ||
| 277 | |||
| 278 | $this->isReplaying = false; | ||
| 279 | |||
| 280 | event(new FinishedEventReplay()); | ||
| 281 | |||
| 282 |         $projectors->call('onFinishedEventReplay'); | ||
| 283 | } | ||
| 284 | } | ||
| 285 | 
