エス技研

WordPress、CakePHP、PHP、baserCMSなどの Web系システムを中心に情報を提供します!


CakePHPのpostlinkで生成した削除リンクをクリックしても処理が実行されない対処法

   

postlinkで生成した削除リンクをクリックしても処理が実行されないときの対処法

 

削除をクリックしても処理されないという発生した事象

 
CakePHP4、CakePHP5環境で、一覧表にある「postlink()」から生成された「削除」のリンクをクリックしても処理が実行されないという不具合が発生しました。
 
 

社員情報の一覧画面


 

postlinkで生成された削除のリンクをクリックしたときに表示されるダイアログ


 
そして「OK」をクリックしても削除処理は実行されない、という不具合です。
 
 

削除をクリックしても処理されない原因

 
今回の原因は、上記の画像にもありますが、「詳細」「変更」「削除」の処理を一覧表の右と左の両方に表示していることでした。
 
 
上記の画像は一覧表の項目が少ないため、表の左右に付ける必要性を感じませんが、実際の表は項目が多くスクロールさせる必要がありました。
そのため、右端までスクロールさせなくてもいいよう、左右にリンクを設置することにしました。
 
その際のコードが下記になります。
 
 

不具合が発生したソースコード

 

<?php
$actionLink  = $this->Html->link("詳細",     ['action'=>'view',  $user->id]) . " ";
$actionLink .= $this->Html->link("変更",     ['action'=>'edit',  $user->id]) . " ";
$actionLink .= $this->Form->postLink("削除", ['action'=>'delete',$user->id], ['confirm' => __('Are you sure you want to delete # {0}?', $user->id)]);
?>

<?php /* 左側の操作の列 */ ?>
<td class="actions"><?= $actionLink ?></td>
   :
   中略
   :

<?php /* 右側の操作の列 */ ?>
<td class="actions"><?= $actionLink ?></td>

 
 

上記のソースコードで不具合が発生する原因

 
このような記述をすると、「$this->Form->postLink()」で生成される formタグの name(「<form name=”post_691428....”」の部分)が同じものが 2つ生成されるのです。
 
「name」の IDが同一なものが複数あるため、いざ処理を実行しようとすると、ブラウザはどちらの formタグの処理を実行すればいいのかが分からないため、処理の継続ができなくなる、という不具合でした。
(不具合が発生するのは「$this->Form->postLink()」だけで、「詳細」「変更」のリンクはただのリンクなので、いくつ複製しても全く問題ありません。)
 
 

不具合を解決するソースコード

 
解決策としては、下記のように出力の都度「$this->Form->postLink()」を実行することです。(もう少しスマートな書き方はできますが...)
 

<?php
$actionLink  = $this->Html->link("詳細",     ['action'=>'view',  $user->id]) . " ";
$actionLink .= $this->Html->link("変更",     ['action'=>'edit',  $user->id]) . " ";
$actionLink .= $this->Form->postLink("削除", ['action'=>'delete',$user->id], ['confirm' => __('Are you sure you want to delete # {0}?', $user->id)]);
?>

<?php /* 左側の操作の列 */ ?>
<td class="actions"><?= $actionLink ?></td>
   :
   中略
   :

<?php
$actionLink  = $this->Html->link("詳細",     ['action'=>'view',  $user->id]) . " ";
$actionLink .= $this->Html->link("変更",     ['action'=>'edit',  $user->id]) . " ";
$actionLink .= $this->Form->postLink("削除", ['action'=>'delete',$user->id], ['confirm' => __('Are you sure you want to delete # {0}?', $user->id)]);
?>

<?php /* 右側の操作の列 */ ?>
<td class="actions"><?= $actionLink ?></td>

 
 

リンクをクリックしても動作しなかった時の詳細な状況

 
今回発生した事象について、どのような状況が発生していたか、改めて説明します。
(似たような症状が発生した方が確認するための情報として書いておきます。)
 

リンクをクリックしても PHPのエラーログは出力されない

 
まず、PHPのエラーログは出力されません。
 
「$this->Form->postLink()」で生成される処理は、JavaScriptを利用して、POSTする処理となっています。
 
そのため、JavaScript側の不具合か、PHP側の不具合か、を見極めるために、PHP側の関数にログを出力する処理を追加しました。
 
しかし、ログは出力されなかったため、PHP側ではなく、その処理に到達するまでに不具合があることを確認しました。
 
 

ChromeのDevToolsのコンソールにエラー出力

 
そのため、今度は Chromeの DevToolsを起動し、実行すると、下記のエラーが発生していることを確認しました。
 

VM597 users:1 Uncaught TypeError: document.post_9999999999.submit is not a function
    at HTMLAnchorElement.onclick (VM597 users:1:82)
onclick @  VM597 users:1

 

if (confirm(this.dataset.confirmMessage)) { document.post_9999999999.submit(); } event.returnValue = false; return false;

 
 
上記のエラーはざっくりとは下記の内容です。
『JavaScriptが「document.post_9999999999」という名前の HTMLフォーム要素を見つけ、その.submit()メソッドを呼び出そうとしました。
しかし、JavaScriptがこの名前の要素を見つけることはできました。』
 
そして、エラーの内容を ChatGTPや Google Geminiに聞いても
「CSRFトークンが欠落している(最も可能性が高い)」
「JavaScriptが正しく実装されていない」
と言った返答をするだけで、正しい解決策には至りませんでした。
 
 
そして、いろいろ確認していく中で、『「document.post_9999999999」を見つけられない』原因が、「document.post_9999999999」が 2つあるためであることを認識し、問題を解決することができた、ということになります。
 
 

「postLink()」で発生した不具合の対処のまとめ

 
今回の不具合は、「$this->Form->postLink()」で生成される HTMLのソースを変数に入れ、複数個所で echoすることで、同一の IDをもつフォームが生成されることが原因でした。
 
 
最近は、不具合が発生しても生成AIが答えてくれるため、このブログに記事を書く必要性を感じなくなりましたので、しばらく記事を書いていませんでした。
ですが、今回の不具合は、おそらく過去に記事として書かれたことがない不具合なのだろうと思いましたので、こうして記事にすることにしました。
 
CakePHPのデフォルトテンプレートの一覧表は、項目が多いとスクロールが表示される仕様になっています。
そのため、今回の私のように、表の左右に「操作」の列を作りたいと思う方もそれなりにいるのではないか、と思いますが、同じような不具合が発生したときの一助になれば、と思っています。

 - CakePHP 3.x 4.x 5.x , ,

最後までお読みいただきましてありがとうございます。
この記事が参考になったと思いましたらソーシャルメディアで共有していただけると嬉しいです!

Message

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

下記の空欄を埋めてください。 * Time limit is exhausted. Please reload CAPTCHA.

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

※入力いただいたコメントは管理者の承認後に掲載されます。

  関連記事

CakePHP3でシェルを作成しコマンドラインから実行・CakePHP2との違い
CakePHP3でシェルを作成しコマンドラインから実行・CakePHP2との違い

CakePHP3のシェルスクリプトを作成し、コマンドラインから実行する方法を解説。複数単語をつなげる場合の対応方法がCakePHP2より制限が厳しくなったのでCakePHP3の命名規則の確認が必要だ。

CakePHP3にOGPをfetch、asignを利用してテンプレートごとに指定する方法を解説
CakePHP3にOGPをfetch、asignを利用してテンプレートごとに指定する方法を解説

CakePHP3でOGPを設定する方法を解説。fetch、assignを使用しレイアウトファイルに編集した変数にテンプレートファイルから値を指定する。これを利用してOGPを編集する。

CakePHP3のユーザ管理・認証プラグイン CakeDC/Usersの導入・機能解説・3.1.5対応
CakePHP3のユーザ管理・ログイン認証プラグインCakeDC/Usersのインストール解説・3.6以降対応

CakePHP3のユーザ管理プラグイン Usersは、ユーザ登録、メール認証、ログイン認証、ユーザ管理、権限管理、reCAPTCHAなど会員制のサイトを簡単に実現可能。その導入方法、カスタマイズ方法を解説。

CakePHP3のキャッシュをクリアする方法「bin/cake cache clear_all」を使う
CakePHP3、CakePHP4のキャッシュをクリアする方法「bin/cake cache clear_all」を使う

CakePHP3、CakePHP4では処理を高速化する手法の一つとしてキャッシュを利用している。しかし、その情報は元の情報を更新しても反映されない場合がある。そんなときはキャッシュを削除する必要がある。

CakePHP3で静的ページの作成は webrootか pagesを使う。トップページを参考に解説
CakePHP3で静的ページの作成は webrootか pagesを使う。トップページを参考に解説

CakePHP3で静的なページを設置する場合の方法(webrootとpagesとを活用する方法)を解説。pagesの解説はデフォルトのトップページがどう表示されているかを参考に解説。ルーティングの機能も。

CakePHP4系、5系でカラムを指定して値があるかないかのチェックする
CakePHP4系、CakePHP5系のexists()でカラムを指定して値の有無をチェックする方法解説

CakePHP4、5で指定したカラムに特定の値に該当のレコードの有無をチェックするにはexists()を使う。単純にカラムを指定する方法から複数条件をand、orで探すこともできる。

CakePHP3ログファイルの出力方法・$this->log()の解説
CakePHP3ログファイルへの出力・$this->log()、独自ログへの出力方法の解説

コントロール、モデルの変数の中身を見るときはログに出力する方法が有効です。$this->log()を利用すると変数だけじゃなく、連想配列、オブジェクトも簡単にログ出力ができます。

CakePHP3にデザインテンプレートBootstrapを導入する方法・friendsofcake/bootstrap-ui使用
CakePHP3にデザインテンプレートBootstrapを導入する方法・friendsofcake/bootstrap-ui使用

CakePHP3にプラグイン「friendsofcake/bootstrap-ui」、デザインテンプレート「Bootstrap」を設置する手順を解説。Bootstrapの簡単な使い方やデフォルトのデザインとの混在方法なども解説。

CakePHP3にWYSIWYGエディタのCKEditor4を設置、カスタマイズ方法を解説
CakePHP3にWYSIWYGエディタのCKEditor4を設置、カスタマイズ方法を解説

WYSIWYGエディタであるCKEditor4をCDNを利用して簡単にCakePHP3に導入する方法とカスタマイズする方法を解説。CakePHP3にはページごとの振り分けを行うブロック化を利用する。

CakePHP3で保存前にバリデーション結果を取得する2つの方法
CakePHP3で保存前にバリデーション結果を取得する2つの方法

CakePHP3でデータベースに値を保存する前にバリデーションを行い、その結果によって処理を振り分ける方法について解説。「$topic->errors()」と「$topic->hasErrors()」の2つの方法がある。