放浪軍師のアプリ開発局

VTuberみたいなアプリケーション夏狂乱など、自由気ままにアプリを開発したりしています。他にもいろいろやってます。尚、このブログはわからないところを頑張って解決するブログであるため、正しい保証がありません。ご注意ください。

Laravel でバックエンド 【Eloquentモデル 基礎・小ネタ 編】

よっしゃー!ガンガン行くぞー Laravel でバックエンド小ネタ集!今回は Eloquent についてです。

Eloquent

データベースの各テーブル操作を容易にするための ORM (オブジェクトリレーショナルマッパー)を担う機能です。テーブル情報の取得、作成、更新や、外部キーでつながっている先のテーブルの情報を、SQL文を書くことなくチェーンメソッド的に持ってきたりできる凄い奴で Laravel においての中核的存在ですね。基本的にテーブルを作成したらこの Eloquent を使用するためのモデルも同時に準備することになります。

Eloquentの準備 10.x Laravel

Eloquent:リレーション 10.x Laravel

基本

例えば以下のような会社とユーザーが 1対N で外部キーで接続されている単純なデータベースで考えてみます。なお、migration は作成済みとします。詳しくは前記事を確認してください。

erDiagram
    companies ||--o{ users : ""
    companies {
      bigint id PK
      string name
      timestamp created_at
      timestamp updated_at
    }   
    users {
      bigint id PK
    bigint company_id FK
      string name
      timestamp created_at
      timestamp updated_at
    }

まず、php artisan make:model Company コマンドで companies テーブルを操作する Eloquent モデルを作成します。作成直後はこんな感じ。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Company extends Model
{
    use HasFactory;
}

次に、php artisan make:model User コマンドで users テーブルを操作する Eloquent モデルを作成します。作成直後はこんな感じ。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    use HasFactory;
}

そしてそれらに対して、リレーションを張ります。Company と User は 1対N の関係なので、 Company クラスでは以下のように HasMany を用いて関係性を記述します。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Company extends Model
{
    use HasFactory;
    protected $guarded = []; //←これも追加。理由は後ほど。

    public function users(): HasMany
    {
        return $this->hasMany(User::class);
    }
}

N側である User クラスでは BelongsTo を使います。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    use HasFactory;

    protected $guarded = []; 

    public function company(): BelongsTo
    {
        return $this->belongsTo(Company::class);
    }
}

これで準備は完了です。php artisan tinker コマンドで対話型コンソールを起動し、色んな実験をしてみましょう。なお、tinker についてはここでは詳しく説明しませんが、要は PHP のコード一行ずつをコマンドで実行できる便利な奴だと思っておけば間違いないかと思います。

レコード作成

Company::create(['name'=>'company_name']); を実行すると、Company テーブルに以下のレコードが作成されます。

id name created_at updated_at
1 company_name 2024-01-10 14:17:46 2024-01-10 14:17:46

同じように User::create(['company_id' => 1, 'name' => 'user_name1']); User::create(['company_id' => 1, 'name' => 'user_name2']); を実行すると、User テーブルに以下のレコードが作成されます。

id company_id name created_at updated_at
1 1 company_name1 2024-01-10 14:17:46 2024-01-10 14:17:46
2 1 company_name2 2024-01-10 14:17:46 2024-01-10 14:17:46

このように、Eloquent クラスの create() を用いてレコードを作成できます。便利ですね。

レコード取得

次に、$company = Company::find(1); を実行すると、以下のように表示されます。

> $company = Company::find(1);
= App\Models\Company {#6604
    id: 1,
    name: "company_name",
    created_at: "2024-01-10 14:17:46",
    updated_at: "2024-01-10 14:17:46",
  }

このコードで、変数 $company に id = 1 のレコード情報を Company クラスとして格納でき、そのプロパティに、各カラムの情報を持つ事ができます。このように、Eloquent では本来ならば SQL 文を記述しないと実現できないようなことを簡潔なコードで実現できるというのが最大の魅力です。もちろん更新や削除、絞り込んでの検索も同じような感じで実現可能! laravel では基本的にはこれらの機能で DB とのやりとりを実現していくことになります。

リレーション先の情報取得

次に、$users = $company->users; を実行してみます。

> $company->users;
= Illuminate\Database\Eloquent\Collection {#7011
    all: [
      App\Models\User {#7226
        id: 1,
        company_id: 1,
        name: "user_name1",
        created_at: "2024-01-10 14:22:36",
        updated_at: "2024-01-10 14:22:36",
      },
      App\Models\User {#7224
        id: 2,
        company_id: 1,
        name: "user_name2",
        created_at: "2024-01-10 15:15:01",
        updated_at: "2024-01-10 15:15:01",
      },
    ],
  }

このように、リレーション先の情報を取得することも可能です。ほんっと便利ですね!

小技

ここからは小技紹介です。活躍の場があると思いますので、記憶の片隅にでも置いておくと助かる場面があるかもしれません。

ホワイトリストよりブラックリストを指定する

前述の Eloquent コード例で唐突に追記されていた protected $guarded = []; の説明ですが、このプロパティはブラックリストになります。どういうことかというと、このプロパティに指定されたカラムへは Eloquent を介しての書き込みを禁止することができ、それ以外は書き込み可能となります。例えば、protected $guarded = ['name']; としておけば、Company::create(['name' => 'company_name'); は、

> Company::create(['name' => 'company_name']);

   Illuminate\Database\QueryException  SQLSTATE[HY000]: General error: 1364 Field 'name' doesn't have a default value (Connection: mysql, SQL: insert into `companies` (`updated_at`, `created_at`) values (2024-01-10 15:21:55, 2024-01-10 15:21:55))

というように、例外を吐くようになります。また、同じような機能で protected $fillable = []; というものも指定できます。こちらは先ほどの逆でホワイトリスト。このプロパティに指定されたカラムへの Eloquent を介しての書き込みを許可することができ、許可されていないものは書き込みできません。また、この $fillable$guardedどちらか一方だけを必ず実装しなければなりません。そのため、どちらにするのかという事を最初に決定しておく必要があります。

まぁどちらでもよいと言えばよいのですが、私は $guarded の指定をお勧めします。というのも単純にめんどくさい!。そもそも、Eloquent を介しての特定のカラムへの書き込みを禁止したい状況というのはあんまり存在せず、禁止させたいのは自動採番される id か、自動記述させる created_at,updated_at ぐらいです。そのため、$guarded に指定するのはすべての Eloquent でほとんど共通です。しかし、$fillable を指定するとなると、各 Eloquent で違ってきて、それぞれのテーブルのカラムをほぼ全部記載していく必要があります。テーブル作成時であればまぁ指定してやってもいいけど、カラム追加する度に追加するのは・・・うん。めんどい! あんまりメリットも感じませんしこだわりが無いのであれば、$guarded を指定したほうが幸せになれると思います。

まとめ

以上が Eloquent の基本および小ネタになります。Eloquent は中核だけあってまだまだ注意点や活用法がありますが、ここで挙げるときりがないのでまた別の機会にまとめていこうと思います。それではみなさん快適な laravel ライフを!