メッセージ欄
2008年2月の日記
▼ 2008/02/27(水) Semail 1.0.1 にバージョンアップ
日本語ワードラップの処理がおかしかったので修正いたしました。
文字列が指定の文字数にならなかったり、文字列が短い場合に不要な改行が入ってたのを修正しました。
興味ある方はこちらより。
CakePHPの日本語高機能メールコンポーネントSemail
文字列が指定の文字数にならなかったり、文字列が短い場合に不要な改行が入ってたのを修正しました。
興味ある方はこちらより。
CakePHPの日本語高機能メールコンポーネントSemail
▼ コメント(0件)
▼ 2008/02/24(日) VALID_NOT_EMPTYの思わぬ動作。CakePHP1.2bバリデーション
CakePHP1.2は1.1に比べて、バリデーション(varidation,varidate)の大幅な機能強化が図られている。
ここでは、NOT EMPTY についてはまった点があったので覚書として書いておきます。
1.2bの話であって、1.1については知りません。
ここでは、NOT EMPTY についてはまった点があったので覚書として書いておきます。
1.2bの話であって、1.1については知りません。
▼ 2008/02/23(土) issetを正しく理解する。null値とunsetの違い-PHP変数管理
nullほど人を惑わすものはないだろう。設定されてない値ってなんだ?
unsetされた変数とは違うの?
様々な疑問があろう。
ここで、明確な理解をしておきたい。(PHPの場合)
なお、ここで以下の質問に理由とともに答えられる人は読む必要のない記事です。
unsetされた変数とは違うの?
様々な疑問があろう。
ここで、明確な理解をしておきたい。(PHPの場合)
なお、ここで以下の質問に理由とともに答えられる人は読む必要のない記事です。
! isset ( $a ) と is_null ( $a ) 等価である。 × or ○
-
▼
[php]phpでNotice Errorの Undefined index等が多発してうざい場合はこれで解決
Kemworld::DiaryphpでNotice Errorの Undefined index等が多発してうざい場合は(エラーレベル落とせいいというのは置いておいて)、 $a = null; という感じで変数を初期化しておくといいかもしれない。issetで条件分岐してる場合はやっか...
▼ 2008/02/20(水) CakePHPの日本語高機能メールコンポーネントSemail
Semail Componentとは
現在はもっと高機能なQdmailがありますのでよかったら、Qdmailの方をお使い下さい。日本語メール&CakePHPのためのメールコンポーネントです。
Semailは更新停止しています。
CakePHP1.2のEmailComponentは、それなりに高機能だけど、やはりマルチバイト(日本語)に若干弱い。なので、日本人のためのEmailComponent(改)として、 SemailComponentを作ってみた。日本語機能の強化だけでなく、簡単に添付ファイルを送れるなど若干の機能向上も図っている。ただし、もともとのEmailComponentがなければ、ここまでのものはできませんでした。オリジナル制作者の方々に敬意を表します。
ただし私の職業をみればわかるように、ITの専門家ではありません。
あくまでも人柱として覚悟のある方がご利用ください。Spokの頭文字をつけさせていただきました。
- (2008/2/27 バージョン1.0.1に上がりました)
- (2008/3/10 バージョン1.0.2に上がりました)
- (2008/3/19 バージョン1.0.3に上がりました)
参照Semail ver1.0.3にバージョンアップ
特徴
- 初心者には簡単に、上級者には複雑な設定も可能な構成
- CakePHP1.2のEmailComponentの改造版なので、基礎的信頼性抜群!(笑)
なので、基本的な使い方はCakePHP1.2EmailCOmponentと同じです。
- to,cc,bccに日本語の宛先使用可能。エンコードの複雑な設定不要。
- cc,bccはもちろん、to にも、複数人を日本語で指定可能
- コーディング文字コードに係わらず動作可能(のはず)
- 文字化けが最小のデフォルト設定
iso-2022-jpがデフォルト
- utf-8,SJIS,その他任意の文字コードのメールを作成可能こちら
- 本文のbase64エンコード対応こちら
- ヘッダーと本文のエンコード分離可能こちら
- htmlメールをCakePHPのView機能で簡単に作成可能
(これはCakePHP1.2EmailComponentの機能です)
- 添付ファイルも簡単に添付可能
- 日本語の添付ファイル名が簡単に作成可能
- 文字列変数をファイルに落とさなくてもそのまま日本語ファイル名で、簡単添付可能
- 添付ファイル名エンコードは、通常のmime方式 と RFC2231 の両方式に対応こちら
- mail関数、smtp送信のどちらもできます。
(これはEmailComponentの機能)
ダウンロード
は下の方にあります。必要なもの
マルチバイト関数 mb_ が使える必要があります。設置方法
ダウンロードしたファイルを解凍して app/controllers/components/ フォルダにコピーしてください。それだけ。
初期設定
使いたいコントローラーで、var $components=array( 'Semail' );
これだけ。
使い方
最も簡単な使い方(初心者向け)
$this->Semail->to[ 'ほげほげさま(日本語OK)' ] = 'hogehoge@example.com' ; $this->Semail->from[ 'スポック(日本語OK)' ] = 'watasi@example.com' ; $this->Semail->subject="日本語の長い長いタイトルもOKですよ~"; $this->Semail->send( 'メールの中身だよ~ん');コーディングの文字コードに係わらず、デフォルトでは強制的に iso-2022-jp に変換して送付します。
(iso-2022-jpは日本語で問題が最も起こりにくい方法です。私が受け取るメールの90%以上は、iso-2022-jpエンコードです。)
もちろん
$this->Semail->to = array( 'ほげほげさま(日本語OK)' => 'hogehoge@example.com' );というような形式でもOKです。
ccやbccは、
$this->Semail->cc = array( 'ほげほげさま(日本語OK)' => 'hogehoge@example.com' ); $this->Semail->bcc = array( 'ほげほげさま(日本語OK)' => 'hogehoge@example.com' );とするだけ。配列でいくらでも追加してください。
toも、いくらでも追加できます。
replyToも
$this->Semail->replyTo['返信先']=''hensin@examaple.com;
で指定できます。
(エラーメールのリターン先 は、$this->Semail->return )
from,replyTo
from,replyToで、メールアドレスだけでいい場合は配列でなく、以下の形式で指定しても大丈夫です。$this->Semail->from="hoge@example.com";
制限事項( to , cc , bcc )
array('名前'=>''メールアドレス) このような指定方式なので、同姓同名の人がいると、前の人のキーが上書きされるので、その人にはメールが送られないことになります。ご注意ください。―――>その場合は、
array( '日本語名前' . '<' . 'hoge@example' . '>' , ・・・・・・・);という形式にすれば、同姓同名でも大丈夫です。
(この形式がCakePHP EmailComponentの本来のデフォルト)
機種依存文字を送りたい
本来は使うべきでない機種依存文字ですが、どうしても送りたいときもあることでしょう。丸数字①②とか(株)とか。
それはSemailで機種依存文字を送るをご参照下さい。
どうも、うまく文字コード変換していないような気がするとき。
Semailで、どうもうまく文字コード変換をしない時の対処法を試してみて下さい。view , Layout 機能の使い方
テキストメールのview 、htmlメール用のview はそれぞれ以下に置いて下さい。view/elements/email/text/hoge_view.ctpLayoutは、それぞれ
view/elements/email/html/hoge_view.ctp
view/layouts/email/text/hoge_layout.ctpに置いて下さい。
view/layouts/email/html/hoge_layout.ctp
「email」の部分は変更することができます。
$this->Semail->spok_view_dir='hoge';
$this->Semail->spok_layout_dir='hoge';
文字コードは何でもいいです。Semailが自動的に判別して、指定の文字コードに置き換えます。
公式Cake1.2 EmailComponentのview , layout が参考になるでしょう。
htmlメールで、view,layout を使う場合
$this->Semail->sendAs='html';((htmlは必ず小文字で指定)) $this->Semail->to[ 'ほげほげさま(日本語OK)' ] = 'hogehoge@example.com' ; $this->Semail->from[ 'スポック(日本語OK)' ] = 'watasi@example.com' ; $this->Semail->send( 'メールの中身だよ~ん' , 'hoge_view.ctp' ,'hoge_layout.ctp');
テキストメールで、view lyaout 機能を使いたい時は
$this->Semail->sendAs='text';
とするだけです。
なお、もともとの EmailComponent の機能ですが、
$this->Semail->sendAs='both';
とすると、マルチパート(1通のメール)で、htmlメールとテキストメールを送ることができます。
(もちろん、view layoutは使い分けることができる)
添付ファイルの送り方 その1 (通常モード)
もっとも簡単な送り方
添付ファイルの置き場所app/attachments/
(フォルダを作って下さい。変更することもできます。)
$attach=array( '添付ファイル名(日本語OK)' => 'filename(サーバー上のファイル名)' ); $this->Semail->send( 'メール本文' , NULL , NULL , $attach );(toの設定などは省略しています。もちろん、view layoutの指定可能です。)
添付ファイルは、いくつでも(とはいえ常識的に)指定することができます。
添付ファイルの置き場所は
$this->Semail->filePaths=array('paths','paths','paths','paths',・・・・);
とサーチ用のパスの設定をすることで変更することができます。
相対パスを指定すると、webrootからの相対パスになります。
添付ファイルの送り方 その2 (ダイレクトモード)
変数の中身をそのまま添付ファイルとして送ることが出来ます。例えば、csvファイルをプログラムで加工したときなどは、これまではいったんディスクに書き込む必要がありましたが、writeしなくても、そのまま添付ファイルとして送ることができます。
画像でもエクセルファイルでもワードでもPDFでも何でも大丈夫(のはず)。
$content = "送りたいファイルの中身データ"; $pre=$this->Semail->directPrefix(); $attach=array( $pre.'添付ファイル名(日本語OK)' => $content ); $this->Semail->send( 'メール本文' , NULL , NULL , $attach );添付ファイルはいくつでも指定でき、それぞれについて、通常モードとダイレクトモードを選択することができます。つまり、その1の通常モードと混ぜることができます。
例えば、
unset($attach); $pre=$this->Semail->directPrefix(); $attach[$pre.'添付ファイル名1(日本語OK)'] = "送りたいファイルの中身データ1"; $attach[$pre.'添付ファイル名2(日本語OK)'] = "送りたいファイルの中身データ2"; $attach['添付ファイル名3(日本語OK)'] = 'filename(ディスク上のファイル名)3' ; $this->Semail->send( 'メール本文' , NULL , NULL , $attach );なお、$this->Semail->directPrefix() は、実行するごとに異なる prefix を返しますので、何度も実行させてはいけません。
これはmd5で、通常はあり得ないファイル名を作り出して、それをプリフィックスとして持っているファイルは、ダイレクトモード、というロジックで判定しています。
つまり、以下のようにしてしまうとエラーになります。
unset($attach); $attach[$this->Semail->directPrefix().'添付ファイル名1(日本語OK)'] = "送りたいファイルの中身データ1"; $attach[$this->Semail->directPrefix().'添付ファイル名2(日本語OK)'] = "送りたいファイルの中身データ2"; $attach['添付ファイル名3(日本語OK)'] = 'filename(ディスク上のファイル名)3' ; $this->Semail->send( 'メール本文' , NULL , NULL , $attach );なお、$this->Semail->directPrefix()のデフォルト値は、「_spokDirect_」なので、
$this->Semail->directPrefix()を呼び出さなくても
unset($attach); $attach['_spokDirect_'.'添付ファイル名1(日本語OK)'] = "送りたいファイルの中身データ1"; $attach['_spokDirect_'.'添付ファイル名2(日本語OK)'] = "送りたいファイルの中身データ2"; $attach['添付ファイル名3(日本語OK)'] = 'filename(ディスク上のファイル名)3' ; $this->Semail->send( 'メール本文' , NULL , NULL , $attach );でも、正常動作します。
ダウンロード
ご指摘があり修正しました。修正箇所:日本語ワードラップでエンコードミス&行が短い場合の処理ミス
rks様、ありがとうございました。というわけでバーション 1.0.1 にあがりました!
(というか前はバージョンさえつけてなかったのだけど。不慣れですいません。というか一番肝心なところミスっていたのに気づかなくてすいません。)
最新バージョン
semail1.0.2.zip
Semail ver1.0.2にバージョンアップに追加の使い方も掲載しています。
これは古いやつ。
semail1.0.1.zip
semail.zip
ちょいとうれしい
参考にしてくれた人がいらっしゃったようです。第2回 CakePHP 勉強会に参加してきた
-
▼
Semail機種依存文字について
CPA-LABテクニカル 機種依存文字についてのメールは難しい。できることなら、使わないのがいいのだけど、どうしても使いたい場合の覚書。CakePHPの日本語メールコンポーネントが大前提。■機種依存文字をメールで送るsjis-win で送る (sjis では×)PCであれば、安心で...
-
▼
Semailでのutf-8,SHIFT-JISメールの送り方
CPA-LABテクニカル Semailはデフォルトでは、iso-2022-jpですが、UTF-8、SJISのメールも送ることが出来ます。CakePHPの日本語メールコンポーネントのお話。 もっとも簡単な送り方utf-8の場合$this->Semail->charset=...
-
▼
Semailで、どうもうまく文字コード変換をしない時の対処法
CPA-LABテクニカル CakePHPの日本語高機能メールコンポーネントSemailでは、まず受け取った文字列の文字コードを自動判別して、ターゲットの文字コードにエンコードします。使っているのは、 mb_detect_encoding関数です。しかし、PHPの設定によっては、自動...
-
▼
Semail 1.0.1 にバージョンアップ
CPA-LABテクニカル 日本語ワードラップの処理がおかしかったので修正いたしました。文字列が指定の文字数にならなかったり、文字列が短い場合に不要な改行が入ってたのを修正しました。興味ある方はこちらより。CakePHPの日本語高機能メールコンポーネントSemail
-
▼
Semailでの添付ファイルで、「別に日本語の添付ファイル名いらないんだけど」の設定
CPA-LABテクニカル CakePHP1.2用高機能メールコンポーネント Semail では、日本語の添付ファイル名を簡単につけることができます。が、改造前のEmailコンポーネントのように、(日本語でなくアルファベットで) 保存ファイル名でそのまま送りたい場合は、次の2つの方法...
-
▼
Semailバージョンアップ1.0.2.b(CakePHP日本語高機能メールコンポーネント)
CPA-LABテクニカル CakePHP用高機能メールコンポーネントSemailのバージョンアップです。ご指摘のあった添付フィルの Content-Typeヘッダ(mimeタイプ)周辺を整備したほか、いくつかの改良をしています。基本的な使い方は、CakePHP用高機能メールコンポー...
-
▼
PHPで簡単にメールを送りたいだけなのに。
CPA-LABテクニカル ユーザーからのアクションをきっかけにちょっとしたメールを送りたいことがある。それは、ユーザー登録の認証だったり、サンクスメールだったり、確認メールだったり。しかし、PHPの mb_send_mail は、toヘッダへの日本語がうまく通らなかったり(上手にや...
-
▼
PHP日本語高機能メールライブラリ-Qdmail-デコメ対応
CPA-LABテクニカル ■QdmailとはQdmailとは、PHPのマルチバイト環境(特に日本語)にて、簡単に"デコメ"やHTMLメール等の電子メールを送ることができるメールクラスライブラリです。「初心者には簡単に、上級者には多彩に」のポリシーのもとに開発しました。設定次第では、...
-
▼
CakePHP高機能メールコンポーネント-Qdmail
CPA-LABテクニカル QdmailをCakePHP対応にしてみました。特徴 CakePHP1.1 & 1.2 の両方に対応 ひとつのファイルで、通常の使い方もCakePHPのコンポーネントとしても動作可能 CakePHPのビュー機構を利用可能 CakePHP1.2デフォルトのe...
▼ 2008/02/19(火) Semaiで、添付ファイル名の日本語をRFC2231に準拠させる
最大のシェアを持つ、マイクロソフトのOutlookExpressは、RFC2231になかなか対応しないため、本来のインターネット上のデフォルトであるRFC2231はなかなか普及していないようです。
なので、Semailも、互換性を重視し、通常のmimeエンコードで日本語添付ファイル名を作っています。
でもきっと将来は、RFC2231に統一されると思いますので、今のうちに対応させておきました。
デフォルトでは false になっています。
でも、現状でこれで送ると文字化けするメールクライアントもあるかもしれません。
でもそれは、そのメーラーさんが悪いのです。。。。
なので、Semailも、互換性を重視し、通常のmimeエンコードで日本語添付ファイル名を作っています。
でもきっと将来は、RFC2231に統一されると思いますので、今のうちに対応させておきました。
$this->Semail->spok_attach_filename_rfc2231=true;これだけです。
デフォルトでは false になっています。
でも、現状でこれで送ると文字化けするメールクライアントもあるかもしれません。
でもそれは、そのメーラーさんが悪いのです。。。。
▼ 2008/02/19(火) Semailで、どうもうまく文字コード変換をしない時の対処法
CakePHPの日本語高機能メールコンポーネントSemailでは、まず受け取った文字列の文字コードを自動判別して、ターゲットの文字コードにエンコードします。
使っているのは、 mb_detect_encoding関数です。
しかし、PHPの設定によっては、自動判別がうまくいかないことがあるかもしれません。
その時は以下の方法をとってみてください。
php.initをいじれない方は、
私は、上記の順番が一番誤りが少ないのですが、もっといい順番があれば、ぜひ教えて下さい。
使っているのは、 mb_detect_encoding関数です。
しかし、PHPの設定によっては、自動判別がうまくいかないことがあるかもしれません。
その時は以下の方法をとってみてください。
php.ini の修正
mbstring.detect_order = eucJP-win,UTF-8,SJIS-win,jisとすると幸せになれるかも知れません。
php.initをいじれない方は、
mb_detect_order関数の使用
mb_detect_order("eucJP-win,UTF-8,SJIS-win,jis");
として、detectの順番を変えてみて下さい。私は、上記の順番が一番誤りが少ないのですが、もっといい順番があれば、ぜひ教えて下さい。
-
▼
Semailバージョンアップ1.0.2.b(CakePHP日本語高機能メールコンポーネント)
CPA-LABテクニカル CakePHP用高機能メールコンポーネントSemailのバージョンアップです。ご指摘のあった添付フィルの Content-Typeヘッダ(mimeタイプ)周辺を整備したほか、いくつかの改良をしています。基本的な使い方は、CakePHP用高機能メールコンポー...
▼ 2008/02/19(火) Semailでのutf-8,SHIFT-JISメールの送り方
Semailはデフォルトでは、iso-2022-jpですが、UTF-8、SJISのメールも送ることが出来ます。
CakePHPの日本語メールコンポーネントのお話。
以上です。
まず、その一致を解くキーは、
なお、デフォルトは
$this->Semail->spok_content_encoding = '7bit';
です。
あと考えられる指定は、
$this->Semail->spok_content_encoding = '8bit';
ですが、こうすることはあまりないでしょう。
CakePHPの日本語メールコンポーネントのお話。
もっとも簡単な送り方
utf-8の場合
$this->Semail->charset='utf-8';とするだけ。
SJISの場合
$this->Semail->charset='sjis';とするだけ。
以上です。
ヘッダーの文字コードと本文の文字コードを別にしたい。
Semailは初心者でも簡単に使えるように、デフォルトでは、ヘッダーと本文の文字コードは一致させています。まず、その一致を解くキーは、
$this->Semail->spok_default=false;その上で、
$this->Semail->charset='sjis'; // ヘッダーのcharset $this->Semail->spok_content_charset='utf-8'; // 本文のcharsetとなります。
本文をbase64エンコードしたい
$this->Semail->spok_content_encoding = 'base64'; //すべて小文字で指定$this->Semail->spok_defaultの値には関係しません。
なお、デフォルトは
あと考えられる指定は、
▼ 2008/02/19(火) Semail機種依存文字について
■機種依存文字をメールで送る
sjis-win で送る (sjis では×)
PCであれば、安心でしょう。対応しているメーラーも多いと思う。携帯メールでは。。。au では本文は大丈夫でした。他は実機がないのでわかりません。
しかし、auでは、ヘッダーがsjis-winだと文字化けします。
なので、ヘッダーは、iso-2022-jp 本文はsjis本文base64という形で送る必要があるでしょう。
機種依存文字を送る場合の一番のオススメ
| ヘッダー | 本文 |
| iso-2022-jp | sjis-win + base64 |
つまり
$this->Semail->spok_default=false; $this->Semail->charset='iso-2022-jp'; // ヘッダーのcharset $this->Semail->spok_content_charset='sjis-win'; // 本文のcharset $this->Semail->spok_content_encoding="base64";//本文のbase64となります。
UTF-8 + 本文base64 で送る
PCであれば、もっとも安心でしょう。対応しているメーラーも多いと思う。| ヘッダー | 本文 |
| utf-8 | utf-8 + base64 |
$this->Semail->charset='utf-8'; // ヘッダーと本文のcharset同時指定 $this->Semail->spok_content_encoding="base64";//本文のbase64utf-8なら、Macとwindows間も問題ない(はず。Mac持っていないので)
しかし、携帯メールでは。。。。少なくともauではダメのよう。
eucJP-win
PCでは大丈夫ですが、auでは全然ダメでした。iso-2022-jp
もちろんダメでした。でも機種依存文字はダメですが、auではそれ以外の文字はちゃんと表示されるので、UTF-8やeucJP^winよりはいいでしょう。ただし、このページでは、機種依存文字についての話なので、その点ではダメなのは同じです。留意点
以上は、すべてSemailコンポーネントの話であり、他の一般のメーラーで実現可能かどうかはわかりませんのでご注意を。▼ 2008/02/17(日) CakePHP1.2をSQLite3で動かしてみた。&ダウンロード
dbo_sqlite3_spok とは
CakePHP1.2b用 SQLite3データベースオブジェクトです。CakePHPでは、SQLiteは、バージョン2までしか対応していませんが、PHP5の機能(PDO)を使って対応させてみました。私はSQLite2でなく、SQLite3が好きなので。。。
以前はSQLite2で動いていたサイトをCakePHPでSQLite3を対応させてみました。
本を買う前にこの書評を読め!
PaginatorでPaginateしてみた。
は、CakePHP version 1.2.0.6311 beta, SQLite 3 で動いています。(最近レンタルサーバーが重いことが多いので、ご容赦を。CakePHPやSQLiteが重いのでなくてサーバー自体の問題です。)
サイトがしょぼいのどうのはともかく、一応、まともに動いています。
私はこれまでに、CakePHPがSQLite3に対応しにくい理由と偉そうなことを書いたり、SQLite2より3の方が断然いい理由やSQLiteを使うべき10の理由と5つのデメリットと、SQLiteマンセーの記事を書いたりしてきたけど、やっぱり自分でやってみたくなってやってみた、ということです。
CakePHPはMITライセンスとのことなので、改造、再配布は問題ないと思うのだけれど。。。
注意
PHP5限定です。PHP4では動きません。(そうかこれがSQLite3にCakePHPが正式対応しない理由かもね)
数少ない状況でしかテストしておりません。複雑なクエリのテストはしておりません。
人柱として理解のある方のみお試し下さい。
制限事項 (追記の追記)
「*」については、すべてのフィールド名を展開してSELECT文を発行することで対処しました。
その他、ご自分で独自SQL文を発行している方については不具合がでるかもしれません。
複雑なSQLは、私自身思いつかないので、テストにも限界があるのが実情です。
うまく動かすコツは、取得するフィールド名については、フィールド名だけでなく、必ずモデル名も指定しておけばいいと思います。
つまり
SELECT id,content FROM ....ではなく
SELECT Hoge.id,Hoge.content FROM ....ということです。
del:また、テーブルをジョインするときは、大文字で「JOIN」として
......JOIN hoge_model_name as "HogeModelName"と、CakePHPが自動作成するSQL文に準じた形で書いていただくとうまくいくかと思います。
ポイントは、「JOIN」は大文字、実テーブル名の後のモデル名(エイリアス)は、”(ダブルクオーテーション)で囲む。
バージョン1.0.5bで対応しました。
とにかく
SELECT Hoge.id,Hoge.content FROM ....を守っていれば、かなり大丈夫と思います。
ダウンロード
1 下記zipファイルをダウンロード- 最新バージョン
(1.07にバージョンアップしました。フィールド名に「name」が使われているとエラーがでる現象に対処しました。)
以前のバージョン
SQLite3_spok1.0.6beta.ZIP
(1.0.6にバージョンアップしました。LEFT JOIN などという形のJOIN形式にも対応しました。以前は、取得フィールド* で JOIN句を使うとエラーでした。)
(1.0.5Bにバージョンアップしました。独自sqlで、JOINするときにカンマ区切りでも大丈夫なようにしてみました。また複雑な副問い合わせの場合にも対処しました(つもり)。その他マッピングの不具合を修正。)
SQLite3_spok1.0.5beta.ZIP
(1.0.4bにバージョンアップしました。独自SQLをfunciton query( 'SELECT .......' );と発行した場合に対処しました。
SQLite3_spok1.0.4beta.ZIP
以前のバージョン
(1.03bにバージョンアップしました。取得フィールドが、「*」 の時にテーブル名(モデル名)が、ゼロになってしまっていたのを修正しました。
SQLite3_spok1.0.3beta.ZIP
以前のバージョン
(1.0.2bにバージョンアップしました。一部、insertでエラーが出たのを修正。アソシエーションで同じフィールド名を持っている場合のマッピングの不具合修正。)
SQLite3_spok1.0.2beta.ZIP
2 解凍した2つのファイルを以下にコピー
- dbo_sqlite3_spok.php は、 app/models/datasources/dbo/ にコピー
- dbo_source.php は、app/models/datasources/ にコピー
3 現在のキャッシュをすべて消去 (意外に重要)
4 config/database.phpの中身の例
var $default = array(
'driver' => 'sqlite3_spok',
'connect' => 'PDO',
'host' => '',
'port' => '',
'login' => '',
'password' => '',
'database' => "sqlite:/home/hoge/hogehoge/filename.sqlite3",
'schema' => '',
'prefix' => '',
'encoding' => ''
);
config の注意点
'database' の sqlite:/home/hoge/hogehoge/name.sqlite3と、「sqlite:」を最初につけるのを忘れないでください。PDOの仕様です。ちなみに、「sqlite2:」とすると、SQLite2にも繋げられます。
ウィンドウズ(Windows)の場合は、「sqlite:c:¥hoge¥hogehoge¥filename.sqlite3」のようになります*1。
ファイル名は、なんだって大丈夫。拡張子はsqlite3である必要もないし、拡張子なしでも大丈夫。
'login' => '','password' => '',は、例のように'' か null に設定してください。
留意点
PDOやSQLite3の特性を生かし切ったコードにはなっていません。SQLite2用のコードを流用させていただいたので、あくまでも、とりあえず動くようにしたレベルです。
不具合?
- 不具合などあれば、ご報告しただければ直せるかも知れないし、直せないかも知れません。
- 考えられる不具合
- カラム名の大文字小文字でトラブルがあり得るかも。
- CakePHPでSQLite3を使う(覚書編) のようなやり方なので、ダブルクオーテーションや、ドットが通常ではない形式でフィールド名にまざると誤動作するかもしれません。
- テーブル名を事前マッピングします。as 句 を使った場合に意図しないテーブル名(モデル名)にデータがセットされるかも知れません。(そうならないように工夫したつもりですが)
SQLiteの管理ツール
SQLite管理ツールをご参考に。
*1 : ¥は半角
-
▼
CakePHPでSQLite3を使う(覚書編)
CPA-LABテクニカル CakePHP1.2で、SQLite2を動かすには、CakePHP1.2をSQLite3で動かしてみた。&ダウンロードをご覧下さい。これは自分のための覚書。背景CakePHPでは、データベースからのfetchでarray( 'テーブル名.フィールド名'...
▼ 2008/02/16(土) フィールドのデフォルト値をセットする。CakePHP1.2
CakePHP1.2bでは、以下の方法で、データベースで設定したデフォルト値を、配列として取得することができる。また、引数を指定することで、そのデフォルト値を書き換えることができる。
CakePHP1.1にはなかった機能。1.2にバージョンアップすると、こんなメリットもあるよ、ということで覚書。
データベースのデフォルト値をセット
(CakePHP1.1では、このメンバ関数は、デフォルト値を返すのでなく、すべて unset していた。)
デフォルト値の書き換え
一時的にデフォルト値を変更する場合に使えよう。
CakePHP1.1にはなかった機能。1.2にバージョンアップすると、こんなメリットもあるよ、ということで覚書。
データベースのデフォルト値をセット
$this->モデル名->create() //返り値 array ( 'フィールド名' => 'デフォルト値' )
(CakePHP1.1では、このメンバ関数は、デフォルト値を返すのでなく、すべて unset していた。)
デフォルト値の書き換え
$data = array( 'フィールド名' => '値' ); $this->モデル名->create($data);ただし、CakePHPの内部値としてのデフォルト値であり、データベースのデフォルト値を書き換えるものはない。
一時的にデフォルト値を変更する場合に使えよう。
▼ 2008/02/15(金) CakePHPでSQLite3を使う(覚書編)
CakePHP1.2で、SQLite3を動かすには、CakePHP1.2をSQLite3で動かしてみた。&ダウンロードをご覧下さい。
これは自分のための覚書。
array( 'テーブル名.フィールド名' => value )
という形を期待して、結果をfetchしている。
しかし、PHP5のPDOのSQLite3用のデバイスは、テーブル名を省略して、結果を返してくる。テーブル名が上記の形になるのは、複数のテーブルを連結した場合&取得するフィールド名が、重なった場合だけである。
(テーブル名を常につけるオプションは、現段階ではサポートされていない)
CakePHPは、この結果から、 $find で返す配列に
array ( 'テーブル名(正しくはモデル名)' => value )
とセットしている。
これをPDO,SQLite3でも実現するため、SELECT文を発行する時に、テーブル名とカラム名の組み合わせを覚えておき、結果セット取得時に、それと照合する、というやり方にする。
幸い、CakePHPは、ユーザーがテーブル名を省略して、取得フィールドを設定しても、必ず、
という形にするので、それを横取りして、この組み合わせをメンバ変数に覚えておかせることにした。
$spok_map_table,$spok_map_col
そして、フィールド名は次のようにしておく。
ただし、問題となるのは、ユーザーが as によって別名をつけた場合や、max( field ) などとした場合である。
この点は、 as があったら、as 以降を カラム名として扱うこととした。
関数を使った場合は、テーブル名を ゼロ とした。
(たぶん、他のDBOも、この仕様になっているはず)
事前に横取りして、テーブル名とカラム名の組み合わせを覚えておくのは
dbo_source.php の function renderStatement の select文発行のところ。
そこに、 $this->spok_sqlite3_maps($data['fields']) と、return直前に、横取りした。
function spok_sqlite3_maps($fields) は、同じファイルの最後に追加した。
sqlite固有の関数は、すべてPDO用に置き換えた。(たぶん問題ないと思う)
function resultSet は、そもそもその結果を使っていなかったので、すぐにreturnするようにしておいた。
function fetchResult() において、事前マッピングしたものを、ここで利用した。
ダブルクオーテーションを抜くことを忘れずに。
実現するには
これは自分のための覚書。
背景
CakePHPでは、データベースからのfetchでarray( 'テーブル名.フィールド名' => value )
という形を期待して、結果をfetchしている。
しかし、PHP5のPDOのSQLite3用のデバイスは、テーブル名を省略して、結果を返してくる。テーブル名が上記の形になるのは、複数のテーブルを連結した場合&取得するフィールド名が、重なった場合だけである。
(テーブル名を常につけるオプションは、現段階ではサポートされていない)
CakePHPは、この結果から、 $find で返す配列に
array ( 'テーブル名(正しくはモデル名)' => value )
とセットしている。
実現方法
これをPDO,SQLite3でも実現するため、SELECT文を発行する時に、テーブル名とカラム名の組み合わせを覚えておき、結果セット取得時に、それと照合する、というやり方にする。
幸い、CakePHPは、ユーザーがテーブル名を省略して、取得フィールドを設定しても、必ず、
”テーブル名(モデル名)”.”フィールド名”
という形にするので、それを横取りして、この組み合わせをメンバ変数に覚えておかせることにした。
$spok_map_table,$spok_map_col
そして、フィールド名は次のようにしておく。
”テーブル名(モデル名)”.”フィールド名” as ”テーブル名(モデル名).フィールド名”(微妙な違いがわかりますでしょうか)
ただし、問題となるのは、ユーザーが as によって別名をつけた場合や、max( field ) などとした場合である。
この点は、 as があったら、as 以降を カラム名として扱うこととした。
関数を使った場合は、テーブル名を ゼロ とした。
(たぶん、他のDBOも、この仕様になっているはず)
事前の横取りマッピング
事前に横取りして、テーブル名とカラム名の組み合わせを覚えておくのは
dbo_source.php の function renderStatement の select文発行のところ。
そこに、 $this->spok_sqlite3_maps($data['fields']) と、return直前に、横取りした。
function spok_sqlite3_maps($fields) は、同じファイルの最後に追加した。
事後のマッピング利用
dbo_sqliteをベースに改造した。sqlite固有の関数は、すべてPDO用に置き換えた。(たぶん問題ないと思う)
function resultSet は、そもそもその結果を使っていなかったので、すぐにreturnするようにしておいた。
function fetchResult() において、事前マッピングしたものを、ここで利用した。
ダブルクオーテーションを抜くことを忘れずに。
データベースconfig
login,paswordは設定しても無駄である。var $default = array( 'driver' => 'sqlite3_spok', 'connect' => 'PDO', 'host' => '', 'port' => '', 'login' => '', 'password' => '', 'database' => 'sqlite:c:\hogehoge\hogehoge\hoge.sqlite3', 'schema' => '', 'prefix' => '', 'encoding' => '' );
「*」 の問題
SELECT * FROM.....となった場合、事前マッピングが不可能になる。実現するには
- *をすべて個別のフィールドに展開してしまう
- フィールドの個数とテーブル名(モデル名)を対応させておく
▼ 2008/02/15(金) recursiveの隠しオプション
ここでは、recursiveが、多くの人が思うような動作にするための隠しオプションをご紹介する。recursive はややこしい。かなりの人が混乱しているように思う。
ただし、お断りしておくと、このオプションは実は隠されているのでなく、複雑なテーブル間連携を別途記述するためのオプションを流用する、というだけの話です。
できれば、recursiveを正しく理解するを読んでいただいたほうがいいかと思います。
本当は違うけど多くのCakePHP初学者が思い込むパラメータ
モデルのアソシエーションの記述に以下のように external を付け加えてください。
他のオプションを設定している方は、それは消去せず、externalオプションだけを付け加えてください。
ただし、決して、 finderQuery オプションは設定してはなりません。
(例)
すると、recursive=0 の場合、アソシエーションはとってきません。このオプションを設定しない場合の recursive= -1 と同じになります。
もちろん、recursive= 1 にすれば、第1次アソシエーションを取得します。recursive= 2 にすれば、第2次アソシエーションも取得します(以下同様)。
参考事例
'Virtual' associations Options -googleディスカッション-CakePHP もうひとつの例-googleディスカッション
recursiveを正しく理解するの図と比べるといいかと。

すべては、dbo_source.php 内の function read にある。
なんで、こんなことやってんのやろ?と思ったのがすべての始まり。
現実的には、このような方法をとるのでなく、正しくrecursiveを理解するのがよいでしょう。データ構造によっては、なんせ、発行するSQL文の量がはんぱじゃないですから。&本来の使い方じゃないですから。
recursiveの正しい使い方は -> recursiveを正しく理解する
ただし、お断りしておくと、このオプションは実は隠されているのでなく、複雑なテーブル間連携を別途記述するためのオプションを流用する、というだけの話です。
できれば、recursiveを正しく理解するを読んでいただいたほうがいいかと思います。
本当は違うけど多くのCakePHP初学者が思い込むパラメータ
recursiv=0 とすると、アソシエーションしているデータはとってこない。という動作にするにはどうするか。
結論 CakePHP 1.2 ですよ!
まず、結論。モデルのアソシエーションの記述に以下のように external を付け加えてください。
他のオプションを設定している方は、それは消去せず、externalオプションだけを付け加えてください。
ただし、決して、 finderQuery オプションは設定してはなりません。
(例)
class Spok extends AppModel{
var $belongsTo = array( 'Kirk' => array( 'extenrl' => true ));
}
すると、recursive=0 の場合、アソシエーションはとってきません。このオプションを設定しない場合の recursive= -1 と同じになります。
もちろん、recursive= 1 にすれば、第1次アソシエーションを取得します。recursive= 2 にすれば、第2次アソシエーションも取得します(以下同様)。
注意!
- こうすると、単純な hasOne,belongsTo の連携の場合も、複数回のSQL文を発行します。つまり、パフォーマンスは(かなり)悪くなります。
- external = false としても、true と同じ動作をします。このオプションを生かさない場合は、 null または、設定しない、としてください。
- この使い方は、externalオプションの本来の使い方ではありません。将来のバージョンアップ時の互換性についてはわかりません。
参考事例
'Virtual' associations Options -googleディスカッション-CakePHP もうひとつの例-googleディスカッション
図で表すと。。。
クリックすると拡大されます。recursiveを正しく理解するの図と比べるといいかと。
この件のヒント
すべては、dbo_source.php 内の function read にある。
$external = isset($assocData['external']);でした。
なんで、こんなことやってんのやろ?と思ったのがすべての始まり。
現実的には
現実的には、このような方法をとるのでなく、正しくrecursiveを理解するのがよいでしょう。データ構造によっては、なんせ、発行するSQL文の量がはんぱじゃないですから。&本来の使い方じゃないですから。
recursiveの正しい使い方は -> recursiveを正しく理解する
▼ 2008/02/14(木) recursiveの正しい理解CakePHP
CakePHPは、データベースのモデルのテーブル設定において、他のテーブル(モデル)に対してアソシエーション(リレーション、連携)の設定をしておけば、当該カレントテーブルの情報を取得するときに、同時に、アソシエーション設定したデータもとってきてくれる。当該カレントモデルのfindAll,findをするだけで、他の連携をとってくれるありがたい機能です。
同時に、recursive というパラメータがあり、再帰的にこのアソシエーションを追っかけてくれる回数を制御するパラメータなのだけど、WEBで検索をすると、かなり混乱しているように見受けられた。(結果オーライの記事が多い)。
なので、ここで、recursiveを正しく使うための基礎知識を若干述べたいな~。
というか自分が理解するために調べたのを覚書として書いておくということだけど。
まず、結論は、図をみていただくのが一番早い。

結論は図の通りです。
ATTENTTIONの部分を見てください。
ATTENTTION 1 にあるように、hasOneとbelongsToについては、recursive=0 であっても、アソシエーションを追跡します。
hasOne,belongsTo と hasMany は、recursive において異なる挙動をします。
つまり、
「recursive は、アソシエーションの階層を規定するものである」
という理解は間違っていることがわかります。
それが言えるのは、recursive が2以上の時であって、-1 ~ 1 の間は、特別に考えなくてはなりません。
しかし多くの人が間違えて理解しているようです。私自身も最初の頃は、ATTENTTION 1 → ATTENTTION 2 の位置にあるように思っており、大変とまどいました。
おそらくcakePHPのデータ構造に合わせるために、このような仕様にしたのだとは思うのですが、かなり戸惑いますよね。
実は、英語のマニュアルにも(例)が書かれています。
若干誤解を生みそうな説明文にとれますが、私が英語に弱いため、正確なところはわかりません。ただ、上記の例は参考になるでしょう。
また、以下のサイトのように recursiv=0 には意味がない!ということにする理解もいいかも知れません。
アソシエーションさせたくない場合の設定方法
なんせ、CakePHP1.2のデフォルトも $this->recursive = 1 ですから。
ソースを読むとわかるのですが、hasOneとbelongsToについては、SQL文にて LEFT JOINして、一度のSQL文の発行で、データを取ってきます。
hasManyとhasAndBelongsToManyについては、一度、カレントテーブルだけのSQL文を発行し、その結果の プライマリーキーを 次の 「in句」 に使用しています。つまり2回のSQL文を発行しています。
このことから、CakePHPは、いわゆる「副問い合わせ(サブクエリー)」については、(自動アソシエーションについては)サポートしていない、と理解できます。たぶんそれは、様々なデータベースに合わせるために仕方がないのでしょう(副問い合わせをサポートしていないデータベースもあるため)。
(追記)これも想像ですが、サポートしていないDBあるというよりも、たぶん、副問い合わせにすると、途中経過のテーブルの情報を抜き出しにくい、ということもあるのかなと思いました。
recursiveがどうしてこのような仕様になったのかは、私にはわかりません。多くの人が単純に考えるように 「recursive=0 で、単体テーブルだけが取得可能」 という仕様のほうが理解しやすいとは思うのですが。。。。。
確かに recursive=0 で、hasOneとbelongsTo を取得するのは、CakePHPの内部プログラムの処理としては、再帰的処理をせず、LEFT JOIN するだけなので、内部的な処理の仕方からの仕様となっていると思います。
内部的にはrecursive変数は、いったん、execute した結果のプライマリーキーを利用して、再帰的に、次のSQL文を作成する、というパラメータになっているのです。hasOne,belongsToは、最初のSQL文で、目的を達成してしまうので、recursive=0でも動作するようになっています。
別の理由として考えられるのは、hasOneとbelongsTo だけの追跡をしたい時には、recursive=0 を使えるということかも知れません。
のどれでも実現可能なので、ユーザーからみるとわからないですね。
ユーザー視点でみれば、recursive=0 で、hasOneを取ってくるのは、違和感はありますよね。
ただし、この記事を読んだ方は、recursiveについて理解したと思うので、今後は迷わないですよね。
以上のようなことを想像したのは実は、次のオプションを発見したからでした。
実は、アソシエーションの設定項目の中には、私や皆さんが誤解していたように、recursive=0で、単体テーブルしか取得しない、という動作をするオプションがあります。
recursive の隠しオプション
ただし、単純なhasOne,belongsToでも、再帰的にSQL文を発行しますので、たくさんのクエリーが投げられることとなり、基本的には速度の低下を招きますので、ご留意を。
また、このオプションの本来の使い方ではない方法です。詳しくは、上記記事をご参照ください。
figure 1 の図は、あくまでも
「取得可能なテーブルの範囲」
なので、取得する field名 に 当該subTableのフィールドを指定しない場合は、例え、hasOne,belogsToであっても、recursive=0 では取得できません。
ちゃんとsubTableのフィールド名を指定するか、もしくは、フィールド全部を取得する、という設定でないと自動的には取得できません。
もし、subTableのフィールド名を指定しない場合には、CakePHP の findAll で効率良く recursiveのような事態になってしまいます。
つまり、subTableのフィールド名を指定しない&&recursive=2以上の値を指定してしまうと、recursive=0 クラスにおいて、LEFT JOIN しない単体でのSQL文を発行したうえで、その結果のプライマリーキーをin句に代入して 再帰的(recursive) に次のSQL文を発行してしまうわけです。
したがって、指定しないフィールドを期待するのはよくない、ということです(当たり前ですが)。CakePHPの場合、recursiveの値によって、指定しないフィールドを取ってくるかどうかが変わってくるのですから、思わぬバグ?を生むことになりかねません。
必ず、フィールドを指定するという方針にしておけば、間違いは少なくなるでしょう。
ただし、フィールドを指定しない、即ち、すべてのフィールドを取得する、という設定も悪くはありません。むしろ、この方が、無駄なメモリを使ったとしても、より簡単に動作するプログラムが作れるかも知れません。というより、そうやって、楽するのが、フレームワークを使う利点ですよね。
ちなみに、hasAndBelongsToManyって HABTM と言うのですね。知りませんでした。
セルフジョインって、階層的なメニューみたいなのをリレーショナルDBで実装するには必要なんですかね。
CakePHPではまったこと17(belongsTo)
$recursive オプション設定方法
cakePHPのfindByにrecursiveを設定する方法
CakePHPのModelのわかりにくいところ
アソシエーションさせたくない場合の設定方法
hasAndBelongsToMany以下の配列
アソシエーション 関連モデルを読み込まないようにする 階層指定
同時に、recursive というパラメータがあり、再帰的にこのアソシエーションを追っかけてくれる回数を制御するパラメータなのだけど、WEBで検索をすると、かなり混乱しているように見受けられた。(結果オーライの記事が多い)。
なので、ここで、recursiveを正しく使うための基礎知識を若干述べたいな~。
というか自分が理解するために調べたのを覚書として書いておくということだけど。
まず、結論は、図をみていただくのが一番早い。
figure 1(クリックで画面いっぱいに表示します。)

結論
結論は図の通りです。
| recursive | 取得可能な範囲 |
| -1 | カレントテーブルのみ(単体) |
| 0 | カレントテーブル+hasOne,belongsToの第1次アソシエーションテーブル |
| 1 | カレントテーブル+すべてのの第1次アソシエーションテーブル |
| 2 | 上記 + subのsub,即ち第2次アソシエーションテーブル |
| 3以上 | 上記 + 第3(以上)次のアソシエーションテーブル*1 |
ATTENTTIONの部分を見てください。
ATTENTTION 1 にあるように、hasOneとbelongsToについては、recursive=0 であっても、アソシエーションを追跡します。
hasOne,belongsTo と hasMany は、recursive において異なる挙動をします。
つまり、
「recursive は、アソシエーションの階層を規定するものである」
という理解は間違っていることがわかります。
それが言えるのは、recursive が2以上の時であって、-1 ~ 1 の間は、特別に考えなくてはなりません。
しかし多くの人が間違えて理解しているようです。私自身も最初の頃は、ATTENTTION 1 → ATTENTTION 2 の位置にあるように思っており、大変とまどいました。
おそらくcakePHPのデータ構造に合わせるために、このような仕様にしたのだとは思うのですが、かなり戸惑いますよね。
実は、英語のマニュアルにも(例)が書かれています。
$recursive
This sets the number of levels you wish Cake to fetch associated model data in find() and findAll() operations.
Imagine you have Groups which have many Users which in turn have many Articles.
Model::recursive options $recursive = -1 No associated data is fetched.
$recursive = 0 Cake fetches Group data
$recursive = 1 Cake fetches a Group and its associated Users
$recursive = 2 Cake fetches a Group, its associated Users, and the Users'
associated Articles
CakePHP Manual-Model
若干誤解を生みそうな説明文にとれますが、私が英語に弱いため、正確なところはわかりません。ただ、上記の例は参考になるでしょう。
また、以下のサイトのように recursiv=0 には意味がない!ということにする理解もいいかも知れません。
アソシエーションさせたくない場合の設定方法
なんせ、CakePHP1.2のデフォルトも $this->recursive = 1 ですから。
背景
ソースを読むとわかるのですが、hasOneとbelongsToについては、SQL文にて LEFT JOINして、一度のSQL文の発行で、データを取ってきます。
hasManyとhasAndBelongsToManyについては、一度、カレントテーブルだけのSQL文を発行し、その結果の プライマリーキーを 次の 「in句」 に使用しています。つまり2回のSQL文を発行しています。
このことから、CakePHPは、いわゆる「副問い合わせ(サブクエリー)」については、(自動アソシエーションについては)サポートしていない、と理解できます。たぶんそれは、様々なデータベースに合わせるために仕方がないのでしょう(副問い合わせをサポートしていないデータベースもあるため)。
(追記)これも想像ですが、サポートしていないDBあるというよりも、たぶん、副問い合わせにすると、途中経過のテーブルの情報を抜き出しにくい、ということもあるのかなと思いました。
recursiveがどうしてこのような仕様になったのかは、私にはわかりません。多くの人が単純に考えるように 「recursive=0 で、単体テーブルだけが取得可能」 という仕様のほうが理解しやすいとは思うのですが。。。。。
確かに recursive=0 で、hasOneとbelongsTo を取得するのは、CakePHPの内部プログラムの処理としては、再帰的処理をせず、LEFT JOIN するだけなので、内部的な処理の仕方からの仕様となっていると思います。
内部的にはrecursive変数は、いったん、execute した結果のプライマリーキーを利用して、再帰的に、次のSQL文を作成する、というパラメータになっているのです。hasOne,belongsToは、最初のSQL文で、目的を達成してしまうので、recursive=0でも動作するようになっています。
この仕様の理由の想像
想像でしかないのですが、きっと初期の初期のCakePHPのDBOは、LEFT JOINさえ使わず、hasOne,belongsToにしても、副問い合わせで処理しようとしたのではないでしょうか。別の理由として考えられるのは、hasOneとbelongsTo だけの追跡をしたい時には、recursive=0 を使えるということかも知れません。
まあ、とにかく
hasOne,belognsToの機能は、- SQL文1回のLEFT JOIN
- SQL文1回の副問い合わせ
- SQL文2回の疑似副問い合わせ
のどれでも実現可能なので、ユーザーからみるとわからないですね。
ユーザー視点でみれば、recursive=0 で、hasOneを取ってくるのは、違和感はありますよね。
ただし、この記事を読んだ方は、recursiveについて理解したと思うので、今後は迷わないですよね。
以上のようなことを想像したのは実は、次のオプションを発見したからでした。
recursive の隠し?オプション
実は、アソシエーションの設定項目の中には、私や皆さんが誤解していたように、recursive=0で、単体テーブルしか取得しない、という動作をするオプションがあります。
recursive の隠しオプション
ただし、単純なhasOne,belongsToでも、再帰的にSQL文を発行しますので、たくさんのクエリーが投げられることとなり、基本的には速度の低下を招きますので、ご留意を。
また、このオプションの本来の使い方ではない方法です。詳しくは、上記記事をご参照ください。
留意点
自動取得の条件
figure 1 の図は、あくまでも
「取得可能なテーブルの範囲」
なので、取得する field名 に 当該subTableのフィールドを指定しない場合は、例え、hasOne,belogsToであっても、recursive=0 では取得できません。
ちゃんとsubTableのフィールド名を指定するか、もしくは、フィールド全部を取得する、という設定でないと自動的には取得できません。
もし、subTableのフィールド名を指定しない場合には、CakePHP の findAll で効率良く recursiveのような事態になってしまいます。
つまり、subTableのフィールド名を指定しない&&recursive=2以上の値を指定してしまうと、recursive=0 クラスにおいて、LEFT JOIN しない単体でのSQL文を発行したうえで、その結果のプライマリーキーをin句に代入して 再帰的(recursive) に次のSQL文を発行してしまうわけです。
したがって、指定しないフィールドを期待するのはよくない、ということです(当たり前ですが)。CakePHPの場合、recursiveの値によって、指定しないフィールドを取ってくるかどうかが変わってくるのですから、思わぬバグ?を生むことになりかねません。
必ず、フィールドを指定するという方針にしておけば、間違いは少なくなるでしょう。
ただし、フィールドを指定しない、即ち、すべてのフィールドを取得する、という設定も悪くはありません。むしろ、この方が、無駄なメモリを使ったとしても、より簡単に動作するプログラムが作れるかも知れません。というより、そうやって、楽するのが、フレームワークを使う利点ですよね。
hasAndBelongsToManyについて
ソースを読む限り、hasAndBelongsToManyについては、hasManyと同じ考え方でいけると思うのですが、テストしていないのでわかりません。ちなみに、hasAndBelongsToManyって HABTM と言うのですね。知りませんでした。
セルフジョインについて
self-joinについてのロジックまでは追いかけませんでした。たぶん、同じ結論だとは思うのですが。。。。セルフジョインって、階層的なメニューみたいなのをリレーショナルDBで実装するには必要なんですかね。
検証したバージョン
CakePHP version 1.2.0.6311 beta,SQLite 2参考にさせていただいたサイト
なお、今回の記事を書くにあたっては以下のサイトを参考にさせていただきました。CakePHPではまったこと17(belongsTo)
$recursive オプション設定方法
cakePHPのfindByにrecursiveを設定する方法
CakePHPのModelのわかりにくいところ
アソシエーションさせたくない場合の設定方法
hasAndBelongsToMany以下の配列
アソシエーション 関連モデルを読み込まないようにする 階層指定
*1 : 2と3は性質は同じです。わかりやすさのため分けてみました。
-
▼
recursiveの隠しオプション
CPA-LABテクニカル ここでは、recursiveが、多くの人が思うような動作にするための隠しオプションをご紹介する。recursive はややこしい。かなりの人が混乱しているように思う。ただし、お断りしておくと、このオプションは実は隠されているのでなく、複雑なテーブル間連携を...
-
▼
[CakePHP]unbindModelでコンパクトなfindを心がける
laboloRailsに影響を受けているcakePHPは当然、強力なDBの操作に関する機能を提供してくれている。簡単に言うと、DBの各テーブルの関連を記述しておけば、1つデータを引くだけでその関連データも一緒に提供してくれる。 この機能はとっても便利なんですが、その...
-
▼
Dynamic Drawの品格
CPA-LABテクニカル 知る人ぞ知る有名ソフトDynamic DrawDynamic Draw Professional図を書くときにいつも使わせてもらっています。とにかく操作が直感的なので、たいへん便利。「recursiveの正しい理解CakePHP」の図も、Dynamic D...
▼ 2008/02/12(火) ヘルパーのurl,acitonの違い。プラグインではまったこと。
プラグイン開発中にformヘルパーではまったのでメモ。
今、controllerの名前が、SpoksControllerとすると、出力されるhtmlは以下のようになる。
では、問題。
プラグイン(plugin)の一般的なアクセス方法は、
すると、$this->params['controller']の値がnullになる。urlにコントローラー名がないから。
で、上記A,Bで出力されるhtmlを比べると。。。。
つまり、$option=array('action'=>'acta')で指定してしまうと、勝手にコントローラー名をつけてしまうので、特例D方式でアクセスしても、次にフォームで飛んだ先は、通常アクセスURLになってしまう。
それを避けるためには必ず、 $option=array('url'=>'acta') で指定しなければならない。
プラグイン&規約違いコントローラー名&特例URLアクセス下で、formをcreateし、そこのオプションで、$option=array( 'action' => 'acta' ) とすると、Rueter:url 内で、ご親切に、モデル名(ModelName)から、複数化関数(infletor::puluralize)によって、コントローラー名を「規約通り」に作ってしまう。
すると、
A)・・・action = ' / プラグイン名 / 意図しないコントローラー名 /acta'
ということになりエラーがでてしまう。
なので、
A) $form->create(' モデル名 ',array('action'=' acta '));
B) $form->create(' モデル名 ',array('url'=' acta '));
の違い。今、controllerの名前が、SpoksControllerとすると、出力されるhtmlは以下のようになる。
A)<form name=・・・・method=・・・action = ' /spoks/acta'> B)<form name=・・・・method=・・・action = '/acta/'>となる。
では、問題。
プラグイン(plugin)の一般的なアクセス方法は、
C) http://(baseurl)/ プラグイン名 / コントローラー名 / アクション名 C') http://(baseurl)/spoks/spoks/actaだけれども、以下の方法でもアクセスできる。
D) http://(baseurl)/ プラグイン名 / アクション名 D') http://(baseurl)/spoks/acta(ただし、プラグイン名と同名のコントローラーがあることが条件)
すると、$this->params['controller']の値がnullになる。urlにコントローラー名がないから。
で、上記A,Bで出力されるhtmlを比べると。。。。
A)<form name=・・・・method=・・・・・・action = ' /spoks/spoks/acta'> B)<form name=・・・・method=・・・・・・action = 'spoks/acta/'>となる。
つまり、$option=array('action'=>'acta')で指定してしまうと、勝手にコントローラー名をつけてしまうので、特例D方式でアクセスしても、次にフォームで飛んだ先は、通常アクセスURLになってしまう。
それを避けるためには必ず、 $option=array('url'=>'acta') で指定しなければならない。
規約と異なるコントローラー名の時の注意
上記でも意図せざるURLとはいえ、アクセスはできるし、コンテンツは問題なく表示される。URLだけの問題だった。しかし。。。プラグイン&規約違いコントローラー名&特例URLアクセス下で、formをcreateし、そこのオプションで、$option=array( 'action' => 'acta' ) とすると、Rueter:url 内で、ご親切に、モデル名(ModelName)から、複数化関数(infletor::puluralize)によって、コントローラー名を「規約通り」に作ってしまう。
すると、
A)・・・action = ' / プラグイン名 / 意図しないコントローラー名 /acta'
ということになりエラーがでてしまう。
なので、
プラグイン&規約違いコントローラー名&特例URLアクセス下で、formをcreateする場合には
$option=array( 'action' => 'acta' )ではなく
$option=array( 'url' => 'acta' )とするように。
▼ 2008/02/11(月) プラグインモデルを読み込まない?Missing Database Table
プラグインのコントローラーでCakePHPの規約と異なるデータベースのテーブルを使用する場合、usesの書き方を間違えると、モデルをうまく読み込まず、Missing Database Tableのエラーが出る。モデルをうまく読み込めないから、「モデルがない」というエラーが出そうなものだけど、なぜかこうなる。
なので、
それはルール通りなんだろうけど、エラーメッセージがちょっと的外れなので、かなり時間を食ってしまった。
CakePHP version 1.2.0.6311 beta
Missing Database Table Error: Database table ・・・・ for model ・・・・ was not found.というエラーがでる。
なので、
var $uses=array( 'モデル名' );ではなく、
var $uses=array( 'プラグイン名.モデル名' );と、小数点(ドット)で、プラグインの名前とモデル名をつながなくてはならない。
それはルール通りなんだろうけど、エラーメッセージがちょっと的外れなので、かなり時間を食ってしまった。
CakePHP version 1.2.0.6311 beta
▼ 2008/02/11(月) EmailComponentをコード改変なしで使うには
CakePHP1.2b EmailComponentをコード改変なしで使おうとする時のまとめ。UTF-8&SMTP送信なら、比較的簡単に日本語も大丈夫のよう(ただし完全ではない)。(コーディングもUTF-8の場合です。)
Shift-JISは試してないけど、JISと同じでしょう。
こうすれば、引数渡し制限の70バイト/行にひっかかることはない。
(NULLのところに本文を渡してもいいけど、70バイト制限で分割されてviewに渡されることとなる。
viewでは、変数$contentに、messageを処理した内容がわたされている。)
SMTP経由の送信であれば、Fromと同じ形式で通る。
au携帯ではutf-8は適切に表示できない。(Docomo,softbankは大丈夫のよう。携帯メールの文字コード)
SMTP送信「EmailComponentの使い方。mail関数を使わず、smtpで送る。CakePHPメール」であれば、うまくいくことがあるが、これもsendmailに直接utf-8を渡すことになるの。
なお、CakePHP1.2b時点では、本文のbase64エンコードはサポートしていないよう。
EmailComponentで簡単日本語メール。CakePHPメールCakePHP1.2b
view,layoutもすべてjisにするか、PHPスクリプトにてISO-2022-JPに変換して出してやらないといけないので、若干面倒&ちょっとしたミスですぐに文字化けのもと。
softbank携帯はうまく表示できないそう。
ソフトバンクもiso-2022-jpOKだそうですが、ちゃんとしたメールヘッダーでないものはプロバイダとして受信拒否する、と書いてあるので、若干心配です。
(Sofbankメール注意点 FAQ)
CakePHPがISO-2022-JPを正しく処理して送れば、クライアント側で文字化けすることはまずない。(機種依存文字除く)
EmailComponentで簡単日本語メール。CakePHPメールCakePHP1.2b
のヘッダーがつかないようで、若干気になる。
この情報は古いうえに、若干間違いもあります。ご注意ください。なお
メールヘッダーの日本語については、ちゃんとCakePHPが mb_encode_mimeheader と同じ変換をしてくれる*1から、素直に日本語が通るようになっている*2。問題が出やすいのは、本文のほう(1行が70バイトを超えた時)。
| UTF-8 | JIS(ISO-2022-JP) | |
| 引数渡し本文の1行字数制限 | あり(70バイト*3) | |
| Viewの文字コード | UTF-8 | JIS |
| Content-Transfer-Encoding | 7bitになってしまうが、メーラーでは読めるよう | 7bitでOK |
| htmlメール | OK | OK |
| 長い日本語subject | 大丈夫 | 渡す前にJISにエンコードしておけばOK |
UTF-8で送る場合
設定
$conponents=array('Email');以外は、になし。本文
$this->Email->send($message=null,'viewName','LayoutName');とし、第1引数のmessageは、すべてviewで処理してしまう。
こうすれば、引数渡し制限の70バイト/行にひっかかることはない。
(NULLのところに本文を渡してもいいけど、70バイト制限で分割されてviewに渡されることとなる。
viewでは、変数$contentに、messageを処理した内容がわたされている。)
subuject(メールのタイトル)
そのままUTF-8で、$this->Email->subject に渡してやれば、CakePHPが、Email::__encode関数にて、mb_encode_mimeheaderと同じ変換をしてくれるので大丈夫。長いタイトルも適切に分割される。From,Reptyto,Bccヘッダの日本語
$this->Email->from='日本語での宛先'.'<example@example.com>'とやって渡せば、CakePHPがUTF-8で、エンコードしてくれる。
Toヘッダの日本語
デフォルトのmail関数を使う方法の場合は、日本語は通らない。SMTP経由の送信であれば、Fromと同じ形式で通る。
UTF-8の場合の欠点
Content-Transfer-Encoding|7bitとなり、若干気持ち悪い。たいていのPCメーラーでは大丈夫のよう。au携帯ではutf-8は適切に表示できない。(Docomo,softbankは大丈夫のよう。携帯メールの文字コード)
文字化け
PHPのmail関数にそのままUTF-8のマルチバイトコードを渡すことになるので、文字化けがでることがある。messageの最初に空行を入れておくとうまくいく場合があるが、危なっかしい。SMTP送信「EmailComponentの使い方。mail関数を使わず、smtpで送る。CakePHPメール」であれば、うまくいくことがあるが、これもsendmailに直接utf-8を渡すことになるの。
なお、CakePHP1.2b時点では、本文のbase64エンコードはサポートしていないよう。
絶対に文字化けさせたくない
という方は、こちらをご参照。EmailComponentで簡単日本語メール。CakePHPメールCakePHP1.2b
利点
文字コードを気にせず、一番簡単にメールを送ることができる。JIS(ISO-2022-JP)の場合
設定
$this->Email->charset='ISO-2022-JP';本文
UTF-8と同じだけれど、引数として渡す前にmb_convert_encodingにて ISO-2022-JP への変換が必要。view,layoutもすべてjisにするか、PHPスクリプトにてISO-2022-JPに変換して出してやらないといけないので、若干面倒&ちょっとしたミスですぐに文字化けのもと。
subuject(メールのタイトル)
$this->Email->subjectに設定する前に、mb_convert_encodingでJISへの変換が必要。
$this->Email->subject=mb_convert_encoding('日本語での件名タイトル',"ISO-2022-JP");
From,Reptyto,Bccヘッダの日本語
$this->Email->from=mb_convert_encoding('日本語での宛先',"ISO-2022-JP").'<example@example.com>
'*2Toヘッダの日本語
UTF-8と同じ事情。SMTPの場合は、Fromと同様に、JIS変換すれば通る。ISO-2022-JPの場合の欠点
文字コードに気を遣うコーディングが必要。特にview,layoutもJISで書かなくてはならないのがちょっと。。。ソフトバンクもiso-2022-jpOKだそうですが、ちゃんとしたメールヘッダーでないものはプロバイダとして受信拒否する、と書いてあるので、若干心配です。
(Sofbankメール注意点 FAQ)
利点
ほとんどの日本語メールは、ISO-2022-JPである。CakePHPがISO-2022-JPを正しく処理して送れば、クライアント側で文字化けすることはまずない。(機種依存文字除く)
もっと楽にメールを送りたい
という方は、こちらをご参照。EmailComponentで簡単日本語メール。CakePHPメールCakePHP1.2b
共通
MIME-Version: 1.0のヘッダーがつかないようで、若干気になる。