Skip to content

Commit

Permalink
Backups restoring big refactoring with tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
floor12 committed Nov 13, 2019
1 parent ba24792 commit 10cbf33
Show file tree
Hide file tree
Showing 14 changed files with 377 additions and 70 deletions.
1 change: 1 addition & 0 deletions composer.json
Expand Up @@ -22,6 +22,7 @@
],
"minimum-stability": "stable",
"require": {
"ext-zlib": "*",
"yiisoft/yii2": "~2.0.19",
"yii2mod/yii2-enum": "^1.7",
"ifsnop/mysqldump-php": "2.*",
Expand Down
72 changes: 12 additions & 60 deletions src/logic/BackupRestore.php
Expand Up @@ -12,9 +12,7 @@
use floor12\backup\models\BackupType;
use Yii;
use yii\base\InvalidConfigException;
use yii\base\UnknownPropertyException;
use yii\db\Connection;
use yii\web\BadRequestHttpException;

/**
* Class BackupRestore
Expand All @@ -32,6 +30,7 @@ class BackupRestore
private $_currentConfig;
private $_model;
private $_connection;
private $backupFilePath;

/**
* BackupRestore constructor.
Expand All @@ -55,72 +54,25 @@ public function __construct(Backup $model)
throw new \ErrorException("Config `{$model->config_id}` not found.");

$this->_model = $model;

$this->backupFilePath = Yii::getAlias(Yii::$app->getModule('backup')->backupFolder . DIRECTORY_SEPARATOR . $this->_model->filename);
}

/** Основной метод, который запускает весь процесс
* @throws \ErrorException
/**
* Ma
* @return bool
* @throws InvalidConfigException
* @throws \Exception
*/
public function run()
{
if ($this->_currentConfig['type'] == BackupType::DB)
return $this->restoreDatabase();

if ($this->_currentConfig['type'] == BackupType::FILES)
return $this->restoreFiles();
}


protected function restoreFiles()
{
$backupFile = Yii::getAlias(Yii::$app->getModule('backup')->backupFolder . DIRECTORY_SEPARATOR . $this->_model->filename);
$restorePath = Yii::getAlias($this->_currentConfig['path']);

if (!file_exists($backupFile))
throw new BadRequestHttpException('Backup file not found.');

if (!file_exists($restorePath))
throw new BadRequestHttpException('Restore path not found.');

exec("cd {$restorePath} && unzip -o {$backupFile}");
}


/** Восстанавливаем базу данных из дампа:
* Сначала пересоздаем её, выбираем, а дальше построчно читаем дамп из гзип-файла
* @throws \ErrorException
* @throws \yii\db\Exception
*/
private function restoreDatabase()
{
try {
if ($this->_currentConfig['type'] == BackupType::DB) {
$this->_connection = Yii::$app->{$this->_currentConfig['connection']};
} catch (UnknownPropertyException $e) {
throw new \ErrorException("Cound not find connection Yii::\$app->{$this->_currentConfig['connection']}");
return Yii::createObject(DatabaseBackupRestorer::class, [$this->backupFilePath, $this->_connection])->execute();
}

if (!function_exists("gzopen")) {
throw new ErrorException("Compression is enabled, but gzip lib is not installed or configured properly");
if ($this->_currentConfig['type'] == BackupType::FILES) {
$targetFolder = Yii::getAlias($this->_currentConfig['path']);
return Yii::createObject(FolderBackupRestorer::class, [$this->backupFilePath, $targetFolder])->execute();
}

$dbName = $this->_connection->createCommand("SELECT DATABASE()")->queryScalar();
$this->_connection->createCommand("DROP DATABASE `{$dbName}`")->execute();
$this->_connection->createCommand("CREATE DATABASE `{$dbName}`")->execute();
$this->_connection->createCommand("USE `{$dbName}`")->execute();

$sql = '';
$lines = gzfile($this->_model->getFullPath());

foreach ($lines as $line) {
if (substr($line, 0, 2) == '--' || $line == '')
continue;
$sql .= $line;
if (substr(trim($line), -1, 1) == ';') {
$this->_connection->createCommand($sql)->execute();
$sql = '';
}
}


}
}
66 changes: 66 additions & 0 deletions src/logic/DatabaseBackupRestorer.php
@@ -0,0 +1,66 @@
<?php


namespace floor12\backup\logic;


use yii\base\Exception;
use yii\db\Connection;

class DatabaseBackupRestorer
{
/**
* @var string
*/
protected $backupFilePath;
/**
* @var Connection
*/
protected $connection;
/**
* @var string
*/
protected $sql;

/**
* DatabaseBackupMaker constructor.
* @param string $backupFilePath
* @param Connection $connection
* @param string $dumperClass
* @throws Exception
*/
public function __construct(string $backupFilePath, Connection $connection)
{
if (!file_exists($backupFilePath))
throw new Exception("Backup file don`t exist.");

$this->backupFilePath = $backupFilePath;
$this->connection = $connection;
}

/**
* @return bool
* @throws \Exception
*/
public function execute()
{
$dbName = $this->connection->createCommand("SELECT DATABASE()")->queryScalar();

$this->connection->createCommand("DROP DATABASE `{$dbName}`")->execute();
$this->connection->createCommand("CREATE DATABASE `{$dbName}`")->execute();
$this->connection->createCommand("USE `{$dbName}`")->execute();

$lines = gzfile($this->backupFilePath);

foreach ($lines as $line) {
if (substr($line, 0, 2) == '--' || $line == '')
continue;
$this->sql .= $line;
if (substr(trim($line), -1, 1) == ';') {
$this->connection->createCommand($this->sql)->execute();
$this->sql = '';
}
}
return true;
}
}
46 changes: 46 additions & 0 deletions src/logic/FolderBackupRestorer.php
@@ -0,0 +1,46 @@
<?php

namespace floor12\backup\logic;

use yii\base\Exception;

class FolderBackupRestorer
{
/**
* @var string
*/
protected $backupFilePath;
/**
* @var string
*/
protected $targetFolder;

/**
* DatabaseBackupMaker constructor.
* @param string $backupFilePath
* @param string $targetFolder
* @throws Exception
*/
public function __construct(string $backupFilePath, string $targetFolder)
{
if (!file_exists($backupFilePath))
throw new Exception("Backup file don`t exist..");

if (!file_exists($targetFolder))
throw new Exception("Target folder don`t exist.");

$this->backupFilePath = $backupFilePath;
$this->targetFolder = $targetFolder;
}

/**
* @return bool
* @throws \Exception
*/
public function execute()
{
$command = "cd {$this->targetFolder} && unzip -o {$this->backupFilePath}";
exec($command, $r);
return true;
}
}
6 changes: 1 addition & 5 deletions src/messages/ru/backup.php
Expand Up @@ -20,16 +20,12 @@
'Done' => 'Готов',
'Error' => 'Ошибка',
'Delete' => 'Удалить',
'Restore' => 'Восстановить',
'Download' => 'Скачать',
'Backup was successful restored.' => 'Бекап успешно восстановлен.',
'Are your realy want to restor thie backup?' => 'Вы уверены, что хотите восстановить этот бекап?',
'Do you want to restore this backup?' => 'Вы уверены, что хотите восстановить этот бекап?',
'Backup was successful created.' => 'Бекап успешно создан.',
'Backup is not found.' => 'Бекап не найден.',
'Backup config is not found.' => 'Конфигурация бекапа не найдена.',
'Backup is deleted.' => 'Бекап удален',
'Run backup' => 'Запустить бекап',
'' => '',
'' => '',
'' => '',
];
4 changes: 2 additions & 2 deletions src/views/admin/index.php
Expand Up @@ -25,13 +25,13 @@

BackupAdminAsset::register($this);

$restoreConfirmText = Yii::t('app.f12.backup', 'Are your realy want to restor thie backup?');
$restoreConfirmText = Yii::t('app.f12.backup', 'Do you want to restore this backup?');
$restoreSuccessText = Yii::t('app.f12.backup', 'Backup was successful restored.');
$backupSuccessText = Yii::t('app.f12.backup', 'Backup was successful created.');
$deleteSuccessText = Yii::t('app.f12.backup', 'Backup is deleted.');
$this->registerJs("restoreConfirmText='{$restoreConfirmText}'", View::POS_READY, 'restoreConfirmText');
$this->registerJs("restoreSuccessText='{$restoreSuccessText}'", View::POS_READY, 'restoreSuccessText');
$this->registerJs("backupeSuccessText='{$backupeSuccessText}'", View::POS_READY, 'backupeSuccessText');
$this->registerJs("backupSuccessText='{$backupSuccessText}'", View::POS_READY, 'backupSuccessText');
$this->registerJs("deleteSuccessText='{$deleteSuccessText}'", View::POS_READY, 'deleteSuccessText');

?>
Expand Down
39 changes: 39 additions & 0 deletions tests/ConnectionMock.php
@@ -0,0 +1,39 @@
<?php


namespace floor12\backup\tests;


use yii\db\Connection;

class ConnectionMock extends Connection
{

public $databaseName;
/**
* @var array
*/
public $sql = [];

public function __construct($config = [])
{
parent::__construct($config);
}

public function createCommand($sql = null, $params = [])
{
$this->sql[] = trim($sql);
return $this;
}

public function execute()
{
return true;
}

public function queryScalar()
{
return $this->databaseName;
}

}
4 changes: 2 additions & 2 deletions tests/TestCase.php
Expand Up @@ -64,8 +64,8 @@ protected function setApp()
Yii::$app->setModule('backup', $backupModule);

$db = [
'class' => 'yii\db\Connection',
'dsn' => "sqlite:$this->sqlite",
'class' => ConnectionMock::class,
'databaseName' => "dataBaseName",
];
Yii::$app->set('db', $db);

Expand Down
Binary file added tests/data/test.tgz
Binary file not shown.
Binary file added tests/data/test.zip
Binary file not shown.

0 comments on commit 10cbf33

Please sign in to comment.