Failed Conditions
Pull Request — experimental/3.1 (#2627)
by
unknown
52:58
created

OwnerStoreController::getRequestApi()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 26
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 16
nc 1
nop 2
dl 0
loc 26
ccs 0
cts 0
cp 0
crap 2
rs 8.8571
c 0
b 0
f 0
1
<?php
2
/*
3
 * This file is part of EC-CUBE
4
 *
5
 * Copyright(c) 2000-2015 LOCKON CO.,LTD. All Rights Reserved.
6
 *
7
 * http://www.lockon.co.jp/
8
 *
9
 * This program is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU General Public License
11
 * as published by the Free Software Foundation; either version 2
12
 * of the License, or (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program; if not, write to the Free Software
21
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
 */
23
namespace Eccube\Controller\Admin\Store;
24
25
use Doctrine\ORM\EntityManager;
26
use Doctrine\ORM\EntityManagerInterface;
27
use Eccube\Annotation\Inject;
28
use Eccube\Application;
29
use Eccube\Common\Constant;
30
use Eccube\Controller\AbstractController;
31
use Eccube\Entity\Plugin;
32
use Eccube\Repository\PluginRepository;
33
use Eccube\Service\Composer\ComposerApiService;
34
use Eccube\Service\PluginService;
35
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
36
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
37
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
38
use Symfony\Component\HttpFoundation\RedirectResponse;
39
use Symfony\Component\HttpFoundation\Request;
40
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
41
42
/**
43
 * @Route(service=OwnerStoreController::class)
44
 */
45
class OwnerStoreController extends AbstractController
46
{
47
    /**
48
     * @Inject("config")
49
     * @var array
50
     */
51
    protected $appConfig;
52
53
    /**
54
     * @Inject(PluginRepository::class)
55
     * @var PluginRepository
56
     */
57
    protected $pluginRepository;
58
59
    /**
60
     * @Inject(PluginService::class)
61
     * @var PluginService
62
     */
63
    protected $pluginService;
64
65
    /**
66
     * @Inject(ComposerApiService::class)
67
     * @var ComposerApiService
68
     */
69
    protected $composerService;
70
71
    /**
72
     * @var EntityManager
73
     * @Inject("orm.em")
74
     */
75
    protected $em;
76
77
    private static $vendorName = 'ec-cube';
78
79
    /**
80
     * Owner's Store Plugin Installation Screen - Search function
81
     *
82
     * @Route("/{_admin}/store/plugin/search", name="admin_store_plugin_owners_search")
83
     * @Template("Store/plugin_search.twig")
84
     * @param Application $app
85
     * @param Request     $request
86
     * @return array
87
     */
88
    public function search(Application $app, Request $request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
89
    {
90
        // Acquire downloadable plug-in information from owners store
91
        $success = 0;
92
        $items = array();
93
        $promotionItems = array();
94
        $message = '';
95
        // Owner's store communication
96
        $url = $this->appConfig['package_repo_url'].'/search/packages.json';
97
        list($json, $info) = $this->getRequestApi($url, $app);
98
        if ($json === false) {
99
            $message = $this->getResponseErrorMessage($info);
100
        } else {
101
            $data = json_decode($json, true);
102
            if (isset($data['success'])) {
103
                $success = $data['success'];
104
                if ($success == '1') {
105
                    $items = array();
106
                    // Check plugin installed
107
                    $arrPluginInstalled = $this->pluginRepository->findAll();
108
                    // Update_status 1 : not install/purchased 、2 : Installed、 3 : Update、4 : paid purchase
109
                    foreach ($data['item'] as $item) {
110
                        // Not install/purchased
111
                        $item['update_status'] = 1;
112
                        /** @var Plugin $plugin */
113
                        foreach ($arrPluginInstalled as $plugin) {
114
                            if ($plugin->getSource() == $item['product_id']) {
115
                                // Need update
116
                                $item['update_status'] = 3;
117
                                if ($plugin->getVersion() == $item['version']) {
118
                                    // Installed
119
                                    $item['update_status'] = 2;
120
                                }
121
                            }
122
                        }
123
                        $items[] = $item;
124
                    }
125
126
                    // EC-CUBE version check
127
                    $arrDependency = [];
0 ignored issues
show
Unused Code introduced by
$arrDependency is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
128
                    foreach ($items as &$item) {
129
                        // Not applicable version
130
                        $item['version_check'] = 0;
131
                        if (in_array(Constant::VERSION, $item['eccube_version'])) {
132
                            // Match version
133
                            $item['version_check'] = 1;
134
                        }
135
                        if ($item['price'] != '0' && $item['purchased'] == '0') {
136
                            // Not purchased with paid items
137
                            $item['update_status'] = 4;
138
                        }
139
140
                        // Add plugin dependency
141
                        $item['depend'] = $this->pluginService->getRequirePluginName($items, $item);
142
                    }
143
                    unset($item);
144
145
                    // Promotion item
146
                    $i = 0;
147 View Code Duplication
                    foreach ($items as $item) {
148
                        if ($item['promotion'] == 1) {
149
                            $promotionItems[] = $item;
150
                            unset($items[$i]);
151
                        }
152
                        $i++;
153
                    }
154
                } else {
155
                    $message = $data['error_code'].' : '.$data['error_message'];
156
                }
157
            } else {
158
                $success = 0;
159
                $message = "EC-CUBEオーナーズストアにエラーが発生しています。";
160
            }
161
        }
162
163
        return [
164
            'success' => $success,
165
            'items' => $items,
166
            'promotionItems' => $promotionItems,
167
            'message' => $message,
168
        ];
169
    }
170
171
    /**
172
     * Do confirm page
173
     *
174
     * @Route("/{_admin}/store/plugin/{id}/confirm", requirements={"id" = "\d+"}, name="admin_store_plugin_install_confirm")
175
     * @Template("Store/plugin_confirm.twig")
176
     * @param Application $app
177
     * @param Request     $request
178
     * @param string      $id
179
     * @return array
180
     */
181
    public function doConfirm(Application $app, Request $request, $id)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
182
    {
183
        // Owner's store communication
184
        $url = $this->appConfig['package_repo_url'].'/search/packages.json';
185
        list($json, $info) = $this->getRequestApi($url, $app);
0 ignored issues
show
Unused Code introduced by
The assignment to $info is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
186
        $data = json_decode($json, true);
187
        $items = $data['item'];
188
189
        // Find plugin in api
190
        $index = array_search($id, array_column($items, 'product_id'));
191
        if ($index === false) {
192
            throw new NotFoundHttpException();
193
        }
194
195
        $pluginCode = $items[$index]['product_code'];
196
197
        $plugin = $this->pluginService->buildInfo($items, $pluginCode);
198
199
        // Prevent infinity loop: A -> B -> A.
200
        $arrDependency[] = $plugin;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$arrDependency was never initialized. Although not strictly required by PHP, it is generally a good practice to add $arrDependency = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
201
        $arrDependency = $this->pluginService->getDependency($items, $plugin, $arrDependency);
0 ignored issues
show
Bug introduced by
It seems like $plugin defined by $this->pluginService->bu...fo($items, $pluginCode) on line 197 can also be of type null; however, Eccube\Service\PluginService::getDependency() 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...
202
        // Unset first param
203
        unset($arrDependency[0]);
204
205
        return [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
206
            'item' => $plugin,
207
            'arrDependency' => $arrDependency
208
        ];
209
    }
210
211
    /**
212
     * Api Install plugin by composer connect with package repo
213
     *
214
     * @Route("/{_admin}/store/plugin/api/{pluginCode}/{eccubeVersion}/{version}" , name="admin_store_plugin_api_install")
215
     *
216
     * @param Application $app
217
     * @param Request     $request
218
     * @param string      $pluginCode
219
     * @param string      $eccubeVersion
220
     * @param string      $version
221
     * @return RedirectResponse
222
     */
223
    public function apiInstall(Application $app, Request $request, $pluginCode, $eccubeVersion, $version)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
224
    {
225
        // Check plugin code
226
        $url = $this->appConfig['package_repo_url'].'/search/packages.json'.'?eccube_version='.$eccubeVersion.'&plugin_code='.$pluginCode.'&version='.$version;
227
        list($json, $info) = $this->getRequestApi($url, $app);
0 ignored issues
show
Unused Code introduced by
The assignment to $info is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
228
        $existFlg = false;
229
        $data = json_decode($json, true);
230
        if ($data && isset($data['success'])) {
231
            $success = $data['success'];
232
            if ($success == '1' && isset($data['item'])) {
233
                foreach ($data['item'] as $item) {
234
                    if ($item['product_code'] == $pluginCode) {
235
                        $existFlg = true;
236
                        break;
237
                    }
238
                }
239
            }
240
        }
241
        if ($existFlg === false) {
242
            $app->log(sprintf('%s plugin not found!', $pluginCode));
243
            $app->addError('admin.plugin.not.found', 'admin');
244
245
            return $app->redirect($app->url('admin_store_plugin_owners_search'));
246
        }
247
248
        $arrDependency = array();
249
        $items = $data['item'];
250
        $plugin = $this->pluginService->buildInfo($items, $pluginCode);
251
        $arrDependency[] = $plugin;
252
        $arrDependency = $this->pluginService->getDependency($items, $plugin, $arrDependency);
0 ignored issues
show
Bug introduced by
It seems like $plugin defined by $this->pluginService->bu...fo($items, $pluginCode) on line 250 can also be of type null; however, Eccube\Service\PluginService::getDependency() 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...
253
254
        // Unset first param
255
        unset($arrDependency[0]);
256
257
        $packageNames = '';
258
        if (!empty($arrDependency)) {
259
            foreach ($arrDependency as $item) {
260
                $packageNames .= ' ' . self::$vendorName . '/' . $item['product_code'];
0 ignored issues
show
Coding Style introduced by
Concat operator must not be surrounded by spaces
Loading history...
261
            }
262
        }
263
264
        $packageNames .= ' '.self::$vendorName.'/'.$pluginCode;
265
266
        /**
267
         * Mysql lock in transaction
268
         * @link https://dev.mysql.com/doc/refman/5.7/en/lock-tables.html
269
         * @var EntityManagerInterface $em
270
         */
271
        $em = $this->em;
272
        if ($em->getConnection()->isTransactionActive()) {
273
            $em->getConnection()->commit();
274
            $em->getConnection()->beginTransaction();
275
        }
276
277
        $return = $this->composerService->execRequire($packageNames);
278
        if ($return) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $return of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
279
            $app->addSuccess('admin.plugin.install.complete', 'admin');
280
281
            return $app->redirect($app->url('admin_store_plugin'));
282
        }
283
        $app->addError('admin.plugin.install.fail', 'admin');
284
285
        return $app->redirect($app->url('admin_store_plugin_owners_search'));
286
    }
287
288
    /**
289
     * Do confirm page
290
     *
291
     * @Route("/{_admin}/store/plugin/delete/{id}/confirm", requirements={"id" = "\d+"}, name="admin_store_plugin_delete_confirm")
292
     * @Template("Store/plugin_confirm_uninstall.twig")
293
     * @param Application $app
294
     * @param Plugin      $Plugin
295
     * @return array
296
     */
297
    public function deleteConfirm(Application $app, Plugin $Plugin)
298
    {
299
        // Owner's store communication
300
        $url = $this->appConfig['package_repo_url'].'/search/packages.json';
301
        list($json, $info) = $this->getRequestApi($url, $app);
0 ignored issues
show
Unused Code introduced by
The assignment to $info is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
302
        $data = json_decode($json, true);
303
        $items = $data['item'];
304
305
        // The plugin depends on it
306
        $pluginCode = $Plugin->getCode();
307
        $otherDepend = $this->pluginService->findDependentPlugin($pluginCode);
308
309
        if (!empty($otherDepend)) {
310
            $DependPlugin = $this->pluginRepository->findOneBy(['code' => $otherDepend[0]]);
311
            $dependName = $otherDepend[0];
312
            if ($DependPlugin) {
313
                $dependName = $DependPlugin->getName();
314
            }
315
316
            $message = '以下のプラグインは、' . $pluginCode . 'プラグインに依存しているため削除することができません。';
0 ignored issues
show
Coding Style introduced by
Concat operator must not be surrounded by spaces
Loading history...
317
            $message .= '先に' . $dependName . 'プラグインを削除してください。';
0 ignored issues
show
Coding Style introduced by
Concat operator must not be surrounded by spaces
Loading history...
318
            $app->addError($message, 'admin');
319
320
            return $app->redirect($app->url('admin_store_plugin'));
321
        }
322
323
        // Check plugin in api
324
        $pluginSource = $Plugin->getSource();
325
        $index = array_search($pluginSource, array_column($items, 'product_id'));
326
        if ($index === false) {
327
            throw new NotFoundHttpException();
328
        }
329
330
        // Build info
331
        $pluginCode = $Plugin->getCode();
332
        $plugin = $this->pluginService->buildInfo($items, $pluginCode);
333
        $plugin['id'] = $Plugin->getId();
334
335
        return [
336
            'item' => $plugin,
337
            'isConfirmDelete' => true,
338
        ];
339
    }
340
341
    /**
342
     * New ways to remove plugin: using composer command
343
     *
344
     * @Method("DELETE")
345
     * @Route("/{_admin}/store/plugin/api/{id}/uninstall", requirements={"id" = "\d+"}, name="admin_store_plugin_api_uninstall")
346
     * @param Application $app
347
     * @param Plugin      $Plugin
348
     * @return RedirectResponse
349
     */
350
    public function apiUninstall(Application $app, Plugin $Plugin)
351
    {
352
        $this->isTokenValid($app);
353
354
        if ($Plugin->getEnable() == Constant::ENABLED) {
355
            $this->pluginService->disable($Plugin);
356
        }
357
        $pluginCode = $Plugin->getCode();
358
359
        $packageName = self::$vendorName.'/'.$pluginCode;
360
361
        /**
362
         * Mysql lock in transaction
363
         * @link https://dev.mysql.com/doc/refman/5.7/en/lock-tables.html
364
         * @var EntityManagerInterface $em
365
         */
366
        $em = $this->em;
367
        if ($em->getConnection()->isTransactionActive()) {
368
            $em->getConnection()->commit();
369
            $em->getConnection()->beginTransaction();
370
        }
371
        $return = $this->composerService->execRemove($packageName);
372
        if ($return) {
373
            $app->addSuccess('admin.plugin.uninstall.complete', 'admin');
374
        } else {
375
            $app->addError('admin.plugin.uninstall.error', 'admin');
376
        }
377
378
        return $app->redirect($app->url('admin_store_plugin'));
379
    }
380
381
    /**
382
     * API request processing
383
     *
384
     * @param string  $url
385
     * @param Application $app
386
     * @return array
387
     */
388
    private function getRequestApi($url, $app)
389
    {
390
        $curl = curl_init($url);
391
392
        // Option array
393
        $options = array(
394
            // HEADER
395
            CURLOPT_HTTPGET => true,
396
            CURLOPT_SSL_VERIFYPEER => false,
397
            CURLOPT_RETURNTRANSFER => true,
398
            CURLOPT_FAILONERROR => true,
399
            CURLOPT_CAINFO => \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath(),
400
        );
401
402
        // Set option value
403
        curl_setopt_array($curl, $options);
404
        $result = curl_exec($curl);
405
        $info = curl_getinfo($curl);
406
        $message = curl_error($curl);
407
        $info['message'] = $message;
408
        curl_close($curl);
409
410
        $app->log('http get_info', $info);
411
412
        return array($result, $info);
413
    }
414
415
    /**
416
     * Get message
417
     *
418
     * @param $info
419
     * @return string
420
     */
421 View Code Duplication
    private function getResponseErrorMessage($info)
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...
422
    {
423
        if (!empty($info)) {
424
            $statusCode = $info['http_code'];
425
            $message = $info['message'];
426
427
            $message = $statusCode.' : '.$message;
428
        } else {
429
            $message = "タイムアウトエラーまたはURLの指定に誤りがあります。";
430
        }
431
432
        return $message;
433
    }
434
}
435