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 – フォームリクエスト

概要

  • FormRequestクラスは、ユーザー権限の認証と入力のバリデーションを専用に扱う
  • 実装は、artisanでFormRequestクラスを継承したクラスを生成し、認証やバリデーションの内容を記述
  • コントローラーのインジェクションをRequestからFormRequestの継承クラスに変更することで、チェック機能をコントローラーから分離することができる

準備

バリデーションで使ったアプリケーションを利用する。

ビュー

コントローラーのアクション

フォームリクエストクラスの生成

以下のコマンドでFormRequestを継承したクラスを作成する。

php artisan make:request リクエストクラス名

リクエストクラスは、app/Http/Requestsディレクトリー下に作成される。

リクエストクラスの内容。ユーザー認証のためのauthorize()メソッドと、バリデーションのためのrules()メソッドが定義されている。

アクションの引数の変更

  • コントローラーの先頭でリクエストクラスをuseでインポート
  • コントローラーのアクションのメソッドインジェクションをRequestからリクエストクラスに変更
  • validate()メソッドはアクションには書かない

今回の例の場合。

ユーザー認証の記述

準備中。認証された場合はauthorize()メソッドの戻り値がtrue

バリデーションルールの記述

rules()メソッドの戻り値の配列に、バリデーションルールを書く。

準備したコントローラーのバリデーション部分をリクエストクラスに記述。

エラーメッセージのカスタマイズ

フォームリクエストのmessages()メソッドをオーバーライドすることで、メッセージのカスタマイズができる。

参考:Laravel 6.x バリデーション~エラーメッセージのカスタマイズ

Laravel – マスアサインメント

概要

  • マスアサインメントによって、フォームからPOSTされたパラメーターを一括してモデルの属性にセットして、データベースに書き込める
  • ただしセットできる属性をモデルの$fillable配列に限定列挙する必要がある
  • モデルのインスタンス生成時に、セットできるパラメーターをonlyメソッドで限定列挙できる
  • $fillableのほかに$guarded配列も指定できて、こちらは指定した属性をモデルのセットの際に排除する

準備

以下のようなフォームがあって、namecommentをPOSTする。

POSTはコントローラーのstore()メソッドにルーティングされる。

ルーティング先のコントローラーでは、モデルのインスタンスを生成し、その属性にPOSTされたパラメーターをセットしてデータベースに書き込む。

マスアサインメント

Requestのall()メソッド

Request引数のall()メソッドで得られる内容を確認。

CSRF対策のトークンを含んだパラメーターの配列が得られる。

$request->all()の結果を、モデルインスタンスのfill()メソッドによって属性にセット。dd()で内容を確認してみる。

エラー。

マスアサインメントのためにはfillable属性に加えなければならないと言われる。

モデルの$fillableプロパティー

モデルの定義で、$fillable配列に取得したいプロパティーを列挙する。

先ほどのコードの実行結果。エラーがなくなる。dd()でプロパティーがセットされたインスタンスの内容を確認。

  • fillableプロパティーに2つのパラメーター名がセットされている
  • attributesに属性とその内容が配列としてセットされている
  • guardedは指定しておらず、サイズ1、内容'*'の配列となっている

以上を踏まえて、fillableがセットされたモデルのマスアサインメントとデータベース登録を以下に例示。

マスアサインメントの記述方法

マスアサインメントの書き方には複数あって、同じ結果が得られる。create()スタティックメソッドは、インスタンスの生成とデータベースの書き込みを一つのメソッドで行う。

Requestのonly()メソッドによる限定

意図しないパラメーターの追加を避けるため、all()メソッドではなくonly()メソッドでパラメーターを限定列挙できる。

 

Git/GitHub

Git

基本

コミット

ブランチ

リモート

GitHub

スタートアップ

操作

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のデータが削除されている。

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

 

Laravel – モデル作成とマイグレーション

データベース設定の確認

アプリケーションディレクトリー直下の.envファイルでデータベースの設定を確認する。DB_DATABASEに設定されたデータベースが作成済みでRDBMSでアクセス可能であることを確認する。

モデルの作成

モデル作成コマンド

モデルの作成には、artisanmake:modelコマンドを使う。同時にデータベースを定義するマイグレーションファイルも作成するときは--migrationオプションを付ける。

php artisan make:model モデル名 --migration

モデル名の考え方は以下の通り。

  • データベースのレコードに保存する対象として、単数の名詞とする
  • モデル名はアッパー・キャメルケース(パスカルケース)で定義する

以下はTestModelというモデルを作成したケース。

モデルの作成に成功したことと、2021_08_23…という名前でマイグレーションファイルが作成されたことが表示されている。

マイグレーションファイルの作成は--migrationオプションを付けたためで、これをつけないとモデルのだけが作成される。

モデルクラスファイル

モデルのクラスファイルはappディレクトリー下に作成される。コマンドで指定したモデル名に拡張子.phpが付けられている。

以下がモデルクラスファイルの内容。

  • 名前空間をAppとしている
  • 名前空間Illuminate\Database\EloquentModelファイルを利用する
  • ModelファイルはModelクラスのファイル
  • 今回作成したTestModelクラスはModelクラスを継承している
  • モデル作成で定義した名前がそのままクラス名になっている
  • 作成したクラスの中身は空

オプション指定

モデル作成コマンドのオプションは-h/--helpオプションで指定できる。

主なオプションは以下の通り。

-c/--controller
コントローラーを作成する。
-m/--migration
マイグレーションファイルを作成する。
-r/--resource
リソースベースのアクションが含まれたコントローラーが生成される。ルーティングでのonlyexceptと関係なく、すべてのアクションが含まれる。
-s/--seed
シーダーファイルを作成する。

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

ファイル名

モデルクラスファイルと同時に作成されたマイグレーションファイルは、database/migrations下にある。新たに作成された2021_08_23...のマイグレーションファイルが確認できる。

マイグレーションファイルのファイル名構成は以下の通り。

日付_時刻_create_テーブル名_table.php

テーブル名はモデル名をスネークケースに変更し、複数形となっている。

マイグレーションファイルの内容は以下の通り。

up()メソッド

up()メソッドではテーブルを作成するときのカラム定義が記述されている。

  • bigincrements()bigint unsigned型、AUTO_INCREMENT設定のカラムidを定義
  • timestamps()timestamp型でcreated_atupdated_atの2つのカラムを定義

bigIncrements()によるIDを外部キーで参照する場合

bigIncrements()で生成されるカラムはbigint(unsigned)となる。他テーブルでこれを外部キーとして参照する場合のカラム型はbigint unsignedとする。マイグレーションファイルで指定する場合はunsignedBigInteger()とする。

down()メソッド

down()メソッドは、test_modelsテーブルが存在する場合にこれを削除(DROP)。

マイグレーション実行

マイグレーションコマンドについてはこちらを参照。

状態確認

マイグレーション実行前のテーブルの状態。準備の時に作成したままになっている。

マイグレーションの実行状態は以下のコマンドで確認。

php artisan migrate:status

今回作成されたマイグレーションファイルだけが未実行となっている。

マイグレート

以下のコマンドで、マイグレーションファイルの設定に従ってテーブルを作成する。

php artisan migrate

マイグレーションの結果、データベースにテーブルが作成される。テーブル名はマイグレーションファイル名にもあるとおりで、以下のように付けられる。

  • モデル名のキャメルケースをスネークケースに変更
  • 複数形にする

データベースでテーブルが作成されていることを確認。

テーブル構造を確認。timestamp()によって、created_atupdated_atの2つのカラムが作られている。

ただしtimestamp型は2038年問題が発生するため、datetime型に変更する方がよい。

ロールバック

ロールバックにより、作成したテーブルを削除してマイグレーション前の状態に戻すことができる。

php artisan migrate:rollback

ロールバックを実行することで、ここまでで作成したtest_modelsテーブルが削除される。

ただしマイグレーションファイルは残っていて、編集などを行った後に再度マイグレーションできる。

マイグレーションファイルの実行状態も未実行に戻る。

マイグレーションファイルの編集とマイグレーション

test_modelsテーブルのカラムを以下のように編集する。

  • idカラムはそのまま
  • VARCHAR(20)product_nameカラムを追加
  • int型でamountカラムを追加
  • created_atupdated_attimestamp型からdatetime型に変更

参考:利用可能なカラムタイプ

マイグレーション前のファイルを以下のように編集してマイグレート。

以下の構造のテーブルが作成される。

モデルの削除

モデルとテーブルを削除する手順は以下の通り。

  1. 該当テーブルのマイグレーションの前までロールバック
  2. マイグレーションファイル削除
  3. モデルファイル削除

timestampの2038年問題について

モデルとマイグレーションファイルを生成させると、自動的にtimestampsが設定されるが、MySQLとの組み合わせの場合に2038年問題が発生する。datetime型で書きなおすなどの対応をしておくべき。

モデル名とテーブル名について

モデルとテーブルを生成するときの命名の流れは以下のようになっている。

  • モデル名は単数形でアッパーキャメルケース
  • モデルクラスファイル名はモデル名に.phpの拡張子
  • モデルクラス名はモデル名と同じ
  • テーブル名はキャメルケースからスネークケースに変換され、複数形になる

複数形への変更はLaravelがエレガントにやってくれて、不規則な複数形にも対応している。ただし不可算名詞にはそのままsが付くようだ。

  • TestModeltest_models
  • TestDiary→test_diaries
  • CompanyPersonCompanyPeople
  • WildGoosWildGees
  • StockWaterStockWaters

なお、敢えてモデル名をスネークケースにすると、クラスファイル名、モデルクラス名もキャメルケースのままで、テーブル名は複数形になる。

  • test_modeltest_models

 

MySQL – 並べ替え~ORDER BY

準備

以下のテーブルで確認する。

指定方法

ORDER BYで指定したカラムをキーにして並べ替える。デフォルトは昇順でASCを指定したのと同じ。

SELECT カラム群 FROM テーブル ORDER BY カラム [ASC/DESC];

以下の例では、2つ目のnum2で昇順にソートしている。

降順でソートする場合はDESCを指定。以下はnum2カラムの内容で降順にソートしている。

複数カラムでのソート

ORDER BYで複数カラムを指定すると、指定したカラムの順でネストの外側のようにしてソートする。

以下の例では、num1で降順ソートし、その中でnum2で降順ソートしている。

順番を入れ替えた例。まずnum2で降順ソートしてから、その中でnum1でソートしている。

 

Linux – 停止中のジョブ

停止しているジョブがあってログアウトできないときなど。

jobsコマンドでジョブとジョブ番号の確認。

fg ジョブ番号コマンドでフォアグラウンド処理に。

ジョブを停止する場合はkill ジョブ番号コマンド。