【问题标题】:Laravel negate local scopeLaravel 否定本地范围
【发布时间】:2016-01-06 23:59:06
【问题描述】:

我在我的项目中使用 laravel 5.2 我刚刚实现了一个本地范围(为简单起见,让我们使用 laravel 文档示例 - https://laravel.com/docs/master/eloquent#local-scopes

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * Scope a query to only include popular users.
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopePopular($query)
    {
        return $query->where('votes', '>', 100);
    }

}

我打电话:

$users = App\User::popular()->get();

它就像一个魅力

是否可以调用范围的否定?

$users = App\User::Notpopular()->get();

或者我必须手动实现上述范围的否定?如果是这样,有更好的方法吗?

提前谢谢你!

【问题讨论】:

    标签: php laravel laravel-5 eloquent


    【解决方案1】:

    我正在使用这段代码来“否定”作用域。

    public function scopePublished($query, $negate = false) {
        return ($negate ? $query->where('published', false) : $query->where('published', true));
    }
    

    现在,如果我只是想要已发布的记录,我会调用 $post-&gt;published()... 我想要所有未发布的记录,我会调用 $post-&gt;published(true)...


    我可能会切换到以下,因为它更容易理解:

    public function scopePublished($query, $override = true) {
        return $query->where('published', $override);
    }
    

    发布记录:$post-&gt;published()...
    未公开记录:$post-&gt;published(false)...

    【讨论】:

    • 很好的解决方案!
    • 你可以通过 return $query->where('published', $negate); 来简化这个过程
    • @RichardLePoidevin 如果您阅读了整个答案,它已经被简化了......
    • 太棒了!我用这个变量名实现了它,让我更清楚:public function scopePublished($query, $is_true_or_false = true) { return $query-&gt;where('published', $is_true_or_false ); }
    【解决方案2】:

    在不实现另一个作用域方法的情况下,创建一个否定另一个局部作用域的本地作用域是不可能的(从技术上讲是这样,但需要更多的代码)。但是,可以在另一个范围内重用来自一个范围的否定标准。

    下面的代码应该可以解决问题:

    public function scopeNotPopular($query) {
      $query->whereNotIn($this->getKeyName(), function($q) {
        $q->select($this->getKeyName())->from($this->getTable());
        $this->scopePopular($q);
      });
    }
    

    此代码使用 whereNotIn 约束从另一个范围应用否定约束。它将允许您重用约束逻辑,而不是在 2 个不同的地方实现原始版本和否定版本。虽然对于文档中的示例范围而言,这么多的代码似乎是相当大的开销,但对于更复杂的约束来说,它更有意义。

    请记住,虽然它允许代码重用,但从性能角度来看,将应用的 SQL 查询可能次优。它使用 subselect 来识别应从结果集中排除的行。

    【讨论】:

      【解决方案3】:

      我认为您需要手动实现,因为 Laravel 不会自动“否定”。

      您可以做的是使用动态查询范围:https://laravel.com/docs/5.0/eloquent#query-scopes

      因此,在 Dynamic Query Scopes 中,您可以传递其他参数,其中之一可能是是否必须获得最受欢迎的人,或者是不太受欢迎的人。

      【讨论】:

      • 查询生成器可以执行以下操作: scope Where popular>100 如果我否定条件 where 子句将为 NOT(popular>100)
      【解决方案4】:

      这是另一种类似于公认答案的方法,但我觉得性能更好,因为它不使用子查询。在我的用例中,我否定的范围有多个复杂的条件,我希望避免复制这些条件。

          public function scopeNotPopular($query)
          {
              // whereNot doesn't exist in Laravel so doing similar logic here to avoid replicating popular logic
              //    whereRaw('TRUE') insures the "AND NOT" on the later WHERE will not be trimmed
              //    end result: WHERE true AND NOT ([popular logic])
              return $query->whereRaw('TRUE')
                  ->where(function ($q) {
                      $q->popular();
                  }, null, null, 'AND NOT');
          }
      

      【讨论】:

        猜你喜欢
        • 2021-11-21
        • 2016-07-22
        • 1970-01-01
        • 1970-01-01
        • 2021-03-05
        • 1970-01-01
        • 1970-01-01
        • 2011-08-21
        • 1970-01-01
        相关资源
        最近更新 更多