Passed
Push — master ( 9db4fb...a44597 )
by Roy
14:32 queued 50s
created

Synchronizer   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 211
Duplicated Lines 0 %

Importance

Changes 6
Bugs 2 Features 0
Metric Value
wmc 18
eloc 42
c 6
b 2
f 0
dl 0
loc 211
rs 10

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A getDirectory() 0 6 2
A getClassName() 0 3 1
A getSynchronizations() 0 10 1
A getFileSystem() 0 3 1
A resolve() 0 5 1
A run() 0 18 1
A getSynchronizationName() 0 5 1
A hasSynchronization() 0 3 1
A startTransaction() 0 4 2
A commitTransaction() 0 4 2
A tryHandle() 0 10 3
A getDefaultDirectory() 0 3 1
1
<?php
2
3
namespace LaravelSynchronize\Console\Synchronizer;
4
5
use Illuminate\Filesystem\Filesystem;
6
use Illuminate\Support\Collection;
7
use Illuminate\Support\Facades\DB;
8
use Illuminate\Support\Str;
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
     *
140
     * @return void
141
     */
142
    public function run(SplFileInfo $file)
143
    {
144
        $this->files->getRequire($file);
145
146
        $synchronization = $this->resolve(
147
            $this->getSynchronizationName($file)
148
        );
149
150
        $this->startTransaction($synchronization);
151
152
        $this->tryHandle($synchronization);
153
154
        $this->repository->log(
155
            $file->getFileName(),
156
            $this->repository->getNextBatchNumber()
157
        );
158
159
        $this->commitTransaction($synchronization);
160
    }
161
162
    /**
163
     * Try to execute the resolved class, if anything fails
164
     * rollback the database changes and throw an exception.
165
     * Rollback will only work when $withTransactions is true
166
     *
167
     * @param mixed $synchronization
168
     *
169
     * @return void
170
     *
171
     * @throws \Exception
172
     */
173
    public function tryHandle($synchronization)
174
    {
175
        try {
176
            $synchronization->handle();
177
        } catch (\Exception $exception) {
178
            if ($synchronization->withTransactions) {
179
                DB::rollBack();
180
            }
181
182
            throw $exception;
183
        }
184
    }
185
186
    /**
187
     * If the synchronization has database transactions enabled, start the transaction
188
     *
189
     * @param mixed $synchronization
190
     *
191
     * @return void
192
     */
193
    private function startTransaction($synchronization)
194
    {
195
        if ($synchronization->withTransactions) {
196
            DB::beginTransaction();
197
        }
198
    }
199
200
    /**
201
     * If the synchronization has database transactions enabled, commit the transaction.
202
     *
203
     * @param mixed $synchronization
204
     *
205
     * @return void
206
     */
207
    private function commitTransaction($synchronization)
208
    {
209
        if ($synchronization->withTransactions) {
210
            DB::commit();
211
        }
212
    }
213
214
    /**
215
     * Get default directive synchronizations are stored
216
     *
217
     * @return string
218
     */
219
    private function getDefaultDirectory()
220
    {
221
        return database_path('synchronizations');
222
    }
223
}
224