Laravel - 11. モデル

マイグレーション、シーディングと見てきたので次はモデルについて取り上げます。MVCモデルおけるモデルとはビジネスロジックやデータを扱うものです。

一般的にLaravelのモデルはActive Recordパターンという考え方に沿っており、データベース上の1つのテーブルと対になるようにクラスを作成していきます。具体的には messages テーブルに対応する Message クラスを用意するという具合です。またモデルクラスの名前は名詞の単数形、テーブル名は複数形にしておくことが推奨されています。この規約を満たしている場合はモデルクラスを通じて、簡単にデータベース上のテーブルにアクセスできます。

このようなLaravelのデータベースとモデルを関連付ける仕組みは Eloquent と呼ばれるライブラリで定義されています。

それではモデルを作成してみましょう。モデルを作成するには php artisan make:model コマンドを使います。

$ php artisan make:model モデルクラス名

ここでは messages テーブルを操作する Message モデルを作るので次のようにコマンドを入力します。

$ php artisan make:model Message
Model created successfully.

コマンドが成功すると app/Message.php ファイルが生成されます。テキストエディタから app/Message.php ファイルを開いてみましょう。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Message extends Model
{
    //
}

生成された Message クラスは Model クラスを継承しています。現時点ではプロパティやメソッドの定義はありませんが、スーパークラスの Model クラスのメソッドを通じて操作できるようになっています。また必要に応じてプロパティやメソッドを追加することも可能です。

モデルを操作する主要なメソッド

それではモデルに対して呼び出し可能なメソッドを確認しておきましょう。ここでは以下に示す主要なメソッドの呼び出しを試してみることにします。

操作 モデルのメソッド呼び出し
レコードの全件取得 $messages = Message::all();
IDによるレコードの取得 $message = Message::find(1);
1件目のレコードの取得 $messages = Message::first();
レコードの条件指定 $messages = Message::where("text", "Hello")->get();
レコードのソート指定 $messages = Message::orderBy("text", "desc")->get();
レコードの作成 $message = new Message();
$message->text = "Hola";
$message->save();
レコードの更新 $message = Message::find(4);
$message->text = "Adios";
$message->save();
レコードの削除 $message = Message::find(4);
$message->delete();
任意のselect文の実行 DB::select("select * from messages");

コマンドラインでのモデルの操作

Laravelはコマンドラインでプログラムを評価する仕組みをサポートしています。コマンドラインでREPL環境としてのLaravelを起動するには php artisan tinker コマンドを使います。

$ php artisan tinker
Psy Shell v0.10.4 (PHP 7.3.21 — cli) by Justin Hileman
>>>

php artisan tinker コマンドを入力すると、コマンドラインからプログラムを入力できるようになります。

>>> 1 + 1
=> 2
>>> mb_strlen("Hello")
=> 5
>>>

上記のように演算や関数の呼び出しなどPHPのプログラムを記述してその場で実行・評価できます。

続いて作成した Message クラスを使ってみましょう。まずは use App\Message と入力して Message クラスをインポートします。

>>> use App\Message
>>>

Message モデルを参照できるようになったので、いくつかのメソッド呼び出しを試してみましょう。

まずはレコードの全件取得です。

>>> $messages = Message::all();
=> Illuminate\Database\Eloquent\Collection {#3864
     all: [
       App\Message {#3863
         id: 1,
         text: "Hello",
         created_at: "2020-09-01 12:34:56",
         updated_at: "2020-09-01 12:34:56",
       },
       App\Message {#3457
         id: 2,
         text: "Bonjour",
         created_at: "2020-09-01 12:34:56",
         updated_at: "2020-09-01 12:34:56",
       },
       App\Message {#3825
         id: 3,
         text: "Ciao",
         created_at: "2020-09-01 12:34:56",
         updated_at: "2020-09-01 12:34:56",
       },
     ],
   }

Message::all(); とすることで messages テーブルから3件のレコードを取得しているのがわかります。また Message::all(); メソッドの戻り値は配列とよく似た EloquentCollection オブジェクトです。

モデルのメソッドを呼び出すことで、Laravelは内部的にSQLを発行しています。

次にIDによるレコードの取得を試してみましょう。

>>> $message = Message::find(1);
=> App\Message {#3929
     id: 1,
     text: "Hello",
     created_at: "2020-09-01 12:34:56",
     updated_at: "2020-09-01 12:34:56",
   }

Message::find(1); のように find メソッドの引数にidを指定することで主キー検索となります。また Message::find(1); メソッドの戻り値は Message オブジェクトです。

次は1件目のレコードの取得を取得する方法です。

>>> Message::first();
=> App\Message {#4018
     id: 1,
     text: "Hello",
     created_at: "2020-09-01 12:34:56",
     updated_at: "2020-09-01 12:34:56",
   }

Message::first(); とすることで先頭のレコードを1件だけ取得できます。メソッドの戻り値は Message オブジェクトです。

次はレコードの条件指定です。

>>> $messages = Message::where("text", "Hello")->get();
=> Illuminate\Database\Eloquent\Collection {#3863
     all: [
       App\Message {#3864
         id: 1,
         text: "Hello",
         created_at: "2020-09-01 12:34:56",
         updated_at: "2020-09-01 12:34:56",
       },
     ],
   }

Message::where("text", "Hello")->get(); と指定することで where 句を指定したSQLを実行できます。メソッドの戻り値は Collection オブジェクトです。

次はレコードのソート指定です。

>>> $messages = Message::orderBy("text", "desc")->get();
=> Illuminate\Database\Eloquent\Collection {#4078
     all: [
       App\Message {#3825
         id: 1,
         text: "Hello",
         created_at: "2020-09-01 12:34:56",
         updated_at: "2020-09-01 12:34:56",
       },
       App\Message {#3930
         id: 3,
         text: "Ciao",
         created_at: "2020-09-01 12:34:56",
         updated_at: "2020-09-01 12:34:56",
       },
       App\Message {#3457
         id: 2,
         text: "Bonjour",
         created_at: "2020-09-01 12:34:56",
         updated_at: "2020-09-01 12:34:56",
       },
     ],
   }

Message::orderBy("text", "desc")->get(); と指定することで order by 句を指定したSQLを実行できます。

where メソッドと order by メソッドの呼び出して連鎖することも可能です。

次はレコードの作成です。

>>> $message = new Message();
=> App\Message {#3863}
>>> $message->text = "Hola";
=> "Hola"
>>> $message->save();
=> true

messages テーブルにレコードを作成するには、Message インスタンスを生成後、プロパティを設定し save メソッドを呼び出します。 save メソッドの呼び出しによって insert 文が発行されます。実際にレコードが作成されたかどうか確認してみましょう。

>>> Message::all();
=> Illuminate\Database\Eloquent\Collection {#4080
     all: [
       App\Message {#4081
         id: 1,
         text: "Hello",
         created_at: "2020-09-01 12:34:56",
         updated_at: "2020-09-01 12:34:56",
       },
       App\Message {#4082
         id: 2,
         text: "Bonjour",
         created_at: "2020-09-01 12:34:56",
         updated_at: "2020-09-01 12:34:56",
       },
       App\Message {#4083
         id: 3,
         text: "Ciao",
         created_at: "2020-09-01 12:34:56",
         updated_at: "2020-09-01 12:34:56",
       },
       App\Message {#4084
         id: 4,
         text: "Hola",
         created_at: "2020-09-01 18:31:54",
         updated_at: "2020-09-01 18:31:54",
       },
     ],
   }

あらたに4件目のレコードが登録されているのがわかります。

次はレコードの更新です。

>>> $message = Message::find(4);
=> App\Message {#4072
     id: 4,
     text: "Hola",
     created_at: "2020-09-01 18:31:54",
     updated_at: "2020-09-01 18:31:54",
   }
>>> $message->text = "Adios";
=> "Adios"
>>> $message->save();
=> true

messages テーブルの既存レコードを更新するには、 find メソッドなどで取得した Message インスタンスのプロパティを更新し save メソッドを呼び出します。 save メソッドの呼び出しによって update 文が発行されます。実際にレコードが更新されたかどうか確認してみましょう。

>>> Message::all();
=> Illuminate\Database\Eloquent\Collection {#4089
     all: [
       App\Message {#4090
         id: 1,
         text: "Hello",
         created_at: "2020-09-01 12:34:56",
         updated_at: "2020-09-01 12:34:56",
       },
       App\Message {#4091
         id: 2,
         text: "Bonjour",
         created_at: "2020-09-01 12:34:56",
         updated_at: "2020-09-01 12:34:56",
       },
       App\Message {#4092
         id: 3,
         text: "Ciao",
         created_at: "2020-09-01 12:34:56",
         updated_at: "2020-09-01 12:34:56",
       },
       App\Message {#4093
         id: 4,
         text: "Adios",
         created_at: "2020-09-01 18:31:54",
         updated_at: "2020-09-01 18:32:41",
       },
     ],
   }

4件目のレコードの text 項目が更新されているのがわかります。

次はレコードの削除です。

>>> $message = Message::find(4);
=> App\Message {#3929
     id: 4,
     text: "Adios",
     created_at: "2020-09-01 08:31:54",
     updated_at: "2020-09-01 08:32:41",
   }
>>> $message->delete();
=> true

messages テーブルの既存レコードを削除するには、 find メソッドなどで取得した Message インスタンスに対して delete メソッドを呼び出します。 delete メソッドの呼び出しによって delete 文が発行されます。実際にレコードが削除されたかどうか確認してみましょう。

>>> Message::all();
=> Illuminate\Database\Eloquent\Collection {#3863
     all: [
       App\Message {#3143
         id: 1,
         text: "Hello",
         created_at: "2020-09-01 12:34:56",
         updated_at: "2020-09-01 12:34:56",
       },
       App\Message {#4088
         id: 2,
         text: "Bonjour",
         created_at: "2020-09-01 12:34:56",
         updated_at: "2020-09-01 12:34:56",
       },
       App\Message {#4083
         id: 3,
         text: "Ciao",
         created_at: "2020-09-01 12:34:56",
         updated_at: "2020-09-01 12:34:56",
       },
     ],
   }

最後に Message モデルの話から少しそれますが DB ファサードを使ったSQLの実行方法も見ておきましょう。

>>> DB::select("select * from messages");
=> [
     {#3148
       +"id": 1,
       +"text": "Hello",
       +"created_at": "2020-09-01 12:34:56",
       +"updated_at": "2020-09-01 12:34:56",
     },
     {#4026
       +"id": 2,
       +"text": "Bonjour",
       +"created_at": "2020-09-01 12:34:56",
       +"updated_at": "2020-09-01 12:34:56",
     },
     {#4079
       +"id": 3,
       +"text": "Ciao",
       +"created_at": "2020-09-01 12:34:56",
       +"updated_at": "2020-09-01 12:34:56",
     },
   ]

上記のように DB::select メソッドを使うことで任意のSELECT文を実行できます。 DB ファサードには他にも insert メソッドや update メソッド、 delete メソッドなどが用意されています。

Laravelで効率よくWebアプリケーションを開発するには Message クラスのようなモデルを上手く活用することが大切です。複雑なSQLを実行するような特殊な要件においてはDBファサードを使用することも検討すると良いでしょう。

まとめ

  • LaravelのモデルはEloquent ORMと呼ばれ、データベースとのやりとりを抽象化する仕組み
  • 一般的なモデルはテーブルと対になるクラス(ActiveRecordパターン)
  • php artisan:model コマンドでモデルクラスを作成できる