CakePHP5入門【CakePHP5実用編⑬】ブラッシュアップ

B美
そろそろインターネット上に公開する?

A子
いや、もう少し機能強化を進めていこう

C菜

A子
あと、テーブルのフェッチをスーパークラスである「AppController」クラスにまとめちゃおう
(今は各クラスの「initialize」メソッドで個別にフェッチしてるけど…)

B美

A子

B美
プログラムの動作を変えずに、ソースコードのムダを省いたり、効率化することよ

C菜
あと、Webアプリケーションの名称を正式決定しましょう~
(バージョンを「1.0.0」にしたり、「DebugKit」アイコンを消したりも…)

B美
(「おしゃべりしよう」って意味で…)
あ、それから前回(チャットルームの入室制限)は口出ししなかったけど、例外リストに表示するユーザの並び(表示順)はあれで良いの?

C菜
「ユーザID(メールアドレス)」か「ハンドルネーム」の昇順にしたほうが良いかもです~

A子
よし、それじゃ、まとめるよ
1.「chat_rooms」テーブルに「text」型の項目(description)を追加する
2.テーブルのフェッチを「AppController」クラスで行う(フィールドは「protected」にする) 3.「config/const.php」でシステム名称を「Be Chattering」に、バージョンを「1.0.0」にする 4.「DebugKit」アイコンを非表示にする 5.例外リストに表示するユーザの一覧を「ユーザID(メールアドレス)」の昇順でソートする |
…くらいかな?

C菜
あ、各ユーザの人物アイコンって、チャット画面上に表示できないでしょうか~?
(LINEみたいに…)

B美
(掲示板アプリのときの話)

C菜
あれを応用すれば良いんですね~

A子

B美
まぁ、画像ファイルのようにブラウザキャッシュも効かないし、画像データ読み出しの処理が(システムにとっての)負担になるからお勧めしないけど…

A子
あ、「users」テーブルの主キーである「id」の値を使ってファイル名を付けるのはどうかな?
(「1.png」とか「2.png」のように)

C菜
それなら「users」テーブル内にファイル名(及びファイルパス)を保存するための項目を追加しなくて済みますね~

A子
人物アイコンの画像ファイルを格納するディレクトリは固定しておいて、かつファイル形式(拡張子)もPNGに決め打ちしておけば、さっきの「idをファイル名にする方法」でいけるじゃん

B美
だったら、ユーザの新規作成時にデフォルトの画像を割り当てるって方法が良いかもね
そうすればファイルの存在確認(file_exists関数)も不要になるし…

C菜
それって、Windowsのユーザアイコンと同じ考え方ですよね~

…って、やつです~

A子
まとめると
1.「chat_rooms」テーブルに「text」型の項目(description)を追加する
2.テーブルのフェッチを「AppController」クラスで行う(フィールドは「protected」にする) 3.「config/const.php」でシステム名称を「Be Chattering」に、バージョンを「1.0.0」にする 4.「DebugKit」アイコンを非表示にする 5.例外リストに表示するユーザの一覧を「ユーザID(メールアドレス)」の昇順でソートする 6.各ユーザの人物アイコンを実装する |
…ってことだね
6番以外はすぐにできるから、ちゃっちゃとやっちゃおう

C菜
1.「chat_rooms」テーブルに「text」型の項目(description)を追加する |
「chat_rooms」テーブルのテーブル定義はこうしましょう~
create table chat_rooms (
id int auto_increment primary key, theme varchar(255) not null, description text, admin_id int not null, delete_flag int not null, access_policy int, created datetime, modified datetime, foreign key(admin_id) references users(id) ) charset=utf8mb4; |
んで、「ALTER TABLE」はこうです~
mysql -u root -p chatdb[Enter] |
ALTER TABLE chat_rooms
ADD description text AFTER theme;[Enter] |


A子
cd html/authapp[Enter]
bin/cake cache clear_all[Enter] |


C菜
(忘れないうちに…)
'description' => true, |


A子

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

↓


A子
「edit.php」のほうも全く同じで良いかな?


C菜
あとは「index.php」と「view.php」ですけど、これで良いでしょうか~?
(「index.php」のほうは、narrow表示のときだけ説明文を表示しています~)



B美
んじゃ、次は2番よ
2.テーブルのフェッチを「AppController」クラスで行う(フィールドは「protected」にする) |

A子
具体的には「ApplicantsController.php」「ChatController.php」「ChatRoomsController.php」「TopController.php」の4つだね
これを「AppController.php」に集約するよ
protected $Users;
protected $Comments; protected $ChatRooms; protected $Exceptions; public function initialize(): void { ・・・ $this->Users = $this->fetchTable('Users'); $this->Comments = $this->fetchTable('Comments'); $this->ChatRooms = $this->fetchTable('ChatRooms'); $this->Exceptions = $this->fetchTable('Exceptions'); } |
あ、もちろん「ApplicantsController.php」「ChatController.php」「ChatRoomsController.php」「TopController.php」のほうは、privateフィールドと「initialize」メソッドを削除したからね



C菜
3.「config/const.php」でシステム名称を「Be Chattering」に、バージョンを「1.0.0」にする |
これはすぐに済みますね~
あ、「HEAD_MAIN」だけじゃなく「APPLICATION_NAME」も同じ名前にしていますよ~



A子
4.「DebugKit」アイコンを非表示にする |
これもすぐに終わるよ
「config」の中にある「app_local.php」を書き換えるだけ…


C菜
5.例外リストに表示するユーザの一覧を「ユーザID(メールアドレス)」の昇順でソートする |
「src/Controller」の中にある「ChatRoomsController.php」の「add」メソッドと「edit」メソッドの記述を書き換えますね~
$users = $this->Users->find()->all(); |
$users = $this->Users->find()->order(['email' => 'ASC'])->all(); |



B美
さて、最後は6番ね
6.各ユーザの人物アイコンを実装する |
これが一番の問題なわけだけど…

A子
LINEの場合はどうだったっけ?

C菜
最低でも480ドット×480ドットらしいですよ~

B美
例えば100ドット×100ドットくらいで…

A子
単なるアイコン画像なんだから、もっと小さくても良いくらいだね

C菜
というわけで、Windowsの「ペイント」を使ってデフォルト画像を作ってみたです~


A子
てか、Windowsアイコンの丸パクリだけど(笑)

C菜
創作性の有無が微妙なので、著作権は発生しないかもしれませんけど~(苦笑)

A子
cd html/authapp/webroot[Enter]
mkdir personal[Enter] |
で良いかな?


C菜
で、さっき「ペイント」で作った画像ファイルをアップロードしますね~
同じファイルをアップロードするつど、ファイル名を変更していくことで、5つのファイルを作りましたよ~
(現時点で4人のユーザがいるので、それぞれの分と、あとデフォルト画像として…)


A子
うーん、その処理も書かないと…

B美
具体的には、「UsersController.php」のほうは「firstUser」メソッドと「add」メソッド、「ApplicantsController.php」のほうは「finalCheck」メソッドね

A子
(子クラスである「UsersController.php」や「ApplicantsController.php」から呼び出せるように…)

C菜
「protected」じゃないと~

B美
それじゃ、やってみなさい

A子
(もちろん、「AppController.php」の中ね)
protected function copyImage($id = null): void
{ if (!is_null($id)) { $webroot = WWW_ROOT; $src = $webroot.'personal'.DS.'default.png'; $dst = $webroot.'personal'.DS.$id.'.png'; copy($src, $dst); } } |
で、このメソッドを「UsersController.php」や「ApplicantsController.php」から、こう呼び出すよ
$this->copyImage($user->id); |


B美
コード自体に問題は無いわ(多分…)
でも、これって必ず失敗するわよ

A子
なんでよ

C菜
あっ、パーミッションです~

B美
さっき作ったディレクトリって、Webサーバ(www-data)の書き込み権限が無いのよね
(パーミッションを変更するか、ディレクトリのオーナーを変更しないと…)
さらに言えば、さっきコピーしたテストデータのパーミッションも問題よ
(Webサーバが上書き処理できないから…)

C菜
cd html/authapp/webroot[Enter]
su[Enter] chown www-data:www-data personal[Enter] cd personal[Enter] chown www-data:www-data *[Enter] exit[Enter] |
で、どうでしょうか~


A子
んじゃ、あとは「UsersController.php」の「firstUser」メソッドと「add」メソッド、「ApplicantsController.php」の「finalCheck」メソッドに追記するよ




B美
次は、チャット画面の中に人物アイコンを表示する処理を書いてみなさいね

C菜
「templates/Chat」の中にある「index.php」を書き換えますね~
・・・

C菜
ふぅ~、めちゃくちゃ大変でした~
まずは過去の履歴を表示する箇所ですけど~
<!-- 他人の発言 -->
<div class="fixed-size-image"> <figure class="image"><?= $this->Html->image("/personal/{$comment->user->id}.png", [ 'width' => '100', 'height' => '100', 'class' => 'is-rounded' ]) ?></figure> </div> <div class="message received"> <p><strong><?= $comment->user->handle_name ?></strong></p> <p><?= $comment->content ?></p> </div> |
これに絡めてCSSのクラス定義を追加します~
.fixed-size-image {
width: 100px; height: auto; max-width: 100px; max-height: 100px; object-fit: contain; } |
んで、JavaScriptの関数部分がこれです~
function addMessage(senderId, user, message) {
const chatBox = document.getElementById("chat-box"); const msgDiv = document.createElement("div"); msgDiv.classList.add("message"); if (senderId == userId) { msgDiv.classList.add("sent"); //自分のメッセージ } else { msgDiv.classList.add("received"); //他人のメッセージ const image = document.createElement('img'); image.src = `/authapp/personal/${senderId}.png`; image.width = 100; image.height = 100; image.classList.add("is-rounded"); const imgDiv = document.createElement("div"); imgDiv.classList.add("fixed-size-image"); const figure = document.createElement("figure"); figure.classList.add("image"); figure.appendChild(image); imgDiv.appendChild(figure); chatBox.appendChild(imgDiv); } msgDiv.innerHTML = `<p><strong>${user}</strong></p><p>${message}</p>`; chatBox.appendChild(msgDiv); chatBox.scrollTop = chatBox.scrollHeight; } |













A子
さすがはC菜と言うべきか(苦笑)

B美
私とA子でチャットしてみるわね
まずは私から発言してみましょう
(左側が私で、右側がA子よ)


A子
(以下、交互に発言…)

↓

↓


C菜
個別の(異なる)アイコン画像にしないと、成功か失敗かが今一つわかりませんけど~(苦笑)

B美
んで、ちょっと長くなっちゃったから、今回はここまでね
(キリの良いところで…)
次回は、人物アイコン画像の変更処理をやっていきましょう

A子
たしかにちょっと疲れたよ…
(充実感はあるけどね(苦笑))