Passed
Pull Request — 9.x (#103)
by Andrey
12:39
created

BaseCommand   B

Complexity

Total Complexity 47

Size/Duplication

Total Lines 327
Duplicated Lines 0 %

Importance

Changes 20
Bugs 14 Features 0
Metric Value
eloc 128
dl 0
loc 327
rs 8.64
c 20
b 14
f 0
wmc 47

29 Methods

Rating   Name   Duplication   Size   Complexity  
A files() 0 12 2
A boolOption() 0 5 2
A action() 0 5 1
A targetLocales() 0 5 1
A start() 0 7 1
A ranFiles() 0 14 2
A ranLocales() 0 11 2
A validateLocale() 0 5 1
A processed() 0 7 1
A ensureDirectory() 0 5 2
A locales() 0 9 2
A process() 0 11 2
A filesLength() 0 17 3
A packages() 0 5 1
A ranPackages() 0 25 4
A localesLength() 0 11 2
A ran() 0 10 2
A hasFull() 0 5 1
A validatePackage() 0 5 1
A hasProcessed() 0 5 2
A hasInline() 0 5 1
A pushProcessed() 0 6 3
A clean() 0 5 1
A end() 0 7 1
A extraPackages() 0 10 2
A hasForce() 0 5 1
A processing() 0 7 1
A handle() 0 7 1
A message() 0 8 1

How to fix   Complexity   

Complex Class

Complex classes like BaseCommand often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use BaseCommand, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Helldar\LaravelLangPublisher\Console;
4
5
use Helldar\LaravelLangPublisher\Concerns\Containable;
6
use Helldar\LaravelLangPublisher\Concerns\Logger;
7
use Helldar\LaravelLangPublisher\Concerns\Pathable;
8
use Helldar\LaravelLangPublisher\Constants\Locales as LocalesList;
9
use Helldar\LaravelLangPublisher\Constants\Packages as PackagesConst;
10
use Helldar\LaravelLangPublisher\Contracts\Actionable;
11
use Helldar\LaravelLangPublisher\Contracts\Processor;
12
use Helldar\LaravelLangPublisher\Facades\Config;
13
use Helldar\LaravelLangPublisher\Facades\Info;
14
use Helldar\LaravelLangPublisher\Facades\Locales;
15
use Helldar\LaravelLangPublisher\Facades\Packages;
16
use Helldar\LaravelLangPublisher\Facades\Validator;
17
use Helldar\LaravelLangPublisher\Services\Command\Locales as LocalesSupport;
18
use Helldar\LaravelLangPublisher\Support\Info as InfoSupport;
19
use Helldar\Support\Facades\Helpers\Arr;
20
use Helldar\Support\Facades\Helpers\Filesystem\Directory;
21
use Helldar\Support\Facades\Helpers\Filesystem\File;
22
use Helldar\Support\Facades\Helpers\Str;
23
use Illuminate\Console\Command;
24
25
abstract class BaseCommand extends Command
26
{
27
    use Containable;
28
    use Logger;
29
    use Pathable;
30
31
    protected $action;
32
33
    protected $locales_length = 0;
34
35
    protected $files_length = 0;
36
37
    protected $files;
38
39
    protected $locales;
40
41
    protected $extra_packages;
42
43
    protected $processed = [];
44
45
    abstract protected function processor(?string $filename): Processor;
46
47
    public function handle()
48
    {
49
        $this->setLogger();
50
        $this->start();
51
        $this->clean();
52
        $this->ran();
53
        $this->end();
54
    }
55
56
    protected function ran(): void
57
    {
58
        $this->log('Starting processing of the package list...');
59
60
        foreach ($this->packages() as $package) {
61
            $this->log('Packages handling:', $package);
62
63
            $this->validatePackage($package);
64
65
            $this->ranLocales($package);
66
        }
67
    }
68
69
    protected function ranLocales(string $package): void
70
    {
71
        $this->log('Starting processing of the locales list for the', $package, 'package...');
72
73
        foreach ($this->locales() as $locale) {
74
            $this->log('Localization handling:', $locale);
75
76
            $this->validateLocale($locale);
77
78
            $this->ranFiles($package, $locale);
79
            $this->ranPackages($package, $locale);
80
        }
81
    }
82
83
    protected function ranFiles(string $package, string $locale): void
84
    {
85
        $this->log('Starting processing of the files for the', $package, 'package and', $locale, 'localization...');
86
87
        foreach ($this->files($package) as $filename) {
88
            $this->log('Processing the localization file:', $filename);
89
90
            $this->processing($locale, $filename, $package);
91
92
            $status = $this->process($package, $locale, $filename, $filename);
93
94
            $this->pushProcessed($filename);
95
96
            $this->processed($locale, $filename, $status, $package);
97
        }
98
    }
99
100
    protected function ranPackages(string $package, string $locale): void
101
    {
102
        $this->log('Starting processing of extra files for the', $package, 'package and', $locale, 'localization...');
103
104
        foreach ($this->extraPackages() as $extra_package) {
105
            if (! $extra_package->has($package, $locale)) {
106
                continue;
107
            }
108
109
            $name      = $extra_package->vendor();
110
            $filenames = $extra_package->source();
111
112
            foreach ($filenames as $filename) {
113
                $path   = $extra_package->targetPath($locale, $filename);
114
                $target = $extra_package->targetFilename($locale, $filename);
115
116
                $this->processing($locale, $name, $package);
117
118
                $this->ensureDirectory($path, true);
119
120
                $status = $this->process($package, $locale, $filename, $target);
121
122
                $this->pushProcessed($path);
123
124
                $this->processed($locale, $name, $status, $package);
125
            }
126
        }
127
    }
128
129
    protected function process(?string $package, ?string $locale, ?string $source_filename, ?string $target_filename): string
130
    {
131
        $this->log('Launching the processor for localization:', $locale, ',', $source_filename);
132
133
        return $this->processor($source_filename)
134
            ->force($this->hasForce() || $this->hasProcessed($source_filename))
135
            ->whenPackage($package)
136
            ->whenLocale($locale)
137
            ->whenSourceFilename($source_filename, $this->hasInline())
138
            ->whenTargetFilename($target_filename)
139
            ->run();
140
    }
141
142
    protected function locales(): array
143
    {
144
        $this->log('Getting a list of localizations...');
145
146
        if (! empty($this->locales)) {
147
            return $this->locales;
148
        }
149
150
        return $this->locales = LocalesSupport::make($this->input, $this->output, $this->action(), $this->targetLocales())->get();
151
    }
152
153
    protected function targetLocales(): array
154
    {
155
        $this->log('Getting a list of installed localizations...');
156
157
        return Locales::installed();
158
    }
159
160
    protected function packages(): array
161
    {
162
        $this->log('Getting a list of packages available for processing...');
163
164
        return Packages::get();
165
    }
166
167
    protected function files(string $package): array
168
    {
169
        $this->log('Getting a list of files for the ', $package, 'package...');
170
171
        if ($this->files[$package] ?? false) {
172
            return $this->files[$package];
173
        }
174
175
        $path = $this->pathSource($package, LocalesList::ENGLISH);
176
177
        return $this->files[$package] = File::names($path, static function ($filename) {
178
            return ! Str::contains($filename, 'inline');
179
        });
180
    }
181
182
    /**
183
     * @return array|\Helldar\LaravelLangPublisher\Packages\Package[]
184
     */
185
    protected function extraPackages(): array
186
    {
187
        if (! empty($this->extra_packages)) {
188
            return $this->extra_packages;
189
        }
190
191
        return $this->extra_packages = array_map(static function ($package) {
192
            /* @var \Helldar\LaravelLangPublisher\Packages\Package $package */
193
            return $package::make();
194
        }, PackagesConst::ALL);
195
    }
196
197
    protected function start(): void
198
    {
199
        $this->log('Running the console command:', parent::class);
200
201
        $action = $this->action()->present(true);
202
203
        $this->info($action . ' localizations...');
204
    }
205
206
    protected function end(): void
207
    {
208
        $this->log('Completing the execution of the console command...');
209
210
        $action = $this->action()->past();
211
212
        $this->info('Localizations have ben successfully ' . $action . '.');
213
    }
214
215
    protected function processing(string $locale, string $filename, string $package = null): void
216
    {
217
        $this->log('Displaying a message about the start of file processing: locale is', $locale, ', filename is', $filename, ', package is', $package . '...');
218
219
        $message = $this->message($locale, $filename, $package)->start();
220
221
        $this->output->write($message);
222
    }
223
224
    protected function processed(string $locale, string $filename, string $status, string $package = null): void
225
    {
226
        $this->log('Displaying a message about the finish of file processing: locale is', $locale, ', filename is', $filename, ', package is', $package . '...');
227
228
        $message = $this->message($locale, $filename, $package)->finish($status);
229
230
        $this->output->writeln($message);
231
    }
232
233
    protected function message(string $locale, string $filename, string $package = null): InfoSupport
234
    {
235
        $this->log('Preparing an object for displaying a message: locale is', $locale, ', filename is', $filename, ', package is', $package . '...');
236
237
        return Info::same()
238
            ->package($package)
239
            ->locale($locale, $this->localesLength())
240
            ->filename($filename, $this->filesLength());
241
    }
242
243
    protected function localesLength(): int
244
    {
245
        $this->log('Getting the maximum length of a localization string...');
246
247
        if ($this->locales_length > 0) {
248
            return $this->locales_length;
249
        }
250
251
        $this->log('Calculating the maximum length of a localization string...');
252
253
        return $this->locales_length = Arr::longestStringLength($this->locales());
254
    }
255
256
    protected function filesLength(): int
257
    {
258
        $this->log('Getting the maximum length of a filenames...');
259
260
        if ($this->files_length > 0) {
261
            return $this->files_length;
262
        }
263
264
        $this->log('Calculating the maximum length of a filenames...');
265
266
        $files = [];
267
268
        foreach ($this->packages() as $package) {
269
            $files = array_merge($files, $this->files($package));
270
        }
271
272
        return $this->files_length = Arr::longestStringLength(array_unique($files));
273
    }
274
275
    protected function hasInline(): bool
276
    {
277
        $this->log('Getting a use case for a validation file.');
278
279
        return Config::hasInline();
280
    }
281
282
    protected function action(): Actionable
283
    {
284
        $this->log('Getting the action...');
285
286
        return $this->container($this->action);
287
    }
288
289
    protected function ensureDirectory(string $path, bool $is_file = false): void
290
    {
291
        $path = $is_file ? $this->pathDirectory($path) : $path;
292
293
        Directory::ensureDirectory($path);
294
    }
295
296
    protected function pushProcessed(?string $filename): void
297
    {
298
        $this->log('Add a link to the processed file to the cache:', $filename);
299
300
        if ($filename && ! $this->hasProcessed($filename)) {
301
            $this->processed[] = $filename;
302
        }
303
    }
304
305
    protected function hasProcessed(?string $filename): bool
306
    {
307
        $this->log('Check if the file was processed earlier:', $filename);
308
309
        return $filename && in_array($filename, $this->processed, true);
310
    }
311
312
    protected function hasForce(): bool
313
    {
314
        $this->log('Getting the value of the "force" option...');
315
316
        return $this->boolOption('force');
317
    }
318
319
    protected function hasFull(): bool
320
    {
321
        $this->log('Getting the value of the "full" option...');
322
323
        return $this->boolOption('full');
324
    }
325
326
    protected function boolOption(string $key): bool
327
    {
328
        $this->log('Getting the value of the "', $key, '" option...');
329
330
        return $this->hasOption($key) && $this->option($key);
331
    }
332
333
    protected function validateLocale(string $locale): void
334
    {
335
        $this->log('Calling the localization validation method: ', $locale, '...');
336
337
        Validator::locale($locale);
338
    }
339
340
    protected function validatePackage(string $package): void
341
    {
342
        $this->log('Calling the package validation method: ', $package, '...');
343
344
        Validator::package($package);
345
    }
346
347
    protected function clean(): void
348
    {
349
        $this->log('Clear the variable from the saved localizations...');
350
351
        $this->locales = null;
352
    }
353
}
354