diff --git a/Neos.ContentRepository.Core/Classes/ContentRepository.php b/Neos.ContentRepository.Core/Classes/ContentRepository.php index fdb29291ad9..f0221f5f79d 100644 --- a/Neos.ContentRepository.Core/Classes/ContentRepository.php +++ b/Neos.ContentRepository.Core/Classes/ContentRepository.php @@ -170,8 +170,11 @@ public function catchUpProjection(string $projectionClassName, CatchUpOptions $o $eventStream = $eventStream->withMaximumSequenceNumber($options->maximumSequenceNumber); } - $eventApplier = function (EventEnvelope $eventEnvelope) use ($projection, $catchUpHook) { + $eventApplier = function (EventEnvelope $eventEnvelope) use ($projection, $catchUpHook, $options) { $event = $this->eventNormalizer->denormalize($eventEnvelope->event); + if ($options->progressCallback !== null) { + ($options->progressCallback)($event, $eventEnvelope); + } if (!$projection->canHandle($event)) { return; } diff --git a/Neos.ContentRepository.Core/Classes/Projection/CatchUpOptions.php b/Neos.ContentRepository.Core/Classes/Projection/CatchUpOptions.php index 9d89baf2980..4e146e0f523 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/CatchUpOptions.php +++ b/Neos.ContentRepository.Core/Classes/Projection/CatchUpOptions.php @@ -4,8 +4,11 @@ namespace Neos\ContentRepository\Core\Projection; +use Closure; use Neos\ContentRepository\Core\ContentRepository; +use Neos\ContentRepository\Core\EventStore\EventInterface; use Neos\EventStore\Model\Event\SequenceNumber; +use Neos\EventStore\Model\EventEnvelope; /** * Options for {@see ContentRepository::catchUpProjection()} @@ -16,9 +19,11 @@ final class CatchUpOptions { /** * @param SequenceNumber|null $maximumSequenceNumber If specified the catch-up will stop at the specified {@see SequenceNumber} + * @param Closure(EventInterface $event, EventEnvelope $eventEnvelope): void|null $progressCallback If specified the given closure will be invoked for every event with the current {@see EventInterface} and {@see EventEnvelope} passed as arguments */ private function __construct( public readonly ?SequenceNumber $maximumSequenceNumber, + public readonly ?Closure $progressCallback, ) { } @@ -30,11 +35,12 @@ private function __construct( */ public static function create( SequenceNumber|int|null $maximumSequenceNumber = null, + Closure|null $progressCallback = null, ): self { if (is_int($maximumSequenceNumber)) { $maximumSequenceNumber = SequenceNumber::fromInteger($maximumSequenceNumber); } - return new self($maximumSequenceNumber); + return new self($maximumSequenceNumber, $progressCallback); } @@ -46,9 +52,11 @@ public static function create( */ public function with( SequenceNumber|int|null $maximumSequenceNumber = null, + Closure|null $progressCallback = null, ): self { return self::create( $maximumSequenceNumber ?? $this->maximumSequenceNumber, + $progressCallback ?? $this->progressCallback, ); } } diff --git a/Neos.ContentRepositoryRegistry/Classes/Command/CrCommandController.php b/Neos.ContentRepositoryRegistry/Classes/Command/CrCommandController.php index 9ce435fdf15..c50a34e0289 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Command/CrCommandController.php +++ b/Neos.ContentRepositoryRegistry/Classes/Command/CrCommandController.php @@ -53,15 +53,18 @@ public function replayCommand(string $projection, string $contentRepository = 'd if (!$quiet) { $this->outputLine('Replaying events for projection "%s" of Content Repository "%s" ...', [$projection, $contentRepositoryId->value]); - // TODO start progress bar + $this->output->progressStart(); } - $options = CatchUpOptions::create(); + $options = CatchUpOptions::create( + progressCallback: fn () => $this->output->progressAdvance(), + ); if ($until > 0) { $options = $options->with(maximumSequenceNumber: SequenceNumber::fromInteger($until)); } $projectionService->replayProjection($projection, $options); if (!$quiet) { - // TODO finish progress bar + $this->output->progressFinish(); + $this->outputLine(); $this->outputLine('Done.'); } }