Completed
Push — master ( 7ecfd2...c84e1c )
by Sergi Tur
03:37
created

LlumCommand::showWarningIfLaravelConfigAlreadySupportsLlum()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
rs 9.4285
cc 2
eloc 4
nc 2
nop 0
1
<?php
2
3
namespace Acacha\Llum\Console;
4
5
use Acacha\Llum\Exceptions\InvalidCommandException;
6
use Illuminate\Config\Repository;
7
use Symfony\Component\Console\Command\Command;
8
use Symfony\Component\Console\Input\InputArgument;
9
use Symfony\Component\Console\Input\InputInterface;
10
use Symfony\Component\Console\Output\OutputInterface;
11
use Symfony\Component\Process\Process;
12
13
/**
14
 * Class LlumCommand.
15
 */
16
abstract class LlumCommand extends Command
17
{
18
    /**
19
     * The output interface.
20
     *
21
     * @var OutputInterface
22
     */
23
    protected $output;
24
25
    /**
26
     * Command name.
27
     *
28
     * @var string
29
     */
30
    protected $commandName;
31
32
    /**
33
     * Command description.
34
     *
35
     * @var string
36
     */
37
    protected $commandDescription;
38
39
    /**
40
     * Command argument.
41
     *
42
     * @var string
43
     */
44
    protected $argument;
45
46
    /**
47
     * Argument type.
48
     *
49
     * @var int
50
     */
51
    protected $argumentType = InputArgument::REQUIRED;
52
53
    /**
54
     * Command argument description.
55
     *
56
     * @var string
57
     */
58
    protected $argumentDescription;
59
60
    /**
61
     * Method to execute.
62
     *
63
     * @var string
64
     */
65
    protected $method;
66
67
    /**
68
     * Laravel config file (config/app.php).
69
     *
70
     * @var string
71
     */
72
    protected $laravel_config_file;
73
74
    /**
75
     * Path to config folder.
76
     *
77
     * @var string
78
     */
79
    protected $configPath;
80
81
    /**
82
     * Avoids using bash using stubs instead to modify config/app.php file.
83
     *
84
     * @var bool
85
     */
86
    protected $noBash = false;
87
88
    /**
89
     * Config repository.
90
     *
91
     * @var Repository
92
     */
93
    protected $config;
94
95
    /**
96
     * LlumCommand constructor.
97
     */
98
    public function __construct()
99
    {
100
        parent::__construct();
101
        $this->configPath = __DIR__.'/../config/';
102
        $this->laravel_config_file = getcwd().'/config/app.php';
103
        $this->config = $this->obtainConfig();
104
    }
105
106
    /**
107
     * Install /config/app.php file using bash script.
108
     */
109
    protected function installConfigAppFileWithBash()
110
    {
111
        passthru(__DIR__.'/../bash_scripts/iluminar.sh '.$this->laravel_config_file);
112
    }
113
114
    /**
115
     * Install /stubs/app.php into /config/app.php.
116
     */
117
    protected function installConfigAppFileWithStubs()
118
    {
119
        copy(__DIR__.'/stubs/app.php', $this->laravel_config_file);
120
    }
121
122
    /**
123
     * Check if Laravel config file exists.
124
     *
125
     * @return bool
126
     */
127
    protected function checkIfLaravelConfigFileExists()
128
    {
129
        return file_exists($this->laravel_config_file);
130
    }
131
132
    /**
133
     * Install llum custom config/app.php file.
134
     *
135
     * @return int
136
     */
137
    protected function installConfigAppFile()
138
    {
139
        $this->testLaravelConfigFileExists();
140
141
        $this->showWarningIfLaravelConfigAlreadySupportsLlum();
142
143
        if ($this->isNoBashActive()) {
144
            $this->installConfigAppFileWithStubs();
145
            $this->output->writeln('<info>File '.$this->laravel_config_file.' overwrited correctly with and stub.</info>');
146
        } else {
147
            $this->installConfigAppFileWithBash();
148
        }
149
150
        return 0;
151
    }
152
153
    /**
154
     * Show warning if Laravel config file already supports llum
155
     *
156
     * @return int
157
     */
158
    private function showWarningIfLaravelConfigAlreadySupportsLlum()
159
    {
160
        if ($this->configAppFileAlreadyInstalled()) {
161
            $this->output->writeln('<info>File '.$this->laravel_config_file.' already supports llum.</info>');
162
163
            return 0;
164
        }
165
    }
166
167
    /**
168
     * Test Laravel config file exists.
169
     *
170
     * @return int
171
     */
172
    private function testLaravelConfigFileExists()
173
    {
174
        if (! $this->checkIfLaravelConfigFileExists()) {
175
            $this->output->writeln('<error>File '.$this->laravel_config_file.' doesn\'t exists');
176
177
            return -1;
178
        }
179
    }
180
181
    /**
182
     * Check if config/app.php stub file is already installed.
183
     *
184
     * @return bool
185
     */
186
    protected function configAppFileAlreadyInstalled()
187
    {
188
        if (strpos(file_get_contents($this->laravel_config_file), '#llum_providers') !== false) {
189
            return true;
190
        }
191
192
        return false;
193
    }
194
195
    /**
196
     * Add Laravel IDE Helper provider to config/app.php file.
197
     *
198
     * @return int|null
199
     */
200
    protected function addLaravelIdeHelperProvider()
201
    {
202
        return $this->addProvider('Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class');
203
    }
204
205
    /**
206
     *  Add provider to config/app.php file.
207
     *
208
     * @param $provider
209
     *
210
     * @return int|null
211
     */
212
    private function addProvider($provider)
213
    {
214
        return $this->addTextIntoMountPoint('#llum_providers', $provider);
215
    }
216
217
    /**
218
     * Add alias to config/app.php file.
219
     *
220
     * @param string $alias
221
     *
222
     * @return int|null
223
     */
224
    private function addAlias($alias)
225
    {
226
        return $this->addTextIntoMountPoint('#llum_aliases', $alias);
227
    }
228
229
    /**
230
     * Insert text into file using mountpoint. Mountpoint is maintained at file.
231
     *
232
     * @param string $mountpoint
233
     * @param $textToAdd
234
     *
235
     * @return int|null
236
     */
237
    private function addTextIntoMountPoint($mountpoint, $textToAdd)
238
    {
239
        passthru(
240
            'sed -i \'s/.*'.$mountpoint.'.*/ \ \ \ \ \ \ \ '.$this->scapeSingleQuotes(preg_quote($textToAdd)).',\n \ \ \ \ \ \ \ '.$mountpoint.'/\' '.$this->laravel_config_file, $error);
241
242
        return $error;
243
    }
244
245
    /**
246
     * scape single quotes for sed using \x27.
247
     *
248
     * @param string $str
249
     *
250
     * @return string
251
     */
252
    private function scapeSingleQuotes($str)
253
    {
254
        return str_replace("'", '\\x27', $str);
255
    }
256
257
    /**
258
     * Require composer package.
259
     *
260
     * @param $package
261
     */
262
    private function requireComposerPackage($package)
263
    {
264
        $composer = $this->findComposer();
265
266
        $process = new Process($composer.' require '.$package.'', null, null, null, null);
267
        $this->output->writeln('<info>Running composer require '.$package.'</info>');
268
        $process->run(function ($type, $line) {
269
            $this->output->write($line);
270
        });
271
    }
272
273
    /**
274
     * Get the composer command for the environment.
275
     *
276
     * @return string
277
     */
278
    private function findComposer()
279
    {
280
        if (file_exists(getcwd().'/composer.phar')) {
281
            return '"'.PHP_BINARY.'" composer.phar"';
282
        }
283
284
        return 'composer';
285
    }
286
287
    /**
288
     * Installs provider in laravel config/app.php file.
289
     *
290
     * @param $provider
291
     */
292
    protected function provider($provider)
293
    {
294
        if ($this->installConfigAppFile() == -1) {
295
            return;
296
        }
297
        $this->addProvider($provider);
298
    }
299
300
    /**
301
     * Installs alias/facade in laravel config/app.php file.
302
     *
303
     * @param $aliasName
304
     * @param $aliasClass
305
     */
306
    protected function alias($aliasName, $aliasClass)
307
    {
308
        if ($this->installConfigAppFile() == -1) {
309
            return;
310
        }
311
        $this->addAlias("'".$aliasName."' => ".$aliasClass);
312
    }
313
314
    /**
315
     * get package from config.
316
     *
317
     * @param $name
318
     *
319
     * @return array
320
     */
321
    private function getPackageFromConfig($name)
322
    {
323
        //Check if package name is a composer package name
324
        if (str_contains($name, '/')) {
325
            return $this->config->get($this->getPackageNameByComposerName($name));
326
        }
327
328
        return $this->config->get($name);
329
    }
330
331
    /**
332
     * Add providers to Laravel config file.
333
     *
334
     * @param $providers
335
     */
336
    protected function addProviders($providers)
337
    {
338
        foreach ($providers as $provider) {
339
            $this->output->writeln('<info>Adding '.$provider.' to Laravel config app.php file</info>');
340
            $this->addProvider($provider);
341
        }
342
    }
343
344
    /**
345
     * Add aliases to Laravel config file.
346
     *
347
     * @param $aliases
348
     */
349
    protected function addAliases($aliases)
350
    {
351
        foreach ($aliases as $alias => $aliasClass) {
352
            $this->output->writeln('<info>Adding '.$aliasClass.' to Laravel config app.php file</info>');
353
            $this->addAlias("'$alias' => ".$aliasClass);
354
        }
355
    }
356
357
    /**
358
     * Installs laravel package form config/packages.php file.
359
     *
360
     * @param string $name
361
     * @return int -1 if error occurred
362
     */
363
    protected function package($name)
364
    {
365
        $package = $this->obtainPackage($name);
366
367
        list($name, $providers, $aliases, $after) = array_fill(0, 4, null);
368
        extract($package, EXTR_IF_EXISTS);
369
370
        $this->requireComposerPackage($name);
371
372
        $this->setupLaravelConfigFile($providers,$aliases);
373
374
        $this->executeScriptAfterPackageInstallation($after);
375
    }
376
377
    /**
378
     * Obtain package.
379
     *
380
     * @param $name
381
     * @return array|int
382
     */
383
    private function obtainPackage($name){
384
        $package = $this->getPackageFromConfig($name);
385
386
        if ($package == null) {
387
            $this->showPackageNotFoundError($name);
388
389
            return -1;
390
        }
391
        return $package;
392
    }
393
394
    /**
395
     * Execute post package installation script
396
     *
397
     * @param $after
398
     */
399
    private function executeScriptAfterPackageInstallation($after){
400
        if ($after != null) {
401
            passthru($after);
402
        }
403
    }
404
405
    /**
406
     * Setup laravel config file adding providers and aliases.
407
     *
408
     * @param $providers
409
     * @param $aliases
410
     * @return int
411
     */
412
    private function setupLaravelConfigFile($providers, $aliases) {
413
        if ($this->installConfigAppFile() == -1) {
414
            return -1;
415
        }
416
417
        $this->addProviders($providers);
418
419
        $this->addAliases($aliases);
420
    }
421
422
    /**
423
     * Get config repository.
424
     *
425
     * @return Repository
426
     */
427
    protected function obtainConfig()
428
    {
429
        return new Repository(require $this->configPath.'packages.php');
430
    }
431
432
    /**
433
     * @param InputInterface  $input
434
     * @param OutputInterface $output
435
     */
436
    protected function initialize(InputInterface $input, OutputInterface $output)
437
    {
438
        parent::initialize($input, $output);
439
        if ($input->hasOption('no-bash')) {
440
            $this->noBash = $input->getOption('no-bash');
441
        }
442
    }
443
444
    /**
445
     * Check is --no-bash option is active.
446
     *
447
     * @return bool
448
     */
449
    private function isNoBashActive()
450
    {
451
        return $this->noBash;
452
    }
453
454
    /**
455
     * Get package name by composer package name.
456
     * 
457
     * @param $composerPackageName
458
     *
459
     * @return string
460
     */
461
    private function getPackageNameByComposerName($composerPackageName)
462
    {
463
        foreach ($this->config->all() as $key => $configItem) {
464
            if ($configItem[ 'name' ] == $composerPackageName) {
465
                return $key;
466
            }
467
        }
468
469
        return;
470
    }
471
472
    /**
473
     * Show package not found error.
474
     *
475
     * @param $name
476
     */
477
    protected function showPackageNotFoundError($name)
478
    {
479
        $this->output->writeln('<error>Package '.$name.' not found in file '.$this->configPath.'packages.php</error>');
480
481
        return;
482
    }
483
484
    /**
485
     * Configure the command options.
486
     *
487
     * @param ConsoleCommand $command
488
     * @throws \Acacha\Llum\Exceptions\InvalidCommandException
489
     */
490
    protected function configureCommand(ConsoleCommand $command)
491
    {
492
        $this->ignoreValidationErrors();
493
494
        $name = $command->name();
495
        $description = $command->description();
496
497
        if (! is_string($name) || ! is_string($description)) {
498
            throw new InvalidCommandException;
499
        }
500
501
        $this->setName($name)
502
             ->setDescription($description);
503
        if ($command->argument() != null) {
504
            $this->addArgument($command->argument()[ 'name' ],
505
                $command->argument()[ 'type' ],
506
                $command->argument()[ 'description' ]
507
            );
508
        }
509
    }
510
511
    /**
512
     * Execute the command.
513
     *
514
     * @param InputInterface  $input
515
     * @param OutputInterface $output
516
     *
517
     * @return int|null|void
518
     */
519
    protected function execute(InputInterface $input, OutputInterface $output)
520
    {
521
        $this->output = $output;
522
        $method = $this->method;
523
        if ($this->argument != null) {
524
            $argument = $input->getArgument($this->argument);
525
            $this->$method($argument);
526
527
            return;
528
        }
529
530
        $this->$method();
531
    }
532
533
    /**
534
     * Configure the command options.
535
     */
536
    protected function configure()
537
    {
538
        $command = new ConsoleCommand();
539
540
        $command->name($this->commandName)
1 ignored issue
show
Bug introduced by
It seems like description() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
541
                ->description($this->commandDescription);
542
543
        if ($this->argument != null) {
544
            $command->argument([
545
                'name' => $this->argument,
546
                'description' => $this->argumentDescription,
547
                'type' => $this->argumentType,
548
            ]);
549
        }
550
        $this->configureCommand($command);
551
    }
552
553
}
554