«Prev 1 2 3 4 5 Next»

[Akelos] options_from_collection_for_select の第2引数に id を指定すると動かない

Akelos|2008年 07月 15日|固定リンクコメント(0) このエントリーを含むlivedoorクリップ このエントリーを含むはてなブックマーク del.icio.usへブックマーク Yahoo!ブックマークに登録
Akelos で、デフォルトのヘルパメソッドで form_options_helper というのがあります。

これは、HTML中のSELECTタグを効率的に出力することを助けてくれるヘルパですが、この中にある options_from_collection_for_select() というメソッドを使用するときにバグっぽいところを発見したのでさらします。

まず、このメソッドは次のように使用します。

たとえば foods テーブルがあって、次のようなスキーマだったとします。

+--------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| created_at | datetime | YES | | NULL | |
| updated_at | datetime | YES | | NULL | |
+--------------+--------------+------+-----+---------+----------------+


これに、たとえば次のような値が入っているとします。

+-----+----------------+---------------------+------------+
| id | name | created_at | updated_at |
+-----+----------------+---------------------+------------+
| 1 | カレー | 2008-02-19 14:34:32 | NULL |
| 2 | ラーメン | 2008-02-19 14:34:32 | NULL |
| 3 | 牛丼 | 2008-02-19 14:34:32 | NULL |
| 4 | ナポリタン | 2008-02-19 14:34:32 | NULL |
| 5 | サンドイッチ | 2008-02-19 14:34:32 | NULL |
+-----+----------------+---------------------+------------+


このデータをHTMLのSELECTタグの中に表示させたい、とします。完成系の想定はこちら。

<select name="food_id">
<option value="">---</option>
<option value="1">カレー</option>
<option value="2">ラーメン</option>
<option value="3">牛丼</option>
<option value="4">ナポリタン</option>
<option value="5">サンドイッチ</option>
</select>


これをヘルパメソッドを使って実装してみる。

<select name="food_id">
<option value="">---</option>
<?php echo $form_options_helper->options_from_collection_for_select($Food->find(), 'id', 'name', $params['food_id']); ?>
</select>


options_from_collection_for_select() の引数の説明は次の通り。

第1引数

母体データオブジェクト。モデルをごっそりfind() した結果が入ってOK。

第2引数

OPTIONタグのvalueにセットするカラム。この場合はidをセットします。

第3引数

選択肢表示用の文字列。今回はフード名を表示したいので、nameをセット。

第4引数

デフォルトで SELECTED にするVALUE。



これで本来はうまく動くはずですが、実際には正しくSELECT〜OPTIONが生成されず、それどころかある件数(220件あたり)を超えるとPHPのfatal error でコードが途中終了してしまいました。ちなみに、第2引数を 'id' ではなく、'code' など別の文字列にすると、コードが途中で異常終了するようなことはなくなります。

これを修正するには、lib/AkActionView/helpers/form_options_helper.php の options_from_collection_for_select() を次のように修正する必要がありました。

lib/AkActionView/helpers/form_options_helper.php 194、195行目
■修正前

$name = method_exists($item,$text_column_name) ? $item->$text_column_name() : $item->get($text_column_name);
$collection_options[$name] = method_exists($item,$value_column_name) ? $item->$value_column_name() : $item->get($value_column_name);


■修正後

$name = method_exists($item,$text_column_name) ? $item->$text_column_name() : $item->get($text_column_name, false);
$collection_options[$name] = method_exists($item,$value_column_name) ? $item->$value_column_name() : $item->get($value_column_name, false);


最後の $item->get($value_column_name) の第二引数に false をつけた、というわけですね。どうもこの第二引数がtrueだと、再帰的になにかをしているようで、その何かの再帰呼び出しがPHPの上限数を超えて異常終了しているような感じ。

この修正方法が正しいかどうかを本家のフォーラムで問い合わせ中。問題なければ反映してもらおうかな、と思ってます。

[Akelos] Akelos-ja 日本語メーリングリストを作りました。

Akelos|2008年 06月 14日|固定リンクコメント(0) このエントリーを含むlivedoorクリップ このエントリーを含むはてなブックマーク del.icio.usへブックマーク Yahoo!ブックマークに登録
ゆるーく動き始めようかな、ということで、Akelos の日本語メーリングリストを作りました。
Akelos 日本語メーリングリスト

本家ですらまだまだな知名度ですが、好きになってしまったのでとことんやることにします。いじっている方、いらっしゃったらぜひ情報交換しましょう。


また、WikiベースのAkelos Memoを、ブログベースに変更することにしました。Wikiだと書式が気になっちゃって、気軽に書けないんですよねぇ。とりあえずこのブログで書いていたAkelosネタを転載するところから始めたいと思いますので、ご興味のある方はこちらへどうぞ。
Akelos Memo Blog


[Akelos] Akelos で set names utf8

Akelos|2008年 06月 09日|固定リンクコメント(0) このエントリーを含むlivedoorクリップ このエントリーを含むはてなブックマーク del.icio.usへブックマーク Yahoo!ブックマークに登録
MySQLで使用するとき、MySQLのバージョンによっては接続直後に set names utf8 のような文字コードを確定させるためのクエリーを投げる必要があります。4.1系ではたしか必須でしたね。5.x系ではどうだったかな。

Akelos で set names を投げるとき、config/boot.php の末尾に次のコードを書くとよいです。


// set names charset
if (!defined('AK_SET_NAMES')) {
require_once(AK_LIB_DIR.DS.'AkActiveRecord.php');
global $dsn;
$dao =& Ak::db(&$dsn);
$dao->Execute('set names utf8');
unset($dao);
define('AK_SET_NAMES', true);
}


これなら、Akelosから投げられるすべてのSQLより前に、set names をセットすることができます。


すでにネット上では次のような方法が紹介されています。

SET NAMES utf8を指定する方法 [Akelos学習法]
⇒この方法は、オフィシャルのフォーラムで出てきた解決方法なのですが、この方法には1つ大きな問題があります。

Akelos には AK_SESSION_HANDLER という定数がありますが、これを1にセットしておくと、セッション情報がファイル管理からDB管理に切り替わります。(セッション用のDBは下記のカラムで事前に作成しておく必要があります)

mysql> desc sessions;
+---------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+-------------+------+-----+---------+-------+
| id | varchar(64) | NO | PRI | NULL | |
| expire | datetime | YES | | NULL | |
| value | longtext | YES | | NULL | |
+---------------+-------------+------+-----+---------+-------+


セッションをDB管理にしておくと、アプリが成長して複数ホストで運用したくなったときに効果を発揮します。ということで、できればセッションはファイル管理よりもDB管理にしておきたいところですが、set names を ApplicationController の コンストラクタに入れておくと、

プログラム開始時にセッション機能がスタートする
(select * from sessions where id = セッションID が実行される)
  ↓
ApplicationController::__constructor() の中で set names utf8 が実行される

という順番にSQLが発行されます。
このとき、Akelos の中でセッションデータがうまく取得できず、以降の処理でセッションの更新が一切できなくなります。セッションは最初に作成されたのみで、更新はされないものになる、ということですね。

すると、アプリ側から

$this->session['foo'] = 'bar';

のようにセッションに値をセットしても動かず、

$this->flash['notice'] = "更新しました";
$this->redirectTo(array('action' => 'finish'));

のような、リダイレクト先でメッセージを表示させる処理も動かなくなります。セッションに値を入れる動作ができず、セッションに保存したはずの値はすべてからっぽになってしまう、ということですね。


ということで、ApplicationController::__constructor() で set names をやるのは、セッションをDBで管理する場合に不具合を発生させるため、やらない方がよいでしょう。一方、セッションをファイル管理で行う(AK_SESSION_HANDLER が false )場合、ApplicationController::__constructor() 内で set names は効きます。これはプログラム開始時のセッションDBへのクエリが発生しなくなるため、set names が常に最初のクエリとなるためです。


もうひとつ紹介されている情報。
Akelosでmysqlの文字化けをどうにかする [ぬかるむ日々]

こちらはフレームワークのソースコードを直接変更する方法。
この方法は基本的に何の問題もありませんが、フレームワーク自体のアップデートなどの作業を考えると、できれば直接編集は避けたいかな、といったところ。もともと僕もこの方法で対応していたんですけどね。

[Akelos] $url_helper->link_to() でHTTPからHTTPSにリンクを張る

Akelos|2008年 06月 04日|固定リンクコメント(0) このエントリーを含むlivedoorクリップ このエントリーを含むはてなブックマーク del.icio.usへブックマーク Yahoo!ブックマークに登録
Akelosネタ。

HTTPのページにいるとき、 の $url_helper->link_to にて、HTTPSにリンクを張る場合の方法。

ビューのファイル内にて、

<?php echo $url_helper->link_to('リンク文字', array('controller' => 'コントローラ名', 'action' => 'アクション名', 'パラメータ名' => 'パラメータ値'); ?>

とすると、

<a href="/コントローラ名/アクション名/?パラメータ名=パラメータ値">リンク文字</a>

というリンクが生成される。

この場合、パスから始まっているので、HTTPからHTTPS(またはその逆)のプロトコル切り替えが当然できない。


ということで、プロトコルを切り替える場合は次のようにする。

<?php echo $url_helper->link_to('リンク文字', array('controller' => 'コントローラ名', 'action' => 'アクション名', 'パラメータ名' => 'パラメータ値', 'only_path' => false, 'protocol' => 'https'); ?>

すると、次のリンクが生成される。

<a href="https://ドメイン名/コントローラ名/アクション名/?パラメータ名=パラメータ値">リンク文字</a>



こういうちょこまかとしたところも使い慣れるとすごくよい感じです。
«Prev 1 2 3 4 5 Next»