4/17CakePHPのformヘルパーのラジオボタンで、デフォルトを指定する。

ちょっとはCakePHPのformヘルパーではまったこと。覚え書きです。

formヘルパーのinputメソッドでラジオボタンを表示できます。

$groups = array(‘a’=>1, ‘b’=>2, ‘c’=>3);

$form->input(‘User/group_id’, array(‘options’=>$groups, ‘type’=>’radio’));

といった書き方です。

こここで、bをデフォルトの選択にしたいとします。

$form->input(‘User/group_id’, array(‘options’=>$groups, ‘type’=>’radio’, ‘checked’=>2));

なんてしてもダメのようです。

正解は、コントローラで

$this->data['User']['group_id']=’2′;

のように初期値を入れていかないといけないようです。

3/10CakePHPのcake i18nで出力したpotファイルをPoeditでマージしたときにエラー

CakePHPで国際化に対応したサイトを作成したときの覚え書きです。はまりました。

__()で出力する文字列をくくってあげると、後でPoeditというリソースエディタ(?)で編集できることはわかりました。同じ文字列を繰り返して使っているときは、国際化しなくても日本語だけで公開することでも、一カ所Poeditで修正すればいいので便利です。これで、grepしてファイルを探して修正することはありません。詳細は、ここを参照してください。

しかし、CakePHPのcakeコマンドでPOTファイルを作成して、Poeditでマージしようとすると、重複エラーになることがあります。ファイルのサイズがいつもと倍近くなるのでおかしいと思っていました。

何回が試してみると、規則性がありました。cake i18nで初めてpotファイルを出力するとうまくいきます。つづけてpotファイルを出力すると重複エラーになります。つまり、potファイルを出力したら、一旦qキーで終了してから、もう一度cake i18nを実行しないといけないのですね。なんかおかしいが、仕方がない。

以上、覚え書きです。

2/24Cake PHPでファイルのアップロードができないことの解決。

自分で解決したことの忘れないうちのメモ。

Cake PHPのビューで$html->file()のヘルパーを使って、Wavファイルを指定してそのファイルをアップロードしたとき、アクション側でファイル名が$this->dataで渡らないことではまりました。

フォームをシンプルにしてもダメ。WindowsのXAMPPではOKだか、LinuxのApache+PHPだとダメ。WavファイルではないJpegファイルだとOK。ファイル名に空白が入っているのではないかとか、いろいろ試しましたがわからず。半日つぶしました。

結果は、単純。CakePHPには関係ない原因でした。原因はアップロードサイズが大きいこと。ファイルサイズが大きいWavファイルなら当たり前のこと。今までは、ファイルサイズが大きいとエラーを表示したと思っていましたので見逃していました。

.iniに

upload_max_filesize = 100M

post_max_size = 100M

のように大きい値(後で調整しましょう)を設定して、Apacheを再起動したらうまくアップロードできるようになりました。

基本に戻ることが大切。考えていることが間違った方向ではまる典型的なミスでした。

2/17CakePHPで画像のリサイズするコンポーネント

CakePHPで画像のリサイズを行うために便利なコンポーネントがありました。Thumbmakeコンポーネント。詳しい使い方はこちらから。

元の画像をアップして、Thumbmakeコンポーネントでいじればリサイズはとても簡単。リサイズの種類は3種類。私は、横に合わせてリサイズをするので、このコンポーネントで十分です。

開発して公開していただいた作者に感謝です。

1/26#CakePHPのhasAndBelongsToMany(HABTM)で、2つのテーブルの関係を削除したい。

これは悩みました。

例えばCakePHPのサイトのように、RecipeとTagとが多対多の関係でhasAndBelongsToMany()で定義されているとき、レシピに複数のタグを追加するには、Recipeモデルで

$data['Tag’] = array(1,2);
$this->create();
$this->saveAll($data);

なんてすればいいのですが、その関係を削除したいことがあります。単純に

$data['Tag’] = array();
$this->create();
$this->saveAll($data);

とすると、全くTagには影響はありませんでした。ではどうすればいいかというと、正解はこのサイト(Thanks!)。

array()をarray(false)にすればいいのですね。

$data['Tag’] = array(false);
$this->create();
$this->saveAll($data);

これはわかりませんでした。でも、何かおかしな仕様ですが、しかたありません。

1/25CakePHPでMySQLを使うと文字化けする件。単純なミス。

CakePHPでMySQLを使うと、phpMyAdminでみると日本語で格納したテキストが文字化けする件。app/config/database.phpの設定をGoogleで検索して確認しました。

参考にしたサイトは、ここ。MySQLのマニュアルを読めよ。> 自分

‘encoding’ => ‘utf8′

にしなければいけないところ、

‘encoding’ => ‘utf-8′

にしていました。何て単純なミスなの。

12/10BaserCMSは正しい方向かもしれないが、まだまだ。

CakePHPで実現するBaserCMSというCMS(コンテンツ管理システム)をここのサイトから知りました。

BaserCMSのサイトでマニュアルを見てみても、どんなことができるかわかりませんでした(見落としているかもしれません)。おそらくメニューの生成と、ページをWebの管理ページから作成、ブログやフォーラムの配置ができるものと推測されます。BaserCMSは、企業向けのサイトができるとは謳っていますが、具体的な機能があるか書かれていないのは残念です。やはり自分でBaserCMSをインストールしてみないといけないのでしょうか? 自由に管理ページまで触れるデモサイトがあればいいのですが。あと、ユーザーフォーラムに記事が0というのも寂しいです。

CMSは、ユーザーにとってはWeb上でページを追加できることが一番のメリットと思いますが、開発側からはモジュールの追加による機能の追加がメリットかもしれません。用意されているモジュールを組み合わせてサイトを構築できるというのはありがたいです。

CakePHPの上で開発されていることは、PHPで有名な某CMSよりは、モジュールを作成してカスタマイズの見通しがよいと考えられます。この点は、BaserCMSはCMSの正しい方向かもしれません。

実は今日、ニュースリリースやお知らせのページをユーザーが作成したり、カレンダーで日程を表示したりなど、CMSで実現できそうな案件がお客様から来ましたが、一から開発ということになりそうで、費用とスケジュールが合わないのでお断りの連絡を入れたところでした。BaserCMSのようなCMSが具体的になっていけばいいかもしれません。

11/26XAMPPのバーチャルホストを設定してCakePHPのテストサイトを構築する。

CakePHPで開発していて、ローカルのサーバーにテストサイトで動かしたいとき、まともにlocalhost直下に置ければいいのですが、いろいろとプロジェクトを抱えていると、たくさんのテストサイトを同時に動かしたいときがあります。サブディレクトリごとに設定してあげてもいいのですが、これだと.htaccessの設定が面倒であったり、絶対アドレスでリンクを指定できないとか制限があります。

ドメイン直下にドキュメントルートを配置できればいいのですが、一つ考えられるのはサブドメインを指定するというのがあります。しかし、これではlocalhostでは指定できないととか、わざわざローカルのPCにサブドメインを指定するのもやっかいであるとなります。

次に考えられるのはポート番号で分けてしまう方法があります。例えば

  • Aプロジェクトは、http://localhost:8080/
  • Bプロジェクトは、http://localhost:8082/

などでアクセスすることになります。これですと、ポート番号を適当に追加していけばプロジェクトを分けてアクセスすることが可能にになります。

簡単にローカルのPCにCakePHPのテスト環境を構築するにはXAMPPをインストールしてしまうのが一番簡単です、XAMPPを一つインストールしてしまえば、CakePHPのテスト環境で必要なApacheや、、MySQLも動かすことがことができます。

ポート番号で分けてCakePHPの環境で動かすには、Apacheのhttpd.confにバーチャルホストの設定を追加してしまいます(ここからが本題)。上記のAプロジェクトの場合はApacheのhttpd.confに以下のバーチャルホストの設定を追加します。

Listen 8080

<VirtualHost *:8080>

DocumentRoot “C:/workspace/TestProject/app/webroot
DirectoryIndex index.html index.php
ServerName localhost

<Directory “C:/workspace/TestProject/app/webroot“>
Options Indexes FollowSymLinks MultiViews Includes ExecCGI
AllowOverride All
Order deny,allow
Allow from all
</Directory>

</VirtualHost>

この場合、ダウンロードしたCakePHPは、c:\workspace\TestProjectにコピーしてしますと(EclipseのPDTで開発しているためこんなディレクトリにプロジェクトを入れています)、ドキュメントルートはその下の\app\webrootになります。プロジェクトを増やす場合は、赤字の部分を変更すればいいでしょう。

Optionsは、適当に動作させる環境に合わせて設定してください。これは、テスト環境を自分のローカルPC以外からアクセスできないようにしたり、ましてインターネットからアクセスできないようにしたり(もちろん当たり前ですが)してしまえば、あまり気にしなくてもよいかもしれません。

以上、いつもhttpd.confの設定でつまずく覚え書きです。

11/15CakePHP:paginateのsortに複数のソート項目を追加する。

CakePHPで用意されているpaginateのsortのメモです。paginateのsortは便利ですが、最初はテーブルの1項目しかソートの対象になりません。お客さんから、「価格」と並び替えるときに、もう一つ「価格条件」でも合わせてソートしてくれという入り用とのこと。しかし、CakePHPのレファレンスによると、ソートするには一つの項目だけしかソート項目を指定できません。・・・/cake/libs/controller/controller.phpのpaginate()のソースを追っても、複数のソート項目を設定できるようにはなっていません。

そこで、再度調べてみると、検索する前にモデルでbeforeFind()を呼んくれるとのこと。そこでモデルでbeforeFind()を定義して、ここでソート項目を追加してしまうことにしました。例えばこんな感じ(だいぶコードを省略しています)。

function beforeFind($queryData) {

   array_unshift($queryData['order'], array(‘XXX.item’ => ‘desc’));

   return($queryData);

}

ORDER BY句の最初に

XXX.item desc

が追加されます。$queryData['order']は配列で、配列の順番でORDER BY句に追加していきますので、

$queryData['order'][] = array(‘XXX.item’ => ‘desc’);

とすると、ORDER BY句の最後に、

, XXX.item desc

が追加されます。これで、複数の項目でSORTできます。

ここからついでの話しです。ORDER BY句に、ちょっとしたSQL関数を追加したい場合、例えば、

XXX.item is NULL desc

を追加した場合(あまりありませんが・・・)、

array(‘XXX.item is NULL’ => ‘desc’)

と指定してしまうと、

“XXX”.”item” is NULL” dess

と解析されてSQLエラーになってしまいます。これは、

array(‘(XXX.item) is NULL’ => ‘desc’)

として括弧で括ってあげれば、ORDER BY句には、期待通り、

(XXX.item) is NULL desc

にしてくれます。

11/12CakePHPのpaginateの最適化

ページングが簡単にできてしまうCakePHPのpaginateはとても便利です。パラメーターをちょっと設定してあげるだけなので、誰でも使いたくなるはず。

しかし、このpaginateには、大きな落とし穴があります。いくつものアソシエーションを設定されているモデルに対してpaginateを使うと、とても遅いのです。

これはpaginateだけではなくfindAllでも言えること。何も考えずに使うと、結果が返ってこないのです。

デバッグレベルを3にするとわかるのですが、大量にSQLが生成されます。この辺りをきちんとチューニングしてあげないといけません。

paginateの最適化を調べましたが、なかなか検索にひっかかりません。仕方ないので、試行錯誤。結局は以下の通り。

必要のないアソシエーションは実行する前に削除しておく。モデルクラスで最初に$hasManyを定義しますが、このままですと勝手にそのモデルへの抽出のためのSQLを発行してくれます。paginateのfieldsオプションに、抽出したい項目を並べておけば、それだけをSQL一つで抽出してくれるかと思っていましたが、これは大間違え。$hasManyに定義されているモデルに対して1レコードづつ改めてSQLを生成します。

あと、アソシエーションが3つになると、例えばA->B->Cと各モデルがhasMany,belongsToのアソシエーションを定義されているとすると、Aに対してpaginateをすると、A->Bで参照されたSQLを発行して、その後各レコードでCを参照するSQLが発行されてしまいます。したがって、Cがあまり大きなテーブルではなくて、ほとんど更新がないようなテーブルだと、データを配列に格納して参照させたほうがいいかもしれません。

とにかく、CakePHPのpaginateやfindAllは、余計なSQLを発行してくれます。いかに無駄なSQLを削除するかがパフォーマンスの分かれ目です。

今回、以上の方法でCakePHPから発行しているSQLの数を一桁以上減らすことで、paginateのパフォーマンスをあげました。一番のCakePHPのチューニング方法は、core.phpでデバッグレベルを3にして表示されるデバッグ情報のSQLダンプを見ながら調整していくことをお勧めします。