Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTTPキャッシュ対応 #1683

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,7 @@ composer.phar
/vendor/
/app/cache/*
!/app/cache/.gitkeep
/app/config/eccube/config.yml
/app/config/eccube/database.yml
/app/config/eccube/constant.yml
/app/config/eccube/mail.yml
/app/config/eccube/path.yml
/app/config/eccube/database.yml
/app/config/eccube/log.yml
/app/config/eccube/*
/app/log/*
!/app/log/.gitkeep
/app/Plugin/*
Expand Down
6 changes: 5 additions & 1 deletion html/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@
if ($app['config']['eccube_install']) {
$app->initialize();
$app->initializePlugin();
$app->run();
if ($app['config']['http_cache']['enabled']) {
$app['http_cache']->run();
} else {
$app->run();
}
} else {
$location = str_replace('index.php', 'install.php', $_SERVER['SCRIPT_NAME']);
header('Location:'.$location);
Expand Down
145 changes: 115 additions & 30 deletions src/Eccube/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
use Eccube\Application\ApplicationTrait;
use Eccube\Common\Constant;
use Eccube\EventListener\TransactionListener;
use Monolog\Logger;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Finder\Finder;
use Symfony\Component\HttpFoundation\Request;
Expand Down Expand Up @@ -82,7 +81,7 @@ public function __construct(array $values = array())
public function initConfig()
{
// load config
$this['config'] = $this->share(function() {
$this['config'] = $this->share(function () {
$ymlPath = __DIR__.'/../../app/config/eccube';
$distPath = __DIR__.'/../../src/Eccube/Resource/config';

Expand Down Expand Up @@ -158,6 +157,19 @@ public function initConfig()

$configAll = array_replace_recursive($configAll, $config_nav_dist, $config_nav);

$config_httpcache = array();
$yml = $ymlPath.'/httpcache.yml';
if (file_exists($yml)) {
$config_httpcache = Yaml::parse(file_get_contents($yml));
}
$config_httpcache_dist = array();
$httpcache_yml_dist = $distPath.'/httpcache.yml.dist';
if (file_exists($httpcache_yml_dist)) {
$config_httpcache_dist = Yaml::parse(file_get_contents($httpcache_yml_dist));
}

$configAll = array_replace_recursive($configAll, $config_httpcache_dist, $config_httpcache);

return $configAll;
});
}
Expand Down Expand Up @@ -186,14 +198,17 @@ public function initialize()
$this->initRendering();

// init provider
$this->register(new \Silex\Provider\HttpCacheServiceProvider(), array(
'http_cache.cache_dir' => __DIR__.'/../../app/cache/http/',
));
$this->register(new \Silex\Provider\HttpFragmentServiceProvider());
$this->register(new \Silex\Provider\UrlGeneratorServiceProvider());
$this->register(new \Silex\Provider\FormServiceProvider());
$this->register(new \Silex\Provider\SerializerServiceProvider());
$this->register(new \Eccube\ServiceProvider\ValidatorServiceProvider());

$app = $this;
$this->error(function(\Exception $e, $code) use ($app) {
$this->error(function (\Exception $e, $code) use ($app) {
if ($app['debug']) {
return;
}
Expand Down Expand Up @@ -257,7 +272,7 @@ public function initLocale()
$this->register(new \Silex\Provider\TranslationServiceProvider(), array(
'locale' => $this['config']['locale'],
));
$this['translator'] = $this->share($this->extend('translator', function($translator, \Silex\Application $app) {
$this['translator'] = $this->share($this->extend('translator', function ($translator, \Silex\Application $app) {
$translator->addLoader('yaml', new \Symfony\Component\Translation\Loader\YamlFileLoader());

$r = new \ReflectionClass('Symfony\Component\Validator\Validator');
Expand Down Expand Up @@ -301,16 +316,16 @@ public function initRendering()
$this->register(new \Silex\Provider\TwigServiceProvider(), array(
'twig.form.templates' => array('Form/form_layout.twig'),
));
$this['twig'] = $this->share($this->extend('twig', function(\Twig_Environment $twig, \Silex\Application $app) {
$this['twig'] = $this->share($this->extend('twig', function (\Twig_Environment $twig, \Silex\Application $app) {
$twig->addExtension(new \Eccube\Twig\Extension\EccubeExtension($app));
$twig->addExtension(new \Twig_Extension_StringLoader());

return $twig;
}));

$this->before(function(Request $request, \Silex\Application $app) {
$this->before(function (Request $request, \Silex\Application $app) {
// フロント or 管理画面ごとにtwigの探索パスを切り替える.
$app['twig'] = $app->share($app->extend('twig', function(\Twig_Environment $twig, \Silex\Application $app) {
$app['twig'] = $app->share($app->extend('twig', function (\Twig_Environment $twig, \Silex\Application $app) {
$paths = array();

// 互換性がないのでprofiler とproduction 時のcacheを分離する
Expand Down Expand Up @@ -362,7 +377,7 @@ public function initRendering()

// twigのグローバル変数を定義.
$app = $this;
$this->on(\Symfony\Component\HttpKernel\KernelEvents::CONTROLLER, function(\Symfony\Component\HttpKernel\Event\FilterControllerEvent $event) use ($app) {
$this->on(\Symfony\Component\HttpKernel\KernelEvents::CONTROLLER, function (\Symfony\Component\HttpKernel\Event\FilterControllerEvent $event) use ($app) {
// ショップ基本情報
$BaseInfo = $app['eccube.repository.base_info']->get();
$app['twig']->addGlobal('BaseInfo', $BaseInfo);
Expand Down Expand Up @@ -422,7 +437,7 @@ public function initMailer()
// メール送信時の文字エンコード指定(デフォルトはUTF-8)
if (isset($this['config']['mail']['charset_iso_2022_jp']) && is_bool($this['config']['mail']['charset_iso_2022_jp'])) {
if ($this['config']['mail']['charset_iso_2022_jp'] === true) {
\Swift::init(function() {
\Swift::init(function () {
\Swift_DependencyContainer::getInstance()
->register('mime.qpheaderencoder')
->asAliasOf('mime.base64headerencoder');
Expand Down Expand Up @@ -451,7 +466,7 @@ public function initDoctrine()
$this->register(new \Silex\Provider\DoctrineServiceProvider(), array(
'dbs.options' => array(
'default' => $this['config']['database']
)));
)));
$this->register(new \Saxulum\DoctrineOrmManagerRegistry\Silex\Provider\DoctrineOrmManagerRegistryProvider());

// プラグインのmetadata定義を合わせて行う.
Expand Down Expand Up @@ -567,19 +582,19 @@ public function initSecurity()
array('^/mypage', 'ROLE_USER'),
);

$this['eccube.password_encoder'] = $this->share(function($app) {
$this['eccube.password_encoder'] = $this->share(function ($app) {
return new \Eccube\Security\Core\Encoder\PasswordEncoder($app['config']);
});
$this['security.encoder_factory'] = $this->share(function($app) {
$this['security.encoder_factory'] = $this->share(function ($app) {
return new \Symfony\Component\Security\Core\Encoder\EncoderFactory(array(
'Eccube\Entity\Customer' => $app['eccube.password_encoder'],
'Eccube\Entity\Member' => $app['eccube.password_encoder'],
));
});
$this['eccube.event_listner.security'] = $this->share(function($app) {
$this['eccube.event_listner.security'] = $this->share(function ($app) {
return new \Eccube\EventListener\SecurityEventListener($app['orm.em']);
});
$this['user'] = function($app) {
$this['user'] = function ($app) {
$token = $app['security']->getToken();

return ($token !== null) ? $token->getUser() : null;
Expand All @@ -590,17 +605,17 @@ public function initSecurity()

// Voterの設定
$app = $this;
$this['authority_voter'] = $this->share(function($app) {
$this['authority_voter'] = $this->share(function ($app) {
return new \Eccube\Security\Voter\AuthorityVoter($app);
});

$app['security.voters'] = $app->extend('security.voters', function($voters) use ($app) {
$app['security.voters'] = $app->extend('security.voters', function ($voters) use ($app) {
$voters[] = $app['authority_voter'];

return $voters;
});

$this['security.access_manager'] = $this->share(function($app) {
$this['security.access_manager'] = $this->share(function ($app) {
return new \Symfony\Component\Security\Core\Authorization\AccessDecisionManager($app['security.voters'], 'unanimous');
});

Expand All @@ -624,7 +639,7 @@ public function initializePlugin()
public function initPluginEventDispatcher()
{
// EventDispatcher
$this['eccube.event.dispatcher'] = $this->share(function() {
$this['eccube.event.dispatcher'] = $this->share(function () {
return new EventDispatcher();
});

Expand Down Expand Up @@ -671,13 +686,13 @@ public function initPluginEventDispatcher()
$app['eccube.event.dispatcher']->dispatch($hookpoint, $event);
});

$this->on(\Symfony\Component\HttpKernel\KernelEvents::RESPONSE, function(\Symfony\Component\HttpKernel\Event\FilterResponseEvent $event) use ($app) {
$this->on(\Symfony\Component\HttpKernel\KernelEvents::RESPONSE, function (\Symfony\Component\HttpKernel\Event\FilterResponseEvent $event) use ($app) {
$route = $event->getRequest()->attributes->get('_route');
$app['eccube.event.dispatcher']->dispatch('eccube.event.render.'.$route.'.before', $event);
});

// Request Event
$this->on(\Symfony\Component\HttpKernel\KernelEvents::REQUEST, function(\Symfony\Component\HttpKernel\Event\GetResponseEvent $event) use ($app) {
$this->on(\Symfony\Component\HttpKernel\KernelEvents::REQUEST, function (\Symfony\Component\HttpKernel\Event\GetResponseEvent $event) use ($app) {

if (\Symfony\Component\HttpKernel\HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return;
Expand Down Expand Up @@ -708,7 +723,7 @@ public function initPluginEventDispatcher()
}, 30); // Routing(32)が解決しし, 認証判定(8)が実行される前のタイミング.

// Controller Event
$this->on(\Symfony\Component\HttpKernel\KernelEvents::CONTROLLER, function(\Symfony\Component\HttpKernel\Event\FilterControllerEvent $event) use ($app) {
$this->on(\Symfony\Component\HttpKernel\KernelEvents::CONTROLLER, function (\Symfony\Component\HttpKernel\Event\FilterControllerEvent $event) use ($app) {

if (\Symfony\Component\HttpKernel\HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return;
Expand Down Expand Up @@ -739,7 +754,7 @@ public function initPluginEventDispatcher()
});

// Response Event
$this->on(\Symfony\Component\HttpKernel\KernelEvents::RESPONSE, function(\Symfony\Component\HttpKernel\Event\FilterResponseEvent $event) use ($app) {
$this->on(\Symfony\Component\HttpKernel\KernelEvents::RESPONSE, function (\Symfony\Component\HttpKernel\Event\FilterResponseEvent $event) use ($app) {

if (\Symfony\Component\HttpKernel\HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return;
Expand Down Expand Up @@ -769,7 +784,7 @@ public function initPluginEventDispatcher()
});

// Exception Event
$this->on(\Symfony\Component\HttpKernel\KernelEvents::EXCEPTION, function(\Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event) use ($app) {
$this->on(\Symfony\Component\HttpKernel\KernelEvents::EXCEPTION, function (\Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event) use ($app) {

if (\Symfony\Component\HttpKernel\HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return;
Expand Down Expand Up @@ -799,7 +814,7 @@ public function initPluginEventDispatcher()
});

// Terminate Event
$this->on(\Symfony\Component\HttpKernel\KernelEvents::TERMINATE, function(\Symfony\Component\HttpKernel\Event\PostResponseEvent $event) use ($app) {
$this->on(\Symfony\Component\HttpKernel\KernelEvents::TERMINATE, function (\Symfony\Component\HttpKernel\Event\PostResponseEvent $event) use ($app) {

$route = $event->getRequest()->attributes->get('_route');

Expand All @@ -823,6 +838,9 @@ public function initPluginEventDispatcher()
// 全体
$app['eccube.event.dispatcher']->dispatch('eccube.event.app.terminate', $event);
});

$this->cacheRequest();

}

public function loadPlugin()
Expand Down Expand Up @@ -862,7 +880,7 @@ public function loadPlugin()
$this['eccube.service.plugin']->checkPluginArchiveContent($path);
} catch (\Eccube\Exception\PluginException $e) {
$this['monolog']->warning("skip {$code} config loading. config.yml not foud or invalid.", array(
'path' => $path,
'path' => $path,
'original-message' => $e->getMessage()
));
continue;
Expand All @@ -875,7 +893,7 @@ public function loadPlugin()

// const
if (isset($config['const'])) {
$this['config'] = $this->share($this->extend('config', function($eccubeConfig) use ($config) {
$this['config'] = $this->share($this->extend('config', function ($eccubeConfig) use ($config) {
$eccubeConfig[$config['code']] = array(
'const' => $config['const'],
);
Expand All @@ -896,7 +914,7 @@ public function loadPlugin()

if (!class_exists($class)) {
$this['monolog']->warning("skip {$code} loading. event class not foud.", array(
'class' => $class,
'class' => $class,
));
$eventExists = false;
}
Expand Down Expand Up @@ -926,7 +944,7 @@ public function loadPlugin()
$class = '\\Plugin\\'.$config['code'].'\\ServiceProvider\\'.$service;
if (!class_exists($class)) {
$this['monolog']->warning("skip {$code} loading. service provider class not foud.", array(
'class' => $class,
'class' => $class,
));
continue;
}
Expand All @@ -941,7 +959,8 @@ public function loadPlugin()
*
* @param boolean $testMode PHPUnit を実行中の場合 true
*/
public function setTestMode($testMode) {
public function setTestMode($testMode)
{
$this->testMode = $testMode;
}

Expand All @@ -959,8 +978,9 @@ public function isTestMode()
*
* データベースの接続を確認
* 成功 : trueを返却
* 失敗 : \Doctrine\DBAL\DBALExceptionエラーが発生( 接続に失敗した場合 )、エラー画面を表示しdie()
* 失敗 : \Doctrine\DBAL\DBALExceptionエラーが発生( 接続に失敗した場合 )、エラー画面を表示しdie()
* 備考 : app['debug']がtrueの際は処理を行わない
*
* @return boolean true
*
*/
Expand All @@ -985,6 +1005,71 @@ protected function checkDatabaseConnection()
$response->send();
die();
}

return true;
}


/**
* Http Cache対応
*/
protected function cacheRequest()
{
$app = $this;

// Response Event(http cache対応、event実行は一番遅く設定)
$this->on(\Symfony\Component\HttpKernel\KernelEvents::RESPONSE, function (\Symfony\Component\HttpKernel\Event\FilterResponseEvent $event) use ($app) {

if ($app['config']['http_cache']['enabled']) {
// httpキャッシュが有効の場合

$request = $event->getRequest();
$response = $event->getResponse();

$route = $request->attributes->get('_route');

$etag = md5($response->getContent());

if (strpos($route, 'admin') === 0) {
// 管理画面

// 管理画面ではコンテンツの中身が変更された時点でキャッシュを更新し、キャッシュの適用範囲はprivateに設定
$response->setCache(array(
'etag' => $etag,
'private' => true,
));

if ($response->isNotModified($request)) {
return $response;
}

} else {
// フロント画面
$cacheRoute = $app['config']['http_cache']['route'];

if (in_array($route, $cacheRoute) === true) {
// キャッシュ対象となる画面lが含まれていた場合、キャッシュ化
// max-ageを設定しているためExpiresは不要
// Last-Modifiedだと比較する項目がないためETagで対応
// max-ageを設定していた場合、contentの中身が変更されても変更されない

$age = $app['config']['http_cache']['age'];

$response->setCache(array(
'etag' => $etag,
'max_age' => $age,
's_maxage' => $age,
'public' => true,
));

if ($response->isNotModified($request)) {
return $response;
}
}
}
}

}, -1024);

}
}
Loading