Completed
Push — master ( 5c84c5...c7f8f4 )
by Marius
01:51
created

ConfigureCommand::checkPayseraPhpCsFixerSupport()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Paysera\PhpStormHelper\Command;
6
7
use Paysera\PhpStormHelper\Service\ConfigurationOptionFinder;
8
use Paysera\PhpStormHelper\Service\GitignoreHelper;
9
use Paysera\PhpStormHelper\Service\SourceFolderHelper;
10
use Paysera\PhpStormHelper\Service\StructureConfigurator;
11
use Paysera\PhpStormHelper\Service\WorkspaceConfigurationHelper;
12
use Symfony\Component\Console\Command\Command;
13
use Symfony\Component\Console\Input\InputArgument;
14
use Symfony\Component\Console\Input\InputInterface;
15
use Symfony\Component\Console\Input\InputOption;
16
use Symfony\Component\Console\Output\OutputInterface;
17
use Symfony\Component\Filesystem\Filesystem;
18
19
class ConfigureCommand extends Command
20
{
21
    private $structureConfigurator;
22
    private $gitignoreHelper;
23
    private $configurationOptionFinder;
24
    private $workspaceConfigurationHelper;
25
    private $sourceFolderHelper;
26
    private $filesystem;
27
28 5
    public function __construct(
29
        StructureConfigurator $structureConfigurator,
30
        GitignoreHelper $gitignoreHelper,
31
        ConfigurationOptionFinder $configurationOptionFinder,
32
        WorkspaceConfigurationHelper $workspaceConfigurationHelper,
33
        SourceFolderHelper $sourceFolderHelper,
34
        Filesystem $filesystem
35
    ) {
36 5
        parent::__construct();
37
38 5
        $this->structureConfigurator = $structureConfigurator;
39 5
        $this->gitignoreHelper = $gitignoreHelper;
40 5
        $this->configurationOptionFinder = $configurationOptionFinder;
41 5
        $this->workspaceConfigurationHelper = $workspaceConfigurationHelper;
42 5
        $this->sourceFolderHelper = $sourceFolderHelper;
43 5
        $this->filesystem = $filesystem;
44 5
    }
45
46 5
    protected function configure()
47
    {
48
        $this
49 5
            ->setName('configure')
50 5
            ->addArgument(
51 5
                'project-root-dir',
52 5
                InputArgument::OPTIONAL,
53 5
                'Default is current directory'
54
            )
55 5
            ->addArgument('path-to-configuration-template-structure', InputArgument::OPTIONAL)
56 5
            ->addOption(
57 5
                'update-gitignore',
58 5
                null,
59 5
                null,
60 5
                'Modify gitignore file – use this when you intend to version common .idea files'
61
            )
62 5
            ->addOption(
63 5
                'docker-image',
64 5
                null,
65 5
                InputOption::VALUE_OPTIONAL,
66
                <<<'DOC'
67 5
Docker image to use for this project. For example, php:7.3-cli or example.org/image:latest.
68
If not provided, currently configured image is maintained in the configuration.
69
DOC
70
            )
71 5
            ->addOption(
72 5
                'webpack-config-path',
73 5
                null,
74 5
                InputOption::VALUE_OPTIONAL,
75
                <<<'DOC'
76 5
Relative path from project root dir to webpack configuration file.
77
If not provided, currently configured path is maintained in the configuration.
78
DOC
79
            )
80 5
            ->addOption(
81 5
                'server',
82 5
                's',
83 5
                InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL,
84
                <<<'DOC'
85 5
Server mappings, for example my-project.docker:443@/path/in/server.
86
Server is added in the list unless one already exists with such host and post.
87
DOC
88
            )
89 5
            ->addOption(
90 5
                'no-diff',
91 5
                null,
92 5
                InputOption::VALUE_NONE,
93 5
                'Pass if you don\'t want diff to be outputed'
94
            )
95
        ;
96 5
    }
97
98 5
    protected function execute(InputInterface $input, OutputInterface $output)
99
    {
100 5
        $target = $input->getArgument('project-root-dir');
101 5
        if ($target === null) {
102
            $target = realpath('.');
103
        }
104
105 5
        $backupFolder = $this->backupConfiguration($target, $output);
0 ignored issues
show
Bug introduced by
It seems like $target defined by $input->getArgument('project-root-dir') on line 100 can also be of type array<integer,string>; however, Paysera\PhpStormHelper\C...::backupConfiguration() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
106 5
        $this->configureStructure($input, $target);
107 5
        $this->configureWorkspace($input, $target);
0 ignored issues
show
Bug introduced by
It seems like $target defined by $input->getArgument('project-root-dir') on line 100 can also be of type array<integer,string>; however, Paysera\PhpStormHelper\C...d::configureWorkspace() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
108
109 5
        if ($input->getOption('update-gitignore')) {
110 1
            $this->gitignoreHelper->setupGitignore($target . '/.gitignore');
111
        }
112
113 5
        if ($backupFolder !== null && !$input->getOption('no-diff')) {
114 4
            $this->printDiffFromBackup($backupFolder, $target, $output);
0 ignored issues
show
Bug introduced by
It seems like $target defined by $input->getArgument('project-root-dir') on line 100 can also be of type array<integer,string>; however, Paysera\PhpStormHelper\C...::printDiffFromBackup() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
115
        }
116
117 5
        $output->writeln('Restart PhpStorm instance for changes to take effect');
118 5
    }
119
120
    /**
121
     * @param InputInterface $input
122
     * @param $target
123
     */
124 5
    private function configureStructure(InputInterface $input, $target)
125
    {
126 5
        $path = $input->getArgument('path-to-configuration-template-structure');
127 5
        if ($path === null) {
128 4
            $path = __DIR__ . '/../../config/default';
129
        }
130
131 5
        $composerPath = $target . '/composer.json';
132 5
        $options = [];
133
134 5
        if ($input->getOption('docker-image')) {
135 1
            $options['dockerImage'] = $input->getOption('docker-image');
136
        } else {
137 4
            $options['dockerImage'] = $this->configurationOptionFinder->findUsedDockerImage($target);
138
        }
139
140 5
        if ($input->getOption('webpack-config-path')) {
141 1
            $options['webpackConfigPath'] = $input->getOption('webpack-config-path');
142
        } else {
143 4
            $options['webpackConfigPath'] = $this->configurationOptionFinder->findWebpackConfigPath($target);
144
        }
145
146 5
        if (file_exists($target . '/.php_cs')) {
147 1
            $options['phpCsFixerConfigPath'] = '.php_cs';
148 1
            $fixerBinary = $this->checkPayseraPhpCsFixerSupport($composerPath) ? 'paysera-php-cs-fixer' : 'php-cs-fixer';
149 1
            $options['phpCsFixerExecutable'] = $this->getBinDirectory($composerPath) . '/' . $fixerBinary;
150
        }
151
152 5
        $options['symfonyEnabled'] = $this->checkSymfonySupport($composerPath);
153
154 5
        $options['sourceFolders'] = $this->sourceFolderHelper->getSourceFolders($target);
155
156 5
        $this->structureConfigurator->configure($path, $target, $options);
0 ignored issues
show
Bug introduced by
It seems like $path defined by $input->getArgument('pat...on-template-structure') on line 126 can also be of type array<integer,string>; however, Paysera\PhpStormHelper\S...nfigurator::configure() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
157 5
    }
158
159 5
    private function configureWorkspace(InputInterface $input, string $target)
160
    {
161 5
        $pathToWorkspaceXml = $target . '/.idea/workspace.xml';
162
163 5
        $this->workspaceConfigurationHelper->configureComposer($pathToWorkspaceXml);
164 5
        $this->workspaceConfigurationHelper->configureFileTemplateScheme($pathToWorkspaceXml);
165 5
        $this->workspaceConfigurationHelper->setupPhpUnitRunConfiguration($pathToWorkspaceXml);
166
167 5
        $serverMappings = $input->getOption('server');
168 5
        $this->workspaceConfigurationHelper->setupServerMappings($pathToWorkspaceXml, $serverMappings);
169 5
    }
170
171 5
    private function checkSymfonySupport(string $composerPath)
172
    {
173
        return (
174 5
            $this->isPackageRequired($composerPath, 'symfony/symfony')
175 5
            || $this->isPackageRequired($composerPath, 'symfony/framework-bundle')
176
        );
177
    }
178
179 1
    private function checkPayseraPhpCsFixerSupport(string $composerPath)
180
    {
181 1
        return $this->isPackageRequired($composerPath, 'paysera/lib-php-cs-fixer-config');
182
    }
183
184 1
    private function getBinDirectory(string $composerPath)
185
    {
186 1
        return $this->parseComposer($composerPath)['config']['bin-dir'] ?? 'vendor/bin';
187
    }
188
189 5
    private function isPackageRequired(string $composerPath, string $package)
190
    {
191 5
        $composerContents = $this->parseComposer($composerPath);
192 5
        return isset($composerContents['require'][$package]) || isset($composerContents['require-dev'][$package]);
193
    }
194
195 5
    private function parseComposer(string $composerPath)
196
    {
197 5
        if (!file_exists($composerPath)) {
198 4
            return [];
199
        }
200
201 1
        return json_decode(file_get_contents($composerPath), true) ?: [];
202
    }
203
204 5
    private function backupConfiguration(string $target, OutputInterface $output)
205
    {
206 5
        $pathToIdea = $target . '/.idea/';
207 5
        if (!is_dir($pathToIdea)) {
208 1
            return null;
209
        }
210
211 4
        $backupFolder = sprintf(
212 4
            '%s/phpstorm-helper-backups/%s/%s',
213 4
            sys_get_temp_dir(),
214 4
            basename($target),
215 4
            time()
216
        );
217
218 4
        $this->filesystem->mirror($pathToIdea, $backupFolder);
219
220 4
        $output->writeln('Made backup of <info>.idea</info> to <info>' . $backupFolder . '</info>');
221
222 4
        return $backupFolder;
223
    }
224
225 4
    private function printDiffFromBackup(string $backupFolder, string $target, OutputInterface $output)
226
    {
227 4
        $command = sprintf(
228 4
            'git --no-pager diff --color=always --no-index %s %s',
229 4
            escapeshellarg($backupFolder),
230 4
            escapeshellarg($target . '/.idea/')
231
        );
232 4
        exec($command, $diffOutput);
233
234 4
        if (count($diffOutput) === 0) {
235
            $output->writeln('No changes were made.');
236
            return;
237
        }
238
239 4
        $filteredDiffOutput = $this->filterDiff($diffOutput);
0 ignored issues
show
Bug introduced by
It seems like $diffOutput can also be of type null; however, Paysera\PhpStormHelper\C...reCommand::filterDiff() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
240
241 4
        if (count($filteredDiffOutput) !== count($diffOutput)) {
242 4
            $output->writeln('Changes in workspace.xml were made or workspace.xml was updated by PhpStorm itself.');
243
        }
244
245 4
        if (count($filteredDiffOutput) === 0) {
246
            return;
247
        }
248
249 4
        $output->writeln("Diff of the changes, excluding workspace.xml:\n\n");
250 4
        $output->writeln(implode("\n", $filteredDiffOutput) . "\n\n");
251 4
    }
252
253 4
    private function filterDiff(array $diffOutput): array
254
    {
255 4
        $include = true;
256 4
        $filtered = [];
257 4
        foreach ($diffOutput as $line) {
258 4
            if (strpos($line, 'diff --git') !== false) {
259 4
                $include = strpos($line, 'workspace.xml') === false;
260
            }
261
262 4
            if ($include) {
263 4
                $filtered[] = $line;
264
            }
265
        }
266
267 4
        return $filtered;
268
    }
269
}
270