Passed
Push — master ( fabd45...a8694e )
by Ron
03:26 queued 11s
created

backupRestore   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 176
Duplicated Lines 0 %

Test Coverage

Coverage 3.25%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 78
c 1
b 0
f 0
dl 0
loc 176
ccs 3
cts 92
cp 0.0325
rs 10
wmc 19

10 Methods

Rating   Name   Duplication   Size   Complexity  
A cleanup() 0 3 1
A prepareBackup() 0 14 1
A handle() 0 36 5
A loadDatabase() 0 5 1
A checkVersion() 0 14 2
A replaceFiles() 0 19 1
A wipeDatabase() 0 7 1
A copyAllFiles() 0 8 2
A __construct() 0 3 1
A clearAllFiles() 0 14 4
1
<?php
2
3
namespace App\Console\Commands;
4
5
use Zip;
6
use Illuminate\Support\Arr;
7
use Illuminate\Console\Command;
8
use Illuminate\Support\Facades\Storage;
9
use Illuminate\Support\Facades\File;
10
use Symfony\Component\Process\Process;
11
use Symfony\Component\Process\Exception\ProcessFailedException;
12
13
use Illuminate\Support\Facades\DB;
14
15
class backupRestore extends Command
16
{
17
    /**
18
     * The name and signature of the console command.
19
     *
20
     * @var string
21
     */
22
    protected $signature = 'tb-backup:restore {filename} {--confirmed}';
23
24
    /**
25
     * The console command description.
26
     *
27
     * @var string
28
     */
29
    protected $description = 'Restore application from a previous backup';
30
    protected $archive, $bar, $baseName;
31
32
    /**
33
     * Create a new command instance.
34
     *
35
     * @return void
36
     */
37 2
    public function __construct()
38
    {
39 2
        parent::__construct();
40 2
    }
41
42
    /**
43
     * Execute the console command.
44
     *
45
     * @return mixed
46
     */
47
    public function handle()
48
    {
49
        if(!Storage::disk('backup')->exists($this->argument('filename')))
0 ignored issues
show
Bug introduced by
It seems like $this->argument('filename') can also be of type string[]; however, parameter $path of Illuminate\Filesystem\FilesystemAdapter::exists() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

49
        if(!Storage::disk('backup')->exists(/** @scrutinizer ignore-type */ $this->argument('filename')))
Loading history...
50
        {
51
            $this->error('The backup filename you entered does not exist.');
52
            $this->error('Exiting                                        ');
53
            return 1;
54
        }
55
56
        if(!$this->option('confirmed'))
57
        {
58
            $this->question('____________________________________________________________');
59
            $this->question('|                  IMPORTANT NOTE:                         |');
60
            $this->question('|   ALL DATA WILL BE ERASED AND REPLACED WITH THE BACKUP   |');
61
            $this->question('|__________________________________________________________|');
62
        }
63
64
        if($this->option('confirmed') || $this->confirm('Are You Sure?'))
65
        {
66
            $this->line('Restoring Backup.  Please Wait');
67
            $this->line('This could take some time');
68
            $this->bar = $this->output->createProgressBar(10);
69
            $this->call('down');
70
            $this->prepareBackup();
71
            $this->checkVersion();
72
            $this->replaceFiles();
73
            $this->wipeDatabase();
74
            $this->loadDatabase();
75
            $this->cleanup();
76
            $this->bar->finish();
77
            $this->line('');
78
            $this->call('up');
79
            $this->line('Restore Completed');
80
        }
81
82
        return 1;
83
    }
84
85
    //  Open the zip and prepare it for restore
86
    protected function prepareBackup()
87
    {
88
        $this->bar->advance();
89
        $fileParts = pathinfo($this->argument('filename'));
0 ignored issues
show
Bug introduced by
It seems like $this->argument('filename') can also be of type string[]; however, parameter $path of pathinfo() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

89
        $fileParts = pathinfo(/** @scrutinizer ignore-type */ $this->argument('filename'));
Loading history...
90
        $this->baseName = $fileParts['filename'];
91
        $this->archive = Zip::open(config('filesystems.disks.backup.root') . DIRECTORY_SEPARATOR.$this->argument('filename'));
0 ignored issues
show
Bug introduced by
Are you sure $this->argument('filename') of type null|string|string[] can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

91
        $this->archive = Zip::open(config('filesystems.disks.backup.root') . DIRECTORY_SEPARATOR./** @scrutinizer ignore-type */ $this->argument('filename'));
Loading history...
92
        // if (!$this->archive->has('version.txt')) {
93
        //     $this->error('THIS IS NOT A VALID TECH BENCH BACKUP');
94
        //     $this->error('Exiting');
95
        //     return 1;
96
        // }
97
98
        $this->archive->extract(config('filesystems.disks.backup.root').DIRECTORY_SEPARATOR.$this->baseName);
99
        $this->bar->advance();
100
    }
101
102
    protected function cleanup()
103
    {
104
        Storage::disk('backup')->deleteDirectory($this->baseName);
105
    }
106
107
    //  Check to verify that the version matches
108
    protected function checkVersion()
109
    {
110
        $backupVer = Storage::disk('backup')->get($this->baseName.DIRECTORY_SEPARATOR.'version.txt');
111
        $appVer = new \PragmaRX\Version\Package\Version();
112
        $this->bar->advance();
113
114
        if($backupVer !== $appVer->version_only())
115
        {
116
            $this->error('Unable to Restore, you are running '.$appVer->version());
117
            $this->error('This backup is for version '.$backupVer);
118
            $this->error('Please load the proper version before loading this backup');
119
120
            $this->cleanup();
121
            return 1;
122
        }
123
    }
124
125
    protected function clearAllFiles($disk)
126
    {
127
        $files = Storage::disk($disk)->files();
128
        foreach($files as $file)
129
        {
130
            if($file != '.gitignore')
131
            {
132
                Storage::disk($disk)->delete($file);
133
            }
134
        }
135
        $folders = Storage::disk($disk)->directories();
136
        foreach($folders as $folder)
137
        {
138
            Storage::disk($disk)->deleteDirectory($folder);
139
        }
140
    }
141
142
    protected function copyAllFiles($backupFolder, $disk)
143
    {
144
        $files = Storage::disk('backup')->allFiles($this->baseName.DIRECTORY_SEPARATOR.$backupFolder);
145
146
        foreach($files as $file)
147
        {
148
            $newFile = str_replace($this->baseName.'/'.$backupFolder.'/', '', $file);
149
            Storage::disk($disk)->put($newFile, Storage::disk('backup')->get($file));
150
        }
151
    }
152
153
    //  Replace the system files
154
    protected function replaceFiles()
155
    {
156
        $this->bar->advance();
157
        //  Start with the .env file
158
        $env = Storage::disk('backup')->get($this->baseName.DIRECTORY_SEPARATOR.'.env');
159
        File::put(base_path().DIRECTORY_SEPARATOR.'.env', $env);
160
        $this->bar->advance();
161
        //  Replace the log files
162
        $this->clearAllFiles('logs');
163
        $this->copyAllFiles('logs', 'logs');
164
        $this->bar->advance();
165
        //  Replace the public files
166
        $this->clearAllFiles('public');
167
        $this->copyAllFiles('public', 'public');
168
        $this->bar->advance();
169
        //  Replace all upladed files
170
        $this->clearAllFiles('local');
171
        $this->copyAllFiles('files', 'local');
172
        $this->bar->advance();
173
    }
174
175
    //  Clear out current database
176
    protected function wipeDatabase()
177
    {
178
        DB::connection(DB::getDefaultConnection())
179
            ->getSchemaBuilder()
180
            ->dropAllTables();
181
        DB::reconnect();
182
        $this->bar->advance();
183
    }
184
185
    //  Load the backed up database
186
    protected function loadDatabase()
187
    {
188
        $dbContents = Storage::disk('backup')->get($this->baseName.DIRECTORY_SEPARATOR.'database.sql');
189
        DB::unprepared($dbContents);
190
        $this->bar->advance();
191
    }
192
}
193