Skip to content

Commit

Permalink
プラグインの config.yml, event.yml をキャッシュするよう修正
Browse files Browse the repository at this point in the history
- EC-CUBE#1812
- debug モードではキャッシュを使用しません
- キャッシュが存在しない場合は自動的に生成します
- キャッシュの更新は、プラグインの install/enable/disable/uninstall/update のタイミングで行います
  • Loading branch information
nanasess committed Oct 18, 2016
1 parent 851875c commit 2d3606d
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 38 deletions.
166 changes: 132 additions & 34 deletions src/Eccube/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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',
Expand Down Expand Up @@ -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()) {

Expand All @@ -847,20 +828,19 @@ 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,
'original-message' => $e->getMessage()
));
continue;
}
$config = $this['eccube.service.plugin']->readYml($dir->getRealPath().'/config.yml');
$config = $pluginConfig['config'];

$plugin = $this['orm.em']
->getRepository('Eccube\Entity\Plugin')
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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('<?php return %s', var_export($pluginConfigs, true)).';');
}

/**
* プラグイン設定情報のキャッシュファイルを削除する.
*
* @return boolean
*/
public function removePluginConfigCache()
{
$cacheFile = $this->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;
}
}
18 changes: 14 additions & 4 deletions src/Eccube/Service/PluginService.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public function install($path, $source = 0)
$tmp = null;

try {
$this->app->removePluginConfigCache();
$tmp = $this->createTempDir();

$this->unpackPluginArchive($path, $tmp); //一旦テンポラリに展開
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -301,13 +307,15 @@ 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);
$em->persist($plugin);
$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;
Expand All @@ -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); //一旦テンポラリに展開
Expand All @@ -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)) {
Expand Down

0 comments on commit 2d3606d

Please sign in to comment.