Skip to content

Commit 644917e

Browse files
authored
Merge pull request #30 from WeareJH/JDTB-46-keep-config-values-or-tables
JDTB-46 Allow to keep core_config_data or cache certain config values
2 parents 98d31e3 + 305cf4c commit 644917e

7 files changed

+199
-5
lines changed

README.md

+14-2
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,22 @@ reimport them
107107
bin/magento wearejh:stripped-db-provider:import-from-remote PROJECT NAME
108108
```
109109

110-
To skip admin accounts backup
110+
#### To skip admin accounts backup
111111

112112
```
113-
bin/magento wearejh:stripped-db-provider:import-from-remote PROJECT NAME --no-admin-backup=1
113+
bin/magento wearejh:stripped-db-provider:import-from-remote PROJECT NAME --no-admin-backup=1
114+
```
115+
116+
#### Config backup
117+
118+
The `config-backup` option accepts 3 values:
119+
* *skip* - skips the backup of local config and imports everything from the remote
120+
* *merge* - backs up only the paths configured under `stripped_db_provider/dump/config_paths_keep` (accepts MySQL wildcards `%`),
121+
imports everything from the remote and merges the backed up config with the remote config
122+
* *preserve-local* - backs up the whole `core_config_data` and restores it after the DB import from remote
123+
124+
```
125+
bin/magento wearejh:stripped-db-provider:import-from-remote PROJECT NAME --config-backup=merge
114126
```
115127

116128
## Issues / Feature Request

src/Console/ImportFromRemoteCommand.php

+42-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ class ImportFromRemoteCommand extends Command
1818
{
1919
private const ARGUMENT_PROJECT_NAME = 'source-project-name';
2020
private const OPTION_NO_ADMIN_ACCOUNT_BACKUP = 'no-admin-backup';
21+
private const OPTION_CONFIG_DATA_BACKUP = 'config-backup';
22+
23+
private CONST VALUE_CONFIG_SKIP = 'skip';
24+
private CONST VALUE_CONFIG_PRESERVE = 'preserve-local';
25+
private CONST VALUE_CONFIG_MERGE = 'merge';
2126

2227
private const SUCCESS = 1;
2328

@@ -47,6 +52,13 @@ protected function configure()
4752
'Set this flag to skip backup of local admin accounts',
4853
false
4954
);
55+
$this->addOption(
56+
self::OPTION_CONFIG_DATA_BACKUP,
57+
null,
58+
InputOption::VALUE_OPTIONAL,
59+
'Set this flag to back up the whole core_config_data table',
60+
self::VALUE_CONFIG_MERGE
61+
);
5062
}
5163

5264
/**
@@ -68,6 +80,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
6880
try {
6981
$sourceProjectMeta = new ProjectMeta($input->getArgument(self::ARGUMENT_PROJECT_NAME));
7082
$backupAdminAccounts = !$input->getOption(self::OPTION_NO_ADMIN_ACCOUNT_BACKUP);
83+
$backupConfig = $this->getConfigBackupOption($input);
7184

7285
$output->writeln('<fg=cyan;options=bold>Downloading Database From Cloud Storage...</>');
7386
$this->dbFacade->downloadDatabaseDump($sourceProjectMeta);
@@ -84,6 +97,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int
8497
$this->dbFacade->backupLocalAdminAccounts($sourceProjectMeta);
8598
}
8699

100+
if ($backupConfig === self::VALUE_CONFIG_PRESERVE) {
101+
$output->writeln('<fg=cyan;options=bold>Backing up config ...</>');
102+
$this->dbFacade->backupLocalConfig($sourceProjectMeta);
103+
} else if ($backupConfig === self::VALUE_CONFIG_MERGE) {
104+
$output->writeln('<fg=cyan;options=bold>Backing up preconfigured config paths ...</>');
105+
$this->dbFacade->backupConfigValues($sourceProjectMeta);
106+
}
107+
87108
$output->writeln("<info>Starting the Database import</info>");
88109
$this->dbFacade->importDatabaseDump($sourceProjectMeta);
89110
$output->writeln("<info>Database successfully imported.</info>");
@@ -92,17 +113,37 @@ protected function execute(InputInterface $input, OutputInterface $output): int
92113
$output->writeln('<fg=cyan;options=bold>Restoring local admin accounts ...</>');
93114
$this->dbFacade->restoreLocalAdminAccountsFromBackup($sourceProjectMeta);
94115
}
116+
117+
if ($backupConfig === self::VALUE_CONFIG_PRESERVE) {
118+
$output->writeln('<fg=cyan;options=bold>Restoring config ...</>');
119+
$this->dbFacade->restoreLocalConfigFromBackup($sourceProjectMeta);
120+
} else if ($backupConfig === self::VALUE_CONFIG_MERGE) {
121+
$output->writeln('<fg=cyan;options=bold>Restoring preconfigured config paths ...</>');
122+
$this->dbFacade->restoreConfigValues();
123+
}
95124
} catch (Exception $e) {
96125
$output->writeln("<error>{$e->getMessage()}</error>");
97126
} finally {
98127
if (isset($sourceProjectMeta)) {
99128
$this->dbFacade->cleanUpLocalDumpFiles($sourceProjectMeta);
100129
}
101-
if ($backupAdminAccounts) {
130+
if (isset($backupAdminAccounts) && $backupAdminAccounts) {
102131
$this->dbFacade->cleanUpAdminAccountsBackup($sourceProjectMeta);
103132
}
133+
if (isset($backupConfig) && $backupConfig === self::VALUE_CONFIG_PRESERVE) {
134+
$this->dbFacade->cleanUpConfigBackup($sourceProjectMeta);
135+
}
104136
}
105137

106138
return self::SUCCESS;
107139
}
140+
141+
private function getConfigBackupOption(InputInterface $input): string
142+
{
143+
$configBackupOption = $input->getOption(self::OPTION_CONFIG_DATA_BACKUP);
144+
if (!in_array($configBackupOption, [self::VALUE_CONFIG_SKIP, self::VALUE_CONFIG_PRESERVE, self::VALUE_CONFIG_MERGE])) {
145+
$configBackupOption = self::VALUE_CONFIG_MERGE;
146+
}
147+
return $configBackupOption;
148+
}
108149
}

src/Model/Config.php

+11
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class Config
2828
* Dump Specific
2929
*/
3030
const XML_PATH_PROJECT_IGNORE_TABLES = 'stripped_db_provider/dump/project_ignore_tables';
31+
const XML_PATH_PROJECT_KEEP_CONFIG_PATHS = 'stripped_db_provider/dump/config_paths_keep';
3132

3233
public function __construct(
3334
private readonly ScopeConfigInterface $config,
@@ -77,4 +78,14 @@ public function getLocalDbConfigData(string $key): ?string
7778
)
7879
);
7980
}
81+
82+
public function getConfigPathsToKeep(): array
83+
{;
84+
$defaultPaths = explode(
85+
',',
86+
(string) $this->config->getValue(self::XML_PATH_PROJECT_KEEP_CONFIG_PATHS)
87+
);
88+
89+
return array_merge($defaultPaths, $projectIgnoredPaths);
90+
}
8091
}

src/Model/Db/DbAdminAccountsManager.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public function restoreAdminAccountsBackup(ProjectMeta $projectMeta): void
5656
"mysql:host={$hostName};dbname={$dbName}",
5757
$this->config->getLocalDbConfigData(ConfigOptionsListConstants::KEY_USER),
5858
$this->config->getLocalDbConfigData(ConfigOptionsListConstants::KEY_PASSWORD),
59-
['skip-definer' => true]
59+
['skip-definer' => true, 'add-drop-table' => true, 'skip-triggers' => true]
6060
);
6161
$dumper->restore($this->getAdminAccountsBackupFilePath($projectMeta));
6262
}
+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Jh\StrippedDbProvider\Model\Db;
6+
7+
use Ifsnop\Mysqldump\Mysqldump;
8+
use Magento\Framework\App\ResourceConnection;
9+
use Magento\Framework\Config\ConfigOptionsListConstants;
10+
use Jh\StrippedDbProvider\Model\Config;
11+
use Jh\StrippedDbProvider\Model\ProjectMeta;
12+
use Magento\Framework\Shell;
13+
14+
class DbConfigBackupManager
15+
{
16+
private const BACKUP_FILENAME = 'core_config_data.sql';
17+
18+
public function __construct(
19+
private Config $config,
20+
private Shell $shell,
21+
private ResourceConnection $resourceConnection,
22+
private array $configCache = []
23+
) {
24+
}
25+
26+
/**
27+
* @throws \Exception
28+
*/
29+
public function backupConfig(ProjectMeta $projectMeta): void
30+
{
31+
$hostName = $this->config->getLocalDbConfigData(ConfigOptionsListConstants::KEY_HOST);
32+
$dbName = $this->config->getLocalDbConfigData(ConfigOptionsListConstants::KEY_NAME);
33+
$dumper = new Mysqldump(
34+
"mysql:host={$hostName};dbname={$dbName}",
35+
$this->config->getLocalDbConfigData(ConfigOptionsListConstants::KEY_USER),
36+
$this->config->getLocalDbConfigData(ConfigOptionsListConstants::KEY_PASSWORD),
37+
[
38+
'skip-definer' => true,
39+
'add-drop-table' => true,
40+
'include-tables' => [
41+
'core_config_data'
42+
]
43+
]
44+
);
45+
46+
$dumper->start($this->getConfigBackupFilePath($projectMeta));
47+
}
48+
49+
public function restoreConfigBackup(ProjectMeta $projectMeta): void
50+
{
51+
$hostName = $this->config->getLocalDbConfigData(ConfigOptionsListConstants::KEY_HOST);
52+
$dbName = $this->config->getLocalDbConfigData(ConfigOptionsListConstants::KEY_NAME);
53+
$dumper = new Mysqldump(
54+
"mysql:host={$hostName};dbname={$dbName}",
55+
$this->config->getLocalDbConfigData(ConfigOptionsListConstants::KEY_USER),
56+
$this->config->getLocalDbConfigData(ConfigOptionsListConstants::KEY_PASSWORD),
57+
['skip-definer' => true, 'add-drop-table' => true, 'skip-triggers' => true]
58+
);
59+
$dumper->restore($this->getConfigBackupFilePath($projectMeta));
60+
}
61+
62+
public function cleanUp(ProjectMeta $projectMeta): void
63+
{
64+
try {
65+
$this->shell->execute("rm %s", [$this->getConfigBackupFilePath($projectMeta)]);
66+
} catch (\Exception $e) {
67+
//empty
68+
}
69+
}
70+
71+
public function cacheConfigValuesToKeep(): void
72+
{
73+
$pathsToCache = $this->config->getConfigPathsToKeep();
74+
$connection = $this->resourceConnection->getConnection();
75+
$tableName = $this->resourceConnection->getTableName('core_config_data');
76+
77+
$select = $connection->select()
78+
->from($tableName,['*']);
79+
80+
foreach ($pathsToCache as $pattern) {
81+
$select->orWhere('path LIKE ?', $pattern);
82+
}
83+
84+
$this->configCache = $connection->fetchAll($select);
85+
}
86+
87+
public function restoreConfigValuesToKeep(): void
88+
{
89+
foreach ($this->configCache as $config) {
90+
$this->resourceConnection->getConnection()->insertOnDuplicate(
91+
$this->resourceConnection->getTableName('core_config_data'),
92+
$config
93+
);
94+
}
95+
}
96+
97+
private function getConfigBackupFilePath(ProjectMeta $projectMeta): string
98+
{
99+
return $projectMeta->getLocalDumpStoragePath() . self::BACKUP_FILENAME;
100+
}
101+
}

src/Model/DbFacade.php

+27-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ public function __construct(
1515
private Db\DbUploader $uploader,
1616
private Db\DbImporter $importer,
1717
private Db\DbCleaner $cleaner,
18-
private Db\DbAdminAccountsManager $adminAccountsManager
18+
private Db\DbAdminAccountsManager $adminAccountsManager,
19+
private Db\DbConfigBackupManager $configBackupManager
1920
) {
2021
}
2122

@@ -83,4 +84,29 @@ public function cleanUpAdminAccountsBackup(ProjectMeta $projectMeta): void
8384
{
8485
$this->adminAccountsManager->cleanUp($projectMeta);
8586
}
87+
88+
public function backupLocalConfig(ProjectMeta $projectMeta): void
89+
{
90+
$this->configBackupManager->backupConfig($projectMeta);
91+
}
92+
93+
public function restoreLocalConfigFromBackup(ProjectMeta $projectMeta): void
94+
{
95+
$this->configBackupManager->restoreConfigBackup($projectMeta);
96+
}
97+
98+
public function cleanUpConfigBackup(ProjectMeta $projectMeta): void
99+
{
100+
$this->configBackupManager->cleanUp($projectMeta);
101+
}
102+
103+
public function backupConfigValues(): void
104+
{
105+
$this->configBackupManager->cacheConfigValuesToKeep();
106+
}
107+
108+
public function restoreConfigValues(): void
109+
{
110+
$this->configBackupManager->restoreConfigValuesToKeep();
111+
}
86112
}

src/etc/config.xml

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
<secret_access_key backend_model="Magento\Config\Model\Config\Backend\Encrypted"></secret_access_key>
88
<access_key_id backend_model="Magento\Config\Model\Config\Backend\Encrypted"></access_key_id>
99
</storage>
10+
<dump>
11+
<config_paths_keep>payment/%</config_paths_keep>
12+
</dump>
1013
</stripped_db_provider>
1114
</default>
1215
</config>

0 commit comments

Comments
 (0)