Laravel – ユーザー登録処理の流れ

登録フォーム表示

ルーティング定義

ルーティングファイルにAuth::routes();を記述することでユーザー認証関係のルーティングが自動設定される。その中には、以下の登録フォーム表示のルーティングも含まれている。

  • メソッド:GET
  • URL:register
  • アクション:Auth\RegisterController@showRegistrationForm
  • ルート名:register

アクション

RegisterControllerコントローラーはRegistersUsersトレイトを利用していて、その中でshowRegistrationFormアクションが定義されている。

RegistersUsersトレイトのshowRegistrationForm()アクションメソッドは以下の通りで、auth.registerビューをレンダリングしている。

auth.registerビューは初期状態では存在しないので、コマンドで生成するかカスタムで作成する必要がある

フォームからのPOSTと登録実行

ルーティング定義

ルーティングファイルへのAuth::routes();の記述によって、以下のルーティングも定義される。

  • メソッド:POST
  • URI:register
  • アクション:Auth\RegisterController@register

アクション

showRegistrationFormアクションと同じく、registerアクションもRegisterControllerでuseされるRegistersUsersトレイトで定義されている。

このアクションの動作は以下の通り。

  • マスアサインメント$request->all()のための$fillableapp\User.phpモデルで定義しておく
  • 入力されたフィールド群を検証するvalidator()メソッドで検証条件を定義
    • validator()RegistersUsersトレイトを利用する親元のRegisterControllersで定義
    • 戻り値のValidatorインスタンスのvalidate()メソッドで検証実行

  • RegistersUsersトレイトを利用する親元のRegisterControllercreate()メソッドを呼んでデータ作成
  • そのUserインスタンスを与えて登録済みのイベント発行

  • $this->registered()は登録確認のようだが、同じトレイトで空で定義されている
  • このため三項演算子のfalse側に書かれているredirect($this->redirectPath())returnの戻り値となる
  • redirectPath()RegistersUsersトレイトでさらにuseされたRedirectsUsersトレイトで定義されていて、
    • redirectTo()メソッドが定義されていれば実行
    • $redirectTo属性が定義されていればそこにリダイレクト
    • いずれでもなければ/homeにリダイレクト
  • 初期状態ではこのトレイトの親元RegisterController$redirectToが定義されているので、この内容(RouteServiceProvider::HOME)にリダイレクトされる

 

Laravel – Userモデル

概要

Laravelプロジェクト作成時にUserモデルのapp/User.phpファイルが自動作成される。この中で、認証関係について調べてみた。

User.phpファイルの内容

app/User.phpの内容は以下のとおり。

認証関係

  • UserクラスはModelクラスを(直接には)継承していない
  • UserクラスはAuthenticatableクラスを継承している
  • AuthenticatableクラスはIlluminate\Foundation\Auth\Userのエイリアスとして定義されている。

Illuminate\Foundation\Auth\Userクラス

UserモデルクラスがAuthenticatbleクラスとして継承しているIlluminate\Foundation\Auth\Userクラスの要点は以下のとおり。

  • Modelクラスを継承している(L14)
  • AuthenticatableContractインターフェイスを適用している(L15)
    • AuthenticatableContractIlluminate\Contracts\Auth\Authenticatableインターフェイスのエイリアス(L15)
  • AuthenticatableContractインターフェイスのメソッドは、Illuminate\Auth\Authenticatableトレイトで実装(L19, L5)

同じAuthenticatableという名前でインターフェイスとトレイトがあるのがややこしい。

Authenticatableインターフェース

Illuminate\Contracts\Auth\Authenticatableインターフェイスは、識別子やパスワード、セッションに関する6つのメソッドの実装を要請する。

Userクラスでこのインターフェイスを適用する際には、エイリアスでAuthenticatbleContractという別名で扱っている。

Authenticatableトレイト

Illuminate\Auth\Authenticatableトレイトは、Authenticatableインターフェイスで要請された6つのメソッドを実装する。

要約

要約すると、プロジェクトで生成されるUserクラスはIlluminate\Foundation\Auth\Userクラスを継承することによって、

  • Illuminate\Database\Eloquent\Modelクラスを継承している
  • Authenticatableインターフェイスの6つのメソッドを実装している
    • これにより、ユーザー認証と継続セッションの機能が実装される。

通知関係

UserモデルクラスはIlluminate\Notifications\Notifiableトレイトを実装している。

属性関係

$fillable

フォームのデータをマスアサインメントで取り込むための設定。

$hidden

モデルを変換する際に、指定した属性を含めないための指定。

$cast

データベースの読み込み時にstringから特定のデータ型にキャストするための指定。

マイグレーションファイル

Userモデルクラスファイルとともに、以下のマイグレーションファイルもLaravelにより生成される。

artisan migrateコマンドで生成されたテーブルの構造は以下のとおり。

ユーザー認証

基本的なユーザー認証の設定はこちらを参照。

また、ユーザー登録処理の内容ログイン処理の内容についてはそれぞれのリンクを参照。

 

Laravel6 – ユーザー認証

 

プロジェクト開始時に作成されるファイル

Userモデル

プロジェクトを作成すると、appディレクトリー下にUser.phpが作成される。

Userモデルの内容についてはこちらを参照。

コントローラー

プロジェクトを作成すると、Controllers/Authディレクトリー下に以下の認証用コントローラー群が自動的に作成される。

ルーティング設定

ユーザー認証のためのルーティング

プロジェクト作成後にUserモデルと必要なコントローラーはLaravelにより作成されるが、ルーティングは設定が必要になる。

ルーティングファイルに以下の1行を記載すると、ユーザー認証用の各種ルーティングがまとめて定義される。

ルーティングリスト

関係するルーティングは以下の通りで、ログイン関係とユーザー登録関係が定義されている。

ビューの作成

自動作成の場合

  • php artisan ui vue --authコマンドでユーザー認証に必要なビューを作成
  • 作成されるビューはresources/views/authディレクトリー下に配置

カスタムビュー作成の場合

authディレクトリーの作成

  • resources/viewsディレクトリー下にauthディレクトリーを作成
  • 作成したauthディレクトリー下に必要なビューを定められたファイル名と内容で作成

登録用フォームビューの作成~register.blade.php

authディレクトリー下に、以下フォームを含む内容でregister.blade.phpを作成。ビュー名はLaravelが生成するコントローラーで想定されているされるため、これに合わせる必要がある。

たとえばユーザー登録フォームのビュー名はRegisterControlleruseされているRegistersUsersトレイトshowRegistrationForm()メソッドにおいて、'auth.register'として呼ばれる。

ブラウザーからURL:ドメイン名/registerでアクセスすると以下のようなフォームが表示される。

カスタマイズしていない状態で登録ボタンを押すと、URL:ドメイン名/homeにリダイレクトされる(後述のように、そのままでは404エラーになる)。

ログインフォームビューの作成~login.blade.php

authディレクトリー下に、以下のフォームを含む内容でlogin.blade.phpを作成。

ブラウザーからURL:ドメイン名/loginでアクセスすると以下のようなフォームが表示される。

カスタマイズしていない状態で登録ボタンを押すと、URL:ドメイン名/homeにリダイレクトされる。

コントローラー設定

ログイン後の画面遷移

たとえばユーザーログイン後のトップページを'posts/index'とする。

デフォルト設定~404エラー

カスタマイズしていない状態では以下の様になっているが、このままログインすると404エラーとなる。

  • ルーティングファイル→特に設定なし
  • コントローラー

このときブラウザーのURL表示はhttp://localhost:3000/homeとなっている。

方法1~コントロールファイルを変更

以下の様に$redirectToの定義を編集すると、意図したページに遷移する。

方法2~ルーティングファイルに追加

コントローラーが以下の様に生成直後の状態で・・・

ルーティングファイルに以下の1行を追加する。

なお、上記をルーティングファイルに追加すれば、コントローラーの定義は以下でもよい。

ルート名は使えない

ルート名が設定されていても、以下の表現はエラーになる(Constant expression contains invalid operations)。

ユーザー登録後の画面遷移

RegisterControllerでもデフォルトで以下の様に定義されている。

LoginControllerと同じようにルーティング設定をすることで、ユーザー登録後の遷移先を設定することができる。

ユーザー認証処理の詳細

ユーザー登録処理の内容ログイン処理の内容についてはそれぞれのリンクを参照。

2038年問題対応

Laravelでモデルの雛形を生成する場合、MySQLだと作成日時と更新日時のtimestamp型の2038年問題が内包される。

database/migrationsディレクトリー下のマイグレーションファイル、...create_users_table.phptimestampsdatetime型に修正しておくべき。

ログアウト処理

ログアウト処理についてはこちら

 

PHP – マジックメソッド – __callStatic()

__callStatic()はマジックメソッドの一つで、実行させようとしたクラスのstaticメソッドが存在しない時に呼ばれる。

以下の例では、MyClass__callStatic()メソッドのみが定義されている。__callStatic()の内容は、引数の$method$argsを表示させるようにしている。

このクラスに存在しないstaticメソッドを、引数なし、引数1個、2個で実行した場合の実行結果。引数は配列として$argsにセットされ、引数がない場合は空の配列、引数が1個の場合は要素数1(要素番号0)の配列となる。

インスタンスに対して存在しないstaticメソッドを呼んで__callStatic()が実行される場合、通常のstaticメソッドと違って'->'はエラーになる。

 

PHP – static::とself::

概要

static::self::はクラスのスタティックメソッドを指すときに使えるが、それぞれ以下のような違いがある。

  • staticはそれが実行されるときのクラスを指す
  • selfはそれが定義されたときのクラスを指す

参照:new staticとnew self

準備

以下のようにParentClassとそれを継承したChildClassを準備する。

  • いずれも同じ名前のstaticメソッドstatic_method()を持つ
  • それぞれのクラスはインスタンスメソッドparent_method()child_method()を持つ
    • 何れの内容も同じで、static::static_method()self::static_method()を実行する

クラスからstaticメソッドを呼ぶ

クラスからstaticメソッドを呼ぶと、当然それぞれに対応したstatic_method()が実行される。

親クラスのメソッドから呼ぶ

親クラスのインスタンスを作って、インスタンスメソッドparent_method()内でstaticselfstatic_method()を呼び出す場合。

親クラスのstaticメソッドしか対象がないので、いずれの場合も親クラスのstatic_method()が実行される。

子クラスのメソッドから呼ぶ

子クラスのインスタンスを作って、インスタンスメソッドchild_method()内でstaticselfstatic_method()を呼び出す場合。

staticselfとも子クラスを指し、子クラスのインスタンスメソッドが実行される。

子クラスで親クラスのメソッドから呼ぶ

子クラスのインスタンスを作って、継承元の親クラスのインスタンスメソッドparent_method()からstaticselfstatic_method()を呼び出す場合。

staticは実行時のクラスを指すため、Childクラスのstatic_method()が実行される。

一方selfは定義時のクラスを指すため、parent_method()が定義されたParentClassstatic_method()が実行される。

Laravel – 名前付きルート

記述方法

ルーティングのname()メソッドで、ルートに名前を付けることができる。

Route::メソッド('URL', 'コントローラー@アクション')->name('ルート名');

この名前を使ってルーティングのURLを得るには、route()ヘルパーを使う。

route('ルート名')

URLにルートパラメーターを含む場合、route()でパラメーターの値を設定して、これを含むURLを得ることができる。

route('ルート名', ['パラメーター' => 値])

ルートパラメーターが複数ある場合は連想配列の要素として列挙。いずれのパラメーターも省略することはできない。

route('ルート名', ['パラメーター1' => 値1, 'パラメーター2' => 値2])

ルーティングで以下のように記述する。

コントローラーのnamed_route()アクションでビューを呼び出す。

ビューの中で、route()ヘルパーによってルーティングのURLを表示させる。

結果は以下のように表示される。

名前付きルート
http://localhost:3000/named_route
http://localhost:3000/named_route/100/set
http://localhost:3000/named_route/first/100/second/200

 

メリット

たとえばアンカータグのURLにルートパラメーターを含む場合、文字列で結合するよりも可読性が高くなる。

URLを変更した場合でも、ルーティングファイルのみ書き換えればよい。

このほか、RESTに基づくリソースルーティングの場合は、自動的に名前が付けられる。

 

Laravel – データモデル操作

概要

Laravelにおけるデータモデルの操作をまとめる。

例としてStickyNoteというアプリケーションを仮定する。StickyNoteは付箋紙のようなアプリケーションで、タイトルとメモ本文を扱う。このアプリケーションを通して、フォーム入力、データの読み込み、書き込み、更新、削除の流れをそれぞれ整理。

データ構造

マイグレーションファイル

マイグレーションファイルにより、StickyNotesの個々の付箋メモのデータ構造を定義。タイトル(title)とメモ本文(body)を定義している。

データベース

マイグレーションの結果得られるテーブルの構造。

データの読み込み

ルーティング

ドメイン名/sticky_noteのURL指定に対してコントローラーStickyNoteControllerindexアクションを呼び出す。

routes/web.php

コントローラーでの処理~all()による全データ取得

全データ取得はコントローラーのスタティックメソッドall()を使い、結果はレコード単位の配列で得られる。

ここでは、

  • indexアクションで$sticky_notesに表示対象の全データを取得
  • 取得した配列をビューに渡して遷移
  • モデルを記述するときはフルパスで書くか冒頭でuse宣言

app/Https/Controllers/StickyNoteController.php

\App\StickyNoteのようにモデルをフルパスで指定する必要がある。あるいは冒頭でuse \App\StickyNoteとしてもよい。

ビューによる表示

ビューで受け取った配列をループで表示させている。データベースのカラムに対応した属性で、各カラムのデータが得られる。

resources/views/sticky_note/index.blade.html

データの書き込み

フォームでの入力と送信

書き込むデータをフォーム入力し、POTSTで送信する。

resources/views/create.blade.php

ルーティング~POSTに対する書き込み処理

POSTのルーティング先をコントローラーのstore()アクションとしている。

routes/web.php

コントローラーでの処理~create()によるデータ書き込み

ルーティング先のアクションではフォームリクエストを引数にとり、マスアサインメントと登録処理を1行で記述している。

また、アクションで引用するモデルとフォームリクエストのクラスをuseでインポートしている。

ここでは、

  • コントローラーの冒頭で、モデルStickyNoteとフォームリクエストStickyNoteRequestuseでインポート
  • フォームリクエストStickyNoteRequestを引数にとっている
  • リクエストのonly()メソッドでマスアサイン
  • アサイン結果をモデルStickyNotecreate()スタティックメソッドの引数に与え、データを登録
  • トップページにリダイレクト

app/Https/Controllers/StickyNoteController.php

モデルでの$fillable定義

コントローラーでのマスアサインメントを有効にするため、データモデルで$fillableプロパティーを定義。

ここでは、StickyNoteモデルクラスで$fillablepublic宣言して、読み込むプロパティーをtitlebodyの2つに限定している。

app/StickyNote.php

データの更新

ルーティング

  • 更新対象を指定するデータのidがルートパラメーターで指定されてGETされることを想定
    • URLにルートパラメーター{id}を含めている
    • GETメソッドでトップページなど他のページを区別するために、URLに/editを付けている
  • GETを受け取ったらeditアクションにルーティング
  • たとえばアンカータグでここに飛ばしたい場合は、url()ヘルパーを使って以下のように指定する
    • <a href="{{ url('/diaries') . '/' . $diary->id . '/edit' }}">

routes/web.php

コントローラーでの処理~find()による更新対象の取得

  • ルーティングで設定されたルートパラメーターは、アクションの引数で参照する
  • モデルのfind()スタティックメソッドで、idに対応するモデルのインスタンスを取得
  • 取得したモデルインスタンスを、更新用のフォームを持つビューに渡す
    • 遷移先のビューでidに対応するデータを初期表示するため

app/Https/Controllers/StickyNoteController.php

フォームでの入力と送信

  • 更新用のフォームを表示する
  • フォームの各要素に、受け取ったデータのタイトルと本文を初期表示する
  • 更新結果はPATCHメソッドで送信
    • HTTPにはGETとPOSTしかないので、formタグではPOSTを指定し、@method()ディレクティブでPATCHを指定している
    • 送信先のactionで、idをルートパラメーターとして付加している

resources/views/edit.blade.php

ルーティング

PATCHメソッドによるルートパラメーターidを含むURLへの送信を、update()アクションにルーティング。

routes/web.php

コントローラーでの処理~update()による更新処理

データの書き込みと同じような手順。

  • ルートパラメーターを引数で受け取り
    • 引数の順番は、フォームリクエスト、ルートパラメーターの順番
  • find()の引数にidを与えてデータを取得
  • マスアサインメントでデータを更新
  • トップページへリダイレクト

app/Https/Controllers/StickyNoteController.php

データの削除

ビュー~削除対象指定

  • 全データを表示する際に、各データをフォームで表示し、データごとに削除ボタンを置く
  • 削除ボタンが押されると、DELETEメソッドでidをルートパラメーターに含むURLを呼び出す
  • HTTPにはGETとPOSTしかないため、@methodディレクティブでDELETEを指定

routes/web.php

ルーティング

DELETEメソッドで所定のURLが要求された場合に、destroy()アクションにルーティング。

routes/web.php

コントローラーでの処理~delete()による削除

  • ルートパラメーターで受け取ったidでデータを取り出し
  • 得られたデータをdelete()で削除
  • トップページにリダイレクト

app/Https/Controllers/StickyNoteController.php

 

Laravel – 外部スタイルファイル

ビューに対するスタイルファイルを外部に置く場合、ビューHTMLのヘッダー部分にlinkタグを記述する。

<link rel="stylesheet" href="スタイルファイルのURL">

アプリケーションのpublicディレクトリー下に置く場合は、asset()ヘルパーを使うことができる。

例えばスタイルファイルをpublic/css/style.cssとして準備する場合は以下のようなタグになる。

httpsによるセキュアーな通信環境の場合はsecure_asset()を使う。

 

Laravel – エラーメッセージの日本語化

日本語化ファイルのダウンロードとインストール

ユーザー認証やバリデーションなどに関するエラーメッセージの日本語化はロケールファイルを編集する方法で可能だが、言語ファイルをダウンロード・インストールする方法がReadDoubleで紹介されている。

以下、プロジェクトのルートディレクトリーで操作。

インストールファイルのダウンロード

インストールファイルの実行

インストールファイルの削除

これによりresources/lang/jaディレクトリーにauth.phppasswords.phppagination.phpvalidation.phpの4つのファイルが生成される。

これでメッセージは日本語化されるが、まだ属性名は以下のようにソースコードで記述したまま。

属性名の日本語化

バリデーションエラーの属性名を日本語化するには、resources/lang/ja/validation.phpを編集する。

たとえばnamehandlenameemailを日本語化するには以下のように編集。

これにより、メッセージ表示は以下のように日本語化される。

 

Laravel – tinker – モデルの操作

tinkerの起動

php artisan tinkerでtinkerを起動。

helpでコマンドが確認できる。

モデル・データベースの操作

データの登録

モデルとマイグレーションで作成したモデルを使う。

まずshowコマンドでモデルクラスを見てみる。

変数$modelTestModelクラスのインスタンスを生成。

マイグレーションファイルで定義したフィールド(product_nameamount)に値を代入。

変数を入力すると、その内容が確認できる。

lsで定義された変数を、ls -lでそれらを少し詳しく見ることができる。

変数の内容をデータベースに保存するステートメントを実行。

データベース側で確認すると、日付もちゃんと登録されている。

さらに2つのデータを登録。

データベース側でも登録されているのが確認できる。

全データ取得

tinkerで変数$modelsにデータベースの全データを取得。

$modelsは配列で要素はゼロから始まるので、$models[1]は2番目のデータ。

データの更新

スタティック関数find()id=2のデータを$modelに取得。

取得したid=2のデータのamount0に変更して保存。

データが更新されているのを確認。

データベースでも確認できる。

データの削除

id=2のデータを取得。

delete()メソッドでデータベースから削除。

全データを取得すると、id=2のデータが削除されている。

データベース側でも確認できる。