CakePHP5入門【CakePHP5実用編④】チャットルーム

A子
「bake all」で作っちゃっても大丈夫だよね?

C菜
あ、ただ発言内容(テーブル名は「comments」)のほうは、「bake model」だけにしたほうが良いんじゃないでしょうか~?

A子
んじゃ、さっそくbakeコマンドを叩きますか
cd html/authapp[Enter]
bin/cake bake all chat_rooms[Enter] bin/cake bake model comments[Enter] |
で、どう?





B美
テーブルの項目名って、工夫することでコード修正の手間が軽減されるのよね
(言い換えれば、法則性を無視した名付けを行うとコード修正の手間が発生するってことなんだけど…)

A子
どういうことよ

B美
・「src/Model/Entity」の中に生成された「ChatRoom.php」及び「Comment.php」
・「src/Model/Table」の中に生成された「ChatRoomsTable.php」及び「CommentsTable.php」 ・「src/Controller」の中に生成された「ChatRoomsController.php」 |
これらのファイルには、なぞの「admin」や「room」という項目名や「Admins」や「Rooms」というクラス名が(存在しないのに)指定されてるから…(苦笑)








C菜
「chat_rooms」テーブルの外部キー「admin_id」、「comments」テーブルの外部キー「room_id」が原因じゃないですか~?
(おそらく「comments」テーブルのもう一つの外部キーである「user_id」は問題ない気がします~)

B美
さすがはC菜ね
外部キー項目の名前って、「参照先のテーブル名の単数形+'_id'」にするのがCakePHPの「命名規則」なの
(「admin_id」は「user_id」に、「room_id」は「chat_room_id」にすべき…ってこと)
まぁ、(規則に反していても)bake後に手動で修正していけば良いだけなんだけどね(苦笑)

A子
まぁ良いわ
とりあえずはModel関係のファイルを修正していこう
Entityファイルからは存在しない項目名を削って、Tableファイルのほうは「Admins」を「Users」に、「Rooms」を「ChatRooms」に変更しただけなんだけどね
(「ChatRoomsController.php」については、あとで変更するよ)







C菜
(「ChatRoom.php」と「Comment.php」のことです~)

B美
(コントローラの処理内容によっては、問題が発生する場合もあるけど…)
まぁ、あまり気にすることは無いわ

C菜
それでは次に見栄えを整えましょう~
「templates/ChatRooms」の中にある「index.php」「add.php」「edit.php」「view.php」を書き換えますね~
(「templates/Users」の中にある同名のファイルを参考にして…)
まずは「index.php」からです~



A子
(注意点としては、「Users」をcontainすることかな)
あ、検索条件としては、削除フラグ(delete_flag)が「0」であるもの…って指定したからね
(削除されたレコードの「delete_flag」には「1」が入る…ってこと)


C菜
ポイントは下のほうにあるhidden(隠し)属性の二行ですよ~


A子


C菜


A子
こっちもほとんど修正してないわ


C菜


A子


B美

A子
「ChatRoomsController.php」の「delete」メソッドがこれね


B美
「contain」に「Users」を指定しているのは、「chat_rooms」テーブルと「users」テーブルを「結合(Join)」するためよ
(【CakePHP5基礎編⑦】を参照)
まぁ、ユーザ情報については全く使っていないみたいだけど…(苦笑)

C菜
えっと~
「$chatRoom->handle_name」で良いんでしょうか~?

B美
まずは「チャットルーム作成」を行ってみなさい
そのあと「表示」をクリックしてね

↓


C菜

B美
「chatRoom」という項目の右端にある右三角をクリックすると詳細な内容が表示されるから、その中の「user」という項目の右三角をクリック
その中にある「handle_name」という項目の値を見てちょうだい

↓


A子
んー
てことは、「$chatRoom->user->handle_name」ってことかな?

C菜
「view.php」を書き換えてから、ブラウザで確認してみるです~

↓


A子
それじゃ、同じように「index.php」のほうにも管理人のハンドルネームを表示してみようか
あれ?
「results」の中の「items」までは出るけど、その中身が出ないよ


B美
これを変えたければ、「config」ディレクトリの中の「bootstrap.php」か「app.php」または「app_local.php」に設定を追記すれば良いわ
そうねぇ
簡単なのは「app_local.php」の末尾に以下の一文を追加することかしら
(これにより、デフォルトの5階層から8階層へと変更されるわ)
'DebugKit.variablesPanelMaxDepth' => 8, |
あ、「bootstrap.php」のほうで設定する場合は以下の一文だから間違えないようにね
Configure::write('DebugKit.variablesPanelMaxDepth', 8); |
あと、これは両方を設定するんじゃなくて、どちらか一方だけ設定すればOKだから
(私は「app_local.php」のほうに書くけどね)


C菜


A子
(「user」から、たどれるってこと)
…ってことは、「index.php」をこう書き換えよう


B美
一点だけ問題があるわ
<?= $this->Paginator->sort('handle_name', '管理人') ?> |
の箇所だけど、
<?= $this->Paginator->sort('Users.handle_name', '管理人') ?> |
に変更してね

↓


A子

B美
これによって「管理人」という項目名のクリックで、ハンドルネームにもとづくソートが可能になるのよ
「なんて簡単な!」って思ったでしょ?

A子
ただ、知らないとハマりそうだけど…(苦笑)

C菜
あ、あと管理人以外は「編集」や「削除」ができないようにしましょう


B美
その場合、リンクの表示・非表示だけじゃなく、「edit」や「delete」のメソッド側のほうも変更しておきなさいね
(リンクが表示されてなくても、直接URLで指定される可能性もあるんだから…)

C菜
こんな感じでいかがでしょう~?



A子
その結果って「ChatRoomsController」クラスのほうで利用できないの?
(下記参照)


C菜
だったら、親クラス側にフィールドを定義しておいて、そこに「getIdentity」メソッドの戻り値を代入しておけば良いんじゃないでしょうか~?
class AppController extends Controller
{ public function beforeFilter(\Cake\Event\EventInterface $event) { parent::beforeFilter($event); $identity = $this->Authentication->getIdentity(); $this->set(compact('identity')); } |
の箇所を
class AppController extends Controller
{ private $identity; public function beforeFilter(\Cake\Event\EventInterface $event) { parent::beforeFilter($event); $this->identity = $this->Authentication->getIdentity(); $this->set('identity', $this->identity); } |
という風にするんですよ~

A子
だったら、さっきの「edit」メソッドと「delete」メソッドの中にあった
$identity = $this->Authentication->getIdentity();
if ($chatRoom->admin_id != $identity->id) { return $this->redirect(['action' => 'index']); } |
の箇所を
if ($chatRoom->admin_id != $this->identity->id) {
return $this->redirect(['action' => 'index']); } |
に変更できるね
(よりシンプルになる)

C菜
…って、めっちゃエラーです~(泣)


B美
「AppController」クラスに追加したフィールド「$identity」に付けている「private」って、自分自身(「AppController」クラス)からしかアクセスできないことを意味するのよ

A子
んじゃ、子クラスにもそのフィールドを引き継ぐにはどうすりゃ良いのさ?

B美
「private」ではなく「protected」にするだけ
class AppController extends Controller
{ private $identity; |
を
class AppController extends Controller
{ protected $identity; |
に変更すればOKってこと
ちなみに、もう一つ「public」という修飾子もあるけど、これはフィールドに付けちゃダメなやつだからね
(「フィールド隠蔽」の考え方に反するので…【CakePHP5基礎編②】を参照)
あと、勘違いしてるみたいだから指摘しておくけど…
親クラスのprivateフィールドであっても、子クラスには引き継がれるわよ
ただ、「子クラスからはアクセスできない」フィールドになる…ってだけね

A子
んじゃ、そういう風に書き換えてっと
おぉ!
ばっちり動いたよ




C菜
(「$this->identity」という形で…)
完璧です~