Skip to content
Merged
37 changes: 27 additions & 10 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
.idea
.vscode
coverage/
.phpunit.cache
.phpunit.result.cache
vendor
node_modules
phpstan.neon
# ide
.idea/
.vscode/

# os
.DS_Store

# node
node_modules/
*.hot-update.js
/var/

# php
vendor/
phpstan.neon
composer.lock
src/Resources/public/administration/
.phpunit.cache
.phpunit.result.cache

# tests
coverage/

# build
src/Resources/public/static/
src/Resources/public/administration/
src/Resources/app/administration/.tmp

# runtime
/var/
.env

# plugin
/migration_assistant.cache
26 changes: 26 additions & 0 deletions src/Core/Migration/Migration1754896654TruncateMigrationLogs.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?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\Core\Migration;

use Doctrine\DBAL\Connection;
use Shopware\Core\Framework\Log\Package;
use Shopware\Core\Framework\Migration\MigrationStep;

#[Package('fundamentals@after-sales')]
class Migration1754896654TruncateMigrationLogs extends MigrationStep
{
public function getCreationTimestamp(): int
{
return 1754896654;
}

public function update(Connection $connection): void
{
$connection->executeStatement('TRUNCATE TABLE `swag_migration_logging`');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
<?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\Core\Migration;

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Platforms\MySQLPlatform;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Shopware\Core\Framework\Log\Package;
use Shopware\Core\Framework\Migration\MigrationStep;

#[Package('fundamentals@after-sales')]
class Migration1754897550AddRequiredFieldsToMigrationLogs extends MigrationStep
{
public const MIGRATION_LOGGING_TABLE = 'swag_migration_logging';

public const REQUIRED_FIELDS = [
'id' => 'BINARY(16) NOT NULL',
'run_id' => null,
'level' => null,
'code' => null,
'profile_name' => 'VARCHAR(255) NOT NULL',
'gateway_name' => 'VARCHAR(255) NOT NULL',
'user_fixable' => 'TINYINT(1) NOT NULL DEFAULT 0',
'auto_increment' => null,
'created_at' => null,
];

public function getCreationTimestamp(): int
{
return 1754897550;
}

/**
* @throws \Throwable
*/
public function update(Connection $connection): void
{
$schemaManager = $connection->createSchemaManager();

if (!$schemaManager->tablesExist([self::MIGRATION_LOGGING_TABLE])) {
return;
}

$this->dropForeignKeyIfExists($connection, self::MIGRATION_LOGGING_TABLE, 'fk.swag_migration_logging.run_id');
$this->dropIndexIfExists($connection, self::MIGRATION_LOGGING_TABLE, 'idx.swag_migration_logging.run_id_code');
$this->dropConstraintIfExists($connection, 'json.swag_migration_logging.log_entry');

$this->dropObsoleteColumns($connection, $schemaManager);
$this->addOrModifyRequiredColumns($connection, $schemaManager);
$this->ensureRelations($connection, $schemaManager);
}

/**
* @param AbstractSchemaManager<MySQLPlatform> $schemaManager
*/
private function dropObsoleteColumns(Connection $connection, AbstractSchemaManager $schemaManager): void
{
$columns = $schemaManager->listTableColumns(self::MIGRATION_LOGGING_TABLE);

foreach ($columns as $column) {
if (!\array_key_exists($column->getName(), self::REQUIRED_FIELDS)) {
$connection->executeStatement(
\sprintf(
'ALTER TABLE `%s` DROP COLUMN `%s`;',
self::MIGRATION_LOGGING_TABLE,
$column->getName()
)
);
}
}
}

/**
* @param AbstractSchemaManager<MySQLPlatform> $schemaManager
*/
private function addOrModifyRequiredColumns(Connection $connection, AbstractSchemaManager $schemaManager): void
{
$columns = $schemaManager->listTableColumns(self::MIGRATION_LOGGING_TABLE);

foreach (self::REQUIRED_FIELDS as $name => $type) {
if ($type === null) {
continue;
}

if (!isset($columns[$name])) {
$connection->executeStatement(
\sprintf(
'ALTER TABLE `%s` ADD COLUMN `%s` %s;',
self::MIGRATION_LOGGING_TABLE,
$name,
$type
)
);
} else {
$connection->executeStatement(
\sprintf(
'ALTER TABLE `%s` MODIFY COLUMN `%s` %s;',
self::MIGRATION_LOGGING_TABLE,
$name,
$type
)
);
}
}
}

/**
* @param AbstractSchemaManager<MySQLPlatform> $schemaManager
*/
private function ensureRelations(Connection $connection, AbstractSchemaManager $schemaManager): void
{
// ensure primary key and index
$indexes = $schemaManager->listTableIndexes(self::MIGRATION_LOGGING_TABLE);

if (isset($indexes['primary'])) {
$connection->executeStatement(
\sprintf(
'ALTER TABLE `%s` DROP PRIMARY KEY;',
self::MIGRATION_LOGGING_TABLE
)
);
}

$connection->executeStatement(
\sprintf(
'ALTER TABLE `%s` ADD PRIMARY KEY (`id`);',
self::MIGRATION_LOGGING_TABLE
)
);

$this->dropIndexIfExists(
$connection,
self::MIGRATION_LOGGING_TABLE,
'idx.run_id'
);
$connection->executeStatement(
\sprintf(
'ALTER TABLE `%s` ADD INDEX `idx.run_id` (`run_id`);',
self::MIGRATION_LOGGING_TABLE
)
);

// ensure foreign key constraint
$connection->executeStatement(
\sprintf(
'ALTER TABLE `%s` ADD CONSTRAINT `fk.swag_migration_logging.run_id` FOREIGN KEY (`run_id`) REFERENCES `swag_migration_run` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE;',
self::MIGRATION_LOGGING_TABLE
)
);
}

private function dropConstraintIfExists(Connection $connection, string $constraintName): void
{
try {
$connection->executeStatement(
\sprintf(
'ALTER TABLE `%s` DROP CONSTRAINT `%s`;',
self::MIGRATION_LOGGING_TABLE,
$constraintName
)
);
} catch (Exception) {
}
}
}
66 changes: 13 additions & 53 deletions src/Migration/Logging/Log/AssociationRequiredMissingLog.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,69 +14,29 @@
{
public function __construct(
string $runId,
string $entity,
string $sourceId,
string $profileName,
string $gatewayName,
private readonly string $requiredFor,

Check failure on line 19 in src/Migration/Logging/Log/AssociationRequiredMissingLog.php

View workflow job for this annotation

GitHub Actions / phpstan

Property SwagMigrationAssistant\Migration\Logging\Log\AssociationRequiredMissingLog::$requiredFor is never read, only written.
) {
parent::__construct($runId, $entity, $sourceId);
}

public function getLevel(): string
{
return self::LOG_LEVEL_WARNING;
}

public function getCode(): string
{
$entity = $this->getEntity();
if ($entity === null) {
return 'SWAG_MIGRATION__SHOPWARE_ASSOCIATION_REQUIRED_MISSING';
}

return \sprintf('SWAG_MIGRATION__SHOPWARE_ASSOCIATION_REQUIRED_MISSING_%s', \mb_strtoupper($entity));
}

public function getTitle(): string
{
$entity = $this->getEntity();
if ($entity === null) {
return 'Associated not found';
}

return \sprintf('Associated %s not found', $entity);
parent::__construct(
$runId,
$profileName,
$gatewayName,
);
}

/**
* @return array{missingEntity: ?string, requiredFor: string, sourceId: ?string}
*/
public function getParameters(): array
public function isUserFixable(): bool
{
return [
'missingEntity' => $this->getEntity(),
'requiredFor' => $this->requiredFor,
'sourceId' => $this->getSourceId(),
];
return false;
}

public function getDescription(): string
{
$args = $this->getParameters();

return \sprintf(
'The %s with the source id "%s" can not be found but is required for %s.',
$args['missingEntity'],
$args['sourceId'],
$args['requiredFor']
);
}

public function getTitleSnippet(): string
public function getLevel(): string
{
return \sprintf('%s.%s.title', $this->getSnippetRoot(), 'SWAG_MIGRATION__SHOPWARE_ASSOCIATION_REQUIRED_MISSING');
return self::LOG_LEVEL_WARNING;
}

public function getDescriptionSnippet(): string
public function getCode(): string
{
return \sprintf('%s.%s.description', $this->getSnippetRoot(), 'SWAG_MIGRATION__SHOPWARE_ASSOCIATION_REQUIRED_MISSING');
return 'SWAG_MIGRATION__SHOPWARE_ASSOCIATION_REQUIRED_MISSING';
}
}
29 changes: 7 additions & 22 deletions src/Migration/Logging/Log/BaseRunLogEntry.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,38 +14,23 @@ abstract class BaseRunLogEntry implements LogEntryInterface
{
public function __construct(
protected string $runId,
protected ?string $entity = null,
protected ?string $sourceId = null,
protected string $profileName,
protected string $gatewayName,
) {
}

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

public function getEntity(): ?string
public function getProfileName(): string
{
return $this->entity;
return $this->profileName;
}

public function getSourceId(): ?string
public function getGatewayName(): string
{
return $this->sourceId;
}

public function getSnippetRoot(): string
{
return 'swag-migration.index.error';
}

public function getTitleSnippet(): string
{
return \sprintf('%s.%s.title', $this->getSnippetRoot(), $this->getCode());
}

public function getDescriptionSnippet(): string
{
return \sprintf('%s.%s.description', $this->getSnippetRoot(), $this->getCode());
return $this->gatewayName;
}
}
Loading
Loading