- 更新日: 2016年2月4日
- PHP & CakePHP
CakePHPでAjaxのPOST送信
CakePHP 開発で、プルダウンメニュー(HTML の select/option タグ)が変更された場合に、Ajax リクエストで POST 送信したい機会があったのでメモ。Rails の Ajax 送信で使う remote: true のような簡単なやり方はできないっぽくて、Ajax 送信する部分の JavaScript/jQuery は自力で書く必要がありました。
— 環境 —
PHP 5.5.19
CakePHP 3.1.1
管理画面のユーザー一覧ページで、role(役割)のプルダウンメニュー選択が変更された場合に(onChange イベント)、Ajax の POST 送信で role カラムの値を更新できるようにしたかった。以下このケースを例としたコードです。
テンプレートでプルダウンメニュー作成
テンプレートでは、普通に select のプルダウンメニューを作成する。後述しますが、Ajax 送信するために、JavaScript 側の webroot/js/admin_users_index.js を読み込むようにします。
src/Template/Admin/Users/index.ctp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<?php // Ajax 送信用の JavaScript を読み込み echo $this->Html->script('admin_users_index'); ?> <p>ユーザー一覧</p> <?php foreach ($users as $user): ?> <?php // ユーザー role のプルダウンメニュー echo $this->Form->select( 'role', // option メニュー [ 'normal' => 'normal', // 一般ユーザー 'admin' => 'admin', // 管理者ユーザー 'ban' => 'ban' // 禁止ユーザー ], [ 'default' => 'normal', 'value' => $user->role, 'id' => "role-select-{$user->id}", // CSSのセレクタID 'onChange' => "changeRole({$user->id})" ] ); // ... ?> <?php endforeach; ?> |
ユーザー一覧(index)の画面でユーザーの id を JS 側に渡す必要があったので、onChange 属性をオプションで追加しています。こういう書き方は今はちょっとまずいかもですけど…管理画面ですし、とりあえず先に進むの優先で。
JavaScript 側コードで Ajax の POST 送信
ユーザーの ID を受け取って、そのユーザーの role カラムを更新する changeRole() 関数を実装しました。この中で Ajax で POST 送信する。jQuery を使っています。
webroot/js/admin_users_index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function changeRole(userId) { // セレクタID var selectorId = '#role-select-' + userId; // Ajax による POST 送信 $.ajax({ url: "/admin/users/role/" + userId, type: "POST", data: { role : $(selectorId).val() }, dataType: "text", success : function(response){ alert('ユーザーの役割が更新されました'); }, error: function(){ alert('ユーザーの役割の更新が失敗しました'); } }); } |
CakePHP 3 の場合、JavaScript は webroot/js 以下に書くらしい。このあたりの Asset 管理は、Rails とはちょっと違う感じです。
また、POST 送信先として /admin/users/role/1 のような URL を指定しているので、この後コントローラーで、ユーザー ID を引数として受けとる role アクションを実装する。
コントローラーで管理画面の Users#role アクションを実装
Ajax リクエストでの POST 送信により、ユーザーの role カラムを更新するアクションをコントローラーに実装します。
src/Controller/Admin/UsersController.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
<?php namespace App\Controller\Admin; use App\Controller\AppController; use Cake\Event\Event; class UsersController extends AppController { public function beforeFilter(Event $event) { // Ajax 送信を処理する role アクションの CSRF チェックを無効にする if (in_array($this->request->action, ['role'])) { $this->eventManager()->off($this->Csrf); } } public function isAuthorized($user) { // 管理者ユーザーのみ認可 if (isset($user['role']) && $user['role'] === 'admin') { return true; } return false; } public function role($id = null) { // Ajax 送信なのでテンプレートを使わない $this->autoRender = FALSE; // ユーザーの role を更新 $user = $this->Users->get($id); if ($this->request->is(['ajax'])) { $user->accessible('role', true); // role カラム代入を許可 $user->role = $this->request->data['role']; $this->Users->save($user); } } } |
beforeFilter() に書いているコードは、管理画面からの Ajax リクエストの場合には CSRF 対策を一時的に無効にするためです。ここちょっとはまりまして、最初 CSRF 対策が有効の状態で、Ajax での POST 送信時に “CSRF token is mismatch” のエラーが出ました。
本来は Ajax リクエストでも CSRF 対策を行ったほうが良いかと思いますが、このケースの場合は管理画面内で、isAuthorized() で管理者ユーザーにのみアクションを認可していることもあり、ちょっと手抜きしました。Ajax リクエストでも CSRF トークンのチェックを行うには、末尾の参照先リンクをご参考お願いします。
以上 CakePHP 3 で Ajax の POST 送信を行う例でした。もっと簡単なやり方があったらご連絡ください!
- – 参考リンク –
- 陽気なシステム屋が世界を変える – CakePHPでSecurityコンポーネント+AjaxでPOST送信
- Disabling CSRF on a specific action CakePHP 3 – Stack Overflow
- Cross Site Request Forgery – CakePHP Cookbook 3.x documentation
- Security – CakePHP Cookbook 3.x documentation
- PHP & CakePHP の関連記事
- PHP+MySQLでNo such file or directoryエラー
- bin/cakeコマンドでintlエラーが出る場合の対処(CakePHP)
- CakePHPアプリケーションをCapistranoでデプロイ
- Integrity constraint violation:Column ‘created’ in order clause is ambiguousエラー/CakePHP
- CakePHPでDB関連テーブルのレコード・データを取得
- CakePHPでカラム属性に別名/エイリアスを付ける仮想フィールド
- CakePHPで日付選択フォームのカスタマイズ
- CakePHP3で現在のコントローラー名・アクション名を取得
- PHPインストールでconfigure: error: freetype.h not foundエラー
- CakePHPでログイン後に元のページにリダイレクトさせる
Leave Your Message!