テクメモ

備忘録

LaraveのEloquentについて

LaravelのEloquentとは?

EloquentはActive RecordライクなORMで、DBとモデルを関連付けてデータ操作をすることが可能。

※Active Recordとは Active RecordはDBからデータを読み出すための手法。DBのtableまたはviewの1行が1つのクラスにラップされ、オブジェクトのインスタンスがそのデータベースの1つの行に結合される。SQLを意識せずにデータベースアクセスを行うことができる。

モデルの作成

Eloquentを利用するにはモデルが必要なのでモデルを作成する

php artisan make:model Task

モデルとDBのテーブルとの関連付けは、テーブル名を複数形、モデルを単数形で作成すると暗黙的に関連付けられる。

例) テーブル名 → tasks モデル名 → Task

テーブル名がスネークケースの場合は、モデルをキャメルケースで作成すると関連付けられる。

例) テーブル名 → task_sample モデル名 → TaskSample

上記2つを適用しない場合は、$tableプロパティで指定し関連付けることができる。

データ検索/更新などの基本メソッド

よく使う基本的なメソッドを以下にまとめる。

全件抽出 all

テーブルの全レコードを取得するメソッド 戻り値はCollectionで、Collectionの要素はModelクラスのインスタンス

$tasks = Task::all();

PrimaryKey指定での抽出 find,findOrFail

find

引数にPrimaryKeyを指定して、合致するレコードのみ取得する。 戻り値はModelのインスタンス

$task = Task:find(10);

findOrFail

findと似てるが、該当レコードが見つからなかった場合、ModelNotFoundExceptionを投げる

try {
       $task = Task::findOrFail(10);
} catch (ModelNotFoundException $e) {
        // 見つからなかった場合の処理
}

条件指定による抽出 whereXX

SQLのwhere区に相当する条件を引数に指定し、絞り込みを行えるメソッド。 XXにはテーブルのカラム名が入る。

$task = Task::whereTitle('タスクタイトル')->get();

レコードの登録 create save firstOrCreatre

create

配列を引数に指定して、レコードを登録できる。

Task::create([
    'title'  =>  'タスクタイトル',
    'content'  =>  'タスクの内容'
]);

save

対象のモデルのインスタンスを新規作成し、各カラムの値を設定し登録できる。

$task = new Task;
$task->title = 'タスクタイトル';
$task->content = 'タスクの内容';

firstOrCreatre

ある条件でレコードを抽出し、レコードが見つからない場合のみ新規登録する。

$task = Task::firstOrCreatre(['title' => 'タスクタイトル']);

レコードの更新 update

更新対象のインスタンスに対して、更新したいカラムと値の配列を引数に指定しレコードを更新できる。

$task = Task::find(1)->update(['title' => 'タスクタイトル2']);

レコード削除 delete, destroy

delete

削除対象のインスタンスに使用し、レコードを削除できる。

$task = Task::find(1);
$task->delete();

destroy

削除対象のPrimaryKeyを指定し、レコードを削除する。

Task::destroy(1);

関連があるテーブル群をまとめて操作する

DBのテーブルは他のテーブルと関連していることが多い。 例えば、ユーザー(users)は複数のタスク(tasks)を持っている、など。 Eloquentはテーブルの関係性を踏まえて処理することができるリレーションという機能を持っっている。 以下はユーザー(users)、タスク(tasks)、カテゴリー(categories)の例で記述していく。

1対1 hasOne, belongsTo

例)書籍(books)テーブルと書籍詳細(book_details)テーブル

第1引数に関連付けるモデル名、第2引数に内部キー、第3キーに外部キーを指定することができる。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Book extends Model
{
    public function detail()
    {
        return $this->hasOne(BookDetail::class);
    }
}

逆はbelongsToで指定することができる。

1対多 hasMany

例)ユーザー(users)テーブルとタスク(tasks)テーブル

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    public function tasks()
    {
        return $this->hasMany(Task::class);
    }
}

hasOneと同様に、第1引数に関連付けるモデル名、第2引数に内部キー、第3キーに外部キーを指定することができる。

逆は、belongsToで指定できる。

多対多 belongsToMany

例)タスク(tasks)テーブルテーブルとカテゴリ(categories)テーブル

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Task extends Model
{
    public function categories()
    {
        return $this->belongsToMany(Category::class);
    }
}

hasOneと同様に、第1引数に関連付けるモデル名、第2引数に内部キー、第3キーに外部キーを指定することができる。

逆もbelongsToManyで指定できる。

多対多では、結果コレクションに中間テーブル情報が付与されてくる。 これを取得したくないときは、モデルに$hiddenを定義することで除外できる。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Task extends Model
{
    // 中間テーブル情報を取得しない
    protected $hidden = ['pivot'];

    public function categories()
    {
        return $this->belongsToMany(Category::class);
    }
}

中間テーブルのカラムを取得したい場合はモデルに取得したいカラムを指定しておき、取得時にpivotプロパティにアクセスする。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Task extends Model
{
    // 中間テーブル情報を取得しない
    protected $hidden = ['pivot'];

    public function categories()
    {
        return $this
            ->belongsToMany(Category::class, 'task_category_ref')
            ->withPivot('task_id', 'category_id')
    }
}

Has Many Through

テーブルをまたぐリレーションを行うことができる。 以下の例で考える。

        users
    ⇅          ⇅
  roles       tasks

rolesからusersを経由してtasksを取得したい時

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Role extends Model
{
    public function tasks()
    {
        return $this->hasManyThrough(Task::class, User::class);
    }
}

第1引数にリレーションを行うモデル、第2引数には経由するモデルを指定する。