読者です 読者をやめる 読者になる 読者になる

AWS / PHP / Python ちょいメモ

amazon web service , PHP, Python を使ったときのメモ。日本語でググってもわからなかった事を中心に。

CakePHP2でカスタムエラーページ、メッセージを準備

開発してると後回しになりがちなエラーページなどの対応を、まとめ。

CakePHPのようなMVCフレームワーク、ルールが多くて勉強の必要性を感じます。確認したバージョンは、CakePHP2.4.6です。

カスタムエラーページ

app/View/Errors/ の中に、デフォルトで次の2つのテンプレートが存在します。

それぞれ、適切なコンテンツに変更すればOKです。

ただデフォルトでは、Layoutが正常系のページと同じ「app/View/Layouts/default.ctp」を使うことになるので、errorテンプレートの最初で、次のようにレイアウト変更して対応すると良い場合が多いかと(例:不要なヘッダーとかJS等を読み込まない)。

<?php $this->layout = "error"; ?>

上記のように書くと、「app/View/Layout/error.ctp」をレイアウトとして使います。

エラーメッセージの多言語化

error_400, error_500ともに、デフォルトのメッセージは英語のみです。日本語ユーザーのアクセスのみというケースでは、ざくっと日本語に書き換えてしまうのもありですが、次のような書式は、CakePHPに標準で組み込まれている多言語対応i18nの書式ですので、i18n側で対応するのも良いかと思います。

パフォーマンス的には、標準でONのキャッシュを利用していれば初回アクセス時に翻訳されたページがファイルキャッシュされるようなので、書換えコストは低いかと。ただし、更新が多いサイトだと、リリース時にファイルキャッシュをクリアしておかないとコンテンツが新しくならないなどの症状は発生する可能性があるので注意(1回、はまりましたわ。。。)

<strong><?php echo __d('cake', 'Error'); ?>: </strong>
<?php printf(
    __d('cake', 'The requested address %s was not found on this server.'),
    "<strong>'{$url}'</strong>"
); ?>

上記の場合、i18nを使って多言語化作業を進めると、__d() の 第一引数で指定されたドメイン名のファイルが生成され(この場合:cake.pot)、それをベースに翻訳を進めます。

# __() メソッドと __d() メソッドが個別に用意されてるのは、翻訳ファイルを個別管理しやすくする為なのかな?

i18nの手順については、後述のサイトなどを参考にしてください。僕の場合は、cake i18n で開始して、Poedit(Windowsの場合。差分を反映したり出来るGUIエディタ)を使って内容を編集しています。

ファイルキャッシュの場所

日本語の場合、次のところに作成されます。翻訳だけを変更した場合に、更新されないことがありましたので、削除してから再度アクセスすると反映されました。(強制更新の方法とかあるのかな?)。

  • app/tmp/cache/persistent/app_cake_core_cake_ja

setFlashメッセージをカシコクしたい

cake bakeしたデフォルト状態だと、処理の成功時も失敗時にも同じデザインでメッセージが表示され、正常系なのに一瞬失敗したかのような錯覚に。。。なりませんか?CSSとかに疎いものとして、簡単に変えれると知ったのでメモ。

SessionComponent の setFlashメソッド:

SessionComponent::setFlash(string $message, string $element = 'default', array $params = array(), string $key = 'flash')

SessionHelper の flashメソッド:

SessionHelper::flash(string $key = 'flash', array $params = array())

次の2種類のやり方があるかな、と思われます。その他、CSSを指定などもありますが割愛。

1.コントローラー(コンポーネント)側でエレメント指定

setFlash()メソッドで、表示するときに使うエレメントが $element で指定できます。View/Elements/flash_success.ctp を事前に準備しておき、失敗時には呼び出す場合は、このように書けます。

cake.generic.css みてたら class="success" が定義されていたので、成功時に使うことにしました。

<?php
// controllerにて
$this->Session->setFlash('Success!', 'flash_success');
// View/Elements/flash_success.ctp
<div id="flashMessage" class="success"><?php echo h($message); ?></div>

// Elementsを指定しない場合:どこで指定されてるかは?
// <div id="flashMessage" class="message"><?php echo h($message); ?></div>


View側は、一つのflash()メソッドだけになるので、エレメントを超えるカスタマイズは出来ないということになるかと。

2.ビュー(ヘルパー)側で表示位置もカスタマイズ

setFlash()メソッドでは、対応するflash()メソッドを指定する $key が指定できます。これを使うと、対応する$key毎にflash()メソッドの配置が行えるので、異常時にはメッセージの位置を変えたいなどの凝ったデザインにも対応できそう。

<?php
// controllerにて
// bad message をセット
$this->Session->setFlash('Something bad.', 'default', array(), 'bad');

// good message をセット
$this->Session->setFlash('Something good.', 'default', array(), 'good');


// viewにて
echo $this->Session->flash('good');
echo $this->Session->flash('bad');


flash()メソッド側でエレメント指定も出来るので、組合わせると自由度があがりますね。


Layout/flash.ctp って使われてる?

次のサイトでは、意見が2分してますが。。。

for:title=What is the flash.ctp layout for?]

scaffold などの動作ではメッセージのみの画面を挟むのですが、このときに使われていそうです。Session->setFlash() を使っていない場合に使われるレイアウトファイルってことですね。ちょっとヤヤコシイ?

参考ページ