トップ «前月 最新 翌月» 追記

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-08 [長年日記]


2006-05-09 [長年日記]


2006-05-10 [長年日記]

_ 息継ぎ

大量のドキュメントとか原稿とかを書き終わるまで、そっちに集中するための他のことはしないようにしようと思っていたら、いつまで経っても終わりゃーしねーでやんの。潜り続けるのに飽きたんで息継ぎ1回。本当は連休中にいろいろやっておくつもりだったんだけど、やっぱり(子供がいる)家では仕事できんなー。

Tags: 日常

2006-05-14 [長年日記]


2006-05-16 [長年日記]

_ やっと終わった

っつーか、ひとまず提出しただけなんだけど、もう長いことずっとかかっていたドキュメント+原稿どっちもいったん手を離れてくれて、ごっつい気が楽になった。久しぶりに趣味のコードでも書くか。

Tags: 日常

2006-05-19 [長年日記]

_ 腰が痛い

今日、明日は、サーバー10台くらい+フルラック2個付きの引っ越し作業。まだ半分くらいしか終わってないのに、マジで腰が痛い。明日残り半分できるんだろうか。っつーか今日の帰りの電車で立ってられないかも。

Tags: 日常

2006-05-20 [長年日記]

_ やばいよやばいよ

一晩寝ても腰の痛みが全然ひいてないよ。

Tags: 日常

2006-05-22 [長年日記]

_ CSSのレイアウト

今後標準的に使っていくものを決める際に、独自のレイアウトCSSを作るか、それともどこか有名どころの(ライセンス的に自由な)CSSを採用するか、検討中。

試しにYUIのgridを使ってみたんだけど、これってYUIライブラリの中でも整合性取れてなくね? っつーか、最初に試したのがgridでレイアウトした中に、カレンダーを表示するという組み合わせで、早速破綻が生じた(カレンダーのタイトル部分がずれる)んで、それ以上試す気力を失ってしまった。

reset.cssでcaption,th {text-align:left;}しているのが原因だということは分かったから、場当たり的に直す(calendar.cssでcaption,th{text-align: center;}するとか)のは簡単なんだけど、そういうことをやらなきゃいけないんだったら、初めから全部自分で把握できるCSSレイアウトを採用した方がましな気もしちゃうんだよなー。

Tags: CSS YUI

_ Zend_Db_Tableの使い勝手の向上

Zend_Db_Tableの使い勝手が良くないんで、独自にjoin対応してみたりもしたんだけど、やっぱりああやって元クラス自体に手を入れなきゃならないアプローチは実用レベルにはなり得ないよなーということで、別アプローチでZend_Db_Table周りを使いやすくしてみた。

ソースを見れば分かるけど、要はZend_Db_Table、Zend_Db_Table_Row、Zend_Db_Table_Rowsetのインスタンスをコンポジットに持つ集約クラスを作って、状況に応じて妥当な内部クラスのメソッドを呼ぶ、というのが基本的な構造。

で、それに加えて、Zend_Db_Tableでは扱えない複数テーブルにまたがったデータのハンドリングを行いやすくするための、拡張カラムの呼び出し機能を追加してある。

Zend_Db_Tableで処理を書こうとすると、

class Foo extends Zend_Db_Table{}
$table = new Foo();
$rowset = $table->fetchAll();
foreach ($rowset as $row) {
  echo $row->id;
}
$row = $table->find(1);
echo $row->id;

みたいな感じで、Table、Row、Rowsetオブジェクトがいちいち発生してうざかった。それを、

class Foo extends Zend_Db_Table{}
$table = new WEBXP_Db_Object(new Foo());
$table->fetchAll();
foreach ($table as $row) {
  echo $row->id;
}
$table->find(1);
echo $table->id;

みたいな感じで、一つのオブジェクトで完結して処理が書けるようになる。

あと、fooテーブルがbar_idカラムでbarテーブルとリンクするような構造だった場合、

$table->fetchAll();
foreach ($table as $row) {
  $bar = $row->bar; // $row->barIdから自動的にbarテーブルオブジェクトを取得
}

といった感じで、規約通りのテーブル構成だった場合は、プロパティ名から自動的にリンクするテーブルのオブジェクトを取得してくれる。

あと、拡張カラム名とその内容を取得するためのselect文を定義しておけば、規約外の構造でリンクされる他テーブルの情報を、プロパティとして取得できるような機能を追加してある。

といったあたりまで拡張したら、Zend_Db_Tableもずいぶん使い物になるんじゃなかろうか。今後互換性のない機能拡張がないことを祈りつつ、このアプローチをしばらく試してみよう。

本日のツッコミ(全2件) [ツッコミを入れる]

_ 八木の野郎 [Zendのフレームワーク、最初のバージョンでViewの実装があんまりイケてないのでしょんぼりしたんですが、今はどうな..]

_ ishinao [Viewは、いろいろあったバグが修正された以外は、初期の頃と変わってません。私も最初はなんだかなーと思ってたんですが..]


2006-05-24 [長年日記]


2006-05-25 [長年日記]

_ pdo-mysqlのbindの挙動の違い

Windows/PHP 5.1.4/MySQL 4.1.7(※$dbはpdoMysqlを使ったZend_Db_Adapterだけど、内部の処理はほぼそのままPDOを叩いているだけ)では、

$sql = 'select id from bar where foo_id = :id';
$result = $db->query($sql, array('id' => 1, 'test' => 'test'));

みたいなコードが動くのに、Fedora Core3/PHP5.1.4/MySQL 4.1.19では、「SQLSTATE[HY093]: Invalid parameter number: parameter was not defined」が出て動かない。これを、

$sql = 'select id from bar where foo_id = :id';
$result = $db->query($sql, array('id' => 1));

に変えると動く。

つまり、プレースホルダーで指定されたパラメータ以外をbindする値として渡すと、エラーが出るらしい。この辺の仕様ってPHPのPDO関連のドキュメントには書かれていないっぽいけど、これはバグなのか仕様なのかどっちだろう

Tags: PHP MySQL PDO

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のバージョンアップ時の追随もそれほどつらくないだろうし。


2006-05-28 [長年日記]

_ URIのホスト名部分

Zend_Filter::isHostname()にd.hatena.ne.jpとかを食わせるとfalseが返ってきて、中を見たら、

'/^(?:[^\W_](?:[^\W_]|-){0,61}[^\W_]\.)+[a-zA-Z]{2,6}\.?$/'

にマッチしないんで、falseになっているらしいんだけど、ホスト名の各要素は2文字以上でなければならない、なんて規則はないよね?

'/^(?:[^\W_]((?:[^\W_]|-){0,61}[^\W_])?\.)+[a-zA-Z]{2,6}\.?$/'

にすればいいのかな?


2006-05-29 [長年日記]

_ SBMをシードにした検索エンジン

いつのまにかHyper Estraierにクローラーまで追加されて、Hyper EstraierだけでWeb検索システム一式そろうようになっていた。1470.netをリニューアルする際に、今度は検索周りをどういう風に作ろうかいろいろ考えていたんだけど、実はSBMで登録されたURLをシードにして、Hyper Estraierのクローラーに巡回させるだけで、十分面白いコンテンツになりそうな気がする。ブックマークすると、Hyper Estraierが関連情報を勝手に集めてきてくれる感じ。バックエンドはHyper Estraierに任せて、あとはUIに凝ればいい。個人(ローカル)でそういうシステムを動かしても便利だろうね。

_ Zend_Db_Tableを使った場合の、DB負荷分散への対応

Zend_Db_Tableを使って検索系クエリーを複数DBバックエンド(レプリケーション)に(コードレベルで)分散したい場合ってどうすればいいんだ? 一応setDefaultAdapterで適当にDB接続を切り替えてから、Zend_Db_Tableオブジェクトを生成すれば、そのオブジェクトでは生成された瞬間のZend_Db_Adapterを維持してくれるみたいだけど、複数のZend_Db_Tableオブジェクトで同じZend_Db_Adapterを使っていることを保証したりはできないよなー。更新系アプリと検索系アプリを分割し、検索系アプリでは全体で接続先を分散するようにする? あるいは基本的に接続先を分散しつつ、更新系処理を行う部分だけは明示的にマスタに接続させる? あるいはコードレベルで対応するのはあきらめて、DBレイヤーに近いところで負荷分散させる?(SQL Relayとかpgpoolとか) RoRとかではどうやっているんだろう? まだざっとしか読んでないけど、「RailsによるアジャイルWebアプリケーション開発」にはその辺ことは書いてなかったよなー。

ちなみに

DB_DataObjectでは、$do->_database_dsnをいじって、オブジェクト単位でDB接続先を変えれば、そのオブジェクトを通した処理は、すべてそのDB接続先に対する処理になるから、それで一応管理できた。Zend_Db_Tableの場合は、基本的に1テーブル単位の処理しかできないから、複数テーブルにまたがったjoin相当の処理をしたければ、複数のZend_Db_Tableオブジェクトを作る必要があり、それらが別のDBに接続されてしまうと、話がややこしくなる。っつーのをどうしようかなー、という話ね。


2006-05-31 [長年日記]

_ Zend_Search_HyperEstraier設計中

PEARスタイルのラッパーがあるのは知っているんだけど、Zend Frameworkスタイルで作り直し中。単なるノードAPIのラッパーはだいたいできたんで、さらにそれにかぶせるラッパーを作成中。

現状の設計だと使い勝手は、

$client = new Zend_Search_HyperEstraier_Node_Client($nodeUrl, $userName, $password);

// シンプルな検索
$searchResult = $client->search('phrase'); 

// 複雑な検索
$condition = $client->getCondition();
$condition->clear();
$condition->setPhrase('phrase');
$condition->addAttribute('name streq value');
$condition->setOrder('@mdate');
$searchResult = $client->search(); // or $client->search($condition);

foreach ($searchResult as $item) {
  echo $item->getUri() . "\n";
  foreach ($item->getAttributes() as $name => $value) {
    echo "$name: $value\n";
  }
  echo 'Keyword: ';
  foreach ($item->getKeywords() as $keyword) {
    echo $keyword . ' ';
  }
  echo "\n";
  echo $item->Snippet() . "\n";
}

// ドキュメントリストを取得
$list = $client->getDocumentList($limit);
foreach ($list as $item) {
  echo $item['@uri'] . "\n";
  echo $item['@cdate'] . "\n";
}

// 新規ドキュメントの登録
$document = $client->createDocument([uri]);
$document->addText('text');
$document->addAttribute('name', 'value');
$document->setKeywords(array('keyword1', 'keyword2'));
$document->save();

// 既存のドキュメントの更新
$document = $client->getDocument([document id or uri]);
$document->addText('new text line');
$document->addAttribute('name', 'value');
$document->setKeywords(array('keyword1', 'keyword2'));
$document->save();

// 既存のドキュメントの削除
$document = $client->getDocument([document id or uri]);
$document->delete();

なんて感じなんだけど、なんか末端部の扱いがこなれてなさ過ぎなんで、もうちょっと練ってみよう。あと、検索条件の設定を、Hyper Estraierのマニュアルなしでできるくらい、わかりやすくできないかなー? Estraierでもそうだったけど、高機能な分、検索条件を組み立てるのが難しい(直感的じゃない)んだよな。

あと今すぐは必要ないだろうけど、estwaverみたいにインデックスへの書き込みを複数のノードに分散させる機能を持つクライアント(Zend_Search_HyperEstraier_Node_Client_Distributedとか)も考えておこう。