【问题标题】:Laravel Eloquent Query Builder chaining affects original base query [duplicate]Laravel Eloquent Query Builder 链接会影响原始基本查询 [重复]
【发布时间】:2020-12-14 18:29:02
【问题描述】:

我怎样才能让这个查询工作?

$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() 操作修改。

谢谢!

【问题讨论】:

  • 它们是“构建器”对象,它们构建查询,因此对它们的每次调用都会向它正在构建或执行的查询添加内容,但构建器始终保存您正在构建的查询
  • @OMR,是的,它会的。基本上这是同一个问题,但措辞不同......对不起,我之前错过了,但它从未出现在我的搜索中。

标签: php laravel eloquent


【解决方案1】:

如果您有一个构建器并且您想要一个构建器的新副本以便您可以继续从中构建查询,您可以“克隆”该构建器:

$cloned = clone $query;

现在$cloned 是它自己的对象,您可以按照自己的方式构建查询,而不会影响原始构建器$query。

如果您真的想要构建器上的 clone 方法并且它不存在,您可以对其进行宏处理:

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

您可以将其放入服务提供者的 boot 方法中。

【讨论】:

    【解决方案2】:

    构建器上有一个可用的克隆方法(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.x 的 Laravel 版本,可以在 AppServiceProvider 或新的 MacroServiceProvider 中定义宏 - 启动方法。

    使用 MacroServiceProvider - 不要忘记将其添加到 config/app.php 中的 providers 数组中

    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()
        {
            //
        }
    }
    

    【讨论】:

    • 感谢@Donkarnash,您是对的,尽管我无法让 clone() 工作。我不断收到: BadMethodCallException 调用未定义的方法 Illuminate\Database\Query\Builder::clone()
    • 你使用的是哪个 Laravel 版本?
    • Laravel 5.8...也许这就是原因。我正在使用 (clone $basic_query),它对于数据库构建器来说工作正常,但我想知道 Illuminate\Database\Eloquent\Builder 是否有类似的功能。
    • 好的,对于低于 v 8.x 的 Laravel,您可以尝试 $basic_query->cloneWithout([])->paid()->get()。只需将clone() 替换为cloneWithout([])
    • @E.Barney 对于低于 8.x 的 Laravel 版本,您可以在 ServiceProvider 中定义宏 - 已更新答案
    猜你喜欢
    • 2015-10-29
    • 2016-07-25
    • 1970-01-01
    • 2022-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多