Completed
Push — 4.0 ( 8a9683...64d855 )
by Ryo
11:41 queued 04:40
created

OwnerStoreController::apiInstall()   A

Complexity

Conditions 2
Paths 3

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
nc 3
nop 1
dl 0
loc 18
rs 9.6666
c 0
b 0
f 0
ccs 0
cts 15
cp 0
crap 6
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')) {
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
        $total = 0;
192
        $items = [];
193
194
        try {
195
            $data = $this->pluginApiService->getPlugins($searchData);
196
            $total = $data['total'];
197
            $items = $data['plugins'];
198
        } catch (PluginApiException $e) {
199
            $this->addError($e->getMessage(), 'admin');
200
        }
201
202
        // The usage is set because `$items` are already paged.
203
        // virtual paging
204
        $pagination = $paginator->paginate($items, 1, $pageCount);
205
        $pagination->setTotalItemCount($total);
206
        $pagination->setCurrentPageNumber($page_no);
207
        $pagination->setItemNumberPerPage($pageCount);
208
209
        return [
210
            'pagination' => $pagination,
211
            'total' => $total,
212
            'searchForm' => $searchForm->createView(),
213
            'page_no' => $page_no,
214
            'Categories' => $category,
215
        ];
216
    }
217
218
    /**
219
     * Do confirm page
220
     *
221
     * @Route("/install/{id}/confirm", requirements={"id" = "\d+"}, name="admin_store_plugin_install_confirm")
222
     * @Template("@admin/Store/plugin_confirm.twig")
223
     *
224
     * @param Request $request
225
     *
226
     * @return array
227
     *
228
     * @throws \Eccube\Exception\PluginException
229
     */
230
    public function doConfirm(Request $request, $id)
231
    {
232
        try {
233
            $item = $this->pluginApiService->getPlugin($id);
234
            // Todo: need define item's dependency mechanism
235
            $requires = $this->pluginService->getPluginRequired($item);
236
237
            return [
238
                'item' => $item,
239
                'requires' => $requires,
240
                'is_update' => $request->get('is_update', false),
241
            ];
242
        } catch (PluginApiException $e) {
243
            $this->addError($e->getMessage(), 'admin');
244
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
     * New ways to remove plugin: using composer command
279
     *
280
     * @Route("/delete/{id}/uninstall", requirements={"id" = "\d+"}, name="admin_store_plugin_api_uninstall", methods={"DELETE"})
281
     *
282
     * @param Plugin $Plugin
283
     *
284
     * @return \Symfony\Component\HttpFoundation\JsonResponse
285
     */
286
    public function apiUninstall(Plugin $Plugin)
287
    {
288
        $this->isTokenValid();
289
290
        if ($Plugin->isEnabled()) {
291
            return $this->json(['success' => false, 'message' => trans('admin.plugin.uninstall.error.not_disable')], 400);
292
        }
293
294
        $pluginCode = $Plugin->getCode();
295
        $otherDepend = $this->pluginService->findDependentPlugin($pluginCode);
296
297
        if (!empty($otherDepend)) {
298
            $DependPlugin = $this->pluginRepository->findOneBy(['code' => $otherDepend[0]]);
299
            $dependName = $otherDepend[0];
300
            if ($DependPlugin) {
301
                $dependName = $DependPlugin->getName();
302
            }
303
            $message = trans('admin.plugin.uninstall.depend', ['%name%' => $Plugin->getName(), '%depend_name%' => $dependName]);
304
305
            return $this->json(['success' => false, 'message' => $message], 400);
306
        }
307
308
        $pluginCode = $Plugin->getCode();
309
        $packageName = self::$vendorName.'/'.$pluginCode;
310
        try {
311
            $log = $this->composerService->execRemove($packageName);
312
313
            return $this->json(['success' => false, 'log' => $log]);
314
        } catch (\Exception $e) {
315
            log_error($e);
316
317
            return $this->json(['success' => false, 'log' => $e->getMessage()], 500);
318
        }
319
    }
320
321
    /**
322
     * オーナーズブラグインインストール、アップデート
323
     *
324
     * @Route("/upgrade", name="admin_store_plugin_api_upgrade", methods={"POST"})
325
     *
326
     * @param Request $request
327
     *
328
     * @return \Symfony\Component\HttpFoundation\JsonResponse
329
     */
330
    public function apiUpgrade(Request $request)
331
    {
332
        $this->isTokenValid();
333
334
        $pluginCode = $request->get('pluginCode');
335
        $version = $request->get('version');
336
337
        $log = null;
338
        try {
339
            $log = $this->composerService->execRequire('ec-cube/'.$pluginCode.':'.$version);
340
341
            return $this->json(['success' => true, 'log' => $log]);
342
        } catch (\Exception $e) {
343
            $log = $e->getMessage();
344
            log_error($e);
345
        }
346
347
        return $this->json(['success' => false, 'log' => $log], 500);
348
    }
349
350
    /**
351
     * オーナーズブラグインインストール、スキーマ更新
352
     *
353
     * @Route("/schema_update", name="admin_store_plugin_api_schema_update", methods={"POST"})
354
     *
355
     * @param Request $request
356
     *
357
     * @return \Symfony\Component\HttpFoundation\JsonResponse
358
     */
359 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...
360
    {
361
        $this->isTokenValid();
362
363
        $pluginCode = $request->get('pluginCode');
364
365
        try {
366
            $Plugin = $this->pluginRepository->findByCode($pluginCode);
367
368
            if (!$Plugin) {
369
                throw new NotFoundHttpException();
370
            }
371
372
            $config = $this->pluginService->readConfig($this->pluginService->calcPluginDir($Plugin->getCode()));
373
374
            ob_start();
375
            $this->pluginService->generateProxyAndUpdateSchema($Plugin, $config);
376
            $log = ob_get_clean();
377
            ob_end_flush();
378
379
            return $this->json(['success' => true, 'log' => $log]);
380
        } catch (\Exception $e) {
381
            $log = $e->getMessage();
382
            log_error($e);
383
384
            return $this->json(['success' => false, 'log' => $log], 500);
385
        }
386
    }
387
388
    /**
389
     * オーナーズブラグインインストール、更新処理
390
     *
391
     * @Route("/update", name="admin_store_plugin_api_update", methods={"POST"})
392
     *
393
     * @param Request $request
394
     *
395
     * @return \Symfony\Component\HttpFoundation\JsonResponse
396
     */
397 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...
398
    {
399
        $this->isTokenValid();
400
401
        $pluginCode = $request->get('pluginCode');
402
403
        $log = null;
404
        try {
405
            $Plugin = $this->pluginRepository->findByCode($pluginCode);
406
            if (!$Plugin) {
407
                throw new NotFoundHttpException();
408
            }
409
410
            $config = $this->pluginService->readConfig($this->pluginService->calcPluginDir($Plugin->getCode()));
411
            ob_start();
412
            $this->pluginService->updatePlugin($Plugin, $config);
413
            $log = ob_get_clean();
414
            ob_end_flush();
415
416
            return $this->json(['success' => true, 'log' => $log]);
417
        } catch (\Exception $e) {
418
            $log = $e->getMessage();
419
            log_error($e);
420
        }
421
422
        return $this->json(['success' => false, 'log' => $log], 500);
423
    }
424
425
    /**
426
     * Do confirm update page
427
     *
428
     * @Route("/upgrade/{id}/confirm", requirements={"id" = "\d+"}, name="admin_store_plugin_update_confirm")
429
     * @Template("@admin/Store/plugin_confirm.twig")
430
     *
431
     * @param Plugin $Plugin
432
     *
433
     * @return array
434
     */
435
    public function doUpdateConfirm(Plugin $Plugin)
436
    {
437
        try {
438
            $item = $this->pluginApiService->getPlugin($Plugin->getSource());
439
440
            return [
441
                'item' => $item,
442
                'requires' => [],
443
                'is_update' => true,
444
                'Plugin' => $Plugin,
445
            ];
446
        } catch (PluginApiException $e) {
447
            $this->addError($e->getMessage(), 'admin');
448
449
            return $this->redirectToRoute('admin_store_authentication_setting');
450
        }
451
    }
452
}
453