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

PluginApiService::getPlugin()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9

Duplication

Lines 9
Ratio 100 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 9
loc 9
rs 9.9666
c 0
b 0
f 0
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\Service;
15
16
use Eccube\Common\Constant;
17
use Eccube\Common\EccubeConfig;
18
use Eccube\Entity\BaseInfo;
19
use Eccube\Entity\Plugin;
20
use Eccube\Exception\PluginApiException;
21
use Eccube\Repository\BaseInfoRepository;
22
use Eccube\Repository\PluginRepository;
23
use Symfony\Component\HttpFoundation\RequestStack;
24
25
class PluginApiService
26
{
27
   /**
28
     * Url for Api
29
     *
30
     * @var string
31
     */
32
    private $apiUrl;
33
34
    /**
35
     * @var EccubeConfig
36
     */
37
    private $eccubeConfig;
38
39
    /**
40
     * @var RequestStack
41
     */
42
    private $requestStack;
43
44
    /**
45
     * @var BaseInfo
46
     */
47
    private $BaseInfo;
48
49
    /**
50
     * @var PluginRepository
51
     */
52
    private $pluginRepository;
53
54
    /**
55
     * PluginApiService constructor.
56
     *
57
     * @param EccubeConfig $eccubeConfig
58
     * @param RequestStack $requestStack
59
     * @param BaseInfoRepository $baseInfoRepository
60
     * @param PluginRepository $pluginRepository
61
     *
62
     * @throws \Doctrine\ORM\NoResultException
63
     * @throws \Doctrine\ORM\NonUniqueResultException
64
     */
65
    public function __construct(EccubeConfig $eccubeConfig, RequestStack $requestStack, BaseInfoRepository $baseInfoRepository, PluginRepository $pluginRepository)
66
    {
67
        $this->eccubeConfig = $eccubeConfig;
68
        $this->requestStack = $requestStack;
69
        $this->BaseInfo = $baseInfoRepository->get();
70
        $this->pluginRepository = $pluginRepository;
71
    }
72
73
    /**
74
     * @return mixed
75
     */
76
    public function getApiUrl()
77
    {
78
        if (empty($this->apiUrl)) {
79
            return $this->eccubeConfig->get('eccube_package_api_url');
80
        }
81
82
        return $this->apiUrl;
83
    }
84
85
    /**
86
     * @param mixed $apiUrl
87
     */
88
    public function setApiUrl($apiUrl)
89
    {
90
        $this->apiUrl = $apiUrl;
91
    }
92
93
    /**
94
     * Get master data: category
95
     *
96
     * @return array
97
     */
98
    public function getCategory()
99
    {
100
        try {
101
            $urlCategory = $this->getApiUrl().'/category';
102
103
            return $this->requestApi($urlCategory);
104
        } catch (PluginApiException $e) {
105
            return [];
106
        }
107
    }
108
109
    /**
110
     * Get plugins list
111
     *
112
     * @param $data
113
     *
114
     * @return array
115
     *
116
     * @throws PluginApiException
117
     */
118
    public function getPlugins($data)
119
    {
120
        $url = $this->getApiUrl().'/plugins';
121
        $params['category_id'] = $data['category_id'];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = 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...
122
        $params['price_type'] = empty($data['price_type']) ? 'all' : $data['price_type'];
123
        $params['keyword'] = $data['keyword'];
124
        $params['sort'] = $data['sort'];
125
        $params['page'] = (isset($data['page_no']) && !empty($data['page_no'])) ? $data['page_no'] : 1;
126
        $params['per_page'] = (isset($data['page_count']) && !empty($data['page_count'])) ? $data['page_count'] : $this->eccubeConfig->get('eccube_default_page_count');
127
128
        $payload = $this->requestApi($url, $params);
129
        $data = json_decode($payload, true);
130
131
        if (isset($data['plugins'])) {
132
            $this->buildPlugins($data['plugins']);
133
        }
134
135
        return $data;
136
    }
137
138
    /**
139
     * Get purchased plugins list
140
     *
141
     * @return array
142
     *
143
     * @throws PluginApiException
144
     */
145 View Code Duplication
    public function getPurchased()
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...
146
    {
147
        $url = $this->getApiUrl().'/plugins/purchased';
148
149
        $payload = $this->requestApi($url);
150
        $plugins = json_decode($payload, true);
151
152
        return $this->buildPlugins($plugins);
153
    }
154
155
    /**
156
     * Get recommended plugins list
157
     *
158
     * @return array($result, $info)
0 ignored issues
show
Documentation introduced by
The doc-type array($result, could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
159
     *
160
     * @throws PluginApiException
161
     */
162 View Code Duplication
    public function getRecommended()
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...
163
    {
164
        $url = $this->getApiUrl().'/plugins/recommended';
165
166
        $payload = $this->requestApi($url);
167
        $plugins = json_decode($payload, true);
168
169
        return $this->buildPlugins($plugins);
170
    }
171
172
    private function buildPlugins(&$plugins)
173
    {
174
        /** @var Plugin[] $pluginInstalled */
175
        $pluginInstalled = $this->pluginRepository->findAll();
176
        // Update_status 1 : not install/purchased 、2 : Installed、 3 : Update、4 : not purchased
177
        foreach ($plugins as &$item) {
178
            // Not install/purchased
179
            $item['update_status'] = 1;
180
            foreach ($pluginInstalled as $plugin) {
181
                if ($plugin->getSource() == $item['id']) {
182
                    // Installed
183
                    $item['update_status'] = 2;
184
                    if ($this->isUpdate($plugin->getVersion(), $item['version'])) {
185
                        // Need update
186
                        $item['update_status'] = 3;
187
                    }
188
                }
189
            }
190
            if ($item['purchased'] == false && (isset($item['purchase_required']) && $item['purchase_required'] == true)) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $item['purchase_required'] of type integer to the boolean true. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
191
                // Not purchased with paid items
192
                $item['update_status'] = 4;
193
            }
194
195
            $this->buildInfo($item);
196
        }
197
198
        return $plugins;
199
    }
200
201
    /**
202
     * Is update
203
     *
204
     * @param string $pluginVersion
205
     * @param string $remoteVersion
206
     *
207
     * @return boolean
208
     */
209
    private function isUpdate($pluginVersion, $remoteVersion)
210
    {
211
        return version_compare($pluginVersion, $remoteVersion, '<');
212
    }
213
214
    /**
215
     * Get a plugin
216
     *
217
     * @param int|string $id Id or plugin code
218
     *
219
     * @return array
220
     *
221
     * @throws PluginApiException
222
     */
223 View Code Duplication
    public function getPlugin($id)
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...
224
    {
225
        $url = $this->getApiUrl().'/plugin/'.$id;
226
227
        $payload = $this->requestApi($url);
228
        $json = json_decode($payload, true);
229
230
        return $this->buildInfo($json);
231
    }
232
233
    public function pluginInstalled(Plugin $Plugin)
234
    {
235
        $this->updatePluginStatus('/status/installed', $Plugin);
236
    }
237
238
    public function pluginEnabled(Plugin $Plugin)
239
    {
240
        $this->updatePluginStatus('/status/enabled', $Plugin);
241
    }
242
243
    public function pluginDisabled(Plugin $Plugin)
244
    {
245
        $this->updatePluginStatus('/status/disabled', $Plugin);
246
    }
247
248
    public function pluginUninstalled(Plugin $Plugin)
249
    {
250
        $this->updatePluginStatus('/status/uninstalled', $Plugin);
251
    }
252
253
    private function updatePluginStatus($url, Plugin $Plugin)
254
    {
255
        if ($Plugin->getSource()) {
256
            try {
257
                $this->requestApi($this->getApiUrl().$url, ['id' => $Plugin->getSource()], true);
258
            } catch (PluginApiException $ignore) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
259
            }
260
        }
261
    }
262
263
    /**
264
     * API request processing
265
     *
266
     * @param string $url
267
     * @param array $data
268
     *
269
     * @return array
270
     *
271
     * @throws PluginApiException
272
     */
273
    public function requestApi($url, $data = [], $post = false)
274
    {
275
        if ($post === false && count($data) > 0) {
276
            $url .= '?'.http_build_query($data);
277
        }
278
279
        $curl = curl_init($url);
280
281
        if ($post) {
282
            curl_setopt($curl, CURLOPT_POST, 1);
283
284
            if (count($data) > 0) {
285
                curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
286
            }
287
        }
288
289
        $key = $this->BaseInfo->getAuthenticationKey();
290
291
        $baseUrl = null;
292
        if ($this->requestStack->getCurrentRequest()) {
293
            $baseUrl = $this->requestStack->getCurrentRequest()->getSchemeAndHttpHost().$this->requestStack->getCurrentRequest()->getBasePath();
294
        }
295
296
        // Option array
297
        $options = [
298
            // HEADER
299
            CURLOPT_HTTPHEADER => [
300
                'X-ECCUBE-KEY: '.$key,
301
                'X-ECCUBE-URL: '.$baseUrl,
302
                'X-ECCUBE-VERSION: '.Constant::VERSION,
303
            ],
304
            CURLOPT_HTTPGET => $post === false,
305
            CURLOPT_SSL_VERIFYPEER => false,
306
            CURLOPT_RETURNTRANSFER => true,
307
            CURLOPT_FAILONERROR => true,
308
            CURLOPT_CAINFO => \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath(),
309
        ];
310
311
        // Set option value
312
        curl_setopt_array($curl, $options);
313
        $result = curl_exec($curl);
314
        $info = curl_getinfo($curl);
315
        $message = curl_error($curl);
316
        $info['message'] = $message;
317
        curl_close($curl);
318
319
        log_info('http get_info', $info);
320
321
        if ($info['http_code'] !== 200) {
322
            throw new PluginApiException($info);
323
        }
324
325
        return $result;
326
    }
327
328
    /**
329
     * Get plugin information
330
     *
331
     * @param array $plugin
332
     *
333
     * @return array
334
     */
335
    public function buildInfo(&$plugin)
336
    {
337
        $this->supportedVersion($plugin);
338
339
        return $plugin;
340
    }
341
342
    /**
343
     * Check support version
344
     *
345
     * @param $plugin
346
     */
347
    public function supportedVersion(&$plugin)
348
    {
349
        // Check the eccube version that the plugin supports.
350
        $plugin['version_check'] = false;
351
        if (in_array(Constant::VERSION, $plugin['supported_versions'])) {
352
            // Match version
353
            $plugin['version_check'] = true;
354
        }
355
    }
356
}
357