Masayan tech blog.

  1. ブログ記事一覧>
  2. 【Laravel】Eloquent/クエリビルダーの主なメソッドまとめ

【Laravel】Eloquent/クエリビルダーの主なメソッドまとめ

公開日

環境

  • windows10
  • DockerDesktop for Win 3.5.x
  • Laravel 8.x
  • PHP 8.x
  • VsCode
  • gitbash 2.32.0.1

前提

本記事を読んでいただくに際して、前提として以下のクラスは必ず押さえておく必要があります。理由としては、Eloquent ORMではいろいろなメソッドを呼び出すことが可能ですが、内部的にはEloquentビルダークラスを呼び出してよしなにクエリを組み立ててくれているからです。

  • EloquentのModelクラス
    • vendor/laravel/framework/src/Illuminate/Database/EloquentModel.php
  • Eloquentビルダークラス
    • vendor/laravel/framework/src/Illuminate/Database/EloquentBuilder.php

メソッド一覧

Laravelで使用可能なEloquent/クエリビルダーの主なメソッドと特徴およびその返り値(戻り値)をまとめました。

メソッド名

処理内容

返り値(戻り値)

find

主キーで単一のレコードを取得

Modelのオブジェクト

first

単一のレコードを取得

Modelのオブジェクト

get

複数のレコードを取得

ModelのオブジェクトのCollection

all

全レコードを取得

Modelクラスからの呼び出しならCollection。
Builderクラスなら配列

with

リレーション

Builderクラスのオブジェクト

where

クエリによる条件付与

Builderクラスのオブジェクト

create

新規追加

※Modelにfillable(ないしguarded)の設定が必要

Modelのオブジェクト

save

新規追加(更新)

bool値

update

更新

Modelクラスのupdateは、bool値。
Eloquentビルダーのupdateはint

delete

削除

Modelクラスなら、bool値。Eloquentビルダーなら処理したレコード数。

destroy

削除

処理したレコード数

各メソッドの詳細

tinkerコマンドで各メソッドの返り値を確認できるのでこちらを使用する

find(findOrFail)

  • メソッド概要
    • 主キーでレコードを取得できるメソッド
  • 属するクラス
    • Eloquentビルダークラス
  • 返り値
    • Modelのオブジェクト(インスタンス)
      ※findOrFailだと、モデルが見つからなかった場合に例外を投げる
>>> App\Models\ModelUser::query()->find(1)
=> App\Models\Model\User {#4617
  id: 1,
  name: "Shaniya Grimes",
  email: "damore.karolann@example.com",
  ..
}

>>> App\Models\ModelUser::query()->findOrFail(198388372) 
Illuminate\Database\Eloquent\ModelNotFoundException with message 'No query results for model [App\Models\ModelUser] 198388372'

ちなみに、公式でも紹介されているように、より簡潔に下記のよう(Model::メソッド名)に記述することも可能ですが、IDEの補完が効かなるのでちょっと微妙。上記のように、明示的にEloquentビルダーを介してメソッドを呼び出す形式のほうがよい。

>>> ModelUser::findOrFail(1)
=> AppModelsModelUser {#3621
  id: 1,
  name: "Shaniya Grimes",
  email: "damore.karolann@example.com",
  ..
}

IDEの補完が効かなくなる理由

  • findメソッドに限った話ではないですが、Modelクラスに存在しないメソッドを直接呼び出そうとすると、IDEから判断できなくなるため
  • 存在しないメソッドが呼び出せるのはおかしくない?となりますが、実際には、Modelクラス(vendorlaravelframeworksrcIlluminateDatabaseEloquentModel.php)の__call()から内部的にEloquentビルダーを呼び、そこからfindメソッドを呼び出すという仕組みになっている
  • もちろん、以下のようなModelクラスに存在するall()などは直接Modelのオブジェクトから呼び出しても補完が効くので特に問題はないが、結局内部的にはquery()でEloquentビルダーを呼び出している
    public static function all($columns = ['*'])
    {
      return static::query()->get(
        is_array($columns) ? $columns : func_get_args()
      );
    }

first()

  • メソッド概要
    • 最初のレコードを1件だけ取得できるメソッド
  • 属するクラス
    • Eloquentビルダークラス
  • 返り値
    • Modelのオブジェクト(インスタンス)
>>> App\Models\ModelUser::query()->first()
=> App\Models\ModelUser {#4585
  id: 1,
  name: "Shaniya Grimes",
  email: "damore.karolann@example.com",
  ..
}

get()

  • メソッド概要
    • 複数レコードを取得できるメソッド
  • 属するクラス
    • Eloquentビルダークラス
  • 返り値
    • Modelのオブジェクト(インスタンス)が入ったコレクション
>>> App\Models\ModelUser::query()->get()
=> IlluminateDatabaseEloquentCollection {#3604
all: [
  App\Models\ModelUser {#3605
    id: 1,
    name: "Shaniya Grimes",
    ..
  },
  App\Models\ModelUser {#3606
    id: 2,
    name: "Isobel Fisher",
    ..
  },
  ..
]

all()

  • メソッド概要
    • 全レコードを取得できるメソッド
  • 属するクラス
    • Modelクラス、Eloquentビルダークラス
  • 返り値
    • Modelクラス
      • Modelのオブジェクト(インスタンス)が入ったコレクション
    • Eloquentビルダークラス
      • Modelのオブジェクト(インスタンス)が入った配列

Modelクラス

>>>
$modelUser = new ModelUser();
$modelUser->all();
=> Illuminate\Database\Eloquent\Collection {#3592
all: [
  App\Models\ModelUser {#3604
    id: 1,
    name: "Shaniya Grimes",
    ..
  },
  App\Models\ModelUser {#3615
    id: 2,
    name: "Isobel Fisher",
    ..
  },
]

Builderクラス

>>> ModelUser::query()->get()->all()
=> [
App\Models\ModelUser {#3614
  id: 1,
  name: "Shaniya Grimes",
},
App\Models\ModelUser {#3600
  id: 2,
  name: "Isobel Fisher",
},

ちなみにcollect()を使用すると、コレクションクラスのオブジェクトを作成することが可能なので、これに対して、all()すると配列が得られる

>>> collect([1, 2, 3])
=> IlluminateSupportCollection {#3594
  all: [
    1,
    2,
    3,
  ],
}

with

  • メソッド概要
    • リレーション
  • 属するクラス
    • Modelクラス、Eloquentビルダークラス
      ※ただし最終的にはEloquentビルダーのwithが実行される
  • 返り値
    • Builderクラスのオブジェクト。whereなり、getなりがチェーンできる
>>> ModelUser::query()->with("stocks")->where('id', '=', "2")->get()
=> Illuminate\Database\Eloquent\Collection {#3569
all: [
  App\Models\ModelUser {#3576
   id: 2,
   name: "Isobel Fisher",
   stocks: Illuminate\Database\Eloquent\Collection {#3593
    all: [
     App\Models\ModelStock {#3567
      id: 2,
      user_id: 3,
      name: "Mr. Lennie Renner V",
     },
    ],
   },
  },
 ],
}

where

  • メソッド概要
    • クエリに条件を付与する
  • 属するクラス
    • Eloquentビルダークラス
  • 返り値
    • Builderクラスのオブジェクト。getなりがチェーンできる
>>> ModelUser::query()->with("stocks")->where('id', '=', "2")
=> Illuminate\Database\Eloquent\Builder {#3568}

create

  • メソッド概要
    • 新規追加
  • 属するクラス
    • Eloquentビルダークラス
  • 返り値
    • Modelのオブジェクト
>>> App\Models\ModelPost::query()->create([
  "user_id" => 1,
  "title" => "hoge",
  "detail" => "foo",
])
=> App\Models\ModelPost {#3592
  user_id: 1,
  title: "hoge",
  detail: "foo",
  ..
}

save

  • メソッド概要
    • 新規追加(更新でも使用可能)
  • 属するクラス
    • Modelクラス
  • 返り値
    • Bool値。成功したら、true失敗したらfalseを返す
$modelPost = new ModelPost();
=> App\Models\ModelPost {#3611}
  $modelPost->user_id = 1;
  $modelPost->title = "hoge";
  $modelPost->detail = "foo";
  $modelPost->save();
=> true

update

  • メソッド概要
    • 新規追加(更新でも使用可能)。
  • 属するクラス
    • Modelクラス・Eloquentビルダークラスの両方から呼び出し可能だが、それぞれプロセスが異なる
  • 返り値
    • Modelクラス
      • bool値
      • 内部的にはfill+saveすることで更新
    • Eloquentビルダークラス
      • 更新件数が返る
      • 内部的には、クエリビルダを使って更新

Modelクラス

>>> $modelPost = new ModelPost();
>>> $modelPost = $modelPost::find(3);
=> App\Models\ModelPost {#3794
  id: 3,
  user_id: 2,
  title: "更新後の記事タイトル",
  detail: "Repellendus ipsa ullam corporis iusto tenetur. Dicta impedit eius minima harum aut et. Molestiae voluptas harum qui magnam. Quibusdam consectetur officiis corporis qui et quasi nihil.",
  created_at: "2022-01-01 03:08:08",
  updated_at: "2022-01-06 08:21:01",
}
>>> $modelPost->title = "更新後の記事タイトル";
>>> $modelPost->update();
=> true

Eloquentビルダー

>>> ModelPost::where("id","=","3")->update(["title" => "hoge"])
=> 1

delete

  • メソッド概要
    • レコードの削除
  • 属するクラス
    • Modelクラス・Eloquentビルダークラスの両方から呼び出し可能だが、それぞれプロセスが異なる
      • ModelクラスはConnectionInterfaceのdeleteメソッドを呼び出して削除
      • Eloquentビルダーはクエリビルダを使って削除
  • 返り値
    • Modelクラス
      • bool値
    • Eloquentビルダークラス
      • 処理したレコード数

Modelクラス

>>> ModelUser::find(3)->delete()
=> true

Eloquentビルダー

>>> ModelPost::where("id", "=", "15")->delete()
=> 1

destroy

主キーを引数に渡すと、そのレコードを削除可能。(主キーの配列を渡せば複数のレコードを削除可能)。また、Modelクラスからのみ呼び出し可能なメソッド

>>> ModelPost::destroy(10)
=> 1

以上です。長々と書きましたが、まとめると、

  • IDEの補完を最大限生かすためにも、Eloquentビルダーを介して(Model::query())クエリを組み立てるほうがよさそう
  • 各メソッドはModelクラス(ないしEloquentビルダー)固有のメソッドなのか、どちらでも使えるメソッドなのかということをある程度理解して使うとスムーズに記述できそう
  • 各メソッドの返り値が何なのかを理解しているとスムーズに記述できそう(Collectionなのか、Eloquentビルダークラスのオブジェクトなのか、Modelのオブジェクトなのか...)

まとめ

いかがでしたでしょうか。本記事では、laravelを学習しはじめの頃に遭遇する419エラーが出る仕組みをざっくり紹介しています。結論から言うと、laravelのフレームワークが、CSRF対策を行ってくれているために、Httpリクエスト時に必要な情報が抜けているとエラーが表示されるという仕組みです。