Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Controller/HistoryController.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
use Shopware\Core\Framework\Routing\RoutingException;
use SwagMigrationAssistant\Exception\MigrationException;
use SwagMigrationAssistant\Migration\History\HistoryServiceInterface;
use SwagMigrationAssistant\Migration\History\LogGroupingServiceInterface;
use SwagMigrationAssistant\Migration\History\LogGroupingService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\HeaderUtils;
use Symfony\Component\HttpFoundation\JsonResponse;
Expand All @@ -28,7 +28,7 @@ class HistoryController extends AbstractController
{
public function __construct(
private readonly HistoryServiceInterface $historyService,
private readonly LogGroupingServiceInterface $logGroupingService,
private readonly LogGroupingService $logGroupingService,
) {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
use Shopware\Core\Framework\Log\Package;
use Shopware\Core\Framework\Migration\MigrationStep;

/**
* @internal
*/
#[Package('fundamentals@after-sales')]
class Migration1759000000AddIsResettingChecksumsToSetting extends MigrationStep
{
Expand Down
1 change: 1 addition & 0 deletions src/DependencyInjection/writer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@

<service id="SwagMigrationAssistant\Migration\ErrorResolution\MigrationErrorResolutionService">
<argument type="service" id="Doctrine\DBAL\Connection"/>
<argument type="service" id="event_dispatcher"/>
</service>
</services>
</container>
12 changes: 0 additions & 12 deletions src/Exception/MigrationException.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,6 @@ class MigrationException extends HttpException

public const API_CONNECTION_ERROR = 'SWAG_MIGRATION__API_CONNECTION_ERROR';

public const FAILED_TO_CREATE_MIGRATION_LOG = 'SWAG_MIGRATION__FAILED_TO_CREATE_MIGRATION_LOG';

public const UNEXPECTED_NULL_VALUE = 'SWAG_MIGRATION__UNEXPECTED_NULL_VALUE';

public const MISSING_MIGRATION_FIX_KEY = 'SWAG_MIGRATION__MISSING_MIGRATION_FIX_KEY';
Expand Down Expand Up @@ -532,16 +530,6 @@ public static function invalidWriteContext(Context $invalidContext): self
);
}

public static function failedToCreateMigrationLog(string $logClass): self
{
return new self(
Response::HTTP_INTERNAL_SERVER_ERROR,
self::FAILED_TO_CREATE_MIGRATION_LOG,
'Failed to create migration log of class "{{ logClass }}".',
['logClass' => $logClass]
);
}

public static function unexpectedNullValue(string $fieldName): self
{
return new self(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php declare(strict_types=1);
/*
* (c) shopware AG <[email protected]>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace SwagMigrationAssistant\Migration\ErrorResolution\Event;

use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\Event\ShopwareEvent;
use Shopware\Core\Framework\Log\Package;
use SwagMigrationAssistant\Migration\ErrorResolution\MigrationErrorResolutionContext;
use Symfony\Contracts\EventDispatcher\Event;

/**
* @final
*/
#[Package('fundamentals@after-sales')]
class MigrationPostErrorResolutionEvent extends Event implements ShopwareEvent
{
public function __construct(private readonly MigrationErrorResolutionContext $errorResolutionContext)
{
}

public function getErrorResolutionContext(): MigrationErrorResolutionContext
{
return $this->errorResolutionContext;
}

public function getContext(): Context
{
return $this->errorResolutionContext->getContext();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php declare(strict_types=1);
/*
* (c) shopware AG <[email protected]>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace SwagMigrationAssistant\Migration\ErrorResolution\Event;

use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\Event\ShopwareEvent;
use Shopware\Core\Framework\Log\Package;
use SwagMigrationAssistant\Migration\ErrorResolution\MigrationErrorResolutionContext;
use Symfony\Contracts\EventDispatcher\Event;

/**
* @final
*/
#[Package('fundamentals@after-sales')]
class MigrationPreErrorResolutionEvent extends Event implements ShopwareEvent
{
public function __construct(private readonly MigrationErrorResolutionContext $errorResolutionContext)
{
}

public function getErrorResolutionContext(): MigrationErrorResolutionContext
{
return $this->errorResolutionContext;
}

public function getContext(): Context
{
return $this->errorResolutionContext->getContext();
}
}
78 changes: 78 additions & 0 deletions src/Migration/ErrorResolution/MigrationErrorResolutionContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php declare(strict_types=1);
/*
* (c) shopware AG <[email protected]>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace SwagMigrationAssistant\Migration\ErrorResolution;

use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\Log\Package;

/**
* @final
*/
#[Package('fundamentals@after-sales')]
class MigrationErrorResolutionContext
{
/**
* @param array<int|string, array<int|string, mixed>> $data
* @param array<string, list<MigrationFix>> $fixes
*/
public function __construct(
private array &$data,
private array &$fixes,
private readonly string $connectionId,
private readonly string $runId,
private readonly Context $context,
) {
}

/**
* @return array<int|string, array<int|string, mixed>>
*/
public function getData(): array
{
return $this->data;
}

/**
* @param array<int|string, array<int|string, mixed>> $data
*/
public function setData(array $data): void
{
$this->data = $data;
}

/**
* @return array<string, list<MigrationFix>>
*/
public function getFixes(): array
{
return $this->fixes;
}

/**
* @param array<string, list<MigrationFix>> $fixes
*/
public function setFixes(array $fixes): void
{
$this->fixes = $fixes;
}

public function getConnectionId(): string
{
return $this->connectionId;
}

public function getRunId(): string
{
return $this->runId;
}

public function getContext(): Context
{
return $this->context;
}
}
71 changes: 54 additions & 17 deletions src/Migration/ErrorResolution/MigrationErrorResolutionService.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,47 @@

use Doctrine\DBAL\ArrayParameterType;
use Doctrine\DBAL\Connection;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\Log\Package;
use Shopware\Core\Framework\Uuid\Uuid;
use SwagMigrationAssistant\Migration\ErrorResolution\Event\MigrationPostErrorResolutionEvent;
use SwagMigrationAssistant\Migration\ErrorResolution\Event\MigrationPreErrorResolutionEvent;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

/**
* @internal
*/
#[Package('fundamentals@after-sales')]
class MigrationErrorResolutionService
readonly class MigrationErrorResolutionService
{
public function __construct(
private readonly Connection $connection,
private Connection $connection,
private EventDispatcherInterface $eventDispatcher,
) {
}

/**
* @param array<int|string, array<int|string, mixed>> $data
*/
public function applyFixes(array &$data, string $connectionId, string $runId): void
public function applyFixes(array &$data, string $connectionId, string $runId, Context $context): void
{
$itemIds = \array_column($data, 'id');
$fixes = $this->getFixes($itemIds, $connectionId, $runId);
$emptyFixes = [];
$errorResolutionContext = new MigrationErrorResolutionContext(
$data,
$emptyFixes,
$connectionId,
$runId,
$context,
);

$this->loadFixes($errorResolutionContext);

$this->eventDispatcher->dispatch(
new MigrationPreErrorResolutionEvent($errorResolutionContext),
);

$fixes = $errorResolutionContext->getFixes();
$data = $errorResolutionContext->getData();

foreach ($data as &$item) {
$id = $item['id'];
Expand All @@ -41,15 +64,29 @@ public function applyFixes(array &$data, string $connectionId, string $runId): v
}

unset($item);

$errorResolutionContext->setData($data);

$this->eventDispatcher->dispatch(
new MigrationPostErrorResolutionEvent($errorResolutionContext),
);

$data = $errorResolutionContext->getData();
}

/**
* @param array<int, string> $ids
*
* @return array<string, list<MigrationFix>>
* Loads fixes from the database and populates them in the context.
*/
private function getFixes(array $ids, string $connectionId, string $runId): array
private function loadFixes(MigrationErrorResolutionContext $errorResolutionContext): void
{
$itemIds = \array_column($errorResolutionContext->getData(), 'id');

if (empty($itemIds)) {
$errorResolutionContext->setFixes([]);

return;
}

// To ensure, only select fixes for the current run, join swag_migration_logging table and filter by run_id
$sql = <<<'SQL'
SELECT fix.entity_id AS entityId, fix.id, fix.value, fix.path
Expand All @@ -64,26 +101,26 @@ private function getFixes(array $ids, string $connectionId, string $runId): arra
$result = $this->connection->fetchAllAssociative(
$sql,
[
'ids' => Uuid::fromHexToBytesList($ids),
'connectionId' => Uuid::fromHexToBytes($connectionId),
'runId' => Uuid::fromHexToBytes($runId),
'ids' => Uuid::fromHexToBytesList($itemIds),
'connectionId' => Uuid::fromHexToBytes($errorResolutionContext->getConnectionId()),
'runId' => Uuid::fromHexToBytes($errorResolutionContext->getRunId()),
],
[
'ids' => ArrayParameterType::STRING,
]
);

$return = [];
$fixes = [];
foreach ($result as $row) {
$entityId = Uuid::fromBytesToHex($row['entityId']);

if (!\array_key_exists($entityId, $return)) {
$return[$entityId] = [];
if (!\array_key_exists($entityId, $fixes)) {
$fixes[$entityId] = [];
}

$return[$entityId][] = MigrationFix::fromDatabaseQuery($row);
$fixes[$entityId][] = MigrationFix::fromDatabaseQuery($row);
}

return $return;
$errorResolutionContext->setFixes($fixes);
}
}
11 changes: 7 additions & 4 deletions src/Migration/ErrorResolution/MigrationFix.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,18 @@
use Shopware\Core\Framework\Uuid\Uuid;
use SwagMigrationAssistant\Exception\MigrationException;

/**
* @final
*/
#[Package('fundamentals@after-sales')]
class MigrationFix
readonly class MigrationFix
{
private const PATH_SEPARATOR = '.';

public function __construct(
public readonly string $id,
public readonly string $value,
public readonly string $path,
public string $id,
public string $value,
public string $path,
) {
}

Expand Down
4 changes: 2 additions & 2 deletions src/Migration/History/LogGroupingService.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
* security review straightforward. Do not scatter validation logic across multiple methods.
*/
#[Package('fundamentals@after-sales')]
class LogGroupingService implements LogGroupingServiceInterface
readonly class LogGroupingService
{
/**
* allowlist of columns that can be used for ORDER BY.
Expand Down Expand Up @@ -65,7 +65,7 @@ class LogGroupingService implements LogGroupingServiceInterface
private const ALLOWED_FILTER_STATUSES = ['resolved', 'unresolved'];

public function __construct(
private readonly Connection $connection,
private Connection $connection,
) {
}

Expand Down
Loading
Loading