WEBアプリケーション研究室 開発ノート TOP

WEBアプリケーション研究室 開発ノート Doctrine

スポンサーサイト

-------- --:--

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

    このエントリーをはてなブックマークに追加

生SQLやPDOStatementをハイドレイトするで単純なクエリーのハイドレイトをやりましたが、Doctrineで私の好きな機能の一つ、1対多のleftJoinを旨い具合にハイドレイトしてくれる奴を生SQLでやってみました。
ちなみにテーブル定義はこんな感じです。


User:
columns:
username: string(255)
password: string(255)
indexes:
myindex:
fields: username
type: unique
actAs: [Timestampable]

Phonenumber:
columns:
user_id: integer
phonenumber: string(255)
primary_num: boolean
relations:
User:
foreignAlias: Phonenumbers
actAs: [Timestampable]
そしてコードが

$conn = Doctrine_Manager::connection();
$stmt = $conn->execute('
SELECT
u.id AS u__id,
u.username AS u__username,
u.password AS u__password,
u.created_at AS u__created_at,
u.updated_at AS u__updated_at,
p.id AS p__id,
p.user_id AS p__user_id,
p.phonenumber AS p__phonenumber,
p.primary_num AS p__primary_num,
p.created_at AS p__created_at,
p.updated_at AS p__updated_at
FROM user u
LEFT JOIN phonenumber p ON u.id = p.user_id
');
$hyd = new Doctrine_Hydrator();
$comp['user'] = array('table'=>Doctrine::getTable('User'));
$comp['phone'] = array(
'table' => Doctrine::getTable('Phonenumber'),
'parent' => 'user',
'relation' => $comp['user']['table']->getRelation('Phonenumbers')
);
$hyd->setQueryComponents($comp);

$result = $hyd->hydrateResultSet($stmt, array('u'=>'user', 'p'=>'phone'));
var_dump($result->toArray(true));

    このエントリーをはてなブックマークに追加

生のSQLで作成したPDOStatementオブジェクトからハイドレイト(クエリーの結果をオブジェクトにマッピングすること)できないかとコードをたどってみました。


$conn = Doctrine_Manager::connection();
$stmt = $conn->execute('SELECT u.id AS u__id, u.username AS u__username, u.password AS u__password, u.created_at AS u__created_at, u.updated_at AS u__updated_at FROM user u');
$hyd = new Doctrine_Hydrator();
$comp['u']['table'] = Doctrine::getTable('User');
$hyd->setQueryComponents($comp);

$result = $hyd->hydrateResultSet($stmt, array('u'=>'u'));
var_dump($result->toArray());
ポイントはSQLのカラムに全てu__columnのように別名をつけます。この名前を元にマッピングしているようです。

hydrateResultSet()の2番目の引数はu__の頭の文字がキーで値がsetQueryComponentsした配列のtableオブジェクトの入ったキーを指定します。どの値をどのテーブルにハイドレイトするか指定してます。

    このエントリーをはてなブックマークに追加

公式ドキュメントをやっていて、また旨く動かないところがありました。
Doctrine_Record::mapValueですが、データベースに保存したくないが、オブジェクトに保持しておきたい値をもたせることが出来るように書いてあります。


class User extends Doctrine_Record
{
public function setTableDefinition()
{
// ...
//nameというカラムはありません
$this->mapValue('name');
}

// ...
}

$user = new User();

$user->name = 'jwage';
echo $user->name; // jwage
で、サンプルコードを実行してみたのですが

Unknown record property / related component "name" on "User"
エラーが出て実行できませんでした。色々試してみたところ

class User extends BaseUser
{
public function construct()
{
$this->mapValue('name');
}
と、constructでmapValueしたら動きました。詳しく追ってませんがタイミングの問題ではないかと思います。constructは__construct()の最後で呼ばれる親クラスでは空のメソッドです。

    このエントリーをはてなブックマークに追加

propelは、特にCriteriaがどうも好きになれなかったのですがDoctrineは良さそうなので、とりあえず、単体で使ってみれば理解の助けになるかなあ、といじってみてます。

本家のチュートリアルをやっていてエラーが出て旨く動かないところがありました。


Doctrine::loadModels('models');
モデルをロードして

$user = new User();
$user->username = 'jwage';
$user->password = 'changeme';

echo $user->password; // outputs md5 hash and not changeme
実行したところ

Fatal error: Class 'BaseUser' not found in /home/sites/doctrine.gomo.jp/web/models/User.php on line 13
Baseクラスの読み込みに失敗しました。動かすには

$manager->setAttribute(Doctrine::ATTR_MODEL_LOADING, Doctrine::MODEL_LOADING_CONSERVATIVE);
ATTR_MODEL_LOADINGをMODEL_LOADING_CONSERVATIVEに設定してやると動くようになります。デフォルトではMODEL_LOADING_AGGRESSIVEになってます。

MODEL_LOADING_CONSERVATIVEはクラス名とそのパスを保持していて、そのクラスが必要な時に読み込まれるいわゆるLasy loadです。その際指定したフォルダにフォルダがあった場合はしたの階層もリスト化します。

対してMODEL_LOADING_AGGRESSIVEはDoctrine::loadModelsで指定したフォルダにあるクラスを一気にrequireします。指定したフォルダの直下のクラスしか読み込まないようです。

流し読みしないで、最初から順を追ってやってればこの問題には引っかからないのですが、このページより前にDoctrine::ATTR_MODEL_LOADINGを切り替える意味について詳細な説明がないので、ざっくり読み飛ばしてました。

    このエントリーをはてなブックマークに追加
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。