Failed Conditions
Push — experimental/3.1 ( c6bbe9...5ca513 )
by Yangsin
235:43 queued 228:52
created

PluginService::uninstall()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 12
nc 1
nop 1
dl 0
loc 17
ccs 11
cts 11
cp 1
crap 1
rs 9.4285
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
93 15
    public function install($path, $source = 0)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
94
    {
95 15
        $pluginBaseDir = null;
96 15
        $tmp = null;
97
98
        // Proxyのクラスをロードせずにスキーマを更新するために、
99
        // インストール時には一時的なディレクトリにProxyを生成する
100 15
        $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...
101 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...
102
103
        try {
104 15
            PluginConfigManager::removePluginConfigCache();
105 15
            Cache::clear($this->app, false);
106 15
            $tmp = $this->createTempDir();
107
108 15
            $this->unpackPluginArchive($path, $tmp); //一旦テンポラリに展開
109 15
            $this->checkPluginArchiveContent($tmp);
110
111 13
            $config = $this->readYml($tmp.'/'.self::CONFIG_YML);
112 13
            $event = $this->readYml($tmp.'/'.self::EVENT_YML);
113 13
            $this->deleteFile($tmp); // テンポラリのファイルを削除
114
115 13
            $this->checkSamePlugin($config['code']); // 重複していないかチェック
116
117 13
            $pluginBaseDir = $this->calcPluginDir($config['code']);
118 13
            $this->createPluginDir($pluginBaseDir); // 本来の置き場所を作成
119
120 13
            $this->unpackPluginArchive($path, $pluginBaseDir); // 問題なければ本当のplugindirへ
121
122 13
            $plugin = $this->registerPlugin($config, $event, $source); // dbにプラグイン登録
123
124
            // インストール時には一時的に利用するProxyを生成してからスキーマを更新する
125 12
            $generatedFiles = $this->regenerateProxy($plugin, true, $tmpProxyOutputDir);
126 12
            $this->schemaService->updateSchema($generatedFiles, $tmpProxyOutputDir);
127
128 12
            ConfigManager::writePluginConfigCache();
129 4
        } catch (PluginException $e) {
130 4
            $this->deleteDirs(array($tmp, $pluginBaseDir));
131 4
            throw $e;
132
        } catch (\Exception $e) { // インストーラがどんなExceptionを上げるかわからないので
133
134
            $this->deleteDirs(array($tmp, $pluginBaseDir));
135
            throw $e;
136 12
        } finally {
137 15
            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...
138 12
                unlink($f);
139
            }
140 15
            rmdir($tmpProxyOutputDir);
141
        }
142
143
        return true;
144
    }
145
146
    public function createTempDir()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
147
    {
148 15
        @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...
149 15
        $d = ($this->appConfig['plugin_temp_realdir'].'/'.sha1(Str::random(16)));
150
151 15
        if (!mkdir($d, 0777)) {
152
            throw new PluginException($php_errormsg.$d);
153
        }
154
155 15
        return $d;
156
    }
157
158
    public function deleteDirs($arr)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
159
    {
160 4
        foreach ($arr as $dir) {
161 4
            if (file_exists($dir)) {
162 3
                $fs = new Filesystem();
163 4
                $fs->remove($dir);
164
            }
165
        }
166
    }
167
168
    public function unpackPluginArchive($archive, $dir)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
169
    {
170 15
        $extension = pathinfo($archive, PATHINFO_EXTENSION);
171
        try {
172 15
            if ($extension == 'zip') {
173
                $zip = new \ZipArchive();
174
                $zip->open($archive);
175
                $zip->extractTo($dir);
176
                $zip->close();
177
            } else {
178 15
                $phar = new \PharData($archive);
179 15
                $phar->extractTo($dir, null, true);
180
            }
181
        } catch (\Exception $e) {
182
            throw new PluginException('アップロードに失敗しました。圧縮ファイルを確認してください。');
183
        }
184
    }
185
186
    public function checkPluginArchiveContent($dir, array $config_cache = array())
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
187
    {
188
        try {
189 1067
            if (!empty($config_cache)) {
190 1067
                $meta = $config_cache;
191
            } else {
192 1067
                $meta = $this->readYml($dir . '/config.yml');
0 ignored issues
show
Coding Style introduced by
Concat operator must not be surrounded by spaces
Loading history...
193
            }
194
        } catch (\Symfony\Component\Yaml\Exception\ParseException $e) {
195
            throw new PluginException($e->getMessage(), $e->getCode(), $e);
196
        }
197
198 1067
        if (!is_array($meta)) {
199 2
            throw new PluginException('config.yml not found or syntax error');
200
        }
201 1067 View Code Duplication
        if (!isset($meta['code']) || !$this->checkSymbolName($meta['code'])) {
202
            throw new PluginException('config.yml code empty or invalid_character(\W)');
203
        }
204 1067
        if (!isset($meta['name'])) {
205
            // nameは直接クラス名やPATHに使われるわけではないため文字のチェックはなしし
206 1
            throw new PluginException('config.yml name empty');
207
        }
208 1067 View Code Duplication
        if (isset($meta['event']) && !$this->checkSymbolName($meta['event'])) { // eventだけは必須ではない
209
            throw new PluginException('config.yml event empty or invalid_character(\W) ');
210
        }
211 1067
        if (!isset($meta['version'])) {
212
            // versionは直接クラス名やPATHに使われるわけではないため文字のチェックはなしし
213
            throw new PluginException('config.yml version invalid_character(\W) ');
214
        }
215 1067
        if (isset($meta['orm.path'])) {
216
            if (!is_array($meta['orm.path'])) {
217
                throw new PluginException('config.yml orm.path invalid_character(\W) ');
218
            }
219
        }
220 1067
        if (isset($meta['service'])) {
221
            if (!is_array($meta['service'])) {
222
                throw new PluginException('config.yml service invalid_character(\W) ');
223
            }
224
        }
225
    }
226
227
    public function readYml($yml)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
228
    {
229 16
        if (file_exists($yml)) {
230 14
            return Yaml::parse(file_get_contents($yml));
231
        }
232
233 13
        return false;
234
    }
235
236
    public function checkSymbolName($string)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
237
    {
238 1067
        return strlen($string) < 256 && preg_match('/^\w+$/', $string);
239
        // plugin_nameやplugin_codeに使える文字のチェック
240
        // a-z A-Z 0-9 _
241
        // ディレクトリ名などに使われれるので厳しめ
242
    }
243
244
    public function deleteFile($path)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
245
    {
246 13
        $f = new Filesystem();
247 13
        $f->remove($path);
248
    }
249
250
    public function checkSamePlugin($code)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
251
    {
252 13
        $repo = $this->pluginRepository->findOneBy(array('code' => $code));
253 13
        if ($repo) {
254 1
            throw new PluginException('plugin already installed.');
255
        }
256
    }
257
258
    public function calcPluginDir($name)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
259
    {
260 13
        return $this->appConfig['plugin_realdir'].'/'.$name;
261
    }
262
263
    public function createPluginDir($d)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
264
    {
265 13
        $b = @mkdir($d);
266 13
        if (!$b) {
267
            throw new PluginException($php_errormsg);
268
        }
269
    }
270
271
    public function registerPlugin($meta, $event_yml, $source = 0)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
272
    {
273 13
        $em = $this->entityManager;
274 13
        $em->getConnection()->beginTransaction();
275
        try {
276 13
            $p = new \Eccube\Entity\Plugin();
277
            // インストール直後はプラグインは有効にしない
278 13
            $p->setName($meta['name'])
279 13
                ->setEnable(Constant::DISABLED)
280 13
                ->setClassName(isset($meta['event']) ? $meta['event'] : '')
281 13
                ->setVersion($meta['version'])
282 13
                ->setSource($source)
283 13
                ->setCode($meta['code']);
284
285 13
            $em->persist($p);
286 13
            $em->flush();
287
288 13
            if (is_array($event_yml)) {
289 2
                foreach ($event_yml as $event => $handlers) {
290 2
                    foreach ($handlers as $handler) {
291 2
                        if (!$this->checkSymbolName($handler[0])) {
292
                            throw new PluginException('Handler name format error');
293
                        }
294 2
                        $peh = new \Eccube\Entity\PluginEventHandler();
295 2
                        $peh->setPlugin($p)
296 2
                            ->setEvent($event)
297 2
                            ->setHandler($handler[0])
298 2
                            ->setHandlerType($handler[1])
299 2
                            ->setPriority($this->pluginEventHandlerRepository->calcNewPriority($event, $handler[1]));
300 2
                        $em->persist($peh);
301 2
                        $em->flush();
302
                    }
303
                }
304
            }
305
306 13
            $em->persist($p);
307
308 13
            $this->callPluginManagerMethod($meta, 'install');
309
310 12
            $em->flush();
311 12
            $em->getConnection()->commit();
312 1
        } catch (\Exception $e) {
313 1
            $em->getConnection()->rollback();
314 1
            throw new PluginException($e->getMessage());
315
        }
316
317 12
        return $p;
318
    }
319
320
    public function callPluginManagerMethod($meta, $method)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
321
    {
322 13
        $class = '\\Plugin'.'\\'.$meta['code'].'\\'.'PluginManager';
323 13
        if (class_exists($class)) {
324 3
            $installer = new $class(); // マネージャクラスに所定のメソッドがある場合だけ実行する
325 3
            if (method_exists($installer, $method)) {
326 3
                $installer->$method($meta, $this->app);
327
            }
328
        }
329
    }
330
331
    public function uninstall(\Eccube\Entity\Plugin $plugin)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
332
    {
333 7
        $pluginDir = $this->calcPluginDir($plugin->getCode());
334 7
        ConfigManager::removePluginConfigCache();
335 7
        Cache::clear($this->app, false);
336 7
        $this->callPluginManagerMethod(Yaml::parse(file_get_contents($pluginDir.'/'.self::CONFIG_YML)), 'disable');
337 7
        $this->callPluginManagerMethod(Yaml::parse(file_get_contents($pluginDir.'/'.self::CONFIG_YML)), 'uninstall');
338 7
        $this->disable($plugin);
339 7
        $this->unregisterPlugin($plugin);
340 7
        $this->deleteFile($pluginDir);
341
342
        // スキーマを更新する
343 7
        $this->schemaService->updateSchema([], $this->appConfig['root_dir'].'/app/proxy/entity');
344
345 7
        ConfigManager::writePluginConfigCache();
346 7
        return true;
0 ignored issues
show
introduced by
Missing blank line before return statement
Loading history...
347
    }
348
349
    public function unregisterPlugin(\Eccube\Entity\Plugin $p)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
350
    {
351
        try {
352 7
            $em = $this->entityManager;
353 7
            foreach ($p->getPluginEventHandlers()->toArray() as $peh) {
354 2
                $em->remove($peh);
355
            }
356 7
            $em->remove($p);
357 7
            $em->flush();
358
        } catch (\Exception $e) {
359
            throw $e;
360
        }
361
    }
362
363
    public function disable(\Eccube\Entity\Plugin $plugin)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
364
    {
365 8
        return $this->enable($plugin, false);
366
    }
367
368
    /**
369
     * Proxyを再生成します.
370
     * @param Plugin $plugin プラグイン
371
     * @param boolean $temporary プラグインが無効状態でも一時的に生成するかどうか
372
     * @param string|null $outputDir 出力先
373
     * @return array 生成されたファイルのパス
374
     */
375
    private function regenerateProxy(Plugin $plugin, $temporary, $outputDir = null)
376
    {
377 12
        if (is_null($outputDir)) {
378 10
            $outputDir = $this->appConfig['root_dir'].'/app/proxy/entity';
379
        }
380 12
        @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...
381
382 12
        $enabledPluginCodes = array_map(
383
            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...
384 12
            $this->pluginRepository->findAllEnabled()
385
        );
386
387 12
        $excludes = [];
388 12
        if ($temporary || $plugin->getEnable() === Constant::ENABLED) {
389 12
            $enabledPluginCodes[] = $plugin->getCode();
390
        } else {
391 8
            $index = array_search($plugin->getCode(), $enabledPluginCodes);
392 8
            if ($index >= 0) {
393 8
                array_splice($enabledPluginCodes, $index, 1);
394 8
                $excludes = [$this->appConfig['root_dir']."/app/Plugin/".$plugin->getCode()."/Entity"];
395
            }
396
        }
397
398
        $enabledPluginEntityDirs = array_map(function($code) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
399 12
            return $this->appConfig['root_dir']."/app/Plugin/${code}/Entity";
400 12
        }, $enabledPluginCodes);
401
402 12
        return $this->entityProxyService->generate(
403 12
            array_merge([$this->appConfig['root_dir'].'/app/Acme/Entity'], $enabledPluginEntityDirs),
404 12
            $excludes,
405 12
            $outputDir
406
        );
407
    }
408
409
    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...
410
    {
411 11
        $em = $this->entityManager;
412
        try {
413 11
            PluginConfigManager::removePluginConfigCache();
414 11
            Cache::clear($this->app, false);
415 11
            $pluginDir = $this->calcPluginDir($plugin->getCode());
416 11
            $em->getConnection()->beginTransaction();
417 11
            $plugin->setEnable($enable ? Constant::ENABLED : Constant::DISABLED);
418 11
            $em->persist($plugin);
419
420 11
            $this->callPluginManagerMethod(Yaml::parse(file_get_contents($pluginDir.'/'.self::CONFIG_YML)), $enable ? 'enable' : 'disable');
421
422
            // Proxyだけ再生成してスキーマは更新しない
423 10
            $this->regenerateProxy($plugin, false);
424
425 10
            $em->flush();
426 10
            $em->getConnection()->commit();
427 10
            PluginConfigManager::writePluginConfigCache();
428 1
        } catch (\Exception $e) {
429 1
            $em->getConnection()->rollback();
430 1
            throw $e;
431
        }
432
433 10
        return true;
434
    }
435
436
    public function update(\Eccube\Entity\Plugin $plugin, $path)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
437
    {
438 1
        $pluginBaseDir = null;
439 1
        $tmp = null;
440
        try {
441 1
            PluginConfigManager::removePluginConfigCache();
442 1
            Cache::clear($this->app, false);
443 1
            $tmp = $this->createTempDir();
444
445 1
            $this->unpackPluginArchive($path, $tmp); //一旦テンポラリに展開
446 1
            $this->checkPluginArchiveContent($tmp);
447
448 1
            $config = $this->readYml($tmp.'/'.self::CONFIG_YML);
449 1
            $event = $this->readYml($tmp.'/event.yml');
450
451 1
            if ($plugin->getCode() != $config['code']) {
452
                throw new PluginException('new/old plugin code is different.');
453
            }
454
455 1
            $pluginBaseDir = $this->calcPluginDir($config['code']);
456 1
            $this->deleteFile($tmp); // テンポラリのファイルを削除
457
458 1
            $this->unpackPluginArchive($path, $pluginBaseDir); // 問題なければ本当のplugindirへ
459 1
            $this->updatePlugin($plugin, $config, $event); // dbにプラグイン登録
460
461 1
            PluginConfigManager::writePluginConfigCache();
462
        } catch (PluginException $e) {
463
            foreach (array($tmp) as $dir) {
464
                if (file_exists($dir)) {
465
                    $fs = new Filesystem();
466
                    $fs->remove($dir);
467
                }
468
            }
469
            throw $e;
470
        }
471
472 1
        return true;
473
    }
474
475
    public function updatePlugin(\Eccube\Entity\Plugin $plugin, $meta, $event_yml)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
476
    {
477
        try {
478 1
            $em = $this->entityManager;
479 1
            $em->getConnection()->beginTransaction();
480 1
            $plugin->setVersion($meta['version'])
481 1
                ->setName($meta['name']);
482
483 1
            if (isset($meta['event'])) {
484 1
                $plugin->setClassName($meta['event']);
485
            }
486
487 1
            $rep = $this->pluginEventHandlerRepository;
488
489 1
            if (is_array($event_yml)) {
490 1
                foreach ($event_yml as $event => $handlers) {
491 1
                    foreach ($handlers as $handler) {
492 1
                        if (!$this->checkSymbolName($handler[0])) {
493
                            throw new PluginException('Handler name format error');
494
                        }
495
                        // updateで追加されたハンドラかどうか調べる
496 1
                        $peh = $rep->findBy(array(
497 1
                            'plugin_id' => $plugin->getId(),
498 1
                            'event' => $event,
499 1
                            'handler' => $handler[0],
500 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...
501
502 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...
503 1
                            $peh = new \Eccube\Entity\PluginEventHandler();
504 1
                            $peh->setPlugin($plugin)
505 1
                                ->setEvent($event)
506 1
                                ->setHandler($handler[0])
507 1
                                ->setHandlerType($handler[1])
508 1
                                ->setPriority($rep->calcNewPriority($event, $handler[1]));
509 1
                            $em->persist($peh);
510 1
                            $em->flush();
511
                        }
512
                    }
513
                }
514
515
                # アップデート後の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...
516 1
                foreach ($rep->findBy(array('plugin_id' => $plugin->getId())) as $peh) {
517 1
                    if (!isset($event_yml[$peh->getEvent()])) {
518
                        $em->remove($peh);
519
                        $em->flush();
520
                    } else {
521 1
                        $match = false;
522 1
                        foreach ($event_yml[$peh->getEvent()] as $handler) {
523 1
                            if ($peh->getHandler() == $handler[0] && $peh->getHandlerType() == $handler[1]) {
524 1
                                $match = true;
525
                            }
526
                        }
527 1
                        if (!$match) {
528 1
                            $em->remove($peh);
529 1
                            $em->flush();
530
                        }
531
                    }
532
                }
533
            }
534
535 1
            $em->persist($plugin);
536 1
            $this->callPluginManagerMethod($meta, 'update');
537 1
            $em->flush();
538 1
            $em->getConnection()->commit();
539
        } catch (\Exception $e) {
540
            $em->getConnection()->rollback();
541
            throw $e;
542
        }
543
    }
544
}
545