Completed
Pull Request — experimental/3.1 (#2588)
by Ryo
139:43 queued 96:01
created

OwnerStoreController::apiInstall()   C

Complexity

Conditions 9
Paths 25

Size

Total Lines 46
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 0
Metric Value
cc 9
eloc 26
nc 25
nop 5
dl 0
loc 46
ccs 0
cts 16
cp 0
crap 90
rs 5.0942
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
24
25
namespace Eccube\Controller\Admin\Store;
26
27
use Doctrine\ORM\EntityManager;
28
use Doctrine\ORM\EntityManagerInterface;
29
use Eccube\Annotation\Inject;
30
use Eccube\Application;
31
use Eccube\Common\Constant;
32
use Eccube\Controller\AbstractController;
33
use Eccube\Entity\Plugin;
34
use Eccube\Repository\PluginRepository;
35
use Eccube\Service\PluginService;
36
use Eccube\Service\ComposerProcessService;
37
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
38
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
39
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
40
use Symfony\Component\HttpFoundation\RedirectResponse;
41
use Symfony\Component\HttpFoundation\Request;
42
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
43
44
/**
45
 * @Route(service=OwnerStoreController::class)
46
 */
47
class OwnerStoreController extends AbstractController
48
{
49
    /**
50
     * @Inject("config")
51
     * @var array
52
     */
53
    protected $appConfig;
54
55
    /**
56
     * @Inject(PluginRepository::class)
57
     * @var PluginRepository
58
     */
59
    protected $pluginRepository;
60
61
    /**
62
     * @Inject(ComposerProcessService::class)
63
     * @var ComposerProcessService
64
     */
65
    protected $composerService;
66
67
    /**
68
     * @var EntityManager
69
     * @Inject("orm.em")
70
     */
71
    protected $em;
72
73
    /**
74
     * Owner's Store Plugin Installation Screen - Search function
75
     *
76
     * @Route("/{_admin}/store/plugin/search", name="admin_store_plugin_owners_search")
77
     * @Template("Store/plugin_search.twig")
78
     * @param Application $app
79
     * @param Request     $request
80
     * @return array
81
     */
82
    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...
83
    {
84
        // Acquire downloadable plug-in information from owners store
85
        $success = 0;
86
        $items = array();
87
        $promotionItems = array();
88
        $message = '';
89
        // Owner's store communication
90
        $url = $this->appConfig['owners_store_url'].'?method=list';
91
        list($json, $info) = $this->getRequestApi($url, $app);
92
        if ($json === false) {
93
            $message = $this->getResponseErrorMessage($info);
94
        } else {
95
            $data = json_decode($json, true);
96
            if (isset($data['success'])) {
97
                $success = $data['success'];
98
                if ($success == '1') {
99
                    $items = array();
100
                    // Check plugin installed
101
                    $arrPluginInstalled = $this->pluginRepository->findAll();
102
                    // Update_status 1 : not install/purchased 、2 : Installed、 3 : Update、4 : paid purchase
103
                    foreach ($data['item'] as $item) {
104
                        // Not install/purchased
105
                        $item['update_status'] = 1;
106
                        /** @var Plugin $plugin */
107
                        foreach ($arrPluginInstalled as $plugin) {
108
                            if ($plugin->getSource() == $item['product_id']) {
109
                                // Need update
110
                                $item['update_status'] = 3;
111
                                if ($plugin->getVersion() == $item['version']) {
112
                                    // Installed
113
                                    $item['update_status'] = 2;
114
                                }
115
                            }
116
                        }
117
                        $items[] = $item;
118
                    }
119
120
                    // EC-CUBE version check
121
                    $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...
122
                    foreach ($items as &$item) {
123
                        // Not applicable version
124
                        $item['version_check'] = 0;
125
                        if (in_array(Constant::VERSION, $item['eccube_version'])) {
126
                            // Match version
127
                            $item['version_check'] = 1;
128
                        }
129
                        if ($item['price'] != '0' && $item['purchased'] == '0') {
130
                            // Not purchased with paid items
131
                            $item['update_status'] = 4;
132
                        }
133
134
                        // Add plugin dependency
135
                        $item['depend'] = $app['eccube.service.plugin']->getRequirePluginName($items, $item);
136
                    }
137
                    unset($item);
138
139
                    // Promotion item
140
                    $i = 0;
141 View Code Duplication
                    foreach ($items as $item) {
142
                        if ($item['promotion'] == 1) {
143
                            $promotionItems[] = $item;
144
                            unset($items[$i]);
145
                        }
146
                        $i++;
147
                    }
148
                } else {
149
                    $message = $data['error_code'] . ' : ' . $data['error_message'];
0 ignored issues
show
Coding Style introduced by
Concat operator must not be surrounded by spaces
Loading history...
150
                }
151
            } else {
152
                $success = 0;
153
                $message = "EC-CUBEオーナーズストアにエラーが発生しています。";
154
            }
155
        }
156
157
        return [
158
            'success' => $success,
159
            'items' => $items,
160
            'promotionItems' => $promotionItems,
161
            'message' => $message,
162
        ];
163
    }
164
165
    /**
166
     * Do confirm page
167
     *
168
     * @Route("/{_admin}/store/plugin/{id}/confirm", requirements={"id" = "\d+"}, name="admin_store_plugin_install_confirm")
169
     * @Template("Store/plugin_confirm.twig")
170
     * @param Application $app
171
     * @param Request     $request
172
     * @param string      $id
173
     * @return array
174
     */
175
    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...
176
    {
177
        // Owner's store communication
178
        $url = $this->appConfig['owners_store_url'].'?method=list';
179
        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...
180
        $data = json_decode($json, true);
181
        $items = $data['item'];
182
183
        // Find plugin in api
184
        $index = array_search($id, array_column($items, 'product_id'));
185
        if ($index === false) {
186
            throw new NotFoundHttpException();
187
        }
188
189
        $pluginCode = $items[$index]['product_code'];
190
191
        /**
192
         * @var PluginService $pluginService
193
         */
194
        $pluginService =  $app['eccube.service.plugin'];
195
        $plugin = $pluginService->buildInfo($items, $pluginCode);
196
197
        // Prevent infinity loop: A -> B -> A.
198
        $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...
199
        $arrDependency = $pluginService->getDependency($items, $plugin, $arrDependency);
0 ignored issues
show
Bug introduced by
It seems like $plugin defined by $pluginService->buildInfo($items, $pluginCode) on line 195 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...
200
        // Unset first param
201
        unset($arrDependency[0]);
202
203
        return [
204
            'item' => $plugin,
205
            'arrDependency' => $arrDependency,
206
        ];
207
    }
208
209
    /**
210
     * Api Install plugin by composer connect with package repo
211
     *
212
     * @Route("/{_admin}/store/plugin/api/{pluginCode}/{eccubeVersion}/{version}" , name="admin_store_plugin_api_install")
213
     *
214
     * @param Application $app
215
     * @param Request     $request
216
     * @param string      $pluginCode
217
     * @param string      $eccubeVersion
218
     * @param string      $version
219
     * @return RedirectResponse
220
     */
221
    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...
222
    {
223
        // Check plugin code
224
        $url = $this->appConfig['owners_store_url'].'?eccube_version='.$eccubeVersion.'&plugin_code='.$pluginCode.'&version='.$version;
225
        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...
226
        $existFlg = false;
227
        $data = json_decode($json, true);
228
        if ($data && isset($data['success'])) {
229
            $success = $data['success'];
230
            if ($success == '1') {
231
                foreach ($data['item'] as $item) {
232
                    if ($item['product_code'] == $pluginCode) {
233
                        $existFlg = true;
234
                        break;
235
                    }
236
                }
237
            }
238
        }
239
        if ($existFlg === false) {
240
            $app->log(sprintf('%s plugin not found!', $pluginCode));
241
            $app->addError('admin.plugin.not.found', 'admin');
242
243
            return $app->redirect($app->url('admin_store_plugin_owners_search'));
244
        }
245
246
        /**
247
         * Mysql lock in transaction
248
         * @link https://dev.mysql.com/doc/refman/5.7/en/lock-tables.html
249
         * @var EntityManagerInterface $em
250
         */
251
        $em = $this->em;
252
        if ($em->getConnection()->isTransactionActive()) {
253
            $em->getConnection()->commit();
254
            $em->getConnection()->beginTransaction();
255
        }
256
257
        $return = $this->composerService->execRequire($pluginCode);
258
        if ($return) {
259
            $app->addSuccess('admin.plugin.install.complete', 'admin');
260
261
            return $app->redirect($app->url('admin_store_plugin'));
262
        }
263
        $app->addError('admin.plugin.install.fail', 'admin');
264
265
        return $app->redirect($app->url('admin_store_plugin_owners_search'));
266
    }
267
268
    /**
269
     * New ways to remove plugin: using composer command
270
     *
271
     * @Method("DELETE")
272
     * @Route("/{_admin}/store/plugin/api/{id}/uninstall", requirements={"id" = "\d+"}, name="admin_store_plugin_api_uninstall")
273
     * @param Application $app
274
     * @param Plugin      $Plugin
275
     * @return RedirectResponse
276
     */
277
    public function apiUninstall(Application $app, Plugin $Plugin)
278
    {
279
        $this->isTokenValid($app);
280
281
        if ($Plugin->getEnable() == Constant::ENABLED) {
282
            $app->addError('admin.plugin.uninstall.error.not_disable', 'admin');
283
284
            return $app->redirect($app->url('admin_store_plugin'));
285
        }
286
287
        $pluginCode = $Plugin->getCode();
288
289
290
        /**
291
         * Mysql lock in transaction
292
         * @link https://dev.mysql.com/doc/refman/5.7/en/lock-tables.html
293
         * @var EntityManagerInterface $em
294
         */
295
        $em = $this->em;
296
        if ($em->getConnection()->isTransactionActive()) {
297
            $em->getConnection()->commit();
298
            $em->getConnection()->beginTransaction();
299
        }
300
301
        $return = $this->composerService->execRemove($pluginCode);
302
        if ($return) {
303
            $app->addSuccess('admin.plugin.uninstall.complete', 'admin');
304
        } else {
305
            $app->addError('admin.plugin.uninstall.error', 'admin');
306
        }
307
308
        return $app->redirect($app->url('admin_store_plugin'));
309
    }
310
311
    /**
312
     * API request processing
313
     *
314
     * @param string  $url
315
     * @param Application $app
316
     * @return array
317
     */
318
    private function getRequestApi($url, $app)
319
    {
320
        $curl = curl_init($url);
321
322
        // Option array
323
        $options = array(
324
            // HEADER
325
            CURLOPT_HTTPGET => true,
326
            CURLOPT_SSL_VERIFYPEER => false,
327
            CURLOPT_RETURNTRANSFER => true,
328
            CURLOPT_FAILONERROR => true,
329
            CURLOPT_CAINFO => \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath(),
330
        );
331
332
        // Set option value
333
        curl_setopt_array($curl, $options);
334
        $result = curl_exec($curl);
335
        $info = curl_getinfo($curl);
336
        $message = curl_error($curl);
337
        $info['message'] = $message;
338
        curl_close($curl);
339
340
        $app->log('http get_info', $info);
341
342
        return array($result, $info);
343
    }
344
345
    /**
346
     * Get message
347
     *
348
     * @param $info
349
     * @return string
350
     */
351 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...
352
    {
353
        if (!empty($info)) {
354
            $statusCode = $info['http_code'];
355
            $message = $info['message'];
356
357
            $message = $statusCode.' : '.$message;
358
        } else {
359
            $message = "タイムアウトエラーまたはURLの指定に誤りがあります。";
360
        }
361
362
        return $message;
363
    }
364
}
365