我在我的项目中使用了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();
或者我必须手动实施上述范围的否定?如果是这样,有更好的方法吗?
提前谢谢!
答案 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');
}