LoginSignup
1

Laravel の Eloquent 拡張機能を作った

Last updated at Posted at 2022-12-24

Eloquent Method Expansion

機能概要

Eloquent を拡張し、where 句と orderBy 句を拡張し新しいメソッドを追加します。

(※正確には拡張しているのは QueryBuilder なのですが、リポジトリ名を先に決めてしまっていたので…)

使用条件

php7.4 以上、Laraevel8.0 以上

github

packagist

作成の経緯

いくつかのプロジェクトに参画して思ったのですが、(同一プロジェクトでも)人によって Eloquent where の書き方が全然違っていて

1つの where() に配列でまとめて書く人もいれば

return $this->product
    ->where([
        [
            'products.sale_date_start', '>=', date('Y-m-d'),
        ],
        [
            'products.sale_date_end', '<=', date('Y-m-d'),
        ],
        [
            'products.discontinued', '=', 0,
        ],
    ])
    ->get();

条件1つにつき1つ where() を書く人もいたり

return $this->product
    ->where('sale_date_start', '>=', date('Y-m-d'))
    ->where('sale_date_end', '<=', date('Y-m-d'))
    ->where('discontinued', 0)
    ->get();

全て whereRaw() で書く強者もいたり

return $this->product
    ->whereRaw('
        sale_date_start >= "' . date('Y-m-d') . '" 
        AND
        sale_date_end <= "' . date('Y-m-d') . '" 
        AND
        discontinued = 0
    ')
    ->get();

scope メソッドを多用する人もいました。

return $this->product
    ->withInTheSalesPerild()
    ->notDiscontinued()
    ->get();

個人的には専用の where 句(whereBetween, whereIn, whereNull, whereDate... 以下略)を駆使して書く方が単純なミスを減らせそうというのは建前で何となくフレームワークを使いこなしている感がして好きなのですが、Eloquent は意外と痒いところに手が届かないというかあまりメソッドが用意されておらず、scope メソッドに頼りがちです。

専用の where 句が増えれば、where() の書き方もある程度共通化されていくのでは…?と思い作成したのが下記の拡張機能です。

使い方

composer でインストール

composer require kanagama/laravel-eloquent-method-expansion

インストール後、下記メソッドが使えるようになります。


拡張 where 句

[columnName] にはテーブルのカラム名をアッパーキャメルで入力します。

where[columnName]IsNull(), orWhere[columnName]IsNull()

where[columnName]IsNull() メソッドは、columnName が NULL である条件を加えます。

$users = DB::table('users')
            ->whereNameIsNull()
            ->get();
# select * from users where name IS NULL;

where[columnName]IsNotNull(), orWhere[columnName]IsNotNull()

where[columnName]IsNull() メソッドは、columnName が NULL でない条件を加えます。

$users = DB::table('users')
            ->whereNameIsNotNull()
            ->get();
# select * from users where name IS NOT NULL;

where[columnName]Eq(), orWhere[columnName]Eq()

AllowEmpty オプション対応

where[columnName]Eq() メソッドは、 パラメータの値が columnName の値と一致する条件を加えます。

$users = DB::table('users')
            ->whereTelEq('09099999999')
            ->get();
# select * from users where tel = '09099999999';

where[columnName]NotEq(), orWhere[columnName]NotEq()

AllowEmpty オプション対応

where[columnName]NotEq() メソッドは、 パラメータの値が columnName の値と一致しない条件を加えます。

$users = DB::table('users')
            ->whereTelNotEq('09099999999')
            ->get();
# select * from users where tel <> '09099999999';

where[columnName]Gt(), orWhere[columnName]Gt()

AllowEmpty オプション対応

where[columnName]Gt() メソッドは、パラメータの値より大きい columnName の値となる条件を加えます。

$users = DB::table('users')
            ->whereCreatedAtGt('1980-05-21')
            ->get();
# select * from users where created_at > '1980-05-21';

where[columnName]Gte(), orWhere[columnName]Gte()

AllowEmpty オプション対応

where[columnName]Gte() メソッドは、パラメータの値以上の columnName の値となる条件を加えます。

$users = DB::table('users')
            ->whereCreatedAtGte('1980-05-21')
            ->get();
# select * from users where created_at >= '1980-05-21';

where[columnName]Lt(), orWhere[columnName]Lt()

AllowEmpty オプション対応

where[columnName]Lt() メソッドは、パラメータの値より小さい columnName の値となる条件を加えます。

$users = DB::table('users')
            ->whereModifiedAtLt('1980-05-21 00:00:00')
            ->get();
# select * from users where modified_at < '1980-05-21 00:00:00';

where[columnName]Lte(), orWhere[columnName]Lte()

AllowEmpty オプション対応

where[columnName]Lte() メソッドは、パラメータの値以下の columnName の値となる条件を加えます。

$users = DB::table('users')
            ->whereModifiedAtLte('1980-05-21 00:00:00')
            ->get();
# select * from users where modified_at <= '1980-05-21 00:00:00';

where[columnName]In(), orWhere[columnName]In()

AllowEmpty オプション対応

where[columnName]In() メソッドは、指定した配列内に columnName の値が含まれる条件を加えます。

$users = DB::table('users')
            ->whereUserStatusIdIn([
                '1','2','3',
            ])
            ->get();
# select * from users where user_status_id in (1, 2, 3);

where[columnName]NotIn(), orWhere[columnName]NotIn()

AllowEmpty オプション対応

where[columnName]NotIn() メソッドは、指定した配列内に columnName の値が含まれない条件を加えます。

$users = DB::table('users')
            ->whereUserStatusIdNotIn([
                '1','2','3',
            ])
            ->get();
# select * from users where user_status_id not in (1, 2, 3);

where[columnName]Like(), orWhere[columnName]Like()

AllowEmpty オプション対応

where[columnName]Like メソッドは、columName の値の中にパラメータの値が部分一致する条件を加えます。

$users = DB::table('users')
            ->whereAddressLike('沖縄県')
            ->get();
# select * from users where address like '%沖縄県%';

where[columnName]NotLike(), orWhere[columnName]NotLike()

AllowEmpty オプション対応

where[columnName]NotLike() メソッドは、columName の値の中にパラメータの値が部分一致しない条件を加えます。

$users = DB::table('users')
            ->whereAddressNotLike('沖縄県')
            ->get();
# select * from users where address not like '%沖縄県%';

where[columnName]LikePrefix(), orWhere[columnName]LikePrefix()

AllowEmpty オプション対応

where[columnName]LikePrefix() メソッドは、columName の値の中にパラメータの値が前方一致する条件を加えます。

$users = DB::table('users')
            ->whereAddressLikePrefix('沖縄県')
            ->get();
# select * from users where address like '沖縄県%';

where[columnName]NotLikePrefix(), orWhere[columnName]NotLikePrefix()

AllowEmpty オプション対応

where[columnName]NotLikePrefix() メソッドは、columName の値の中にパラメータの値が前方一致しない条件を加えます。

$users = DB::table('users')
            ->whereAddressNotLikePrefix('沖縄県')
            ->get();
# select * from users where address not like '沖縄県%';

where[columnName]LikeBackword(), orWhere[columnName]Backword()

AllowEmpty オプション対応

where[columnName]LikePrefix() メソッドは、columName の値の中にパラメータの値が後方一致する条件を加えます。

$users = DB::table('users')
            ->whereAddressLikeBackword('沖縄県')
            ->get();
# select * from users where address like '%沖縄県';

where[columnName]NotLikeBackword(), orWhere[columnName]NotBackword()

AllowEmpty オプション対応

where[columnName]LikePrefix メソッドは、columName の値の中にパラメータの値が後方一致しない条件を加えます。

$users = DB::table('users')
            ->whereAddressNotLikeBackword('沖縄県')
            ->get();
# select * from users where address not like '%沖縄県';

where[columnName]Date(), orWhere[columnName]Date()

AllowEmpty オプション対応

where[columnName]Date() メソッドは、columName の値と日付を比較します。

$users = DB::table('users')
            ->whereRentDatetimeDate('2022-12-02')
            ->get();
# select * from `products` where date(`rent_datetime`) = "2022-12-02"

where[columnName]DateGt(), orWhere[columnName]DateGt()

AllowEmpty オプション対応

where[columnName]DateGt メソッドは、columName の値と日付を > で比較します。

$users = DB::table('users')
            ->whereRentDatetimeDateGt('2022-12-02')
            ->get();
# select * from `products` where date(`rent_datetime`) > "2022-12-12"

where[columnName]DateGte(), orWhere[columnName]DateGte()

AllowEmpty オプション対応

where[columnName]DateGte() メソッドは、columName の値と日付を >= で比較します。

$users = DB::table('users')
            ->whereRentDatetimeDateGte('2022-12-02')
            ->get();
# select * from `products` where date(`rent_datetime`) >= "2022-12-12"

where[columnName]DateLt(), orWhere[columnName]DateLt()

AllowEmpty オプション対応

where[columnName]DateLt() メソッドは、columName の値と日付を < で比較します。

$users = DB::table('users')
            ->whereRentDatetimeDateLt('2022-12-02')
            ->get();
# select * from `products` where date(`rent_datetime`) < "2022-12-12"

where[columnName]DateLte(), orWhere[columnName]DateLte()

AllowEmpty オプション対応

where[columnName]DateLte() メソッドは、columName の値と日付を <= で比較します。

$users = DB::table('users')
            ->whereRentDatetimeDateLte('2022-12-02')
            ->get();
# select * from `products` where date(`rent_datetime`) <= "2022-12-12"

where[columnName]Month(), orWhere[columnName]Month()

AllowEmpty オプション対応

where[columnName]Month() メソッドは、columName の値と特定の月を比較します。

$users = DB::table('users')
            ->whereRentDatetimeMonth('12')
            ->get();
# select * from `products` where month(`rent_datetime`) = "12"

where[columnName]MonthGt(), orWhere[columnName]MonthGt()

AllowEmpty オプション対応

where[columnName]MonthGt() メソッドは、columName の値と特定の月を > で比較します。

$users = DB::table('users')
            ->whereRentDatetimeMonthGt('10')
            ->get();
# select * from `products` where month(`rent_datetime`) > "10"

where[columnName]MonthGte(), orWhere[columnName]MonthGte()

AllowEmpty オプション対応

where[columnName]MonthGte() メソッドは、columName の値と特定の月を >= で比較します。

$users = DB::table('users')
            ->whereRentDatetimeMonthGte('10')
            ->get();
# select * from `products` where month(`rent_datetime`) >= "10"

where[columnName]MonthLt(), orWhere[columnName]MonthLt()

AllowEmpty オプション対応

where[columnName]MonthLt() メソッドは、columName の値と特定の月を < で比較します。

$users = DB::table('users')
            ->whereRentDatetimeMonthLt('10')
            ->get();
# select * from `products` where month(`rent_datetime`) < "10"

where[columnName]MonthLte(), orWhere[columnName]MonthLte()

AllowEmpty オプション対応

where[columnName]MonthLte() メソッドは、columName の値と特定の月を <= で比較します。

$users = DB::table('users')
            ->whereRentDatetimeMonthLte('10')
            ->get();
# select * from `products` where month(`rent_datetime`) <= "10"

where[columnName]Day(), orWhere[columnName]Day()

AllowEmpty オプション対応

where[columnName]Day() メソッドは、columName の値と特定の日を比較します。

$users = DB::table('users')
            ->whereRentDatetimeMonth('31')
            ->get();
# select * from `products` where day(`rent_datetime`) = "31"

where[columnName]DayGt(), orWhere[columnName]DayGt()

AllowEmpty オプション対応

where[columnName]DayGt() メソッドは、columName の値と特定の日を > で比較します。

$users = DB::table('users')
            ->whereRentDatetimeMonthGt('15')
            ->get();
# select * from `products` where day(`rent_datetime`) > "15"

where[columnName]DayGte(), orWhere[columnName]DayGte()

AllowEmpty オプション対応

where[columnName]DayGte() メソッドは、columName の値と特定の日を >= で比較します。

$users = DB::table('users')
            ->whereRentDatetimeMonthGte('15')
            ->get();
# select * from `products` where day(`rent_datetime`) >= "15"

where[columnName]DayLt(), orWhere[columnName]DayLt()

AllowEmpty オプション対応

where[columnName]DayLt() メソッドは、columName の値と特定の日を < で比較します。

$users = DB::table('users')
            ->whereRentDatetimeMonthLt('15')
            ->get();
# select * from `products` where day(`rent_datetime`) < "15"

where[columnName]DayLte(), orWhere[columnName]DayLte()

AllowEmpty オプション対応

where[columnName]DayLte() メソッドは、columName の値と特定の日を <= で比較します。

$users = DB::table('users')
            ->whereRentDatetimeMonthLte('15')
            ->get();
# select * from `products` where day(`rent_datetime`) <= "15"

where[columnName]Year(), orWhere[columnName]Year()

AllowEmpty オプション対応

where[columnName]Year() メソッドは、columName の値と特定の年を比較します。

$users = DB::table('users')
            ->whereRentDatetimeYear('2022')
            ->get();
# select * from `products` where year(`rent_datetime`) = "2022"

where[columnName]YearGt(), orWhere[columnName]YearGt()

AllowEmpty オプション対応

where[columnName]YearGt() メソッドは、columName の値と特定の年を > で比較します。

$users = DB::table('users')
            ->whereRentDatetimeYearGt('2022')
            ->get();
# select * from `products` where year(`rent_datetime`) > "2022"

where[columnName]YearGte(), orWhere[columnName]YearGte()

AllowEmpty オプション対応

where[columnName]YearGte() メソッドは、columName の値と特定の年を >= で比較します。

$users = DB::table('users')
            ->whereRentDatetimeYearGte('2022')
            ->get();
# select * from `products` where year(`rent_datetime`) >= "2022"

where[columnName]YearLt(), orWhere[columnName]YearLt()

AllowEmpty オプション対応

where[columnName]YearLt() メソッドは、columName の値と特定の年を < で比較します。

$users = DB::table('users')
            ->whereRentDatetimeYearLt('2022')
            ->get();
# select * from `products` where year(`rent_datetime`) < "2022"

where[columnName]YearLte(), orWhere[columnName]YearLte()

AllowEmpty オプション対応

where[columnName]YearLte() メソッドは、columName の値と特定の年を <= で比較します。

$users = DB::table('users')
            ->whereRentDatetimeYearLte('2022')
            ->get();
# select * from `products` where year(`rent_datetime`) <= "2022"

where[columnName]Time(), orWhere[columnName]Time()

AllowEmpty オプション対応

where[columnName]Time() メソッドは、columName の値と特定の時間を比較します。

$users = DB::table('users')
            ->whereRentDatetimeTime('12:00:00')
            ->get();
# select * from `products` where time(`rent_datetime`) = "12:00:00"

where[columnName]TimeGt(), orWhere[columnName]TimeGt()

AllowEmpty オプション対応

where[columnName]TimeGt() メソッドは、columName の値と特定の時間を > で比較します。

$users = DB::table('users')
            ->whereRentDatetimeTimeGt('12:00:00')
            ->get();
# select * from `products` where time(`rent_datetime`) > "12:00:00"

where[columnName]TimeGte(), orWhere[columnName]TimeGte()

AllowEmpty オプション対応

where[columnName]TimeGte() メソッドは、columName の値と特定の時間を >= で比較します。

$users = DB::table('users')
            ->whereRentDatetimeTimeGte('12:00:00')
            ->get();
# select * from `products` where time(`rent_datetime`) >= "12:00:00"

where[columnName]TimeLt(), orWhere[columnName]TimeLt()

AllowEmpty オプション対応

where[columnName]TimeLt() メソッドは、columName の値と特定の時間を < で比較します。

$users = DB::table('users')
            ->whereRentDatetimeTimeLt('12:00:00')
            ->get();
# select * from `products` where time(`rent_datetime`) < "12:00:00"

where[columnName]TimeLte(), orWhere[columnName]TimeLte()

AllowEmpty オプション対応

where[columnName]TimeLte() メソッドは、columName の値と特定の時間を <= で比較します。

$users = DB::table('users')
            ->whereRentDatetimeTimeLte('12:00:00')
            ->get();
# select * from `products` where time(`rent_datetime`) <= "12:00:00"

where[columnName]Column(), orWhere[columnName]Column()

AllowEmpty オプション対応

where[columnName]Column() メソッドは、columnName と指定したカラムの値が等しい条件を加えます。

$users = DB::table('users')
            ->whereRentDateColumn('return_date')
            ->get();
# select * from `products` where `rent_date` = `return_date`

where[columnName]ColumnGt(), orWhere[columnName]ColumnGt()

AllowEmpty オプション対応

where[columnName]ColumnGt() メソッドは、columnName が指定したカラムの値より大きい条件を加えます。

$users = DB::table('users')
            ->whereRentDateColumnGt('return_date')
            ->get();
# select * from `products` where `rent_date` > `return_date`

where[columnName]ColumnGte(), orWhere[columnName]ColumnGte()

AllowEmpty オプション対応

where[columnName]ColumnGt() メソッドは、columnName が指定したカラムの値以上となる条件を加えます。

$users = DB::table('users')
            ->whereRentDateColumnGte('return_date')
            ->get();
# select * from `products` where `rent_date` >= `return_date`

where[columnName]ColumnLt(), orWhere[columnName]ColumnLt()

AllowEmpty オプション対応

where[columnName]ColumnLt() メソッドは、columnName が指定したカラムの値より小さい条件を加えます。

$users = DB::table('users')
            ->whereRentDateColumnLt('return_date')
            ->get();
# select * from `products` where `rent_date` < `return_date`

where[columnName]ColumnLte(), orWhere[columnName]ColumnLte()

AllowEmpty オプション対応

where[columnName]ColumnLte() メソッドは、columnName が指定したカラムの値以下となる条件を加えます。

$users = DB::table('users')
            ->whereRentDateColumnLt('return_date')
            ->get();
# select * from `products` where `rent_date` <= `return_date`

where[columnName]Between(), orWhere[columnName]Between()

AllowEmpty オプション対応

where[columnName]Between() メソッドは、columnName の値が2つの値の間にある条件を加えます

$users = DB::table('users')
            ->whereCreatedAtBetween(['2022-12-01', '2022-12-10',])
            ->get();
# select * from users where created_at between '2022-12-01' AND '2022-12-10'

where[columnName]NotBetween(), orWhere[columnName]NotBetween()

AllowEmpty オプション対応

where[columnName]NotBetween() メソッドは、columnName の値が2つの値の間にない条件を加えます

$users = DB::table('users')
            ->whereCreatedAtNotBetween(['2022-12-01', '2022-12-10',])
            ->get();
# select * from users where created_at not between '2022-12-01' AND '2022-12-10'

allowEmpty

allowEmptyオプション

where の後に AllowEmpty オプションを付与すると、パラメータが null や [] や 文字列の '' となる場合にその条件を省略します。

# $rentDatetime = null;
# $returnDatetime = '1980-05-21 00:00:00'
$users = DB::table('users')
            ->whereAllowEmptyRentDatetimeGte($rentDatetime)
            ->whereAllowEmptyReturnDatetimeGte($returnDatetime)
            ->get();
# null のため、whereAllowEmptyRentDatetimeGte() は省略される
# select * from users where return_datetime >= '1980-05-21 00:00:00';

AllowEmpty チェックしている条件は下記の通りです

# 渡されたパラメータがこの条件を満たさない場合、その条件は省略されます
# int の 0 と string の '0" は省略させたくなかったので、この条件にしています
if (!empty($parameters) || is_numeric($parameter)) {

allowEmpty の使い所

管理画面(※予約管理画面など)では、予約者名、予約日、メールアドレス、電話番号、予約ステータス、その他多岐にわたる絞り込み条件が用意されていると思いますが、それを空かどうかチェックして空でなければ絞り込み条件に追加、というのを Eloquent で書くのは意外と労力が掛かります。

$query = DB::table('reservations');

# 絞り込み条件がリクエストパラメータに存在しているかチェックして where に追加しないといけない
if ($request->has('reserve_name')) {
    $query->where('reservations.name', 'LIKE', '%'. $request->reserve_name . '%');
}
if ($request->has('reserve_date')) {
    $query->whereDate('reservations.reserve_date_at', $request->reserve_date);
}
if ($request->has('email')) {
    $query->whereEmail($request->email);
}
if ($request->has('tel')) {
    $query->whereTel($request->tel);
}
if ($request->has('status')) {
    $query->whereStatus($request->status);
}
// 絞り込み条件の数だけ続く

全部 if 文で囲むとかそんなんやってらんないよ、と思った際に使うのが AllowEmpty オプションです。

null や [] が渡された場合、その絞り込み条件を省略しますので、メソッドチェーンで全て繋げることが可能です。

return DB::table('reservations')
    ->whereAllowEmptyNameLike($request->reserve_name)
    ->whereAllowEmptyReserveDateAtDate($request->reserve_date)
    ->whereAllowEmptyEmailEq($request->email)
    ->whereAllowEmptyTelEq($request->tel)
    ->whereAllowEmptyStatusEq($request->status)
    ->get();

AllowEmpty オプション利用不可

  • where[columnName]IsNull()
  • orWhere[columnName]IsNull()
  • where[columnName]Null()
  • orWhere[columnName]Null()
  • where[columnName]NotNull()
  • orWhere[columnName]NotNull()
  • where[columnName]IsNotNull()
  • orWhere[columnName]IsNotNull()

拡張 orderBy 句

orderBy[columnName]Asc()

orderBy[columnName]Asc() メソッドは、columnName の昇順で並び替えます。

$users = DB::table('users')
            ->orderByCreatedAtAsc()
            ->get();
# select * from users order by created_at asc

orderBy[columName]Desc()

orderBy[columnName]Desc() メソッドは、columnName の降順で並び替えます。

$users = DB::table('users')
            ->orderByCreatedAtDesc()
            ->get();
# select * from users order by created_at desc

orderBy[columnName]Field()

orderBy[columnName]Field() メソッドは、columnName の指定した順番で並び替えます。
null を末尾に配置するため、Desc が付与されます

$users = DB::table('users')
            ->orderByIdField([2, 1, 4, 3,])
            ->get();
# select * from users order by FIELD(id, 3, 4, 1, 2) DESC;

注意事項

scope メソッド名と衝突した場合、scope メソッドが優先されます。

class Prefecture
{
    /**
     * わざと重複するメソッド名にする
     * Name is null なのに 'test' と一致するレコードを探す
     * 
     * @param  Builder  $query
     * @return Builder
     */
    public function scopeWhereNameIsNull(Builder $uqery): Builder
    {
        return $query->where('name', 'test');
    }
}

上記の場合、whereNameIsNull() を呼び出すとスコープメソッドが適用されます。

Prefecture::whereNameIsNull()->get();
// select * from prefectures where name = 'test'

こんな狂ったスコープメソッドを作る方は居ないと思いますが念のため。


更新履歴

v1.3.0 - 2023/03/17

php7.4、Laravel8 に対応


ご利用いただける方へのお願い

何かしら問題ありそうな挙動見つけましたらこちらの記事でコメントいただくか github の issue でご指摘お願いいたします。

機能が思いつく限りバージョンアップしていきたいと思っていますので、定期的に最新にバージョンアップお願いします!

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1