アソシエーション「hasOne」

2007/04/25 | cakePHP

少し時間ができたので、cakePHPのリレーション関連のまとめ。
ちなみにデータベースで言うところのリレーション(って言わないのかな?)はcakePHPではアソシエーションという。まず一つ目「hasOne」。
関連付けるモデルはあらかじめそれぞれ作っておく(「主」側のモデルをmodelA、「従」側のモデルをmodelBとする)。ここで「主」側、すなわちmodelAに設定するのがhasOneだ(「従」側つまりmodelBではbelongsToを設定することになる)。
実際の記述方法は以下のようになる。

var $hasOne = array(‘(1) 関連先のモデル名’=>
 array(
  ‘className’=>'(2) 関連先のモデルで使用されているクラス名’,
  ‘conditions’=>'(3) 関連を定義するSQL条件の一部’,
  ‘order’=>'(4) 関連先のデータの並び順’,
  ‘dependent’=>'(5) 関連先データの同時削除’,
  ‘foreignKey’=>'(6) 関連先テーブル側の外部キー’
 )
);

(1)はここでいうmodelBの名前のこと。
(2)は(1)内で定義されているクラス名。
(3)は条件を与えてデータを限定する際に使用する。
(4)は・・・いるのかな?。
(5)は「外部キー」という考え方にふさわしく、「主」側のデータが削除された場合に、それに関連付けられた「従」側のデータも削除するかどうかの設定(trueかfalse)。
(6)はmodelB内でmodelAの主キーをなんという名前のカラムで設定しているかを記述。cakePHPの記法にそって書いていれば省略できる。

メッセージがこなれていないmdb2

2007/04/24 | その他PEAR全般

あいかわらずmdb2のエラーメッセージはこなれていないと思った出来事。
mdb2でプリペアードステートメントを使ってデータをINSERTするプログラムを書いていて、ちょうどINSERTを実行するときにエラーが出る。

$myDB->extended->executeMultiple($prepared,$data);
のコマンド実行時に以下のエラー。

Fatal error: Call to undefined function: execute() in /(ペアへのパス)/pear/PEAR/MDB2/Extended.php on line 644

え?、え?。意味がわからない。
どうしてPEARスクリプト内で関数が定義されていないなんてエラーが出るわけ?。だったらバグじゃん。

ちょっと驚いていろいろあたってみる。ウェブで検索しても該当するようなページが見つからない。もう一度プログラムをじーっくり見てわかったこと。最初に用意したSQL内にスペルミスがあった(カラム名のスペルミス)。

単なるスペルミスなのだから、プリペアードステートメントを使用しないときと同じように「存在しないカラムを指定しているよ」というようなメッセージを出してくれればいいようなものなのに・・・。きっとこれにははまってしまう人も多いと思う。
ほんとエラーメッセージにはなかされることが多い・・・mdb2。

MDB2のプリペアードステートメント記述メモ

2007/04/22 | その他PEAR全般

MDB2でのプリペアードステートメントの記述方法。いつも忘れてしまうのでメモ。事前に接続を確立したオブジェクト(ここでは「$myDB」)を生成しておく。

[1] $data=array(array(‘a’,’b’,’c’),array(‘d’,’e’,’f’));
[2] $myDB->loadModule(‘Extended’, null, false);
[3] $sql=’INSERT INTO tbl_test VALUES (?,?,?);’
[4] $prepared=$myDB->prepare($sql);
[5] $result=$myDB->extended->executeMultiple($prepared,$data);

[1]でデータの準備。データ自体は連想配列ではなくて普通の配列にする。
[2]で拡張モジュールを使用する旨宣言。
[3]でプリペアードステートメント用のSQLを用意。
[4]で、[3]で用意したSQLからプリペアードステートメントのオブジェクト(?)を用意。
[5]で処理を実行。

登録する値を自動でエスケープしてくれるので楽チン。

逆転の発想(データの取り出し方)

2007/04/18 | cakePHP

「hasAndBelongsToMany」。諸問題はあったがなんとか動くことが確認できた。しかし必要なデータを取り出す手法がわからなかった。
ブログの記事とタグの関係を例に出すとする。記事はたくさんあるし、タグもたくさんあり、両者の関係は「多」対「多」で表すことができる。モデルとしては「article(記事)」と「tag(タグ)」の二つを作るとする。
この条件で、特定のタグを持つ記事を抽出しようと試みた。記事を抽出したいのだから、articleモデル内でhasAndBelongsToManyの設定を記述し、articleコントローラでデータを取り出そうと試みた。しかしどのように記述しても記事は全部抽出されてしまう。それぞれの記事には関連するタグが割り付けられているので、特定のタグのあるなしで、どの記事が必要なのか、ということはわかるが、記事が全て抽出されてしまっているため、なんとも不細工な処理だ。
酒を飲みつつ、ふと思いついた。逆の発想、タグからたどればいいじゃない!。タグと記事は多対多で同等の関係にあるわけだから、逆から見ても同様にデータを取得できる。つまり特定のタグに紐付けられた記事を全て抽出できるわけだ。あとはfindメソッドで、特定のタグのみ抽出すれば、これで全て事足りる。目からうろこの処理だった。
お酒もたまにはいいことあるね。

hasAndBelongsToManyは少し厄介

2007/04/17 | cakePHP

リレーションのための「hasAndBelongsToMany」。これは少々厄介だ。かなりトラぶったのでメモしておく。
まずこのリレーションを使おうとすると、使用する環境に注意が必要だ。環境とはすなわち、MySQLのバージョンとcakePHPのバージョンだ。cakePHPのデフォルトの記述方法だとMySQL3.23.58ではエラーが発生する(要はMySQL4で記述せよ、ということ)。
まず状況の説明。最初はMySQL3.23.58とcakePHP1.1.13.4450な環境で動作させようと試みた。しかしどうやってもリレーション先のテーブルのデータを取ってこれない。そこでMySQL5な環境で試してみたが、それでもやっぱり動かない。
ここではたと気づいた、バグがあるのでは・・・。調べてみたら賢者はいました。すばらしい。
http://cl.pocari.org/2007-04-06-2.html

ちなみにうちではcakePHP1.1.13.4450ではエラーは出なかった。それにMySQL5でもうまくいかなかった(これはテスト不足なだけかもしれない)。そこでまずcakePHP1.1.14.4797(執筆時点の最新バージョン)にアップデート(cakePHPのアップデートは簡単で、cakeディレクトリ内のファイルをごっそり入れ替えるだけ)。そうすると出ました、エラーメッセージ。ここで上記サイトに記載があるように、以下のように修正。

cake/libs/model/datasources/dbo_source.phpの1050行目

「’alias’ => $joinAssoc,」の記述があるのでその下に以下の一行を追加。
「’type’ => ‘INNER’,」

これで見事に解決した。3時間近く悩んだだけに感慨もひとしお。しかし上記ページの作者曰く「上記の修正はあくまで,hasAndBelongsToMany を使いたい場合で,そのほかの項目はあまりテストしていませんのでご注意を.」とのこと。まぁ問題が出たらその都度対応することにしよう。
貴重な情報に感謝。


守谷市(まちの情報ポータル) 無料アンケートレンタルjpForm.net