Backbone.js Model.save()によるPOSTデータをPHPで読み込む

最近Backbone.jsを使い始めました。
JavaScriptのMVCフレームワークの内、知名度が最も高いらしいということで。

日本語の入門記事としてはこちらが非常に分かりやすく、参考にさせていただいています。
Backbone.js 入門

Model.save()のサンプル

Backbone.jsのModelを使ってデータ登録・更新を行う場合、通常はModelメソッドのsave() を使うと思いますが、save()の動作を確認する簡単なサンプルを作ってみました。
(save()を使うと、リソースAPIに対してPOST(またはPUT)リクエストが送信されます。)

Backbone.js saveサンプル

サンプルの動作

  1. 「送信」ボタンをクリックすると、入力された名前と住所をPOSTリクエストで送信する。
  2. POST送信された名前と住所のJSON文字列が、ボディに含まれてレスポンスが返ってくる。
  3. レスポンスされた名前と住所を画面に表示する。

サンプルを構成するファイル

以下、上記サンプルを動作させているファイルの一覧と、ファイルの内容です。

ファイル一覧

backbone-save-test.html
名前と住所を送信する画面
backbone_save_test.js
名前と住所の値をModelに保持して、save(POSTリクエスト)するJavaScript
backbone_save_test.php
POSTリクエスト先のPHPファイル

backbone-save-test.htmlの一部

名前と住所の入力部分と、レスポンスデータを表示するテンプレート部分です。

<table class="table table-bordered">
  <thead>
  </thead>
  <tbody>
    <tr>
      <th>名前</th>
      <td><input type="text" id="user_name"></td>
    </tr>
    <tr>
      <th>住所</th>
      <td><input type="text" id="address"></td>
    </tr>
  </tbody>
</table>
<input type="button" id="btn_send" value="送信">
<br><br>

<!-- テンプレート(post_data_template)を表示する領域 -->
<div id="post_data_area"></div>
<!-- /テンプレート(post_data_template)を表示する領域 -->

<!-- レスポンスを受け取って表示するテンプレート -->
<script type="text/template" id="post_data_template">
  <table class="table table-bordered">
    <caption>POSTされたデータ</caption>
    <thead>
      <tr><th>名前</th><th>住所</th></tr>
    </thead>
    <tbody>
      <tr>
        <td><%= user_name %></td>
        <td><%= address %></td>
      </tr>
    </tbody>
  </table>
</script>
<!-- /レスポンスを受け取って表示するテンプレート -->

 

backbone_save_test.js

名前と住所の値をModelに保持して、save(POSTリクエスト)します。

$(function() {

    var User = Backbone.Model.extend({
        // ModelのリソースURI(本サンプルでは、Model.save()によるPOSTリクエスト先)
        urlRoot : './backbone_save_test.php',
        defaults : function() {
            return {
                'user_name' : null,
                'address' : null
            };
        }
    });

    var BtnSend = Backbone.View.extend({
        el : $('#btn_send'),
        model : User,
        initialize : function(options) {
            this.model = options.model;
        },
        events: {
            'click' : 'click'
        },
        click : function(e) {
            var reqData = {
                'user_name' : $('#user_name').val(),
                'address' : $('#address').val()
            };
            // 送信するデータをModelにセット
            this.model.set(reqData);
            // save()を呼び出すと、model.urlRootにPOSTリクエストが送信される
            this.model.save(null, {
                success : function(model, resp) {
                    // レスポンスを受け取ってalert表示する
                    alert('名前:'+resp.user_name+' 住所:'+resp.address+' を受け付けました。');
                    // レスポンスを受け取ってテンプレートに表示する
                    $('#post_data_area').html(_.template($('#post_data_template').html(), resp));
                },
                error : function(model, resp) {
                    alert('エラー:送信に失敗しました。');
                    return false;
                }
            });
        }
    });

    var user = new User();
    var btnSend = new BtnSend({model: user});
});

 

backbone_save_test.php(修正前)

Model.save()により送信されたPOSTデータを、$_POSTから取得しようとしています。

<?php

$reqData = $_POST;
$respBody = array('user_name' => $reqData['user_name'], 'address' => $reqData['address']);
echo json_encode($respBody);

// end of file

 

$_POSTでは、application/jsonのPOSTデータを取得できない

Backbone.jsのsave()によるPOSTデータをPHPで取得する際に、少し困ったことがありました。

リクエストをPHPで受け付けた場合、$_POST($_REQUEST)などのスーパーグローバルを使ってリクエストデータを取得すると思いますが、$_POSTにはリクエストデータが入っていないのです。

Backbone.jsはPOSTリクエストボディにJSON文字列をそのまま入れて送信するため、
$_POSTが想定している形式と違うということのようです。

Backbone.jsとPHPが扱うContent-Typeの違い

Backbone.js のPOSTリクエスト
Content-Type: application/json
PHPが想定しているPOSTリクエスト
Content-Type: application/x-www-form-urlencoded

 

PHPでBackbone.jsのPOSTデータを取得する方法

方法は二つあります。

  • “php://input”からリクエストボディを直接読み込む
  • Backbone.emulateJSON = true に設定する

 

php:// — さまざまな入出力ストリームへのアクセス

php://input は読み込み専用のストリームで、 リクエストの body 部から生のデータを読み込むことができます。 POST リクエストの場合は $HTTP_RAW_POST_DATA よりも php://input を使うのが望ましいでしょう。php.ini ディレクティブの設定に依存しないからです。 さらに、$HTTP_RAW_POST_DATA がデフォルトで設定されない場合は、 always_populate_raw_post_data を有効にするよりも $HTTP_RAW_POST_DATA を使うほうがメモリの消費量が少なくなるでしょう。 php://input は、 enctype=”multipart/form-data” に対しては使用できません。

 

emulateJSON 

If you’re working with a legacy web server that can’t handle requests encoded asapplication/json, setting Backbone.emulateJSON = true; will cause the JSON to be serialized under a model parameter, and the request to be made with aapplication/x-www-form-urlencoded mime type, as if from an HTML form.

 

上記の通り、Backbone.emulateJSONをtrueに設定する方法だと、Content-Type:application/x-www-form-urlencoded でPOSTリクエストが送信されるようになりますが、

今回は”php://input”を使う方法で対応します。

emulateJSONの説明文中の”a legacy web server”の部分が気に入らないというのもあって(レガシーとかじゃないだろとw)

 

backbone_save_test.php(修正後)

backbone_save_test.phpの内容を、以下のように修正します。

<?php

$reqData = json_decode(file_get_contents('php://input'), TRUE);
$respBody = array('user_name' => $reqData['user_name'], 'address' => $reqData['address']);
echo json_encode($respBody);

// end of file

 

修正後のサンプル

修正後のサンプルが、冒頭にも紹介したこちらです。(冒頭と同じ内容です)
Backbone.js saveサンプル

 

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

Post Navigation