From 2d3606d5421c0acefb9f41a31dba1053cbf94190 Mon Sep 17 00:00:00 2001 From: Kentaro Ohkouchi Date: Tue, 18 Oct 2016 17:41:52 +0900 Subject: [PATCH] =?UTF-8?q?=E3=83=97=E3=83=A9=E3=82=B0=E3=82=A4=E3=83=B3?= =?UTF-8?q?=E3=81=AE=20config.yml,=20event.yml=20=E3=82=92=E3=82=AD?= =?UTF-8?q?=E3=83=A3=E3=83=83=E3=82=B7=E3=83=A5=E3=81=99=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - #1812 - debug モードではキャッシュを使用しません - キャッシュが存在しない場合は自動的に生成します - キャッシュの更新は、プラグインの install/enable/disable/uninstall/update のタイミングで行います --- src/Eccube/Application.php | 166 +++++++++++++++++++++------ src/Eccube/Service/PluginService.php | 18 ++- 2 files changed, 146 insertions(+), 38 deletions(-) diff --git a/src/Eccube/Application.php b/src/Eccube/Application.php index a32eb1b0152..63f725afc52 100644 --- a/src/Eccube/Application.php +++ b/src/Eccube/Application.php @@ -410,12 +410,7 @@ public function initDoctrine() $this->register(new \Saxulum\DoctrineOrmManagerRegistry\Silex\Provider\DoctrineOrmManagerRegistryProvider()); // プラグインのmetadata定義を合わせて行う. - $pluginBasePath = __DIR__.'/../../app/Plugin'; - $finder = Finder::create() - ->in($pluginBasePath) - ->directories() - ->depth(0); - + $pluginConfigs = $this->getPluginConfigAll(); $ormMappings = array(); $ormMappings[] = array( 'type' => 'yml', @@ -426,23 +421,13 @@ public function initDoctrine() ), ); - foreach ($finder as $dir) { - - $file = $dir->getRealPath().'/config.yml'; - - if (file_exists($file)) { - $config = Yaml::parse(file_get_contents($file)); - } else { - $code = $dir->getBaseName(); - $this['monolog']->warning("skip {$code} orm.path loading. config.yml not found.", array('path' => $file)); - continue; - } - + foreach ($pluginConfigs as $code) { + $config = $code['config']; // Doctrine Extend if (isset($config['orm.path']) && is_array($config['orm.path'])) { $paths = array(); foreach ($config['orm.path'] as $path) { - $paths[] = $pluginBasePath.'/'.$config['code'].$path; + $paths[] = $this['config']['plugin_realdir'].'/'.$config['code'].$path; } $ormMappings[] = array( 'type' => 'yml', @@ -821,19 +806,15 @@ public function initPluginEventDispatcher() public function loadPlugin() { // プラグインディレクトリを探索. - $basePath = __DIR__.'/../../app/Plugin'; - $finder = Finder::create() - ->in($basePath) - ->directories() - ->depth(0); - - $finder->sortByName(); + $basePath = $this['config']['plugin_realdir']; + $pluginConfigs = $this->getPluginConfigAll(); // ハンドラ優先順位をdbから持ってきてハッシュテーブルを作成 $priorities = array(); $handlers = $this['orm.em'] ->getRepository('Eccube\Entity\PluginEventHandler') ->getHandlers(); + foreach ($handlers as $handler) { if ($handler->getPlugin()->getEnable() && !$handler->getPlugin()->getDelFlg()) { @@ -847,12 +828,11 @@ public function loadPlugin() // プラグインをロードする. // config.yml/event.ymlの定義に沿ってインスタンスの生成を行い, イベント設定を行う. - foreach ($finder as $dir) { - //config.ymlのないディレクトリは無視する - $path = $dir->getRealPath(); - $code = $dir->getBaseName(); + foreach ($pluginConfigs as $code => $pluginConfig) { + // 正しい形式の pluginConfig のみ読み込む + $path = $basePath.'/'.$code; try { - $this['eccube.service.plugin']->checkPluginArchiveContent($path); + $this['eccube.service.plugin']->checkPluginArchiveContent($path, $pluginConfig['config']); } catch (\Eccube\Exception\PluginException $e) { $this['monolog']->warning("skip {$code} config loading. config.yml not foud or invalid.", array( 'path' => $path, @@ -860,7 +840,7 @@ public function loadPlugin() )); continue; } - $config = $this['eccube.service.plugin']->readYml($dir->getRealPath().'/config.yml'); + $config = $pluginConfig['config']; $plugin = $this['orm.em'] ->getRepository('Eccube\Entity\Plugin') @@ -894,11 +874,11 @@ public function loadPlugin() $eventExists = false; } - if ($eventExists && file_exists($dir->getRealPath().'/event.yml')) { + if ($eventExists && isset($config['event'])) { $subscriber = new $class($this); - foreach (Yaml::parse(file_get_contents($dir->getRealPath().'/event.yml')) as $event => $handlers) { + foreach ($pluginConfig['event'] as $event => $handlers) { foreach ($handlers as $handler) { if (!isset($priorities[$config['event']][$event][$handler[0]])) { // ハンドラテーブルに登録されていない(ソースにしか記述されていない)ハンドラは一番後ろにする $priority = \Eccube\Entity\PluginEventHandler::EVENT_PRIORITY_LATEST; @@ -1120,4 +1100,122 @@ protected function initCacheRequest() }, -1024); } + + /** + * すべてのプラグインの設定情報を返す. + * + * すべてのプラグインの config.yml 及び event.yml を読み込み、連想配列で返す. + * キャッシュファイルが存在する場合は、キャッシュを利用する. + * キャッシュファイルが存在しない場合は、キャッシュを生成する. + * $app['debug'] = true の場合は、キャッシュを利用しない. + * + * @return array + */ + public function getPluginConfigAll() + { + if ($this['debug']) { + return $this->parsePluginConfigs(); + } + $pluginConfigCache = $this->getPluginConfigCacheFile(); + if (file_exists($pluginConfigCache)) { + return require $pluginConfigCache; + } + if ($this->writePluginConfigCache($pluginConfigCache) === false) { + return $this->parsePluginConfigs(); + } else { + return require $pluginConfigCache; + } + } + + /** + * プラグイン設定情報のキャッシュを書き込む. + * + * @param string $cacheFile + * @return int|boolean file_put_contents() の結果 + */ + public function writePluginConfigCache($cacheFile = null) + { + if (is_null($cacheFile)) { + $cacheFile = $this->getPluginConfigCacheFile(); + } + $pluginConfigs = $this->parsePluginConfigs(); + if (!file_exists($this['config']['plugin_temp_realdir'])) { + @mkdir($this['config']['plugin_temp_realdir']); + } + $this['monolog']->debug("write plugin config cache", array($pluginConfigs)); + return file_put_contents($cacheFile, sprintf('getPluginConfigCacheFile(); + if (file_exists($cacheFile)) { + $this['monolog']->debug("remove plugin config cache"); + return unlink($cacheFile); + } + return false; + } + + /** + * プラグイン設定情報のキャッシュファイルパスを返す. + * + * @return string + */ + public function getPluginConfigCacheFile() + { + return $this['config']['plugin_temp_realdir'].'/config_cache.php'; + } + + /** + * プラグイン設定情報をパースし, 連想配列で返す. + * + * すべてのプラグインを探索し、 config.yml 及び event.yml をパースする. + * パースした情報を連想配列で返す. + * + * @return array + */ + public function parsePluginConfigs() + { + + $finder = Finder::create() + ->in($this['config']['plugin_realdir']) + ->directories() + ->depth(0); + $finder->sortByName(); + + $pluginConfigs = array(); + foreach ($finder as $dir) { + $code = $dir->getBaseName(); + $file = $dir->getRealPath().'/config.yml'; + $config = null; + if (file_exists($file)) { + $config = Yaml::parse(file_get_contents($file)); + } else { + $this['monolog']->warning("skip {$code} orm.path loading. config.yml not found.", array('path' => $file)); + continue; + } + + $file = $dir->getRealPath().'/event.yml'; + $event = null; + if (file_exists($file)) { + $event = Yaml::parse(file_get_contents($file)); + } else { + $this['monolog']->info("skip {$code} event.yml not found.", array('path' => $file)); + } + if (!is_null($config)) { + $pluginConfigs[$code] = array( + 'config' => $config, + 'event' => $event + ); + $this['monolog']->debug("parse {$code} config", array($code => $pluginConfigs[$code])); + } + } + + return $pluginConfigs; + } } diff --git a/src/Eccube/Service/PluginService.php b/src/Eccube/Service/PluginService.php index 16e96e93613..bcaae9bd86d 100644 --- a/src/Eccube/Service/PluginService.php +++ b/src/Eccube/Service/PluginService.php @@ -47,6 +47,7 @@ public function install($path, $source = 0) $tmp = null; try { + $this->app->removePluginConfigCache(); $tmp = $this->createTempDir(); $this->unpackPluginArchive($path, $tmp); //一旦テンポラリに展開 @@ -64,6 +65,7 @@ public function install($path, $source = 0) $this->unpackPluginArchive($path, $pluginBaseDir); // 問題なければ本当のplugindirへ $this->registerPlugin($config, $event, $source); // dbにプラグイン登録 + $this->app->writePluginConfigCache(); } catch (PluginException $e) { $this->deleteDirs(array($tmp, $pluginBaseDir)); throw $e; @@ -116,10 +118,14 @@ public function unpackPluginArchive($archive, $dir) } } - public function checkPluginArchiveContent($dir) + public function checkPluginArchiveContent($dir, array $config_cache = array()) { try { - $meta = $this->readYml($dir . '/config.yml'); + if (!empty($config_cache)) { + $meta = $config_cache; + } else { + $meta = $this->readYml($dir . '/config.yml'); + } } catch (\Symfony\Component\Yaml\Exception\ParseException $e) { throw new PluginException($e->getMessage(), $e->getCode(), $e); } @@ -262,12 +268,12 @@ public function callPluginManagerMethod($meta, $method) public function uninstall(\Eccube\Entity\Plugin $plugin) { $pluginDir = $this->calcPluginDir($plugin->getCode()); - + $this->app->removePluginConfigCache(); $this->callPluginManagerMethod(Yaml::parse(file_get_contents($pluginDir.'/'.self::CONFIG_YML)), 'disable'); $this->callPluginManagerMethod(Yaml::parse(file_get_contents($pluginDir.'/'.self::CONFIG_YML)), 'uninstall'); $this->unregisterPlugin($plugin); $this->deleteFile($pluginDir); - + $this->app->writePluginConfigCache(); return true; } @@ -301,6 +307,7 @@ public function enable(\Eccube\Entity\Plugin $plugin, $enable = true) { $em = $this->app['orm.em']; try { + $this->app->removePluginConfigCache(); $pluginDir = $this->calcPluginDir($plugin->getCode()); $em->getConnection()->beginTransaction(); $plugin->setEnable($enable ? Constant::ENABLED : Constant::DISABLED); @@ -308,6 +315,7 @@ public function enable(\Eccube\Entity\Plugin $plugin, $enable = true) $this->callPluginManagerMethod(Yaml::parse(file_get_contents($pluginDir.'/'.self::CONFIG_YML)), $enable ? 'enable' : 'disable'); $em->flush(); $em->getConnection()->commit(); + $this->app->writePluginConfigCache(); } catch (\Exception $e) { $em->getConnection()->rollback(); throw $e; @@ -321,6 +329,7 @@ public function update(\Eccube\Entity\Plugin $plugin, $path) $pluginBaseDir = null; $tmp = null; try { + $this->app->removePluginConfigCache(); $tmp = $this->createTempDir(); $this->unpackPluginArchive($path, $tmp); //一旦テンポラリに展開 @@ -342,6 +351,7 @@ public function update(\Eccube\Entity\Plugin $plugin, $path) $this->unpackPluginArchive($path, $pluginBaseDir); // 問題なければ本当のplugindirへ $this->updatePlugin($plugin, $config, $event); // dbにプラグイン登録 + $this->app->writePluginConfigCache(); } catch (PluginException $e) { foreach (array($tmp) as $dir) { if (file_exists($dir)) {