Completed
Push — experimental/3.1 ( eaf44a...674117 )
by Ryo
25s
created

PluginService::getDependency()   C

Complexity

Conditions 8
Paths 10

Size

Total Lines 32
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 72

Importance

Changes 0
Metric Value
cc 8
eloc 15
nc 10
nop 3
dl 0
loc 32
ccs 0
cts 0
cp 0
crap 72
rs 5.3846
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of EC-CUBE
5
 *
6
 * Copyright(c) 2000-2015 LOCKON CO.,LTD. All Rights Reserved.
7
 *
8
 * http://www.lockon.co.jp/
9
 *
10
 * This program is free software; you can redistribute it and/or
11
 * modify it under the terms of the GNU General Public License
12
 * as published by the Free Software Foundation; either version 2
13
 * of the License, or (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program; if not, write to the Free Software
22
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23
 */
24
25
namespace Eccube\Service;
26
27
use Doctrine\ORM\EntityManager;
28
use Eccube\Annotation\Inject;
29
use Eccube\Annotation\Service;
30
use Eccube\Application;
31
use Eccube\Common\Constant;
32
use Eccube\Entity\Plugin;
33
use Eccube\Exception\PluginException;
34
use Eccube\Plugin\ConfigManager;
35
use Eccube\Plugin\ConfigManager as PluginConfigManager;
36
use Eccube\Repository\PluginEventHandlerRepository;
37
use Eccube\Repository\PluginRepository;
38
use Eccube\Util\Cache;
39
use Eccube\Util\Str;
40
use Symfony\Component\Filesystem\Filesystem;
41
use Symfony\Component\Yaml\Yaml;
42
43
/**
44
 * @Service
45
 */
46
class PluginService
47
{
48
    /**
49
     * @Inject(PluginEventHandlerRepository::class)
50
     * @var PluginEventHandlerRepository
51
     */
52
    protected $pluginEventHandlerRepository;
53
54
    /**
55
     * @Inject("orm.em")
56
     * @var EntityManager
57
     */
58
    protected $entityManager;
59
60
    /**
61
     * @Inject(PluginRepository::class)
62
     * @var PluginRepository
63
     */
64
    protected $pluginRepository;
65
66
    /**
67
     * @Inject("config")
68
     * @var array
69
     */
70
    protected $appConfig;
71
72
    /**
73
     * @Inject(Application::class)
74
     * @var Application
75
     */
76
    protected $app;
77
78
    /**
79
     * @var EntityProxyService
80
     * @Inject(EntityProxyService::class)
81
     */
82
    protected $entityProxyService;
83
84
    /**
85
     * @Inject(SchemaService::class)
86
     * @var SchemaService
87
     */
88
    protected $schemaService;
89
90
    const CONFIG_YML = 'config.yml';
91
    const EVENT_YML = 'event.yml';
92
    const VENDOR_NAME = 'ec-cube';
93 15
94
    // ファイル指定してのプラグインインストール
95 15
    public function install($path, $source = 0)
0 ignored issues
show
introduced by
You must use "/**" style comments for a function comment
Loading history...
96 15
    {
97
        $pluginBaseDir = null;
98
        $tmp = null;
99
100 15
        try {
101 15
            // プラグイン配置前に実施する処理
102
            $this->preInstall();
103
104 15
            $tmp = $this->createTempDir();
105 15
106 15
            $this->unpackPluginArchive($path, $tmp); //一旦テンポラリに展開
107
            $this->checkPluginArchiveContent($tmp);
108 15
109 15
            $config = $this->readYml($tmp.'/'.self::CONFIG_YML);
110
            $event = $this->readYml($tmp.'/'.self::EVENT_YML);
111 13
            $this->deleteFile($tmp); // テンポラリのファイルを削除
112 13
113 13
            $this->checkSamePlugin($config['code']); // 重複していないかチェック
114
115 13
            $pluginBaseDir = $this->calcPluginDir($config['code']);
116
            $this->createPluginDir($pluginBaseDir); // 本来の置き場所を作成
117 13
118 13
            $this->unpackPluginArchive($path, $pluginBaseDir); // 問題なければ本当のplugindirへ
119
120 13
            // プラグイン配置後に実施する処理
121
            $this->postInstall($config, $event, $source);
122 13
        } catch (PluginException $e) {
123
            $this->deleteDirs(array($tmp, $pluginBaseDir));
124
            throw $e;
125 12
        } catch (\Exception $e) { // インストーラがどんなExceptionを上げるかわからないので
126 12
127
            $this->deleteDirs(array($tmp, $pluginBaseDir));
128 12
            throw $e;
129 4
        }
130 4
131 4
        return true;
132
    }
133
134
    // インストール事前処理
135
    public function preInstall()
0 ignored issues
show
introduced by
You must use "/**" style comments for a function comment
Loading history...
136 12
    {
137 15
        // キャッシュの削除
138 12
        PluginConfigManager::removePluginConfigCache();
139
        Cache::clear($this->app, false);
140 15
    }
141
142
    // インストール事後処理
143
    public function postInstall($config, $event, $source)
0 ignored issues
show
introduced by
You must use "/**" style comments for a function comment
Loading history...
144
    {
145
        // Proxyのクラスをロードせずにスキーマを更新するために、
146
        // インストール時には一時的なディレクトリにProxyを生成する
147
        $tmpProxyOutputDir = sys_get_temp_dir() . '/proxy_' . Str::random(12);
0 ignored issues
show
Coding Style introduced by
Concat operator must not be surrounded by spaces
Loading history...
148 15
        @mkdir($tmpProxyOutputDir);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
149 15
150
        try {
151 15
            // dbにプラグイン登録
152
            $plugin = $this->registerPlugin($config, $event, $source);
153
154
            // インストール時には一時的に利用するProxyを生成してからスキーマを更新する
155 15
            $generatedFiles = $this->regenerateProxy($plugin, true, $tmpProxyOutputDir);
156
            $this->schemaService->updateSchema($generatedFiles, $tmpProxyOutputDir);
157
158
            ConfigManager::writePluginConfigCache();
159
        } finally {
160 4
            foreach (glob("${tmpProxyOutputDir}/*") as  $f) {
0 ignored issues
show
Coding Style introduced by
There should be 1 space after "as" as per the coding-style, but found 2.
Loading history...
161 4
                unlink($f);
162 3
            }
163 4
            rmdir($tmpProxyOutputDir);
164
        }
165
    }
166
167
    public function createTempDir()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
168
    {
169
        @mkdir($this->appConfig['plugin_temp_realdir']);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
170 15
        $d = ($this->appConfig['plugin_temp_realdir'].'/'.sha1(Str::random(16)));
171
172 15
        if (!mkdir($d, 0777)) {
173
            throw new PluginException($php_errormsg.$d);
174
        }
175
176
        return $d;
177
    }
178 15
179 15
    public function deleteDirs($arr)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
180
    {
181
        foreach ($arr as $dir) {
182
            if (file_exists($dir)) {
183
                $fs = new Filesystem();
184
                $fs->remove($dir);
185
            }
186
        }
187
    }
188
189 1067
    public function unpackPluginArchive($archive, $dir)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
190 1067
    {
191
        $extension = pathinfo($archive, PATHINFO_EXTENSION);
192 1067
        try {
193
            if ($extension == 'zip') {
194
                $zip = new \ZipArchive();
195
                $zip->open($archive);
196
                $zip->extractTo($dir);
197
                $zip->close();
198 1067
            } else {
199 2
                $phar = new \PharData($archive);
200
                $phar->extractTo($dir, null, true);
201 1067
            }
202
        } catch (\Exception $e) {
203
            throw new PluginException('アップロードに失敗しました。圧縮ファイルを確認してください。');
204 1067
        }
205
    }
206 1
207
    public function checkPluginArchiveContent($dir, array $config_cache = array())
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
208 1067
    {
209
        try {
210
            if (!empty($config_cache)) {
211 1067
                $meta = $config_cache;
212
            } else {
213
                $meta = $this->readYml($dir . '/config.yml');
0 ignored issues
show
Coding Style introduced by
Concat operator must not be surrounded by spaces
Loading history...
214
            }
215 1067
        } catch (\Symfony\Component\Yaml\Exception\ParseException $e) {
216
            throw new PluginException($e->getMessage(), $e->getCode(), $e);
217
        }
218
219
        if (!is_array($meta)) {
220 1067
            throw new PluginException('config.yml not found or syntax error');
221
        }
222 View Code Duplication
        if (!isset($meta['code']) || !$this->checkSymbolName($meta['code'])) {
223
            throw new PluginException('config.yml code empty or invalid_character(\W)');
224
        }
225
        if (!isset($meta['name'])) {
226
            // nameは直接クラス名やPATHに使われるわけではないため文字のチェックはなしし
227
            throw new PluginException('config.yml name empty');
228
        }
229 16 View Code Duplication
        if (isset($meta['event']) && !$this->checkSymbolName($meta['event'])) { // eventだけは必須ではない
230 14
            throw new PluginException('config.yml event empty or invalid_character(\W) ');
231
        }
232
        if (!isset($meta['version'])) {
233 13
            // versionは直接クラス名やPATHに使われるわけではないため文字のチェックはなしし
234
            throw new PluginException('config.yml version invalid_character(\W) ');
235
        }
236
        if (isset($meta['orm.path'])) {
237
            if (!is_array($meta['orm.path'])) {
238 1067
                throw new PluginException('config.yml orm.path invalid_character(\W) ');
239
            }
240
        }
241
        if (isset($meta['service'])) {
242
            if (!is_array($meta['service'])) {
243
                throw new PluginException('config.yml service invalid_character(\W) ');
244
            }
245
        }
246 13
    }
247 13
248
    public function readYml($yml)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
249
    {
250
        if (file_exists($yml)) {
251
            return Yaml::parse(file_get_contents($yml));
252 13
        }
253 13
254 1
        return false;
255
    }
256
257
    public function checkSymbolName($string)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
258
    {
259
        return strlen($string) < 256 && preg_match('/^\w+$/', $string);
260 13
        // plugin_nameやplugin_codeに使える文字のチェック
261
        // a-z A-Z 0-9 _
262
        // ディレクトリ名などに使われれるので厳しめ
263
    }
264
265 13
    public function deleteFile($path)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
266 13
    {
267
        $f = new Filesystem();
268
        $f->remove($path);
269
    }
270
271
    public function checkSamePlugin($code)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
272
    {
273 13
        $repo = $this->pluginRepository->findOneBy(array('code' => $code));
274 13
        if ($repo) {
275
            throw new PluginException('plugin already installed.');
276 13
        }
277
    }
278 13
279 13
    public function calcPluginDir($name)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
280 13
    {
281 13
        return $this->appConfig['plugin_realdir'].'/'.$name;
282 13
    }
283 13
284
    public function createPluginDir($d)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
285 13
    {
286 13
        $b = @mkdir($d);
287
        if (!$b) {
288 13
            throw new PluginException($php_errormsg);
289 2
        }
290 2
    }
291 2
292
    public function registerPlugin($meta, $event_yml, $source = 0)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
293
    {
294 2
        $em = $this->entityManager;
295 2
        $em->getConnection()->beginTransaction();
296 2
        try {
297 2
            $p = new \Eccube\Entity\Plugin();
298 2
            // インストール直後はプラグインは有効にしない
299 2
            $p->setName($meta['name'])
300 2
                ->setEnable(Constant::DISABLED)
301 2
                ->setClassName(isset($meta['event']) ? $meta['event'] : '')
302
                ->setVersion($meta['version'])
303
                ->setSource($source)
304
                ->setCode($meta['code']);
305
306 13
            $em->persist($p);
307
            $em->flush();
308 13
309
            if (is_array($event_yml)) {
310 12
                foreach ($event_yml as $event => $handlers) {
311 12
                    foreach ($handlers as $handler) {
312 1
                        if (!$this->checkSymbolName($handler[0])) {
313 1
                            throw new PluginException('Handler name format error');
314 1
                        }
315
                        $peh = new \Eccube\Entity\PluginEventHandler();
316
                        $peh->setPlugin($p)
317 12
                            ->setEvent($event)
318
                            ->setHandler($handler[0])
319
                            ->setHandlerType($handler[1])
320
                            ->setPriority($this->pluginEventHandlerRepository->calcNewPriority($event, $handler[1]));
321
                        $em->persist($peh);
322 13
                        $em->flush();
323 13
                    }
324 3
                }
325 3
            }
326 3
327
            $em->persist($p);
328
329
            $this->callPluginManagerMethod($meta, 'install');
330
331
            $em->flush();
332
            $em->getConnection()->commit();
333 7
        } catch (\Exception $e) {
334 7
            $em->getConnection()->rollback();
335 7
            throw new PluginException($e->getMessage());
336 7
        }
337 7
338 7
        return $p;
339 7
    }
340 7
341
    public function callPluginManagerMethod($meta, $method)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
342
    {
343 7
        $class = '\\Plugin'.'\\'.$meta['code'].'\\'.'PluginManager';
344
        if (class_exists($class)) {
345 7
            $installer = new $class(); // マネージャクラスに所定のメソッドがある場合だけ実行する
346 7
            if (method_exists($installer, $method)) {
347
                $installer->$method($meta, $this->app);
348
            }
349
        }
350
    }
351
352 7
    public function uninstall(\Eccube\Entity\Plugin $plugin)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
353 7
    {
354 2
        $pluginDir = $this->calcPluginDir($plugin->getCode());
355
        ConfigManager::removePluginConfigCache();
356 7
        Cache::clear($this->app, false);
357 7
        $this->callPluginManagerMethod(Yaml::parse(file_get_contents($pluginDir.'/'.self::CONFIG_YML)), 'disable');
358
        $this->callPluginManagerMethod(Yaml::parse(file_get_contents($pluginDir.'/'.self::CONFIG_YML)), 'uninstall');
359
        $this->disable($plugin);
360
        $this->unregisterPlugin($plugin);
361
        $this->deleteFile($pluginDir);
362
363
        // スキーマを更新する
364
        $this->schemaService->updateSchema([], $this->appConfig['root_dir'].'/app/proxy/entity');
365 8
366
        ConfigManager::writePluginConfigCache();
367
        return true;
0 ignored issues
show
introduced by
Missing blank line before return statement
Loading history...
368
    }
369
370
    public function unregisterPlugin(\Eccube\Entity\Plugin $p)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
371
    {
372
        try {
373
            $em = $this->entityManager;
374
            foreach ($p->getPluginEventHandlers()->toArray() as $peh) {
375
                $em->remove($peh);
376
            }
377 12
            $em->remove($p);
378 10
            $em->flush();
379
        } catch (\Exception $e) {
380 12
            throw $e;
381
        }
382 12
    }
383
384 12
    public function disable(\Eccube\Entity\Plugin $plugin)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
385
    {
386
        return $this->enable($plugin, false);
387 12
    }
388 12
389 12
    /**
390
     * Proxyを再生成します.
391 8
     * @param Plugin $plugin プラグイン
392 8
     * @param boolean $temporary プラグインが無効状態でも一時的に生成するかどうか
393 8
     * @param string|null $outputDir 出力先
394 8
     * @return array 生成されたファイルのパス
395
     */
396
    private function regenerateProxy(Plugin $plugin, $temporary, $outputDir = null)
397
    {
398
        if (is_null($outputDir)) {
399 12
            $outputDir = $this->appConfig['root_dir'].'/app/proxy/entity';
400 12
        }
401
        @mkdir($outputDir);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
402 12
403 12
        $enabledPluginCodes = array_map(
404 12
            function($p) { return $p->getCode(); },
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
Coding Style introduced by
Opening brace must be the last content on the line
Loading history...
introduced by
Missing blank line before return statement
Loading history...
405 12
            $this->pluginRepository->findAllEnabled()
406
        );
407
408
        $excludes = [];
409
        if ($temporary || $plugin->getEnable() === Constant::ENABLED) {
410
            $enabledPluginCodes[] = $plugin->getCode();
411 11
        } else {
412
            $index = array_search($plugin->getCode(), $enabledPluginCodes);
413 11
            if ($index >= 0) {
414 11
                array_splice($enabledPluginCodes, $index, 1);
415 11
                $excludes = [$this->appConfig['root_dir']."/app/Plugin/".$plugin->getCode()."/Entity"];
416 11
            }
417 11
        }
418 11
419
        $enabledPluginEntityDirs = array_map(function($code) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
420 11
            return $this->appConfig['root_dir']."/app/Plugin/${code}/Entity";
421
        }, $enabledPluginCodes);
422
423 10
        return $this->entityProxyService->generate(
424
            array_merge([$this->appConfig['root_dir'].'/app/Acme/Entity'], $enabledPluginEntityDirs),
425 10
            $excludes,
426 10
            $outputDir
427 10
        );
428 1
    }
429 1
430 1
    public function enable(\Eccube\Entity\Plugin $plugin, $enable = true)
0 ignored issues
show
introduced by
Declare public methods first, then protected ones and finally private ones
Loading history...
introduced by
Missing function doc comment
Loading history...
431
    {
432
        $em = $this->entityManager;
433 10
        try {
434
            PluginConfigManager::removePluginConfigCache();
435
            Cache::clear($this->app, false);
436
            $pluginDir = $this->calcPluginDir($plugin->getCode());
437
            $em->getConnection()->beginTransaction();
438 1
            $plugin->setEnable($enable ? Constant::ENABLED : Constant::DISABLED);
439 1
            $em->persist($plugin);
440
441 1
            $this->callPluginManagerMethod(Yaml::parse(file_get_contents($pluginDir.'/'.self::CONFIG_YML)), $enable ? 'enable' : 'disable');
442 1
443 1
            // Proxyだけ再生成してスキーマは更新しない
444
            $this->regenerateProxy($plugin, false);
445 1
446 1
            $em->flush();
447
            $em->getConnection()->commit();
448 1
            PluginConfigManager::writePluginConfigCache();
449 1
        } catch (\Exception $e) {
450
            $em->getConnection()->rollback();
451 1
            throw $e;
452
        }
453
454
        return true;
455 1
    }
456 1
457
    public function update(\Eccube\Entity\Plugin $plugin, $path)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
458 1
    {
459 1
        $pluginBaseDir = null;
460
        $tmp = null;
461 1
        try {
462
            PluginConfigManager::removePluginConfigCache();
463
            Cache::clear($this->app, false);
464
            $tmp = $this->createTempDir();
465
466
            $this->unpackPluginArchive($path, $tmp); //一旦テンポラリに展開
467
            $this->checkPluginArchiveContent($tmp);
468
469
            $config = $this->readYml($tmp.'/'.self::CONFIG_YML);
470
            $event = $this->readYml($tmp.'/event.yml');
471
472 1
            if ($plugin->getCode() != $config['code']) {
473
                throw new PluginException('new/old plugin code is different.');
474
            }
475
476
            $pluginBaseDir = $this->calcPluginDir($config['code']);
477
            $this->deleteFile($tmp); // テンポラリのファイルを削除
478 1
479 1
            $this->unpackPluginArchive($path, $pluginBaseDir); // 問題なければ本当のplugindirへ
480 1
            $this->updatePlugin($plugin, $config, $event); // dbにプラグイン登録
481 1
482
            PluginConfigManager::writePluginConfigCache();
483 1
        } catch (PluginException $e) {
484 1
            foreach (array($tmp) as $dir) {
485
                if (file_exists($dir)) {
486
                    $fs = new Filesystem();
487 1
                    $fs->remove($dir);
488
                }
489 1
            }
490 1
            throw $e;
491 1
        }
492 1
493
        return true;
494
    }
495
496 1
    public function updatePlugin(\Eccube\Entity\Plugin $plugin, $meta, $event_yml)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
497 1
    {
498 1
        try {
499 1
            $em = $this->entityManager;
500 1
            $em->getConnection()->beginTransaction();
501
            $plugin->setVersion($meta['version'])
502 1
                ->setName($meta['name']);
503 1
504 1
            if (isset($meta['event'])) {
505 1
                $plugin->setClassName($meta['event']);
506 1
            }
507 1
508 1
            $rep = $this->pluginEventHandlerRepository;
509 1
510 1
            if (is_array($event_yml)) {
511
                foreach ($event_yml as $event => $handlers) {
512
                    foreach ($handlers as $handler) {
513
                        if (!$this->checkSymbolName($handler[0])) {
514
                            throw new PluginException('Handler name format error');
515
                        }
516 1
                        // updateで追加されたハンドラかどうか調べる
517 1
                        $peh = $rep->findBy(array(
518
                            'plugin_id' => $plugin->getId(),
519
                            'event' => $event,
520
                            'handler' => $handler[0],
521 1
                            'handler_type' => $handler[1],));
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 24 spaces, but found 28.
Loading history...
introduced by
Add a single space after each comma delimiter
Loading history...
522 1
523 1
                        if (!$peh) { // 新規にevent.ymlに定義されたハンドラなのでinsertする
0 ignored issues
show
Bug Best Practice introduced by
The expression $peh of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
524 1
                            $peh = new \Eccube\Entity\PluginEventHandler();
525
                            $peh->setPlugin($plugin)
526
                                ->setEvent($event)
527 1
                                ->setHandler($handler[0])
528 1
                                ->setHandlerType($handler[1])
529 1
                                ->setPriority($rep->calcNewPriority($event, $handler[1]));
530
                            $em->persist($peh);
531
                            $em->flush();
532
                        }
533
                    }
534
                }
535 1
536 1
                # アップデート後のevent.ymlで削除されたハンドラをdtb_plugin_event_handlerから探して削除
0 ignored issues
show
Coding Style introduced by
Perl-style comments are not allowed. Use "// Comment." or "/* comment */" instead.
Loading history...
537 1
                foreach ($rep->findBy(array('plugin_id' => $plugin->getId())) as $peh) {
538 1
                    if (!isset($event_yml[$peh->getEvent()])) {
539
                        $em->remove($peh);
540
                        $em->flush();
541
                    } else {
542
                        $match = false;
543
                        foreach ($event_yml[$peh->getEvent()] as $handler) {
544
                            if ($peh->getHandler() == $handler[0] && $peh->getHandlerType() == $handler[1]) {
545
                                $match = true;
546
                            }
547
                        }
548
                        if (!$match) {
549
                            $em->remove($peh);
550
                            $em->flush();
551
                        }
552
                    }
553
                }
554
            }
555
556
            $em->persist($plugin);
557
            $this->callPluginManagerMethod($meta, 'update');
558
            $em->flush();
559
            $em->getConnection()->commit();
560
        } catch (\Exception $e) {
561
            $em->getConnection()->rollback();
562
            throw $e;
563
        }
564
    }
565
566
    /**
567
     * Do check dependency plugin
568
     *
569
     * @param array $arrPlugin
570
     * @param array $plugin
571
     * @param array $arrDependency
572
     * @return array|mixed
573
     */
574
    public function getDependency($arrPlugin, $plugin, $arrDependency = array())
575
    {
576
        // Prevent infinity loop
577
        if (empty($arrDependency)) {
578
            $arrDependency[] = $plugin;
579
        }
580
581
        // Check dependency
582
        if (!isset($plugin['require']) || empty($plugin['require'])) {
583
            return $arrDependency;
584
        }
585
586
        $require = $plugin['require'];
587
        // Check dependency
588
        foreach ($require as $pluginName => $version) {
589
            $dependPlugin = $this->buildInfo($arrPlugin, $pluginName);
590
            // Prevent call self
591
            if (!$dependPlugin || $dependPlugin['product_code'] == $plugin['product_code']) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $dependPlugin of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
592
                continue;
593
            }
594
595
            // Check duplicate in dependency
596
            $index = array_search($dependPlugin['product_code'], array_column($arrDependency, 'product_code'));
597
            if ($index === false) {
598
                $arrDependency[] = $dependPlugin;
599
                // Check child dependency
600
                $arrDependency = $this->getDependency($arrPlugin, $dependPlugin, $arrDependency);
601
            }
602
        }
603
604
        return $arrDependency;
605
    }
606
607
    /**
608
     * Get plugin information
609
     *
610
     * @param array  $arrPlugin
611
     * @param string $pluginCode
612
     * @return array|null
613
     */
614
    public function buildInfo($arrPlugin, $pluginCode)
615
    {
616
        $plugin = [];
617
        $index = $this->checkPluginExist($arrPlugin, $pluginCode);
618
        if ($index === false) {
619
            return $plugin;
620
        }
621
        // Get target plugin in return of api
622
        $plugin = $arrPlugin[$index];
623
624
        // Check the eccube version that the plugin supports.
625
        $plugin['is_supported_eccube_version'] = 0;
626
        if (in_array(Constant::VERSION, $plugin['eccube_version'])) {
627
            // Match version
628
            $plugin['is_supported_eccube_version'] = 1;
629
        }
630
631
        $plugin['depend'] = $this->getRequirePluginName($arrPlugin, $plugin);
632
633
        return $plugin;
634
    }
635
636
    /**
637
     * Get dependency name and version only
638
     *
639
     * @param array $arrPlugin
640
     * @param array $plugin
641
     * @return mixed
642
     */
643
    public function getRequirePluginName($arrPlugin, $plugin)
644
    {
645
        $depend = [];
646
        if (isset($plugin['require']) && !empty($plugin['require'])) {
647
            foreach ($plugin['require'] as $name => $version) {
648
                $ret = $this->checkPluginExist($arrPlugin, $name);
649
                if ($ret === false) {
650
                    continue;
651
                }
652
                $depend[] = [
653
                    'name' => $arrPlugin[$ret]['name'],
654
                    'version' => $version,
655
                ];
656
            }
657
        }
658
659
        return $depend;
660
    }
661
662
    /**
663
     * @param $arrPlugin
664
     * @param $pluginCode
665
     * @return false|int|string
666
     */
667
    private function checkPluginExist($arrPlugin, $pluginCode)
668
    {
669
        if (strpos($pluginCode, self::VENDOR_NAME.'/') !== false) {
670
            $pluginCode = str_replace(self::VENDOR_NAME.'/', '', $pluginCode);
671
        }
672
        // Find plugin in array
673
        $index = array_search($pluginCode, array_column($arrPlugin, 'product_code'));
674
675
        return $index;
676
    }
677
}
678