Friction River Software

  • お問い合わせ

CakePHP5入門【CakePHP5実用編⑨】ユーザ登録申込み①

A子

ねぇ、現状って、ユーザの新規登録(追加)は(BASIC認証を通過した)管理者しかできないよね

誰でもユーザ申込みを行うことができて、(申し込んだ人が)勝手にユーザ登録されるようにはできないかな?

B美

できるけど、いたずらも増えるわよ
(本番環境に公開したあとの話だけど)

そもそも(存在しない)適当なメールアドレスで申し込むかもしれないし…

C菜

申し込み時に、そのメールアドレス宛に確認メールを送るようにしたらどうでしょうか~?

そうすれば存在しないメールアドレスや、他人のメールアドレスを使うことはできなくなりますよね~?

A子

お、良いねぇ

システム側は申込者専用のURLを作って、それをメールに記載して送信
メールを受け取った申込者は、そのURLリンクをクリックすることで確認ページに到達するって感じで…

あと、時間制限も設ければ完璧じゃない?

B美

そのユーザって、正規ユーザと同じ扱いにするの?

チャットルームの新規作成や削除をする権限を与えるのかってことだけど…

C菜

お試しユーザということにして、チャットに参加することはできますけど、チャットルームを新規作成することはできないようにしましょう~

でもそうすると、「users」テーブルの構造も変えなきゃですね~

A子

うーん
「管理者」「一般ユーザ」「お試しユーザ」の3種類にして

管理者…何でもできる特権ユーザ
一般ユーザ…ユーザ管理以外は全てOK(チャットルームの作成も可)
お試しユーザ…チャットルームに入室して、発言だけ可能

…って感じで、どうかな?

あ、当然「users」テーブルには項目を一つ追加するよ
int型の「role_num」って項目名でどう?

C菜

良いと思います~

あと、「管理者」はユーザ管理画面の中で、「お試しユーザ」を「一般ユーザ」に昇格させることができるようにしましょう~

B美

最初に登録したユーザが自動的に「管理者」になるのは当然として…

複数の「管理者」権限を許可するの?

A子

それは難しいところだよね

本来は「一人だけ」にすべきだろうけど、もしも一人しかいない「管理者」が突然失踪したりすると…(笑)

C菜

ですね~

「管理者」は、他のユーザを「管理者」に任命(というか昇格)できるようにしましょうよ~

A子

「保険」って意味でも、そのほうが無難かな

んじゃ、まずは「users」テーブルの修正からね

create table users (
    id int auto_increment primary key,
    email varchar(255),
    password varchar(255),
    status int,
    session varchar(255),
    login_time datetime,
    logout_time datetime,
    role_num int,
    created datetime,
    modified datetime
);

で、どうかな?

C菜

その項目(role_num)に格納する値ですけど、定数化しましょう~
(「config/const.php」ファイルに追加)

define("ADMIN", 1);    //管理者
define("NORMAL", 2);    //一般ユーザ
define("GUEST", 3);    //お試しユーザ

B美

ふむ、良いわね
それじゃ、とりあえず「ALTER TABLE」で「users」テーブルに項目を追加したあと、関連のControllerコントローラーViewビューを修正してみなさい

あ、多分だけどModelモデルである「User.php」や「UsersTable.php」の変更は必要ないと思う
(キャッシュクリアは必要だけど…)

C菜

わかりました~

まずは「ALTER TABLE」です~
えっと「MATE端末」を開いてから「mysql」コマンドを叩きますね~

mysql -u root -p chatdb[Enter]

ALTER TABLE users
    ADD role_num int AFTER logout_time;[Enter]

B美

念のため、テーブルスキーマを確認しておきましょうか

show fields from users;[Enter]

A子

うん、問題ないみたいだね
んじゃ、何はともあれキャッシュクリアをやっておこう

cd html/authapp[Enter]
bin/cake cache clear_all[Enter]

C菜

ではViewビューから修正していきますね~

「templates/Users」の中にある「index.php」「view.php」「edit.php」だけで良いでしょうか~?

A子

ん?
add.php」は良いの?

C菜

ユーザ管理画面におけるユーザの新規作成(add.php)については、デフォルトとして「一般ユーザ」になるようにしましょう~
(最初のユーザ作成である「first_user.php」で登録した人が、自動的に「管理者」になるのと一緒です~)

A子

なるほどねー

あ、先に「config/const.php」の中に定数を追加しておこう

C菜

「role_num」の値に基づいて「管理者」や「一般ユーザ」と表示するわけですが、if文や三項演算子で記述するのが面倒です~

B美

ふむ、そういうときは配列を定数化しておくと良いわよ

define("ROLE_NAME", ["-", "管理者", "一般ユーザ", "お試しユーザ"]);

とすれば、「ROLE_NAME[$user->role_num]」で簡単に表示できるから…
(配列の添字がゼロから始まることに注意してね)

A子

へぇー

もしかして連想配列も定数化できるの?

B美

もちろん!

define("定数名", ["キー1" => "値1", "キー2" => "値2", "キー3" => "値3", ・・・]);

…って感じね

C菜

えっと~、それって前に習いましたよ~
(【コラム③】を参照)

A子

あれ?

そうだったっけ?(汗)

B美

私も忘れてた…(苦笑)

C菜

それはともかくとして、配列の定数化をやってみるです~

C菜

まずは「index.php」から修正していきますね~

wide表示のほうだけ「ユーザ権限」を表示しましょう~
(narrow表示のほうは以前のままです~)

A子

view.php」も簡単だね

B美

うーん
「role_num」がnullであるときの対応を記述しているのは大したものだけど、実際にはnullになることは無いと思うわよ

なので、既存のユーザの「role_num」をSQL文でセットしてからテストしたほうが良いかもね

mysql -u root -p chatdb[Enter]

UPDATE users SET role_num=1 WHERE id=1;
UPDATE users SET role_num=2 WHERE id=2;
UPDATE users SET role_num=3 WHERE id=3;

これで私(B美)が「管理者」、A子が「一般ユーザ」、C菜が「お試しユーザ」になるわ

C菜

さっきの「index.php」と「view.php」ですけど、もっとシンプルな感じに書き換えたほうが良いでしょうか~?

B美

いいえ

わざわざ書き換える必要は無いわよ
(蛇足にはなるけど、「念のため」という観点では悪くないしね)

A子

んじゃ、あとは「edit.php」だね

「ユーザ権限」をラジオボタンで選択できるようにしたいんだけど、どうすれば良い?

B美

こんな感じかな

<?= $this->Form->radio('role_num', [
    ['value' => 1, 'text' => ' '.ROLE_NAME[1]],
    ['value' => 2, 'text' => ' '.ROLE_NAME[2]],
    ['value' => 3, 'text' => ' '.ROLE_NAME[3]],
], [
    'label' => ['style' => 'display: block;margin-bottom: 5px;']
]) ?>

これで現在の(role_numの)値によって自動的に選択状態になるの
(ちなみに、style指定しているところがポイントね)

A子

ん?
どういうこと?

B美

普通に書くと、実行結果は(各項目の並びが)「横一列」になっちゃうからね

上記のようにstyle指定すると、三つの項目が「縦方向」に並ぶってわけ
(あと、ROLE_NAMEの左の「' '.」は、黒丸とラベルがくっつき過ぎないように付けてるだけ)

C菜

あの~

よくよく考えると、パスワードの変更は「本人のみが行えるように」すべきではないでしょうか~?
(管理者の権限で変更できるのは「ハンドルネーム」と「ユーザ権限」だけにして…)

A子

ログインした本人専用の「パスワード変更画面」を作るってことだね
うん、そのほうが良いかも…

それじゃ、「edit.php」を「change_password.php」というファイル名で保存して、不要な部分を削除だね

C菜

そのあと、「edit.php」の中からパスワードに関する箇所を削除するです~


B美

ブラウザで確認すると、こんな感じね

A子

「パスワード変更」画面へのリンクはトップページに作ろう
(具体的には「templates/Top」の中にある「index.php」ね)



C菜

「src/Controller」の中にある「UsersController.php」にメソッドを追加しますね~

public function changePassword()
{
    $user = $this->Users->get($this->identity->id, contain: []);
    if ($this->request->is(['patch', 'post', 'put'])) {
        $user = $this->Users->patchEntity($user, $this->request->getData());
        if ($this->Users->save($user)) {
            $this->Flash->success(__('パスワードを変更しました。'));

            return $this->redirect(['controller' => 'Top', 'action' => 'index']);
        }
        $this->Flash->error(__('パスワードの変更に失敗しました。'));
    }
    $this->set(compact('user'));
}

ポイントは、メソッド名が(「change_password」ではなく)「changePassword」であることと、「$this->identity->id」で自分自身のidを取得していることですね~

A子

良いんじゃない?

あとは「最初のユーザ作成(first_user.php)」と「ユーザ登録(add.php)」について、「src/Controller」の中にある「UsersController.php」を修正するだけだね
(「firstUser」メソッドと「add」メソッドね)


C菜

それではテストしてみるです~

データベースを初期化するために以下のコマンドを打ち込みますね~

mysql -u root -p chatdb[Enter]
drop database chatdb;[Enter]
quit[Enter]
mysql -u root -p < chatdb.sql[Enter]
cd html/authapp[Enter]
bin/cake cache clear_all[Enter]

あ、もちろん「chatdb.sql」には「users」テーブルに「role_num」の項目を追加済みです~



A子

ブラウザで「https://192.168.1.205/authapp」にアクセスしてっと…

最初のユーザとして私(A子)を登録したよ
そのあと、ユーザ管理画面に入って、「新規ユーザ登録」でB美とC菜の二人を登録した

C菜

A子社長が「管理者」で、B美部長と私(C菜)が「一般ユーザ」になってますね~

ここからB美部長を「管理者」にできますか~?

A子

やってみよう

うん、バッチリ昇格できたみたい

B美

あ、そうだ

「管理者」でないと「ユーザ管理画面」へのリンクが出現しないようにして、さらに「UsersController.php」でも管理者チェックを行うようにしておきなさいね

A子

分かったよ

まずは「UsersController.php」だけど、管理者用のメソッドである「index」「view」「add」「edit」「delete」の五つについて、管理者権限があるかどうかのチェックを入れよう

C菜

チェックメソッドをprivateメソッドとして別に作って、それを呼び出すようにしたらどうでしょうか~?

A子

ふむ、たしかにそのほうが良さげだね

private function checkAdmin()
{
    if ($this->identity->role_num != ADMIN) {
        $this->Flash->error(__('管理者以外はアクセスできません。'));

        return $this->redirect(['controller' => 'Top', 'action' => 'index']);
    }
}

これをさっきの五つのメソッドから呼び出すよ

$this->checkAdmin();

上記の一文を各メソッドの先頭行に追記ね


B美

ふむ、本当はBASIC認証のミドルウェア(HttpBasicAuthMiddleware.php)側で制御したいところだけどね

まぁ、難しくなっちゃうからそこまでは求めないわ
(A子のやり方のほうがシンプルで分かりやすいし…)

C菜

あとは、管理者ページへのリンクを管理者だけに表示するようにしましょう~

「templates/Top」の中にある「index.php」を修正するです~

<?php if ($identity->role_num == ADMIN) { ?>
    ・・・
<?php } ?>

を使って「ユーザ管理」へのリンクタグを囲みますね~

B美

うん、テストした結果もバッチリね

ただ、ちょっと長くなっちゃったから、お試しユーザの自動登録機能は次回に回しましょう

A子

OK

C菜

了解です~