Completed
Push — experimental/3.1 ( 26b8cd...7f7c1e )
by Ryo
157:54 queued 151:41
created

OwnerStoreController::search()   C

Complexity

Conditions 14
Paths 3

Size

Total Lines 71
Code Lines 40

Duplication

Lines 7
Ratio 9.86 %

Code Coverage

Tests 0
CRAP Score 210

Importance

Changes 0
Metric Value
cc 14
eloc 40
nc 3
nop 2
dl 7
loc 71
ccs 0
cts 29
cp 0
crap 210
rs 5.5568
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 Eccube\Annotation\Inject;
27
use Eccube\Application;
28
use Eccube\Common\Constant;
29
use Eccube\Controller\AbstractController;
30
use Eccube\Entity\Plugin;
31
use Eccube\Repository\PluginRepository;
32
use Eccube\Service\Composer\ComposerServiceInterface;
33
use Eccube\Service\PluginService;
34
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
35
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
36
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
37
use Symfony\Component\HttpFoundation\RedirectResponse;
38
use Symfony\Component\HttpFoundation\Request;
39
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
40
41
/**
42
 * @Route(service=OwnerStoreController::class)
43
 */
44
class OwnerStoreController extends AbstractController
45
{
46
    /**
47
     * @Inject("config")
48
     * @var array
49
     */
50
    protected $appConfig;
51
52
    /**
53
     * @Inject(PluginRepository::class)
54
     * @var PluginRepository
55
     */
56
    protected $pluginRepository;
57
58
    /**
59
     * @Inject(PluginService::class)
60
     * @var PluginService
61
     */
62
    protected $pluginService;
63
64
    /**
65
     * @Inject("eccube.service.composer")
66
     * @var ComposerServiceInterface
67
     */
68
    protected $composerService;
69
70
    /**
71
     * @var EntityManager
72
     * @Inject("orm.em")
73
     */
74
    protected $em;
75
76
    private static $vendorName = 'ec-cube';
77
78
    /**
79
     * Owner's Store Plugin Installation Screen - Search function
80
     *
81
     * @Route("/{_admin}/store/plugin/search", name="admin_store_plugin_owners_search")
82
     * @Template("Store/plugin_search.twig")
83
     * @param Application $app
84
     * @param Request     $request
85
     * @return array
86
     */
87
    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...
88
    {
89
        // Acquire downloadable plug-in information from owners store
90
        $items = array();
91
        $promotionItems = array();
92
        $message = '';
93
        // Owner's store communication
94
        $url = $this->appConfig['package_repo_url'].'/search/packages.json';
95
        list($json, $info) = $this->getRequestApi($url, $app);
96
        if ($json === false) {
97
            $message = $this->getResponseErrorMessage($info);
98
        } else {
99
            $data = json_decode($json, true);
100
            if (isset($data['success']) && $data['success']) {
101
                // Check plugin installed
102
                $pluginInstalled = $this->pluginRepository->findAll();
103
                // Update_status 1 : not install/purchased 、2 : Installed、 3 : Update、4 : paid purchase
104
                foreach ($data['item'] as $item) {
105
                    // Not install/purchased
106
                    $item['update_status'] = 1;
107
                    /** @var Plugin $plugin */
108
                    foreach ($pluginInstalled as $plugin) {
109
                        if ($plugin->getSource() == $item['product_id']) {
110
                            // Installed
111
                            $item['update_status'] = 2;
112
                            if ($this->pluginService->isUpdate($plugin->getVersion(), $item['version'])) {
113
                                // Need update
114
                                $item['update_status'] = 3;
115
                            }
116
                        }
117
                    }
118
                    $items[] = $item;
119
                }
120
121
                // EC-CUBE version check
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
                    // Add plugin dependency
134
                    $item['depend'] = $this->pluginService->getRequirePluginName($items, $item);
135
                }
136
                unset($item);
137
138
                // Promotion item
139
                $i = 0;
140 View Code Duplication
                foreach ($items as $item) {
141
                    if ($item['promotion'] == 1) {
142
                        $promotionItems[] = $item;
143
                        unset($items[$i]);
144
                    }
145
                    $i++;
146
                }
147
            } else {
148
                $message = $app->trans('admin.plugin.authentication.fail');
149
            }
150
        }
151
152
        return [
153
            'items' => $items,
154
            'promotionItems' => $promotionItems,
155
            'message' => $message,
156
        ];
157
    }
158
159
    /**
160
     * Do confirm page
161
     *
162
     * @Route("/{_admin}/store/plugin/{id}/confirm", requirements={"id" = "\d+"}, name="admin_store_plugin_install_confirm")
163
     * @Template("Store/plugin_confirm.twig")
164
     * @param Application $app
165
     * @param Request     $request
166
     * @param string      $id
167
     * @return array
168
     */
169
    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...
170
    {
171
        // Owner's store communication
172
        $url = $this->appConfig['package_repo_url'].'/search/packages.json';
173
        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...
174
        $data = json_decode($json, true);
175
        $items = $data['item'];
176
177
        // Find plugin in api
178
        $index = array_search($id, array_column($items, 'product_id'));
179
        if ($index === false) {
180
            throw new NotFoundHttpException();
181
        }
182
183
        $pluginCode = $items[$index]['product_code'];
184
185
        $plugin = $this->pluginService->buildInfo($items, $pluginCode);
186
187
        // Prevent infinity loop: A -> B -> A.
188
        $dependents[] = $plugin;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$dependents was never initialized. Although not strictly required by PHP, it is generally a good practice to add $dependents = 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...
189
        $dependents = $this->pluginService->getDependency($items, $plugin, $dependents);
0 ignored issues
show
Bug introduced by
It seems like $plugin defined by $this->pluginService->bu...fo($items, $pluginCode) on line 185 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...
190
        // Unset first param
191
        unset($dependents[0]);
192
193
        return [
194
            'item' => $plugin,
195
            'dependents' => $dependents,
196
        ];
197
    }
198
199
    /**
200
     * Api Install plugin by composer connect with package repo
201
     *
202
     * @Route("/{_admin}/store/plugin/api/{pluginCode}/{eccubeVersion}/{version}" , name="admin_store_plugin_api_install")
203
     *
204
     * @param Application $app
205
     * @param Request     $request
206
     * @param string      $pluginCode
207
     * @param string      $eccubeVersion
208
     * @param string      $version
209
     * @return RedirectResponse
210
     */
211
    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...
212
    {
213
        // Check plugin code
214
        $url = $this->appConfig['package_repo_url'].'/search/packages.json'.'?eccube_version='.$eccubeVersion.'&plugin_code='.$pluginCode.'&version='.$version;
215
        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...
216
        $existFlg = false;
217
        $data = json_decode($json, true);
218
        if ($data && isset($data['success'])) {
219
            $success = $data['success'];
220
            if ($success == '1' && isset($data['item'])) {
221
                foreach ($data['item'] as $item) {
222
                    if ($item['product_code'] == $pluginCode) {
223
                        $existFlg = true;
224
                        break;
225
                    }
226
                }
227
            }
228
        }
229
        if ($existFlg === false) {
230
            $app->log(sprintf('%s plugin not found!', $pluginCode));
231
            $app->addError('admin.plugin.not.found', 'admin');
232
233
            return $app->redirect($app->url('admin_store_plugin_owners_search'));
234
        }
235
        $dependents = array();
236
        $items = $data['item'];
237
        $plugin = $this->pluginService->buildInfo($items, $pluginCode);
238
        $dependents[] = $plugin;
239
        $dependents = $this->pluginService->getDependency($items, $plugin, $dependents);
0 ignored issues
show
Bug introduced by
It seems like $plugin defined by $this->pluginService->bu...fo($items, $pluginCode) on line 237 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...
240
241
        // Unset first param
242
        unset($dependents[0]);
243
        $packageNames = '';
244
        if (!empty($dependents)) {
245
            foreach ($dependents as $item) {
246
                $packageNames .= self::$vendorName.'/'.$item['product_code'].' ';
247
            }
248
        }
249
        $packageNames .= self::$vendorName.'/'.$pluginCode;
250
        $return = $this->composerService->execRequire($packageNames);
251
        if ($return) {
252
            $app->addSuccess('admin.plugin.install.complete', 'admin');
253
254
            return $app->redirect($app->url('admin_store_plugin'));
255
        }
256
        $app->addError('admin.plugin.install.fail', 'admin');
257
258
        return $app->redirect($app->url('admin_store_plugin_owners_search'));
259
    }
260
261
    /**
262
     * Do confirm page
263
     *
264
     * @Route("/{_admin}/store/plugin/delete/{id}/confirm", requirements={"id" = "\d+"}, name="admin_store_plugin_delete_confirm")
265
     * @Template("Store/plugin_confirm_uninstall.twig")
266
     * @param Application $app
267
     * @param Plugin      $Plugin
268
     * @return array|RedirectResponse
269
     */
270
    public function deleteConfirm(Application $app, Plugin $Plugin)
271
    {
272
        // Owner's store communication
273
        $url = $this->appConfig['package_repo_url'].'/search/packages.json';
274
        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...
275
        $data = json_decode($json, true);
276
        $items = $data['item'];
277
278
        // The plugin depends on it
279
        $pluginCode = $Plugin->getCode();
280
        $otherDepend = $this->pluginService->findDependentPlugin($pluginCode);
281
282
        if (!empty($otherDepend)) {
283
            $DependPlugin = $this->pluginRepository->findOneBy(['code' => $otherDepend[0]]);
284
            $dependName = $otherDepend[0];
285
            if ($DependPlugin) {
286
                $dependName = $DependPlugin->getName();
287
            }
288
289
            $message = $app->trans('admin.plugin.uninstall.depend', ['%name%' => $Plugin->getName(), '%depend_name%' => $dependName]);
290
            $app->addError($message, 'admin');
291
292
            return $app->redirect($app->url('admin_store_plugin'));
293
        }
294
295
        // Check plugin in api
296
        $pluginSource = $Plugin->getSource();
297
        $index = array_search($pluginSource, array_column($items, 'product_id'));
298
        if ($index === false) {
299
            throw new NotFoundHttpException();
300
        }
301
302
        // Build info
303
        $pluginCode = $Plugin->getCode();
304
        $plugin = $this->pluginService->buildInfo($items, $pluginCode);
305
        $plugin['id'] = $Plugin->getId();
306
307
        return [
308
            'item' => $plugin,
309
        ];
310
    }
311
312
    /**
313
     * New ways to remove plugin: using composer command
314
     *
315
     * @Method("DELETE")
316
     * @Route("/{_admin}/store/plugin/api/{id}/uninstall", requirements={"id" = "\d+"}, name="admin_store_plugin_api_uninstall")
317
     * @param Application $app
318
     * @param Plugin      $Plugin
319
     * @return RedirectResponse
320
     */
321
    public function apiUninstall(Application $app, Plugin $Plugin)
322
    {
323
        $this->isTokenValid($app);
324
325
        if ($Plugin->isEnable()) {
326
            $this->pluginService->disable($Plugin);
327
        }
328
        $pluginCode = $Plugin->getCode();
329
        $packageName = self::$vendorName.'/'.$pluginCode;
330
        $return = $this->composerService->execRemove($packageName);
331
        if ($return) {
332
            $app->addSuccess('admin.plugin.uninstall.complete', 'admin');
333
        } else {
334
            $app->addError('admin.plugin.uninstall.error', 'admin');
335
        }
336
337
        return $app->redirect($app->url('admin_store_plugin'));
338
    }
339
340
    /**
341
     * API request processing
342
     *
343
     * @param string  $url
344
     * @param Application $app
345
     * @return array
346
     */
347
    private function getRequestApi($url, $app)
348
    {
349
        $curl = curl_init($url);
350
351
        // Option array
352
        $options = array(
353
            // HEADER
354
            CURLOPT_HTTPGET => true,
355
            CURLOPT_SSL_VERIFYPEER => false,
356
            CURLOPT_RETURNTRANSFER => true,
357
            CURLOPT_FAILONERROR => true,
358
            CURLOPT_CAINFO => \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath(),
359
        );
360
361
        // Set option value
362
        curl_setopt_array($curl, $options);
363
        $result = curl_exec($curl);
364
        $info = curl_getinfo($curl);
365
        $message = curl_error($curl);
366
        $info['message'] = $message;
367
        curl_close($curl);
368
369
        $app->log('http get_info', $info);
370
371
        return array($result, $info);
372
    }
373
374
    /**
375
     * Get message
376
     *
377
     * @param $info
378
     * @return string
379
     */
380 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...
381
    {
382
        if (!empty($info)) {
383
            $statusCode = $info['http_code'];
384
            $message = $info['message'];
385
386
            $message = $statusCode.' : '.$message;
387
        } else {
388
            $message = "タイムアウトエラーまたはURLの指定に誤りがあります。";
389
        }
390
391
        return $message;
392
    }
393
}
394