Skip to content

Commit 4e78c38

Browse files
committed
BUGFIX: flow neosBetaMigration:reorderNodeAggregateWasRemoved
reparation for upgrading to beta 15 see also neos#5364
1 parent eed50fb commit 4e78c38

File tree

1 file changed

+67
-0
lines changed

1 file changed

+67
-0
lines changed

Neos.ContentRepositoryRegistry/Classes/Command/NeosBetaMigrationCommandController.php

+67
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,25 @@
44

55
namespace Neos\ContentRepositoryRegistry\Command;
66

7+
use Doctrine\DBAL\ArrayParameterType;
78
use Doctrine\DBAL\Connection;
89
use Neos\ContentGraph\DoctrineDbalAdapter\DoctrineDbalContentGraphProjection;
10+
use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceFactoryDependencies;
11+
use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceFactoryInterface;
12+
use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceInterface;
13+
use Neos\ContentRepository\Core\Feature\ContentStreamEventStreamName;
914
use Neos\ContentRepository\Core\Projection\CatchUpOptions;
1015
use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId;
16+
use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName;
1117
use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry;
1218
use Neos\ContentRepositoryRegistry\Factory\EventStore\DoctrineEventStoreFactory;
19+
use Neos\EventStore\Model\Event\EventType;
20+
use Neos\EventStore\Model\Event\EventTypes;
1321
use Neos\EventStore\Model\Event\SequenceNumber;
22+
use Neos\EventStore\Model\EventEnvelope;
23+
use Neos\EventStore\Model\Events;
24+
use Neos\EventStore\Model\EventStream\EventStreamFilter;
25+
use Neos\EventStore\Model\EventStream\ExpectedVersion;
1426
use Neos\Flow\Annotations as Flow;
1527
use Neos\Flow\Cli\CommandController;
1628
use Symfony\Component\Console\Helper\ProgressBar;
@@ -23,6 +35,44 @@ class NeosBetaMigrationCommandController extends CommandController
2335
#[Flow\Inject()]
2436
protected Connection $connection;
2537

38+
public function reorderNodeAggregateWasRemovedCommand(string $contentRepository = 'default', string $workspaceName = 'live'): void
39+
{
40+
$contentRepositoryId = ContentRepositoryId::fromString($contentRepository);
41+
$this->backup($contentRepositoryId);
42+
43+
$workspace = $this->contentRepositoryRegistry->get($contentRepositoryId)->findWorkspaceByName(WorkspaceName::fromString($workspaceName));
44+
if (!$workspace) {
45+
$this->outputLine('Workspace not found');
46+
$this->quit(1);
47+
}
48+
49+
$streamName = ContentStreamEventStreamName::fromContentStreamId($workspace->currentContentStreamId)->getEventStreamName();
50+
51+
$internals = $this->getInternals($contentRepositoryId);
52+
53+
// get all NodeAggregateWasRemoved from the content stream
54+
$eventsToReorder = iterator_to_array($internals->eventStore->load($streamName, EventStreamFilter::create(EventTypes::create(EventType::fromString('NodeAggregateWasRemoved')))), false);
55+
56+
// remove all the NodeAggregateWasRemoved events at their sequenceNumbers
57+
$eventTableName = DoctrineEventStoreFactory::databaseTableName($contentRepositoryId);
58+
$this->connection->beginTransaction();
59+
$this->connection->executeStatement(
60+
'DELETE FROM ' . $eventTableName . ' WHERE sequencenumber IN (:sequenceNumbers)',
61+
[
62+
'sequenceNumbers' => array_map(fn (EventEnvelope $eventEnvelope) => $eventEnvelope->sequenceNumber->value, $eventsToReorder)
63+
],
64+
[
65+
'sequenceNumbers' => ArrayParameterType::STRING
66+
]
67+
);
68+
$this->connection->commit();
69+
70+
// reapply the NodeAggregateWasRemoved events at the end
71+
$internals->eventStore->commit($streamName, Events::fromArray(array_map(fn (EventEnvelope $eventEnvelope) => $eventEnvelope->event, $eventsToReorder)), ExpectedVersion::ANY());
72+
73+
$this->outputLine('Reordered %d removals. Please replay and rebase your other workspaces.', [count($eventsToReorder)]);
74+
}
75+
2676
public function fixReplayCommand(string $contentRepository = 'default', bool $resetProjection = true): void
2777
{
2878
$contentRepositoryId = ContentRepositoryId::fromString($contentRepository);
@@ -149,4 +199,21 @@ private function copyEventTable(string $backupEventTableName, ContentRepositoryI
149199
FROM ' . $eventTableName
150200
);
151201
}
202+
203+
private function getInternals(ContentRepositoryId $contentRepositoryId): ContentRepositoryServiceFactoryDependencies
204+
{
205+
// NOT API!!!
206+
$accessor = new class implements ContentRepositoryServiceFactoryInterface {
207+
public ContentRepositoryServiceFactoryDependencies|null $dependencies;
208+
public function build(ContentRepositoryServiceFactoryDependencies $serviceFactoryDependencies): ContentRepositoryServiceInterface
209+
{
210+
$this->dependencies = $serviceFactoryDependencies;
211+
return new class implements ContentRepositoryServiceInterface
212+
{
213+
};
214+
}
215+
};
216+
$this->contentRepositoryRegistry->buildService($contentRepositoryId, $accessor);
217+
return $accessor->dependencies;
218+
}
152219
}

0 commit comments

Comments
 (0)