Skip to content

Commit 029481b

Browse files
committed
Add command to backup the configuration files seprately
1 parent 038c69d commit 029481b

File tree

2 files changed

+186
-2
lines changed

2 files changed

+186
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
<?php
2+
3+
namespace App\Command\Crons;
4+
5+
use App\Controller\Core\Application;
6+
use App\Services\Files\Archivizer\ZipArchivizer;
7+
use Exception;
8+
use Symfony\Component\Console\Command\Command;
9+
use Symfony\Component\Console\Input\InputArgument;
10+
use Symfony\Component\Console\Input\InputInterface;
11+
use Symfony\Component\Console\Output\OutputInterface;
12+
use Symfony\Component\Console\Style\SymfonyStyle;
13+
use TypeError;
14+
15+
/**
16+
* This command handles creating backup of configuration files
17+
* - separated from @see CronMakeBackupCommand to make it run more often
18+
*
19+
* Class CronMakeConfigBackupCommand
20+
* @package App\Command
21+
*/
22+
class CronMakeConfigBackupCommand extends Command
23+
{
24+
const MINIMUM_ARCHIVE_SIZE_IN_BYTES= 6000; // bytes ~6 kilobytes
25+
26+
const ARGUMENT_BACKUP_DIRECTORY = 'backup-directory';
27+
const ARGUMENT_BACKUP_FILE_FILENAME = "backup-file-name";
28+
29+
30+
const ENV_FILE_PATH = ".env";
31+
const CONFIGURATION_FOLDER_PATH = "./config";
32+
33+
const ALL_FOLDERS_TO_BACKUP = [
34+
self::CONFIGURATION_FOLDER_PATH,
35+
];
36+
37+
const ALL_FILES_TO_BACKUP = [
38+
self::ENV_FILE_PATH
39+
];
40+
41+
protected static $defaultName = 'cron:make-config-backup';
42+
43+
/**
44+
* @var ZipArchivizer $archivizer
45+
*/
46+
private ZipArchivizer $archivizer;
47+
48+
/**
49+
* @var SymfonyStyle $io
50+
*/
51+
private SymfonyStyle $io;
52+
53+
/**
54+
* @var string $backupFileName
55+
*/
56+
private string $backupFileName;
57+
58+
/**
59+
* @var Application $app
60+
*/
61+
private Application $app;
62+
63+
public function __construct(ZipArchivizer $archivizer, Application $app, string $name = null) {
64+
parent::__construct($name);
65+
66+
$this->app = $app;
67+
$this->archivizer = $archivizer;
68+
}
69+
70+
protected function configure()
71+
{
72+
$this
73+
->setDescription('This command allows to make backup of config files, must be called as sudo to ensure directories creating. ')
74+
->addArgument(self::ARGUMENT_BACKUP_DIRECTORY, InputArgument::REQUIRED,'Given directory will be used to store the backups (absolute path, ended with slash)')
75+
->addArgument(self::ARGUMENT_BACKUP_FILE_FILENAME, InputArgument::REQUIRED,'Database backup will be saved under that file name')
76+
->addUsage("
77+
sudo php7.4 bin/console cron:make-config-backup /backups/pms config_files_backups (will create a config file backup in the `/backups/pms`)
78+
")
79+
->setHelp("bin/console cron:make-config-backup /backupDir fileName");
80+
}
81+
82+
/**
83+
* @param InputInterface $input
84+
* @param OutputInterface $output
85+
* @throws Exception
86+
*/
87+
function initialize(InputInterface $input, OutputInterface $output)
88+
{
89+
$this->io = new SymfonyStyle($input, $output);
90+
if( !is_string($input->getArgument(self::ARGUMENT_BACKUP_FILE_FILENAME)) ){
91+
throw new Exception("Expected backup filename to be a string! Got: " . gettype(is_string($input->getArgument(self::ARGUMENT_BACKUP_FILE_FILENAME))));
92+
}
93+
$this->backupFileName = $input->getArgument(self::ARGUMENT_BACKUP_FILE_FILENAME);
94+
$backupDirectory = $input->getArgument(self::ARGUMENT_BACKUP_DIRECTORY);
95+
96+
$this->archivizer->setTargetDirectory($backupDirectory);
97+
$this->archivizer->setArchiveRecursively(true);
98+
99+
if( !file_exists($backupDirectory) ){
100+
mkdir($backupDirectory, 0777, true);
101+
}
102+
103+
// the directory still doesn't exists after attempt of crating such
104+
if( !file_exists($backupDirectory) ){
105+
throw new Exception("Target backup directory does not exist, even after attempt to create it");
106+
}
107+
108+
if( !is_writable($backupDirectory) ){
109+
throw new Exception("Folder does exist but it's not writable");
110+
}
111+
}
112+
113+
/**
114+
* @param InputInterface $input
115+
* @param OutputInterface $output
116+
* @return int
117+
* @throws Exception
118+
*/
119+
protected function execute(InputInterface $input, OutputInterface $output): int
120+
{
121+
$io = new SymfonyStyle($input, $output);
122+
123+
$io->warning("This command must be called from the root of the project. It won't work from other locations!");
124+
$io->note("Started config backup process");
125+
{
126+
try{
127+
$this->backupFiles();
128+
}catch(Exception | TypeError $e){
129+
$this->app->logExceptionWasThrown($e, [
130+
"info" => "Could not backup the config files",
131+
]);
132+
return self::FAILURE;
133+
}
134+
}
135+
$io->note("Config backup process has been completed");
136+
137+
return self::SUCCESS;
138+
}
139+
140+
/**
141+
* This function creates zip archive for config files
142+
*/
143+
private function backupFiles(){
144+
145+
$absolutePathsOfFilesToBackup = array_map(
146+
fn(string $pathOfFile) => getcwd() . DIRECTORY_SEPARATOR . $pathOfFile,
147+
self::ALL_FILES_TO_BACKUP
148+
);
149+
150+
$this->archivizer->setArchiveName($this->backupFileName);
151+
$this->archivizer->setDirectoriesToArchive(self::ALL_FOLDERS_TO_BACKUP);
152+
$this->archivizer->setFilesToArchive($absolutePathsOfFilesToBackup);
153+
$this->archivizer->setMinimalArchiveSize(self::MINIMUM_ARCHIVE_SIZE_IN_BYTES);
154+
$this->archivizer->handleArchivizing();
155+
156+
$message = $this->archivizer->getArchivingStatus();
157+
if( $this->archivizer->isArchivedSuccessfully() ){
158+
$this->io->success($message);
159+
}else{
160+
$this->io->warning($message);
161+
}
162+
}
163+
}

src/Services/Files/Archivizer/Archivizer.php

+23-2
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ abstract class Archivizer {
8585
*/
8686
protected $app;
8787

88+
/**
89+
* @var int $minimalArchiveSize
90+
*/
91+
private int $minimalArchiveSize = self::MINIMUM_ARCHIVE_SIZE;
92+
8893
/**
8994
* @return string
9095
*/
@@ -237,6 +242,22 @@ private function setArchiveFullPath(string $archiveFullPath): void {
237242
$this->archiveFullPath = $archiveFullPath;
238243
}
239244

245+
/**
246+
* @return int
247+
*/
248+
public function getMinimalArchiveSize(): int
249+
{
250+
return $this->minimalArchiveSize;
251+
}
252+
253+
/**
254+
* @param int $minimalArchiveSize
255+
*/
256+
public function setMinimalArchiveSize(int $minimalArchiveSize): void
257+
{
258+
$this->minimalArchiveSize = $minimalArchiveSize;
259+
}
260+
240261
/**
241262
* @param string $archiveName
242263
*/
@@ -326,7 +347,7 @@ private function checkArchive(){
326347
}else{
327348
$archiveSize = filesize($this->getArchiveFullPath());
328349

329-
if( self::MINIMUM_ARCHIVE_SIZE > $archiveSize ){
350+
if( $this->getMinimalArchiveSize() > $archiveSize ){
330351
$this->setIsArchivedSuccessfully(false);
331352
$this->setArchivingStatus(self::EXPORT_MESSAGE_EXPORTED_DATABASE_IS_TO_SMALL);
332353
return;
@@ -393,4 +414,4 @@ protected function extractArchiveFileFromAbsolutePath(string $absolutePath, stri
393414

394415
return $archivedFile;
395416
}
396-
}
417+
}

0 commit comments

Comments
 (0)