Laravel否定了当地的范围

时间:2016-01-06 23:59:07

标签: php laravel laravel-5 eloquent

我在我的项目中使用了laravel 5.2我刚刚实现了一个本地范围(为了简单起见,让我们使用laravel docs示例 - 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();

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

提前谢谢!

4 个答案:

答案 0 :(得分:4)

我正在使用这段代码&#34;否定&#34;作用域。

db.collection.stats()

现在,如果我只是想要发布的记录,我会致电public function scopePublished($query, $negate = false) { return ($negate ? $query->where('published', false) : $query->where('published', true)); } 我想要所有未发布的记录,我称之为$post->published()...

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

$post->published(true)...

发布的记录:public function scopePublished($query, $override = true) { return $query->where('published', $override); }
未发表的记录:$post->published()...

答案 1 :(得分:2)

不可能(技术上是,但需要更多代码)来创建本地范围,否定另一个本地范围而不实现另一个范围方法。但是,可以在另一个范围内重用来自一个范围的否定标准。

以下代码可以解决这个问题:

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

此代码使用 whereNotIn 约束从另一个范围应用否定约束。它允许您重用约束逻辑,而不是在两个不同的位置实现原始和否定版本。虽然这些代码量似乎与文档中的示例范围相当,但是对于更复杂的约束更有意义。

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

答案 2 :(得分:1)

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

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

因此,在动态查询范围中,您可以传递其他参数,其中一个参数必须是最受欢迎的人,或者不那么受欢迎。

答案 3 :(得分:0)

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

    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');
    }