CakePHP2の機能のうち利用頻度の高い機能に絞って深く解説したリファレンス本である「Webアプリ開発を加速する CakePHP2定番レシピ119」という本を書きました。
執筆のきっかけ
長谷川は2007年頃に当時1.1だったCakePHPに出会ってその魅力にとりつかれ、それ以来個人的に作成するプロダクトのほぼ全てにCakePHPを使っています。
また、個人で十分にその取扱に習熟した上でデジタルサーカスの業務へ標準フレームワークとして導入し、生産性やメンテナンス性にとても良い影響を与えています。
CakePHPは小規模から大規模まで幅広く適用が可能なフレームワークですが、CakePHPに限らずフレームワークは最初に使い方を覚えるまでが大変です。
初めて使った時には「PHPは十分経験があるのにCakePHPで推奨される書き方が分からず時間がかかる」であるとか、「書き方が分からないので無理矢理PHPの書き方をしてしまいCakePHPの美味しいところを使えないばかりか余計な手間がかかる」という状態になりがちです。
長谷川も開発プロジェクトに途中から参加したCakePHP開発経験の無いメンバーがこの様な状態になるのをたびたび目にしました。
幸いにしてCakePHPはPHPのフレームワークの中ではメジャーで、書籍やWebの情報が豊富に存在しています。そのため初めてCakePHPを使用する場合にも比較的短時間で基本的な使い方を学習することができます。
ただ、現状では基本的な使い方を学習した後の使い勝手の良いリファレンスが不足していました。
既刊で、すべてを網羅したとても壮大なリファレンスがあるのですが、その網羅性の反面個々の項目の記述が簡潔で困ることもありました。
そこで、記述範囲をCakePHP2のよく使う機能に絞り、その範囲の機能について深く記述されたリファレンスとして本書を企画し、執筆することにしました。
本書は「CakePHPがどの様にコントローラ・モデル・ビューを連携させようとしているか」を理解することを第1の目的としています。
そのために、モデルのアソシエーション(JOIN)やバリデーション、FormHelperの詳細なオプションとその書き方をリファレンスとして特に詳細に解説しています。
これに加えて、会員登録、ログイン、一覧画面、編集画面などで「だいたいこうやって書くんだよ」というシンプルなサンプルソースのセットを掲載しています。
サンプルソースを見て全体的な形を理解し、自分が作成したいアプリケーションの要件に合わせるためにリファレンスを使用して頂くと良いでしょう。
また、CakePHPには便利なコンポーネントが多数内蔵されていたり公開されていたりします。この中で使い勝手が良く、一般的なWebアプリケーションでよく使われるコンポーネントについても厳選して詳細に解説しています。
対象とするCakePHPのバージョンは2.0~2.4です。
もくじ
01 設定のレシピ
- 001 SQL実行結果を動的に表示する
- 002 デバッグツールを導入する
- 003 エラー発生時にメールで管理者に通知する
- 004 複数台のWebサーバに対応したシステムを構築する
- 005 開発環境と本番環境で設定を自動切り替えする
- 006 ファイルを独自のディレクトリに配置する
02 コントローラ&ビューのレシピ
- 007 ログインしない状態では閲覧できない画像を出力する
- 008 AJAX(非同期通信)用のJSONを出力する
- 009 ファイルをアップロードする
- 010 ファイルをダウンロードさせる
- 011 PDFファイルを生成する
- 012 ユーザ画面と管理画面で異なるレイアウトを使用する
- 013 リクエストを別のURLにリダイレクトする
- 014 ログファイルに実行状況を記録する
- 015 ?を含まないURLで処理を実行させる
- 016 URLからデータを取得する
- 017 フォームから送信されたデータを取得する
- 018 コントローラの処理の前後に共通の処理を実行する
- 019 すべてのコントローラに共通の処理を記述する
- 020 コントローラからビューに値を引き渡す
- 021 エラーページをカスタマイズする
- 022 ビューの一部を共通要素として切り出す
- 023 2カラムのレイアウトを使用する
- 024 URLから実行されるコントローラを設定する
03 モデルのレシピ
- 025 検索条件を指定してデータを取得する
- 026 SQLのWHERE句を使用してデータを取得する
- 027 必要なフィールドのみを取得する
- 028 データ取得時のソート順を指定する
- 029 SQLを使ってデータベースを直接操作する
- 030 特定の列に含まれる最大値を取得する
- 031 条件に合致するレコード数を取得する
- 032 開始行、取得行数を指定してデータを取得する
- 033 データベースからデータを削除する
- 034 データベースに新しいレコードを作成する
- 035 保存されたデータを更新する
- 036 作成日・更新日を自動的に保存する
- 037 SQLインジェクション対策をする
- 038 レコード作成・更新時にXSS対策の変換をする
- 039 CakePHPの名前規則に従っていないテーブルを使用する
- 040 すべてのモデルに共通の処理を定義する
- 041 ビヘイビアを使ってモデルの動作を拡張する
04 アソシエーションのレシピ
- 042 「注文と注文明細の関係」(has many)をアソシエーション設定する
- 043 「社員と部署マスタの関係」(belongs to)をアソシエーション設定する
- 044 「記事とタグの関係」(HABTM)をアソシエーション設定する
- 045 アソシエーションされたモデルのデータ取得範囲を指定する
- 046 検索条件としてアソシエーションされたモデルのフィールドを指定する
- 047 プログラム中でアソシエーションを設定・解除する
- 048 外部キーやモデルを独自に指定してアソシエーションを設定する
- 049 データ削除時にアソシエーションされたモデルのデータもまとめて削除する
- 050 アソシエーション先のレコード数を自動的に更新する
05 バリデーション(検証)のレシピ
- 051 ユーザが入力した値にエラーがあるかを検証する
- 052 CakePHPの組み込みバリデータを使って値を検証する
- 053 バリデーションでエラーになった場合のエラーメッセージを設定する
- 054 入力されたユーザ名がすでに使用されているかの検証をする
- 055 日本語を考慮した文字数制限の検証をする
- 056 2回入力したメールアドレスが等しいか検証する
- 057 プログラム中でバリデーションを設定・解除する
06 コンポーネントのレシピ
- AuthComponent
- 058 ログイン・ログアウト処理を行う
- 059 ユーザを登録・編集する
- 060 一部の画面のみログインを必須にする
- 061 ログイン中のユーザの情報を取得する
- 062 ユーザがログイン済かを調べる
- 063 ログインが必要なURLを直接指定されたときにログイン画面にリダイレクトする
- 064 ログイン後に任意のURLに戻る
- 065 強制的にログイン状態にする
- 066 AuthComponentの動作をカスタマイズする
- CookieComponent
- 067 Cookieに値を設定する
- 068 Cookieに値が設定されているかチェックする
- 069 Cookieから値を取得する
- 070 指定したCookieの値を削除する
- 071 Cookieの期限やパスを設定する
- SessionComponent
- 072 セッションに値を設定する
- 073 セッションに値が設定されているかチェックする
- 074 セッションから値を取得する
- 075 指定したセッションの値を削除する
- 076 セッションの期限や動作を設定する
- SecurityComponent
- 077 CSRF対策を行う
- 078 POST以外でリクエストされた時にエラーとする
- 079 HTTPS(SSL)以外でリクエストされた時にエラーとする
- その他
- 080 コンポーネントを自作する
- 081 コンポーネントからモデルを使用する
- 082 コンポーネントから他のコンポーネントを使用する
07 ヘルパーのレシピ
- HtmlHelper
- 083 ヘッダ用のHTMLタグを生成する
- 084 画像タグを生成する
- 085 リンクタグを生成する
- 086 パンくずリストを表示する
- FormHelper
- 087 フォームの開始・終了タグを生成する
- 088 フォームの部品を生成する
- 089 送信ボタンを生成する
- 090 hiddenタグを生成する
- 091 指定したフィールドにエラーがあるかを調べる
- 092 エラーメッセージを表示する
- 093 ラジオボタンを整列して表示する
- 094 AJAX(非同期通信)でSELECTの中身を書き換える
- 095 tableタグの中にフォームの部品を表示する
- その他
- 096 PaginatorHelper 一覧のページ分けをする
- 097 ヘルパーを自作する
08 応用レシピ
- 098 メールを送信する
- 099 Memcachedを使う
- 100 Facebookで認証しログイン状態にする
- 101 Twitterで認証しツイートを読み込む
- 102 ビューにSmartyを使う
09 問題発生時の解決レシピ
- 103 プログラムを本番環境にアップしても反映されない
- 104 シェルを実行するとファイルパーミッションエラーが発生してしまう
10 MVCのサンプルソース集
- 105 会員登録のサンプル
- 106 ユーザログインのサンプル
- 107 一覧画面のサンプル
- 108 確認画面付き編集画面のサンプル
11 1.x→2.x移行のレシピ
- 109 CakePHP1.3への移行
- 110 CakePHP2.0への移行の概要
- 111 UpgradeShellによる移行
- 112 CakePHP2.0~2.4の移行
12 シェルのレシピ
- 113 シェルを自作する
- 114 シェルを実行する
- 115 シェルからモデルを使用する
- 116 シェルからコンポーネントを使用する
- 117 シェルのパラメータを取得する
- 118 シェル実行時にヘルプメッセージを表示する
- 119 シェルを定期的に実行する
まとめ
とまあ、こんな感じの本書ですが長谷川としては現時点で持っているノウハウを十分に注ぎ込めたと思っています。
CakePHPを使い始めたばかりの方にも、CakePHPを使いこなしている方にも、机の上に置いてお役に立てる1冊だと思います。
(個人的にも早速自分の原稿がリファレンスとして役に立っています。)
書店で見かけたら是非ご覧になってください。
そしてもし気に入ってレビューを書いて頂いた場合には是非ご連絡ください!喜んで拝見します!
突然のご連絡申し訳ありません。
「CakePHP2定番レシピ119」を参考にさせていただきながらサービスを作っております。
しかし、「100 Facebookで認証しログイン状態にする」をうまく動かすことができずに、困っております。
ソースの途中に、間違えなどございましたら、教えていただけないでしょうか。
FacebookAuthenticate.phpの途中に、”redirect_uri”という誤植と思われる部分を発見し、”redirect_url”と直したのですが、それでもうまく動きません。
症状としては、Facebookにて認証の後、”リダイレクト ループが含まれています”というエラーメッセージが出てしまっております。
突然のご連絡で大変恐縮ですが、最新の修正情報等ございましたら教えていただけないでしょうか。それとも、本書の通りにソースを作成すれば、間違いなく動作するものでしょうか?
書籍のご購入ありがとうございます。
FacebookAuthenticate.phpのredirect_uriはこれで合っています。
(URLはUniform Resource Locatorの省略ですが、URIはもう少し広い言葉のUniform Resource Identifierの略なのです。)
このメソッドはFacebook SDKをそのまま使用しています。
https://developers.facebook.com/docs/reference/php/facebook-getLoginUrl/
リダイレクトループはまさに文字通り、同じページをリダイレクトで行き来してしまっていることが原因と思われます。
Facebookのログインは以下の様になっています。
1. ログインページからPOSTでPHPプログラムに処理が渡る
2. PHPプログラムはブラウザに対してFacebookの認証URLへのリダイレクトを指示する
3. ブラウザはFacebookの認証ページを開き、ユーザがID/パスワードを入力するなどする。
4. Facebookシステムはブラウザに redirect_uri へのリダイレクトを指示する。
5. ブラウザはログイン完了画面を表示する
ここで、2.と4.で同じURLが指定されると2~4を行き来する(=リダイレクトループ)が発生してしまいます。
URLがどの様に遷移しているか、そしてその遷移は設計どおりか、を確認してみてください。
(そしてこの問題が発生する場合、多くは4.のリダイレクトで戻ってきたURLから再度2.のリダイレクトが発生します。)
紙面のソースコードは少なくとも執筆時点では動いていましたが現時点で動くかの確認には少し時間がかかりますので取り急ぎのお返事でした。
この情報でうまく動くと良いのですが…。
本を買いました。
cakephp2自体、触れるのが初めてなのでこちらのミスだとは思いますが、
106の「ユーザーログインのサンプル」が認証されません。
ダウンロードしたソースをコピペしても”メールアドレスかパスワードが違います”と表示されます。
105「会員登録のサンプル」は問題なく動いています。
セッションの設定が必要なのでしょうか?
Queryを見るとemailの表示はされているのに、暗号化されたpasswordが表示されていないのです。
おそらく解決しました。
105で登録された仮登録データを削除したところ認証してくれました。
サンプルでは本登録後に仮登録データを削除するコードがないので他の人もひっかかるのではないでしょうか。
書籍のご購入ありがとうございます。
そして、確かにそうですね。105で仮登録のままのレコードがあると106は意図通りに動かないですね。
次版が作れればそのときにケアしようと思います。
ご指摘 & 解決のご連絡、ありがとうございました。
先週購入させていただきました
まだCakePHP自体触り始めて2週程度なのですが、このようなレシピ本は助かります。
要望としては各セクションのソースをできるだけ公開していただけると助かります。
Chapter10のソースは公開されておいでですが…
さて肝心な質問になります。CakePHPの理解が足りないので間違っているかもしれませんご容赦ください
P.228 094「AJAX(非同期通信)でSELECTの中身を書き換える」ですが
リスト1 のHTMLの例よりCakePHPの書き方ほしかったです。
リスト2 リスト3のCakePHPから受け取る値と整合してますか?
JavaScriptの正しい読み込み方も欲しかったり(分ってはいるのですが)
リスト3 どこのコントローラに記述すれば良いかわかりにくいです
findを利用しているのでCitiesController.phpへ書込して
リスト3を cities/json/ にしたりしてます
(若干手を加えなければ使えませんでした。
少なくとも最後から1つ前の行 セミコロン要です。
リスト3ではfindで listで出力した場合
{
“1”: “札幌市”,
“2”: “函館市”
.
.
.
ですが
JavaScriptソースでは
{
{
“id”: “1”,
“name”: “札幌市”
},
{
“id”: “2”,
“name”: “函館市”
},
.
.
.
を期待した書き方ではないでしょうか?
改訂版などの時でかまいませんけどご検討くだると有難いです。
続けて「102 ビューにSmartyを使う」ですが、残念ながら搭載されたURLのパッケージからは
使えませんでした。
一部コメントアウトすれば動く部分もありますがヘルパーは全滅でした
以下にあるSmartyView を使うことでSmarty 3.1.19+CakePHP2.5.2 では動作しました
https://codeload.github.com/mtakaaki/smartyview/zip/master