Completed
Push — dev/recommend-plugins ( b4eeb7...acd8c2 )
by Kiyotaka
08:44
created

ComposerApiService::configureRepository()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of EC-CUBE
5
 *
6
 * Copyright(c) LOCKON CO.,LTD. All Rights Reserved.
7
 *
8
 * http://www.lockon.co.jp/
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Eccube\Service\Composer;
15
16
use Composer\Console\Application;
17
use Eccube\Common\EccubeConfig;
18
use Eccube\Entity\BaseInfo;
19
use Eccube\Exception\PluginException;
20
use Eccube\Repository\BaseInfoRepository;
21
use Symfony\Component\Console\Input\ArrayInput;
22
use Symfony\Component\Console\Output\BufferedOutput;
23
use Symfony\Component\Console\Output\OutputInterface;
24
25
/**
26
 * Class ComposerApiService
27
 */
28
class ComposerApiService implements ComposerServiceInterface
29
{
30
    /**
31
     * @var EccubeConfig
32
     */
33
    protected $eccubeConfig;
34
35
    /**
36
     * @var Application
37
     */
38
    private $consoleApplication;
39
40
    private $workingDir;
41
    /**
42
     * @var BaseInfoRepository
43
     */
44
    private $baseInfoRepository;
45
46
    public function __construct(EccubeConfig $eccubeConfig, BaseInfoRepository $baseInfoRepository)
47
    {
48
        $this->eccubeConfig = $eccubeConfig;
49
        $this->baseInfoRepository = $baseInfoRepository;
50
    }
51
52
    /**
53
     * Run get info command
54
     *
55
     * @param string $pluginName format foo/bar or foo/bar:1.0.0 or "foo/bar 1.0.0"
56
     * @param string|null $version
57
     *
58
     * @return array
59
     *
60
     * @throws PluginException
61
     */
62
    public function execInfo($pluginName, $version)
63
    {
64
        $output = $this->runCommand([
65
            'command' => 'info',
66
            'package' => $pluginName,
67
            'version' => $version,
68
            '--available' => true,
69
        ]);
70
71
        return OutputParser::parseInfo($output);
72
    }
73
74
    /**
75
     * Run execute command
76
     *
77
     * @param string $packageName format "foo/bar foo/bar:1.0.0"
78
     * @param null|OutputInterface $output
79
     *
80
     * @return string
81
     *
82
     * @throws PluginException
83
     */
84
    public function execRequire($packageName, $output = null)
85
    {
86
        $packageName = explode(' ', trim($packageName));
87
88
        return $this->runCommand([
89
            'command' => 'require',
90
            'packages' => $packageName,
91
            '--no-interaction' => true,
92
            '--profile' => true,
93
            '--prefer-dist' => true,
94
            '--ignore-platform-reqs' => true,
95
            '--update-with-dependencies' => true,
96
            '--no-scripts' => true,
97
        ], $output);
98
    }
99
100
    /**
101
     * Run remove command
102
     *
103
     * @param string $packageName format "foo/bar foo/bar:1.0.0"
104
     * @param null|OutputInterface $output
105
     *
106
     * @return string
107
     *
108
     * @throws PluginException
109
     */
110
    public function execRemove($packageName, $output = null)
111
    {
112
        $packageName = explode(' ', trim($packageName));
113
114
        return $this->runCommand([
115
            'command' => 'remove',
116
            'packages' => $packageName,
117
            '--ignore-platform-reqs' => true,
118
            '--no-interaction' => true,
119
            '--profile' => true,
120
            '--no-scripts' => true,
121
        ], $output);
122
    }
123
124
    /**
125
     * Run update command
126
     *
127
     * @param boolean $dryRun
128
     * @param null|OutputInterface $output
129
     *
130
     * @throws PluginException
131
     */
132 View Code Duplication
    public function execUpdate($dryRun, $output = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
133
    {
134
        $this->runCommand([
135
            'command' => 'update',
136
            '--no-interaction' => true,
137
            '--profile' => true,
138
            '--no-scripts' => true,
139
            '--dry-run' => (bool) $dryRun,
140
        ], $output);
141
    }
142
143
    /**
144
     * Run install command
145
     *
146
     * @param boolean $dryRun
147
     * @param null|OutputInterface $output
148
     *
149
     * @throws PluginException
150
     */
151 View Code Duplication
    public function execInstall($dryRun, $output = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
152
    {
153
        $this->runCommand([
154
            'command' => 'install',
155
            '--no-interaction' => true,
156
            '--profile' => true,
157
            '--no-scripts' => true,
158
            '--dry-run' => (bool) $dryRun,
159
        ], $output);
160
    }
161
162
    /**
163
     * Get require
164
     *
165
     * @param string $packageName
166
     * @param string|null $version
167
     * @param string $callback
168
     * @param null $typeFilter
169
     * @param int $level
170
     *
171
     * @throws PluginException
172
     */
173
    public function foreachRequires($packageName, $version, $callback, $typeFilter = null, $level = 0)
174
    {
175
        if (strpos($packageName, '/') === false) {
176
            return;
177
        }
178
        $info = $this->execInfo($packageName, $version);
179
        if (isset($info['requires'])) {
180
            foreach ($info['requires'] as $name => $version) {
0 ignored issues
show
Bug introduced by
The expression $info['requires'] of type array|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
181
                if (isset($info['type']) && $info['type'] === $typeFilter) {
182
                    $this->foreachRequires($name, $version, $callback, $typeFilter, $level + 1);
183
                    if (isset($info['descrip.'])) {
184
                        $info['description'] = $info['descrip.'];
185
                    }
186
                    if ($level) {
187
                        $callback($info);
188
                    }
189
                }
190
            }
191
        }
192
    }
193
194
    /**
195
     * Run get config information
196
     *
197
     * @param string $key
198
     * @param null $value
199
     *
200
     * @return array|mixed
201
     *
202
     * @throws PluginException
203
     */
204
    public function execConfig($key, $value = null)
205
    {
206
        $commands = [
207
            'command' => 'config',
208
            'setting-key' => $key,
209
            'setting-value' => $value,
210
        ];
211
        if ($value) {
212
            $commands['setting-value'] = $value;
213
        }
214
        $output = $this->runCommand($commands, null, false);
215
216
        return OutputParser::parseConfig($output);
217
    }
218
219
    /**
220
     * Get config list
221
     *
222
     * @return array
223
     *
224
     * @throws PluginException
225
     */
226
    public function getConfig()
227
    {
228
        $output = $this->runCommand([
229
            'command' => 'config',
230
            '--list' => true,
231
        ], null, false);
232
233
        return OutputParser::parseList($output);
234
    }
235
236
    /**
237
     * Set work dir
238
     *
239
     * @param string $workingDir
240
     */
241
    public function setWorkingDir($workingDir)
242
    {
243
        $this->workingDir = $workingDir;
244
    }
245
246
    /**
247
     * Run composer command
248
     *
249
     * @param array $commands
250
     * @param null|OutputInterface $output
251
     *
252
     * @return string
253
     *
254
     * @throws PluginException
255
     */
256
    public function runCommand($commands, $output = null, $init = true)
257
    {
258
        if ($init) {
259
            $this->init();
260
        }
261
        $commands['--working-dir'] = $this->workingDir;
262
        $commands['--no-ansi'] = true;
263
        $input = new ArrayInput($commands);
264
        $useBufferedOutput = $output === null;
265
266
        if ($useBufferedOutput) {
267
            $output = new BufferedOutput();
268
            ob_start(function ($buffer) use ($output) {
269
                $output->write($buffer);
270
271
                return null;
272
            });
273
        }
274
275
        $exitCode = $this->consoleApplication->run($input, $output);
276
277
        if ($useBufferedOutput) {
278
            ob_end_clean();
279
            $log = $output->fetch();
280
            if ($exitCode) {
281
                log_error($log);
282
                throw new PluginException($log);
283
            }
284
            log_info($log, $commands);
285
286
            return $log;
287
        } elseif ($exitCode) {
288
            throw new PluginException();
289
        }
290
    }
291
292
    /**
293
     * Init composer console application
294
     * @param BaseInfo|null $BaseInfo
295
     * @throws PluginException
296
     * @throws \Doctrine\ORM\NoResultException
297
     * @throws \Doctrine\ORM\NonUniqueResultException
298
     */
299
    private function init($BaseInfo = null)
300
    {
301
        $BaseInfo = $BaseInfo ?: $this->baseInfoRepository->get();
302
303
        set_time_limit(0);
304
        ini_set('memory_limit', '-1');
305
        // Config for some environment
306
        putenv('COMPOSER_HOME='.$this->eccubeConfig['plugin_realdir'].'/.composer');
307
        $this->initConsole();
308
        $this->workingDir = $this->workingDir ? $this->workingDir : $this->eccubeConfig['kernel.project_dir'];
309
        $url = $this->eccubeConfig['eccube_package_api_url'];
310
        $json = json_encode([
311
            'type' => 'composer',
312
            'url' => $url,
313
            'options' => [
314
                'http' => [
315
                    'header' => ['X-ECCUBE-KEY: '.$BaseInfo->getAuthenticationKey()]
316
                ]
317
            ]
318
        ]);
319
        $this->execConfig('repositories.eccube', [$json]);
320
        if (strpos($url, 'http://') == 0) {
321
            $this->execConfig('secure-http', ['false']);
322
        }
323
        $this->initConsole();
324
    }
325
326
    private function initConsole()
327
    {
328
        $consoleApplication = new Application();
329
        $consoleApplication->resetComposer();
330
        $consoleApplication->setAutoExit(false);
331
        $this->consoleApplication = $consoleApplication;
332
    }
333
334
    public function configureRepository(BaseInfo $BaseInfo)
335
    {
336
        $this->init($BaseInfo);
337
    }
338
339
    /**
340
     * Get version of composer
341
     *
342
     * @return null|string
343
     *
344
     * @throws PluginException
345
     */
346
    public function composerVersion()
347
    {
348
        $this->init();
349
        $output = $this->runCommand([
350
            '--version' => true,
351
        ]);
352
353
        return OutputParser::parseComposerVersion($output);
354
    }
355
356
    /**
357
     * Get mode
358
     *
359
     * @return string
360
     */
361
    public function getMode()
362
    {
363
        return 'API';
364
    }
365
}
366