Laravel4バンドルのCookieクラスをwrapして使える子にする、というお話


目標

Laravel4のCookieクラス、インターフェイスはとてもわかりやすくていいんだけど、

  • 値をすべてCookieに埋め込む(ある意味当然だけど)
  • しかもその時暗号化する

ので、かなりあっさりRFCの4KB上限を超える。(しかもそれを例外スローなどで開発者に伝えてくれないのでハマリやすい)
なので、CookieクラスをWrapして容量無制限のHugeCookieクラスを実装してみる。

前提

実装

WrapperクラスなのでModelとして実装してみる。ワンファイルでおしまい。

app/models/HugeCookie.php

<?php
// see : http://laravel.com/docs/requests#cookies

class HugeCookie extends Moloquent {
    // see https://github.com/jenssegers/Laravel-MongoDB.
    protected $collection = 'huge_cookies';
    protected $softDelete = false;
    protected $guarded = array();

    //
    const real_cookie_name = 'hgc';


    /**
     * Retrieve or New HugeCookie (Moloquent)  Object.
     *
     * @return HugeCookie
     */
    static function me(){
        $huge_cookie_id = Cookie::get(self::real_cookie_name, null);
        if(empty($huge_cookie_id) || is_null(self::find($huge_cookie_id))){
            $huge_cookie = new self;
        }else{
            $huge_cookie = self::find($huge_cookie_id);
        }
        return $huge_cookie;
    }


    /**
     * Create a new cookie instance.
     *
     * @param  string  $name
     * @return
     */
    static function get($name, $default_value){
        $huge_cookie = self::me();
        return !empty($huge_cookie->$name)? $huge_cookie->$name: $default_value;
    }

    /**
     * Create a new cookie instance.
     *
     * @param  string  $name
     * @param  mix  $value
     * @param  int     $minutes
     * @param  string  $path
     * @param  string  $domain
     * @param  bool    $secure
     * @param  bool    $httpOnly
     * @return \Symfony\Component\HttpFoundation\Cookie
     */
    static function make($name, $value, $minutes = 60, $path = null,
                         $domain = null, $secure = false, $httpOnly = true){
        $huge_cookie = self::me();
        $huge_cookie->$name = $value;
        $huge_cookie->save();

        return Cookie::make(self::real_cookie_name, $huge_cookie->_id, $minutes, $path, $domain, $secure, $httpOnly);
    }

    /**
     * Create a cookie that lasts "forever" (five years).
     *
     * @param  string  $name
     * @param  mix  $value
     * @param  string  $path
     * @param  string  $domain
     * @param  bool    $secure
     * @param  bool    $httpOnly
     * @return \Symfony\Component\HttpFoundation\Cookie
     */
    static function forever($name, $value, $path = null,
                            $domain = null, $secure = false, $httpOnly = true){
        $minutes = 2628000; // Cookie::forever() と同様に5年
        return self::make($name, $value, $minutes, $path, $domain, $secure, $httpOnly);
    }

    /**
     * Expire the given cookie.
     *
     * @param  string  $name
     * @param  string  $path
     * @param  string  $domain
     * @return \Symfony\Component\HttpFoundation\Cookie
     */
    static function forget($name, $path = null, $domain = null){
        return Cookie::make($name, null, -2628000, $path, $domain);
    }

    /**
     * Queue a cookie to send with the next response.
     *
     * @param  dynamic
     * @return void
     */
    static function queue($name, $value, $minutes = 60){
        $huge_cookie = self::me();
        $huge_cookie->$name = $value;
        $huge_cookie->save();
        Cookie::queue(self::real_cookie_name, $huge_cookie->_id, $minutes);
    }

}

ちょっと解説

やっていることをざっくり言うと、

使い方

http://laravel.com/docs/requests#cookies
で列挙されている使用例を真似れば特に使い方に迷うことはないでしょう。
"Cookie"を"HugeCookie"に置き換えるだけです。

HugeCookie使用例

$response = Response::make('Hello World');
$response->withCookie(HugeCookie::make('huge_data', 'Some Huge Data', $minutes));
$huge_data = HugeCookie::get('huge_data');

今回はLaravel-MongoDBに依存した実装になってますが、他のドライバーやストレージでも似たくさいことは実現できるでしょう。

以上です。Enjoy Laravel!


告知

というか宣伝ですが、このエントリーも関係してますが、

2chまとめ巡査長β

http://j.inthemaking.net/
というのを作ってみました。PCでも見れますがスマホ用です。
よろしければ暇つぶしに使って感想いただければ嬉しいです。