Completed
Push — master ( e15c58...b150a8 )
by Changwan
07:08
created

InstallCommand::saveAutoloadToComposer()   B

Complexity

Conditions 5
Paths 12

Size

Total Lines 25
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
cc 5
eloc 16
nc 12
nop 3
dl 0
loc 25
ccs 0
cts 23
cp 0
crap 30
rs 8.439
c 0
b 0
f 0
1
<?php
2
namespace Wandu\Installation\Commands;
3
4
use Symfony\Component\Console\Input\InputInterface;
5
use Symfony\Component\Console\Output\OutputInterface;
6
use Symfony\Component\Console\Style\SymfonyStyle;
7
use Symfony\Component\Process\PhpExecutableFinder;
8
use Symfony\Component\Process\Process;
9
use Symfony\Component\Process\ProcessUtils;
10
use Wandu\Console\Command;
11
use Wandu\DI\ContainerInterface;
12
use Wandu\Installation\Replacers\OriginReplacer;
13
use Wandu\Installation\SkeletonBuilder;
14
15
class InstallCommand extends Command
16
{
17
    /** @var string */
18
    protected $description = "Install <comment>Wandu Framework</comment> to your project directory.";
19
20
    /** @var \Symfony\Component\Console\Style\SymfonyStyle */
21
    protected $io;
22
23
    /** @var string */
24
    protected $basePath;
25
26
    /** @var string */
27
    protected $appPath;
28
29
    public function __construct(ContainerInterface $container)
30
    {
31
        $this->basePath = $container['base_path'];
32
        $this->appPath = $container['app_path'];
33
    }
34
35
    /**
36
     * {@inheritdoc}
37
     */
38
    public function withIO(InputInterface $input, OutputInterface $output)
39
    {
40
        $this->io = new SymfonyStyle($input, $output);
41
        return parent::withIO($input, $output);
42
    }
43
44
    public function execute()
45
    {
46
        if (file_exists($this->appPath . '/.wandu.php')) {
47
            throw new \RuntimeException('already installed. if you want to re-install, remove the ".wandu.php" file!');
48
        }
49
50
        $this->output->writeln('Hello, <info>Welcome to Wandu Framework!</info>');
51
52
        $composerFile = $this->basePath . '/composer.json';
53
54
        $appBasePath = $this->askAppBasePath('install path?', $this->basePath);
55
        $appNamespace = $this->askAppNamespace('app namespace?', 'Wandu\\App');
56
57
//        $templateEngine = $this->io->choice(
0 ignored issues
show
Unused Code Comprehensibility introduced by
51% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
58
//            'template engine?',
59
//            ['php' => 'PHP', 'twig' => 'Twig(Sensio Labs)', 'latte' => 'Latte(Nette)', ],
60
//            'PHP'
61
//        );
62
//
63
//        $database = $this->io->choice(
64
//            'orm(database)?',
65
//            ['none' => 'None', 'eloquent' => 'Eloquent(Laravel)', ],
66
//            'None'
67
//        );
68
69
        $path = str_replace($this->basePath, '', $appBasePath);
70
        $path = ltrim($path ? $path . '/' : '', '/');
71
72
        $this->install($appBasePath, $appNamespace, $path);
73
74
        // set composer
75
        $this->saveAutoloadToComposer($appNamespace, $composerFile, $path);
76
77
        // run composer
78
        $this->runDumpAutoload($composerFile);
79
80
        $this->output->writeln("<info>Install Complete!</info>");
81
    }
82
83
    protected function install($appBasePath, $appNamespace, $path)
84
    {
85
        $installer = new SkeletonBuilder($appBasePath, __DIR__ . '/../skeleton');
86
87
        $replacers = [
88
            'YourOwnApp' => $appNamespace,
89
            '{path}' => $path,
90
            '%%origin%%' => new OriginReplacer(),
91
        ];
92
        $installer->build($replacers);
93
94
        file_put_contents($appBasePath . '/.wandu.php', <<<PHP
95
<?php
96
return new {$appNamespace}\ApplicationDefinition();
97
98
PHP
99
        );
100
    }
101
    
102
    protected function runDumpAutoload($composerFile)
103
    {
104
        $basePath = dirname($composerFile);
105
        if (file_exists($basePath . '/composer.phar')) {
106
            $binary = ProcessUtils::escapeArgument((new PhpExecutableFinder)->find(false));
0 ignored issues
show
Security Bug introduced by
It seems like (new \Symfony\Component\...eFinder())->find(false) targeting Symfony\Component\Proces...xecutableFinder::find() can also be of type false; however, Symfony\Component\Proces...Utils::escapeArgument() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
107
            $composer = "{$binary} composer.phar";
108
        } else {
109
            $composer = 'composer';
110
        }
111
        (new Process("{$composer} dump-autoload", $basePath))->run();
112
    }
113
114
    protected function saveAutoloadToComposer($appNamespace, $composerFile, $path = '')
115
    {
116
        $this->output->write("save autoload setting to composer... ");
117
118
        $composerJson = [];
119
        if (file_exists($composerFile)) {
120
            $composerJson = json_decode(file_get_contents($composerFile), true);
121
            if (json_last_error()) {
122
                $composerJson = [];
123
            }
124
        }
125
126
        if (!isset($composerJson['autoload'])) {
127
            $composerJson['autoload'] = [];
128
        }
129
        if (!isset($composerJson['autoload']['psr-4'])) {
130
            $composerJson['autoload']['psr-4'] = [];
131
        }
132
        $composerJson['autoload']['psr-4'][$appNamespace . '\\'] = $path . 'src/';
133
        file_put_contents(
134
            $composerFile,
135
            json_encode($composerJson, JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT) . "\n"
136
        );
137
        $this->output->writeln("<info>ok</info>");
138
    }
139
140
    protected function askAppNamespace($message, $default)
141
    {
142
        return $this->io->ask($message, $default, function ($namespace) {
143
            return rtrim($namespace, '\\');
144
        });
145
    }
146
147
    protected function askAppBasePath($message, $default)
148
    {
149
        $appBasePath = $this->io->ask($message, $default);
150
        if ($appBasePath[0] === '~') {
151
            if (!function_exists('posix_getuid')) {
152
                throw new \InvalidArgumentException('cannot use tilde(~) character in your php enviroment.');
153
            }
154
            $info = posix_getpwuid(posix_getuid());
155
            $appBasePath = str_replace('~', $info['dir'], $appBasePath);
156
        }
157
        if ($appBasePath[0] !== '/') {
158
            $appBasePath = $this->basePath . "/{$appBasePath}";
159
        }
160
        return rtrim($appBasePath, '/');
161
    }
162
}
163