【CakePHP×Ajax】CakePHPでAjaxを使ってデータベースを更新する

プログラミングのイメージ

今回はphpのフレームワークCakePHPでAjax通信を使ってデータベースを更新する方法を紹介します。

最近インターン先でcakePHPのチュートリアルを進めている大学生です。
pythonで開発できるのかなと思っていたところ、社員のスキルでPHPでの開発となりそうです。

しかし、他の言語と言っても学べることは非常に多いです。
自動化や機械学習しか学んでいなかったので、MVCモデルであったり、認証、非同期通信など初めて聞く言葉から、なんとなく分かる言葉まで深く学ぶことができます。

今回はcakePHPでjQueryでAjaxを使って非同期通信をしようとした時につまづいたのでメモがてら書き残します。cakePHPのバージョンは3.9.9です。

非同期通信とは

コンピューター間で送信者のデータ送信タイミングと受信者のデータ受信タイミングを合わせずに通信を行う通信方式である。

と調べたら出てきますが、簡単に言えばページ遷移せずにデータベースと通信を行う事です。
ユーザー登録の時に、都道府県を選べばその都道府県の市町村が出てくるフォームのイメージです。
非同期通信のイメージ

今回やろうと思った事

cakePHPの勉強で、メンバー紹介アプリを作っていました。
そこでメンバーを役職ごとに並べようと考えて、その役職の並び順の並び換えを非同期通信で実装しようと考えました。
アクションのイメージ

エラーの内容

いろんなWebサイトを参考にjQueryとAjaxで実装したのはいいですが、何度テストをしてもデータベースに値が更新されません。
デベロッパツールで確認したところエラーの内容は、403エラー。

cakePHP3.9.9では、Ajaxなどでform要素以外からPOSTメソッドするとエラーが返ります。

セキュリティ的には、良い事らしいです。

エラーの解決方法

ポイントは、beforesendです。
AjaxでPOSTする前に、csrfトークンをbeforesendしてあげる事でエラーが回避できます。
jQueryのコードは以下です。

jQuery

$(function(){
    var csrf = $('input[name=_csrfToken]').val();
    const page= $('#sort-order-url').data('url');
    $('#position_sort').sortable({
        update: function() {
            var ids = $(this).sortable('toArray').toString();
            console.log( ids );
            $.ajax({
                url: page,
                type: "POST",
                data:{"ids":ids},
                beforeSend: function(xhr){
                    xhr.setRequestHeader('X-CSRF-Token', csrf);
                }
            });
        }
    });
});

簡単に説明をすると、
①「id:position_sort」をsortableを使って、ドラッグ&ドロップで動かせるようにして動かしたときに発火します。
②csrfトークンを作ってあげて、ajaxの中身でbeforesendします。

注意:ajaxの中身でPOST先のurlがpageとなっていますが、これはViewファイル内で、「id:sort-order-url」のdata-urlをbuildして2行目で受け取っています。

<span id="sort-order-url" data-url="<?= $this->Url->build(['Controller' => 'positions', 'action' => 'sortOrder']) ?>"></span>

ここでのurlは、ajax用のアクションです。

cakePHPではajax用のアクションを作っといて、「autoRender=false」でViewファイルを不要とするのが普通らしいです。
他でも一緒だと思います。
③並び替えた順にidを配列に格納してアクションに渡します。

Action

以下ajax用アクションのコードです。

public function sortOrder(){
    $this->autoRender = false;
    if($this->request->is('ajax')){
        $list = $this->request->getData()['ids'];
        $lists = explode(',', $list);
        $sort= 1;
        $positionsTable = TableRegistry::getTableLocator()->get('Positions');

        foreach($lists as $id){
             $newsort = $positionsTable->get((int)$id);
             $sort_data = ['sort_order' => $sort];
             $newsort = $this->Positions->patchEntity($newsort, $sort_data);
             $positionsTable->save($newsort);
             $sort++;
        }
    }
}

うろ覚えですが、説明します。
①まずajaxか確認する
②受け取った配列をforeachで回して、並び順を更新していく。
ただし、このやり方は全データ分まわすのであまり上手ではないと感じています。
もっと簡単に変更のあったとこだけ更新するなどのやり方があるような気がします。

まとめ

今回はcakePHPで開発していてつまづいた、jQueryでAjaxを使った非同期通信についてまとめました。
エラーについて理解して解決できた瞬間は快感です。
またどこかでつまづいたら書いていきます。
最後までありがとうございました:)

コメント

タイトルとURLをコピーしました