Synchronizer::run()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 10
c 1
b 0
f 0
dl 0
loc 19
rs 9.9332
cc 1
nc 1
nop 2
1
<?php
2
3
namespace LaravelSynchronize\Console\Synchronizer;
4
5
use Illuminate\Support\Str;
6
use Illuminate\Support\Collection;
7
use Illuminate\Support\Facades\DB;
8
use Illuminate\Filesystem\Filesystem;
9
use Symfony\Component\Finder\SplFileInfo;
10
11
class Synchronizer
12
{
13
    /**
14
     * The filesystem instance.
15
     *
16
     * @var \Illuminate\Filesystem\Filesystem
17
     */
18
    protected $files;
19
20
    /**
21
     * The Repository instance.
22
     *
23
     * @var \LaravelSynchronize\Console\Synchronizer\SynchronizerRepository $repository
24
     */
25
    protected $repository;
26
27
    /**
28
     * Create a new controller creator command instance.
29
     *
30
     * @param  \Illuminate\Filesystem\Filesystem  $files
31
     * @param  \LaravelSynchronize\Console\Synchronizer\SynchronizerRepository  $repository
32
     *
33
     * @return void
34
     */
35
    public function __construct(FileSystem $files, SynchronizerRepository $repository)
36
    {
37
        $this->repository = $repository;
38
        $this->files = $files;
39
    }
40
41
    /**
42
     * Get the directory where synchronizations are saved
43
     * It will be created if the directive doesn't exist.
44
     *
45
     * @return string
46
     */
47
    public function getDirectory()
48
    {
49
        $directory = config('synchronizer.folder') ?? $this->getDefaultDirectory();
50
        $this->files->isDirectory($directory) ?: $this->files->makeDirectory($directory);
51
52
        return $directory;
53
    }
54
55
    /**
56
     * Get the instance of Filesystem
57
     *
58
     * @return \Illuminate\Filesystem\Filesystem
59
     */
60
    public function getFileSystem()
61
    {
62
        return $this->files;
63
    }
64
65
    /**
66
     * Get all synchronization files
67
     *
68
     * @return \Illuminate\Support\Collection
69
     */
70
    public function getSynchronizations(): Collection
71
    {
72
        return collect($this->files->files($this->getDirectory()))
73
            ->filter()
74
            ->values()
75
            ->keyBy(function ($file) {
76
                return $this->getSynchronizationName($file);
77
            })
78
            ->sortBy(function ($file, $key) {
79
                return $key;
80
            });
81
    }
82
83
    /**
84
     * Get the name of the synchronization stripped of the date and time.
85
     *
86
     * @param  string  $path
87
     *
88
     * @return string
89
     */
90
    public function getSynchronizationName($path)
91
    {
92
        $path = str_replace($this->getDirectory(), '', $path);
93
94
        return str_replace('.php', '', basename($path));
95
    }
96
97
    /**
98
     * Get the class name of a synchronization name.
99
     *
100
     * @param  string  $fileName
101
     *
102
     * @return string
103
     */
104
    public function getClassName(string $fileName)
105
    {
106
        return Str::studly(implode('_', array_slice(explode('_', $fileName), 4)));
107
    }
108
109
    /**
110
     * Determine if a synchronization exists with given name
111
     *
112
     * @param string $name
113
     *
114
     * @return boolean
115
     */
116
    public function hasSynchronization(string $name)
117
    {
118
        return !empty($this->files->glob($this->getDirectory() . "/*_*_{$name}.php"));
119
    }
120
121
    /**
122
     * Resolve a synchronization instance from a file.
123
     *
124
     * @param  string  $fileName
125
     *
126
     * @return object
127
     */
128
    public function resolve($fileName)
129
    {
130
        $class = $this->getClassName($fileName);
131
132
        return new $class();
133
    }
134
135
    /**
136
     * include the file with Require and call the class it's handler
137
     *
138
     * @param  \Symfony\Component\Finder\SplFileInfo $file
139
     * @param  string $operation
140
     *
141
     * @return void
142
     */
143
    public function run(SplFileInfo $file, string $operation)
144
    {
145
        $this->files->getRequire($file);
146
147
        $synchronization = $this->resolve(
148
            $this->getSynchronizationName($file)
149
        );
150
151
        $this->startTransaction($synchronization);
152
153
        $this->tryHandle($synchronization, $operation);
154
155
        $this->repository->log(
156
            $file->getFileName(),
157
            $this->repository->getNextBatchNumber(),
158
            $operation
159
        );
160
161
        $this->commitTransaction($synchronization);
162
    }
163
164
    /**
165
     * Try to execute the resolved class, if anything fails
166
     * rollback the database changes and throw an exception.
167
     * Rollback will only work when $withTransactions is true
168
     *
169
     * @param mixed $synchronization
170
     * @param string $operation
171
     *
172
     * @return void
173
     *
174
     * @throws \Exception
175
     */
176
    public function tryHandle($synchronization, string $operation)
177
    {
178
        try {
179
            if ($operation === 'up') {
180
                $synchronization->up();
181
            } else {
182
                $synchronization->down();
183
            }
184
        } catch (\Exception $exception) {
185
            if ($synchronization->withTransactions) {
186
                DB::rollBack();
187
            }
188
189
            throw $exception;
190
        }
191
    }
192
193
    /**
194
     * If the synchronization has database transactions enabled, start the transaction
195
     *
196
     * @param mixed $synchronization
197
     *
198
     * @return void
199
     */
200
    private function startTransaction($synchronization)
201
    {
202
        if ($synchronization->withTransactions) {
203
            DB::beginTransaction();
204
        }
205
    }
206
207
    /**
208
     * If the synchronization has database transactions enabled, commit the transaction.
209
     *
210
     * @param mixed $synchronization
211
     *
212
     * @return void
213
     */
214
    private function commitTransaction($synchronization)
215
    {
216
        if ($synchronization->withTransactions) {
217
            DB::commit();
218
        }
219
    }
220
221
    /**
222
     * Get default directive synchronizations are stored
223
     *
224
     * @return string
225
     */
226
    private function getDefaultDirectory()
227
    {
228
        return database_path('synchronizations');
229
    }
230
}
231