Failed Conditions
Push — dev/recommend-plugins ( 237cf5 )
by Kiyotaka
07:46
created

OwnerStoreController::search()   C

Complexity

Conditions 12
Paths 129

Size

Total Lines 94

Duplication

Lines 16
Ratio 17.02 %

Importance

Changes 0
Metric Value
cc 12
nc 129
nop 3
dl 16
loc 94
rs 5.5109
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
/*
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\Controller\Admin\Store;
15
16
use Eccube\Controller\AbstractController;
17
use Eccube\Entity\BaseInfo;
18
use Eccube\Entity\Master\PageMax;
19
use Eccube\Entity\Plugin;
20
use Eccube\Exception\PluginApiException;
21
use Eccube\Form\Type\Admin\SearchPluginApiType;
22
use Eccube\Repository\BaseInfoRepository;
23
use Eccube\Repository\PluginRepository;
24
use Eccube\Service\Composer\ComposerApiService;
25
use Eccube\Service\Composer\ComposerProcessService;
26
use Eccube\Service\Composer\ComposerServiceInterface;
27
use Eccube\Service\PluginApiService;
28
use Eccube\Service\PluginService;
29
use Eccube\Service\SystemService;
30
use Eccube\Util\FormUtil;
31
use Knp\Component\Pager\Paginator;
32
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
33
use Symfony\Component\HttpFoundation\RedirectResponse;
34
use Symfony\Component\HttpFoundation\Request;
35
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
36
use Symfony\Component\Routing\Annotation\Route;
37
38
/**
39
 * @Route("/%eccube_admin_route%/store/plugin/api")
40
 */
41
class OwnerStoreController extends AbstractController
42
{
43
    /**
44
     * @var PluginRepository
45
     */
46
    protected $pluginRepository;
47
48
    /**
49
     * @var PluginService
50
     */
51
    protected $pluginService;
52
53
    /**
54
     * @var ComposerServiceInterface
55
     */
56
    protected $composerService;
57
58
    /**
59
     * @var SystemService
60
     */
61
    protected $systemService;
62
63
    /**
64
     * @var PluginApiService
65
     */
66
    protected $pluginApiService;
67
68
    private static $vendorName = 'ec-cube';
69
70
    /** @var BaseInfo */
71
    private $BaseInfo;
72
73
    /**
74
     * OwnerStoreController constructor.
75
     *
76
     * @param PluginRepository $pluginRepository
77
     * @param PluginService $pluginService
78
     * @param ComposerProcessService $composerProcessService
79
     * @param ComposerApiService $composerApiService
80
     * @param SystemService $systemService
81
     * @param PluginApiService $pluginApiService
82
     * @param BaseInfoRepository $baseInfoRepository
83
     *
84
     * @throws \Doctrine\ORM\NoResultException
85
     * @throws \Doctrine\ORM\NonUniqueResultException
86
     */
87
    public function __construct(
88
        PluginRepository $pluginRepository,
89
        PluginService $pluginService,
90
        ComposerProcessService $composerProcessService,
91
        ComposerApiService $composerApiService,
92
        SystemService $systemService,
93
        PluginApiService $pluginApiService,
94
        BaseInfoRepository $baseInfoRepository
95
    ) {
96
        $this->pluginRepository = $pluginRepository;
97
        $this->pluginService = $pluginService;
98
        $this->systemService = $systemService;
99
        $this->pluginApiService = $pluginApiService;
100
        $this->BaseInfo = $baseInfoRepository->get();
101
102
        // TODO: Check the flow of the composer service below
103
        $memoryLimit = $this->systemService->getMemoryLimit();
104
        if ($memoryLimit == -1 or $memoryLimit >= $this->eccubeConfig['eccube_composer_memory_limit']) {
105
            $this->composerService = $composerApiService;
106
        } else {
107
            $this->composerService = $composerProcessService;
108
        }
109
    }
110
111
    /**
112
     * Owner's Store Plugin Installation Screen - Search function
113
     *
114
     * @Route("/search", name="admin_store_plugin_owners_search")
115
     * @Route("/search/page/{page_no}", name="admin_store_plugin_owners_search_page", requirements={"page_no" = "\d+"})
116
     * @Template("@admin/Store/plugin_search.twig")
117
     *
118
     * @param Request     $request
119
     * @param int $page_no
120
     * @param Paginator $paginator
121
     *
122
     * @return array
123
     */
124
    public function search(Request $request, $page_no = null, Paginator $paginator)
125
    {
126
        if (empty($this->BaseInfo->getAuthenticationKey())) {
127
            $this->addWarning('認証キーを設定してください。', 'admin');
128
129
            return $this->redirectToRoute('admin_store_authentication_setting');
130
        }
131
132
        // Acquire downloadable plug-in information from owners store
133
        $category = [];
134
135
        $json = $this->pluginApiService->getCategory();
136
        if (!empty($json)) {
137
            $data = json_decode($json, true);
138
            $category = array_column($data, 'name', 'id');
139
        }
140
141
        // build form with master data
142
        $builder = $this->formFactory
143
            ->createBuilder(SearchPluginApiType::class, null, ['category' => $category]);
144
        $searchForm = $builder->getForm();
145
146
        $searchForm->handleRequest($request);
147
        $searchData = $searchForm->getData();
148
        if ($searchForm->isSubmitted()) {
149
            if ($searchForm->isValid()) {
150
                $page_no = 1;
151
                $searchData = $searchForm->getData();
152
                $this->session->set('eccube.admin.plugin_api.search', FormUtil::getViewData($searchForm));
153
                $this->session->set('eccube.admin.plugin_api.search.page_no', $page_no);
154
            }
155
        } else {
156
            // quick search
157
            if (is_numeric($categoryId = $request->get('category_id')) && array_key_exists($categoryId, $category)) {
158
                $searchForm['category_id']->setData($categoryId);
159
            }
160
            // reset page count
161
            $this->session->set('eccube.admin.plugin_api.search.page_count', $this->eccubeConfig->get('eccube_default_page_count'));
162 View Code Duplication
            if (null !== $page_no || $request->get('resume')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
163
                if ($page_no) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $page_no of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
164
                    $this->session->set('eccube.admin.plugin_api.search.page_no', (int) $page_no);
165
                } else {
166
                    $page_no = $this->session->get('eccube.admin.plugin_api.search.page_no', 1);
167
                }
168
                $viewData = $this->session->get('eccube.admin.plugin_api.search', []);
169
                $searchData = FormUtil::submitAndGetData($searchForm, $viewData);
170
            } else {
171
                $page_no = 1;
172
                // submit default value
173
                $viewData = FormUtil::getViewData($searchForm);
174
                $searchData = FormUtil::submitAndGetData($searchForm, $viewData);
175
                $this->session->set('eccube.admin.plugin_api.search', $searchData);
176
                $this->session->set('eccube.admin.plugin_api.search.page_no', $page_no);
177
            }
178
        }
179
180
        // set page count
181
        $pageCount = $this->session->get('eccube.admin.plugin_api.search.page_count', $this->eccubeConfig->get('eccube_default_page_count'));
182
        if (($PageMax = $searchForm['page_count']->getData()) instanceof PageMax) {
183
            $pageCount = $PageMax->getId();
184
            $this->session->set('eccube.admin.plugin_api.search.page_count', $pageCount);
185
        }
186
187
        // Owner's store communication
188
        $searchData['page_no'] = $page_no;
189
        $searchData['page_count'] = $pageCount;
190
191
        $data = null;
192
        $total = 0;
193
        $items = [];
194
195
        try {
196
            $data = $this->pluginApiService->getPlugins($searchData);
197
            $total = $data['total'];
198
            $items = $data['plugins'];
199
        } catch (PluginApiException $e) {
200
            $this->addError($e->getMessage(), 'admin');
201
        }
202
203
        // The usage is set because `$items` are already paged.
204
        // virtual paging
205
        $pagination = $paginator->paginate($items, 1, $pageCount);
206
        $pagination->setTotalItemCount($total);
207
        $pagination->setCurrentPageNumber($page_no);
208
        $pagination->setItemNumberPerPage($pageCount);
209
210
        return [
211
            'pagination' => $pagination,
212
            'total' => $total,
213
            'searchForm' => $searchForm->createView(),
214
            'page_no' => $page_no,
215
            'Categories' => $category,
216
        ];
217
    }
218
219
    /**
220
     * Do confirm page
221
     *
222
     * @Route("/install/{id}/confirm", requirements={"id" = "\d+"}, name="admin_store_plugin_install_confirm")
223
     * @Template("@admin/Store/plugin_confirm.twig")
224
     *
225
     * @param Request $request
226
     *
227
     * @return array
228
     *
229
     * @throws \Eccube\Exception\PluginException
230
     */
231
    public function doConfirm(Request $request, $id)
232
    {
233
        try {
234
            $item = $this->pluginApiService->getPlugin($id);
235
            // Todo: need define item's dependency mechanism
236
            $requires = $this->pluginService->getPluginRequired($item);
0 ignored issues
show
Bug introduced by
It seems like $item defined by $this->pluginApiService->getPlugin($id) on line 234 can also be of type null; however, Eccube\Service\PluginService::getPluginRequired() does only seem to accept array|object<Eccube\Entity\Plugin>, 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...
237
238
            return [
239
                'item' => $item,
240
                'requires' => $requires,
241
                'is_update' => $request->get('is_update', false),
242
            ];
243
        } catch (PluginApiException $e) {
244
            $this->addError($e->getMessage(), 'admin');
245
            return $this->redirectToRoute('admin_store_authentication_setting');
246
        }
247
    }
248
249
    /**
250
     * Api Install plugin by composer connect with package repo
251
     *
252
     * @Route("/install", name="admin_store_plugin_api_install", methods={"POST"})
253
     *
254
     * @param Request $request
255
     *
256
     * @return \Symfony\Component\HttpFoundation\JsonResponse
257
     */
258
    public function apiInstall(Request $request)
259
    {
260
        $this->isTokenValid();
261
262
        $pluginCode = $request->get('pluginCode');
263
264
        $log = null;
265
        try {
266
            $log = $this->composerService->execRequire('ec-cube/'.$pluginCode);
267
268
            return $this->json(['success' => true, 'log' => $log]);
269
        } catch (\Exception $e) {
270
            $log = $e->getMessage();
271
            log_error($e);
272
        }
273
274
        return $this->json(['success' => false, 'log' => $log], 500);
275
    }
276
277
    /**
278
     * Do confirm page
279
     *
280
     * @Route("/delete/{id}/confirm", requirements={"id" = "\d+"}, name="admin_store_plugin_delete_confirm")
281
     * @Template("@admin/Store/plugin_confirm_uninstall.twig")
282
     *
283
     * @param Plugin $Plugin
284
     *
285
     * @return array|RedirectResponse
286
     */
287
    public function deleteConfirm(Plugin $Plugin)
288
    {
289
        // Owner's store communication
290
        $url = $this->eccubeConfig['eccube_package_api_url'].'/search/packages.json';
291
        list($json,) = $this->getRequestApi($url);
0 ignored issues
show
Deprecated Code introduced by
The method Eccube\Controller\Admin\...roller::getRequestApi() has been deprecated with message: since release, please preference PluginApiService

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
292
        $data = json_decode($json, true);
293
        $items = $data['item'];
294
295
        // The plugin depends on it
296
        $pluginCode = $Plugin->getCode();
297
        $otherDepend = $this->pluginService->findDependentPlugin($pluginCode);
298
299
        if (!empty($otherDepend)) {
300
            $DependPlugin = $this->pluginRepository->findOneBy(['code' => $otherDepend[0]]);
301
            $dependName = $otherDepend[0];
302
            if ($DependPlugin) {
303
                $dependName = $DependPlugin->getName();
304
            }
305
            $message = trans('admin.plugin.uninstall.depend', ['%name%' => $Plugin->getName(), '%depend_name%' => $dependName]);
306
            $this->addError($message, 'admin');
307
308
            return $this->redirectToRoute('admin_store_plugin');
309
        }
310
311
        // Check plugin in api
312
        $pluginSource = $Plugin->getSource();
313
        $index = array_search($pluginSource, array_column($items, 'product_id'));
314
        if ($index === false) {
315
            throw new NotFoundHttpException();
316
        }
317
318
        // Build info
319
        $plugin = $this->pluginService->buildInfo($items);
320
        $plugin['id'] = $Plugin->getId();
321
322
        return [
323
            'item' => $plugin,
324
        ];
325
    }
326
327
    /**
328
     * New ways to remove plugin: using composer command
329
     *
330
     * @Route("/delete/{id}/uninstall", requirements={"id" = "\d+"}, name="admin_store_plugin_api_uninstall", methods={"DELETE"})
331
     *
332
     * @param Plugin $Plugin
333
     *
334
     * @return \Symfony\Component\HttpFoundation\JsonResponse
335
     */
336
    public function apiUninstall(Plugin $Plugin)
337
    {
338
        $this->isTokenValid();
339
340
        if ($Plugin->isEnabled()) {
341
            return $this->json(['success' => false, 'message' => trans('admin.plugin.uninstall.error.not_disable')], 400);
342
        }
343
344
        $pluginCode = $Plugin->getCode();
345
        $otherDepend = $this->pluginService->findDependentPlugin($pluginCode);
346
347
        if (!empty($otherDepend)) {
348
            $DependPlugin = $this->pluginRepository->findOneBy(['code' => $otherDepend[0]]);
349
            $dependName = $otherDepend[0];
350
            if ($DependPlugin) {
351
                $dependName = $DependPlugin->getName();
352
            }
353
            $message = trans('admin.plugin.uninstall.depend', ['%name%' => $Plugin->getName(), '%depend_name%' => $dependName]);
354
355
            return $this->json(['success' => false, 'message' => $message], 400);
356
        }
357
358
        $pluginCode = $Plugin->getCode();
359
        $packageName = self::$vendorName.'/'.$pluginCode;
360
        try {
361
            $log = $this->composerService->execRemove($packageName);
362
363
            return $this->json(['success' => false, 'log' => $log]);
364
        } catch (\Exception $e) {
365
            log_error($e);
366
367
            return $this->json(['success' => false, 'log' => $e->getMessage()], 500);
368
        }
369
    }
370
371
    /**
372
     * オーナーズブラグインインストール、アップデート
373
     *
374
     * @Route("/upgrade", name="admin_store_plugin_api_upgrade", methods={"POST"})
375
     *
376
     * @param Request $request
377
     *
378
     * @return \Symfony\Component\HttpFoundation\JsonResponse
379
     */
380
    public function apiUpgrade(Request $request)
381
    {
382
        $this->isTokenValid();
383
384
        $pluginCode = $request->get('pluginCode');
385
        $version = $request->get('version');
386
387
        $log = null;
388
        try {
389
            $log = $this->composerService->execRequire('ec-cube/'.$pluginCode.':'.$version);
390
391
            return $this->json(['success' => true, 'log' => $log]);
392
        } catch (\Exception $e) {
393
            $log = $e->getMessage();
394
            log_error($e);
395
        }
396
397
        return $this->json(['success' => false, 'log' => $log], 500);
398
    }
399
400
    /**
401
     * オーナーズブラグインインストール、スキーマ更新
402
     *
403
     * @Route("/schema_update", name="admin_store_plugin_api_schema_update", methods={"POST"})
404
     *
405
     * @param Request $request
406
     *
407
     * @return \Symfony\Component\HttpFoundation\JsonResponse
408
     */
409 View Code Duplication
    public function apiSchemaUpdate(Request $request)
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...
410
    {
411
        $this->isTokenValid();
412
413
        $pluginCode = $request->get('pluginCode');
414
415
        try {
416
            $Plugin = $this->pluginRepository->findByCode($pluginCode);
417
418
            if (!$Plugin) {
419
                throw new NotFoundHttpException();
420
            }
421
422
            $config = $this->pluginService->readConfig($this->pluginService->calcPluginDir($Plugin->getCode()));
423
424
            ob_start();
425
            $this->pluginService->generateProxyAndUpdateSchema($Plugin, $config);
426
            $log = ob_get_clean();
427
            ob_end_flush();
428
429
            return $this->json(['success' => true, 'log' => $log]);
430
        } catch (\Exception $e) {
431
            $log = $e->getMessage();
432
            log_error($e);
433
434
            return $this->json(['success' => false, 'log' => $log], 500);
435
        }
436
    }
437
438
    /**
439
     * オーナーズブラグインインストール、更新処理
440
     *
441
     * @Route("/update", name="admin_store_plugin_api_update", methods={"POST"})
442
     *
443
     * @param Request $request
444
     *
445
     * @return \Symfony\Component\HttpFoundation\JsonResponse
446
     */
447 View Code Duplication
    public function apiUpdate(Request $request)
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...
448
    {
449
        $this->isTokenValid();
450
451
        $pluginCode = $request->get('pluginCode');
452
453
        $log = null;
454
        try {
455
            $Plugin = $this->pluginRepository->findByCode($pluginCode);
456
            if (!$Plugin) {
457
                throw new NotFoundHttpException();
458
            }
459
460
            $config = $this->pluginService->readConfig($this->pluginService->calcPluginDir($Plugin->getCode()));
461
            ob_start();
462
            $this->pluginService->updatePlugin($Plugin, $config);
463
            $log = ob_get_clean();
464
            ob_end_flush();
465
466
            return $this->json(['success' => true, 'log' => $log]);
467
        } catch (\Exception $e) {
468
            $log = $e->getMessage();
469
            log_error($e);
470
        }
471
472
        return $this->json(['success' => false, 'log' => $log], 500);
473
    }
474
475
    /**
476
     * Do confirm update page
477
     *
478
     * @Route("/upgrade/{id}/confirm", requirements={"id" = "\d+"}, name="admin_store_plugin_update_confirm")
479
     * @Template("@admin/Store/plugin_confirm.twig")
480
     *
481
     * @param Plugin $Plugin
482
     *
483
     * @return array
484
     */
485
    public function doUpdateConfirm(Plugin $Plugin)
486
    {
487
        try {
488
            $item = $this->pluginApiService->getPlugin($Plugin->getSource());
489
            return [
490
                'item' => $item,
491
                'requires' => [],
492
                'is_update' => true,
493
                'Plugin' => $Plugin,
494
            ];
495
        } catch (PluginApiException $e) {
496
            $this->addError($e->getMessage(), 'admin');
497
            return $this->redirectToRoute('admin_store_authentication_setting');
498
        }
499
    }
500
501
    /**
502
     * API request processing
503
     *
504
     * @param string $url
505
     *
506
     * @return array
507
     *
508
     * @deprecated since release, please preference PluginApiService
509
     */
510
    private function getRequestApi($url)
511
    {
512
        $curl = curl_init($url);
513
514
        // Option array
515
        $options = [
516
            // HEADER
517
            CURLOPT_HTTPGET => true,
518
            CURLOPT_SSL_VERIFYPEER => false,
519
            CURLOPT_RETURNTRANSFER => true,
520
            CURLOPT_FAILONERROR => true,
521
            CURLOPT_CAINFO => \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath(),
522
        ];
523
524
        // Set option value
525
        curl_setopt_array($curl, $options);
526
        $result = curl_exec($curl);
527
        $info = curl_getinfo($curl);
528
        $message = curl_error($curl);
529
        $info['message'] = $message;
530
        curl_close($curl);
531
532
        log_info('http get_info', $info);
533
534
        return [$result, $info];
535
    }
536
}
537