Laravel Eloquent QueryBuilderチェーンは元のベースクエリに影響します[重複]

Dec 15 2020

このクエリを機能させるにはどうすればよいですか?

$basic_query = Invoices::between_days(15, 7); // This is a collection of invoices from 15 days ago, to seven days in the future. Notice I am not getting this query, it´s still just a builder instance. If you do dd($basic_query->get()) you get 100 invoices, 60 of them paid, 40 of them outstanding.

$paid_invoices = $basic_query->paid()->get(); // This returns the collection of 60 paid invoices without problems. BUT MODIFIES $basic query, if you dd($basic query->get()) at this point, you only get the 60 paid invoices, not the full 100 invoices collection. ¿?!!!

$outstanding_invoices = $basic_query->paid(false)->get(); // This query will always be empty, even though there are many outstanding invoices. If you dd($basic_query->get()) at this point, you get an empty collection. The 100 invoices are lost.

次に、後続のget()操作によって変更されないスターターポイントとして基本コレクションを作成するにはどうすればよいですか。

ありがとうございました!

回答

2 lagbox Dec 15 2020 at 01:31

ビルダーがあり、ビルダーの新しいコピーが必要な場合は、ビルダーからクエリを作成し続けることができます。ビルダーを「複製」できます。

$cloned = clone $query;

これ$clonedは独自のオブジェクトであり$query、元のビルダーに影響を与えることなく、必要に応じてクエリを作成できます。

cloneビルダーでメソッドが本当に必要で、それが存在しない場合は、マクロ化できます。

Illuminate\Database\Query\Builder::macro('clone', function () {
    return clone $this;
});

あなたはそれをサービスプロバイダーのboot方法で投げることができます。

2 Donkarnash Dec 15 2020 at 01:35

ビルダー(Illuminate \ Database \ Query \ Builder)で使用できるクローンメソッドがあります。

$basic_query = Invoices::between_days(15, 7); $paid_invoices = $basic_query->clone()->paid()->get(); $outstanding_invoices = $basic_query->clone()->paid(false)->get();

更新

8.xa未満のLaravelバージョンの場合、マクロはAppServiceProviderまたは新しいMacroServiceProvider(ブートメソッド)のいずれかで定義できます。

MacroServiceProviderを使用する場合-のproviders配列に追加することを忘れないでください config/app.php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Database\Query\Builder;

class MacroServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Builder::macro('clone', function() {
            return clone $this;
        });
    }

    public function register()
    {
        //
    }
}