symfonyでETag設定を有効にした場合に304応答が返されるように修正

先日調査したsymfonyのキャッシュの挙動まとめ - しんふぉにゃんのエントリに書いた修正点ですが、symfomnyのコードを直接書き換えるのではなく、以下のようにして適用しました。

1. sfCacheFilterの派生クラスを作成して、lib配下に保存(ここれはxnniCacheFilter.class.phpとしています)

<?php
// lib/xnniCacheFilter.class.php
//
class xnniCacheFilter extends sfCacheFilter {

    //
    //  executeBeforeExecutionをオーバーライド(挙動がおかしいのを修正)
    //
    public function executeBeforeExecution() {
        $uri = $this->routing->getCurrentInternalUri();

        if (is_null($uri)) {
            return true;
        }

        // page cache
        $cacheable = $this->cacheManager->isCacheable($uri);
        if ($cacheable && $this->cacheManager->withLayout($uri)) {
            $inCache = $this->cacheManager->getPageCache($uri);
            $this->response = $this->context->getResponse(); // <GOTO> キャッシュから読み込んだ場合はresponseオブジェクトの参照を再設定する
            $this->cache[$uri] = $inCache;

            if ($inCache) {
                // page is in cache, so no need to run execution filter
                return false;
            }
        }

        return true;
    }

    //
    //  checkCacheValidationのオーバーライド(挙動がおかしいのを修正)
    //
    protected function checkCacheValidation() {
        // Etag support
        if (sfConfig :: get('sf_etag')) {
            $etag = '"' . md5($this->response->getContent()) . '"';

            if ($this->request->getHttpHeader('IF_NONE_MATCH') == $etag) {
                $this->response->setStatusCode(304);
                $this->response->setHeaderOnly(true);

                if (sfConfig :: get('sf_logging_enabled')) {
                    $this->context->getEventDispatcher()->notify(new sfEvent($this, 'application.log', array (
                        'ETag matches If-None-Match (send 304)'
                    )));
                }
            }
        }

        // conditional GET support
        // never in debug mode
        if ($this->response->hasHttpHeader('Last-Modified') && !sfConfig :: get('sf_debug')) {
            $lastModified = $this->response->getHttpHeader('Last-Modified');
            if ( is_array($lastModified) ) {            //  <GOTO> 戻り値が配列なら処理する
                $lastModified = $lastModified[0];
            }
            if ($this->request->getHttpHeader('IF_MODIFIED_SINCE') == $lastModified) {
                $this->response->setStatusCode(304);
                $this->response->setHeaderOnly(true);

                if (sfConfig :: get('sf_logging_enabled')) {
                    $this->context->getEventDispatcher()->notify(new sfEvent($this, 'application.log', array (
                        'Last-Modified matches If-Modified-Since (send 304)'
                    )));
                }
            }
        }
    }
}


2. このフィルタを使用するようにfilters.yml(app/frontend/config/filters.yml)を修正

cache:
  class:  xnniCacheFilter


これでキャッシュをクリアすると、sfCacheFilterの代わりにxnniCacheFilterが使われるようになり、オーバーロードしたメソッドが呼び出されるようになります。


で、ETagが一致する場合は304 Not Modifiedが正しく返されるようになります。