トップ «前の日記(2006-05-25) 最新 次の日記(2006-05-28)» 編集

2002|01|02|03|04|05|06|07|08|11|12|
2003|01|02|03|04|05|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|02|03|04|07|

2006-05-26 [長年日記]

_ Zend_Db_Tableにシリアライズしたデータを格納する方法は?

text型(blogblobでもいいけど)のカラムを一個作っておいて、コードからはそれを連想配列として扱いつつ、DBに書き込む前にseriailizeして保存、DBから取得する際にはunserializeしてから取得したいわけだ。

保存する方だけならば、

class Foo extends Zend_Db_Table
{
  public function insert(&$data)
  {
    $data['bar'] = serialize($data['bar']);
    return parent::insert($data);
  }
  // updateも同様
}

とかすればいいけど、読み込む際に自動的にunserializeするいい方法はないだろうか。

読み込みの実体はZend_Db_Table_RowとかZend_Db_Table_Rowsetクラスが受け持っているせいで、Zend_Db_Table側に直接読み込み全体をハンドリングする口がない。一応Zend_Db_Table::fetchRowをoverrideすれば、1行単位での読み込みはフックできるけど、fetchAllとか配列渡しのfindとかには対応できないしなー。

というのを昨日から考えているんだけどまだいい方法を思いつかない。

_ Zend_Db_Tableにシリアライズしたデータを格納する方法 その2

外部から解決する方法をいろいろ試してみたけれど、結局きれいに対応するのは無理っぽい。っつーか外部からの対応だと、不完全な方法しか思いつかね。

ってことで、直接Zend_Db_Table_Rowを書き換える汚い方法で対処してみた。

class Zend_Db_Table_Row
{
  public function __construct($config)
  {
    ....
    } else {
      $this->_data = (array) $config['data'];
      if (is_callable(array($this->_table, 'fetchCallback'))) {
        $this->_table->fetchCallback($this->_data);
      }
    }
  }
}

なんてものを追加してしまう。すると、データ付きのRowが生成されるときに、そのZend_Db_TableオブジェクトにfetchCallbackというメソッドがあれば、データハッシュを引数にしてそのメソッドを呼び出す。そうしておけば、

class Foo extends Zend_Db_Table
{
  public function insert(&data)
  {
    $data['bar'] = serialize($data['bar']);
    return parent::insert($data);
  }

  // updateも同様

  public function fetchCallback(&$data)
  {
    $data['bar'] = unserialize($data['bar']);
  }
}

なんて感じで、読み書きでの自動シリアライズ、アンシリアライズを書けるようになる。ひとまずしばらくこれでごまかしておこう。2行の追加程度ならば、Zend Frameworkのバージョンアップ時の追随もそれほどつらくないだろうし。