やかん部@FLATz

PropelでSQLを書くときのヒント

このエントリをdel.icio.usに追加このエントリをはてなブックマークに追加 |2008年09月22日(月)13:37|nasu

那須です


PHPフレームワークの1つSymfonyでは、PropelというORマッパを使って、データベースにアクセスすることが多いと思います。ただ、どうしても複雑な検索結果がほしい場合、自分でSQLを書く必要があります(書かなくてもなんとかなったりしますが、SQL書いた方がすっきりします)。
ただ、自分でSQLを書くとその結果はPropelのオブジェクトとしては扱えません。そこで、今回は自分で書いたSQLからPropelのオブジェクトを生成する方法を整理しておきます。


以前、Propelお役立ちサイトの中に自分で書いた SQL から populated Object を作るなどにもまとめられていますので、そちらも参照してください。


 


例として、次のような構成のテーブルがあり外部結合しているとします。


  • Userテーブル
  • UserAttributesテーブル

ここで、UserAttributesテーブルのデータを条件として、Userテーブルの情報が欲しいとします。この例は簡単なので、UserAttributesテーブルとUserテーブルをaddJoin()してもいいと思いますが、これがさらに入り組んでくるとPropelで表現するのはかなり複雑になります。そこで直接SQLを書くと次のようなコードになります。


 


$con = Propel::getConnection(UserPeer::DATABASE_NAME);
$field_names = UserPeer::getFieldNames(BasePeer::TYPE_FIELDNAME);
// 2008年8月以降にログインしたユーザを取得する
$sql = sprintf(”
SELECT %s
FROM %s u, %s ua
WHERE ua.last_logon >= ‘2008-08-01′
AND u.id = ua.user_id

, join(‘,’, array_map(create_function(‘$v’, ‘return “u.” . $val;’), $field_names))
, UserPeer::TABLE_NAME
, UserAttributesPeer::TABLE_NAME
);
$stmt = $con->prepareStatement($sql);
$rs = $stmt->executeQuery(ResultSet::FETCHMODE_NUM);
$users = UserPeer::populateObjects($rs);

foreach ($users as $user) {
echo $user->getName();
}


ここで肝となるのは


$field_names = UserPeer::getFieldNames(BasePeer::TYPE_FIELDNAME);



 join(‘,’, array_map(create_function(‘$v’, ‘return “u.” . $val;’), $field_names))


です。普通に、u.* でもいいのですが、これだとカラムの順番がUserオブジェクト内で定義されている順番と異なってしまい、期待しない動作をすることがあります。このようにしておくことで、DB上の定義とPropel上での定義の違いを気にすることなく、Userオブジェクトを作ることができます。


ちなみにこの方法は、UserAttributeテーブルの情報もまとめて取得したいと言うときやグルーピングして集計結果を取得したいというときには役立ちません。Userオブジェクトには定義されていないので当然と言えば当然ですが。そのときは、自分でModelを用意するか、viewを作ってそのviewをbuild modelするのがいいでしょう。

この記事に関するお問い合わせはこちら


関連記事


Trackback URL


このページの先頭へ