在 Laravel 5.2 之前
现在我们也可以使用 Laravel 4.2 中引入的全局作用域来解决这个问题(如果我错了,请纠正我)。我们可以像这样定义一个作用域类:
<?php namespace App;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\ScopeInterface;
class OrderScope implements ScopeInterface {
private $column;
private $direction;
public function __construct($column, $direction = 'asc')
{
$this->column = $column;
$this->direction = $direction;
}
public function apply(Builder $builder, Model $model)
{
$builder->orderBy($this->column, $this->direction);
// optional macro to undo the global scope
$builder->macro('unordered', function (Builder $builder) {
$this->remove($builder, $builder->getModel());
return $builder;
});
}
public function remove(Builder $builder, Model $model)
{
$query = $builder->getQuery();
$query->orders = collect($query->orders)->reject(function ($order) {
return $order['column'] == $this->column && $order['direction'] == $this->direction;
})->values()->all();
if (count($query->orders) == 0) {
$query->orders = null;
}
}
}
然后,在您的模型中,您可以在 boot() 方法中添加范围:
protected static function boot() {
parent::boot();
static::addGlobalScope(new OrderScope('date', 'desc'));
}
现在模型是默认排序的。请注意,如果您也在查询中手动定义顺序:MyModel::orderBy('some_column'),那么它只会添加它作为二级排序(当第一次排序的值相同时使用),它会不覆盖。为了使手动使用另一个排序成为可能,我添加了一个(可选)宏(见上文),然后你可以这样做:MyModel::unordered()->orderBy('some_column')->get()。
Laravel 5.2 及更高版本
Laravel 5.2 引入了一种更简洁的方式来处理全局范围。现在,我们唯一需要写的是:
<?php namespace App;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
class OrderScope implements Scope
{
private $column;
private $direction;
public function __construct($column, $direction = 'asc')
{
$this->column = $column;
$this->direction = $direction;
}
public function apply(Builder $builder, Model $model)
{
$builder->orderBy($this->column, $this->direction);
}
}
然后,在您的模型中,您可以在 boot() 方法中添加范围:
protected static function boot() {
parent::boot();
static::addGlobalScope(new OrderScope('date', 'desc'));
}
要删除全局范围,只需使用:
MyModel::withoutGlobalScope(OrderScope::class)->get();
没有额外作用域类的解决方案
如果你不喜欢为作用域设置一个完整的类,你也可以(从 Laravel 5.2 开始)在你的模型的 boot() 方法中定义全局作用域:
protected static function boot() {
parent::boot();
static::addGlobalScope('order', function (Builder $builder) {
$builder->orderBy('date', 'desc');
});
}
您可以使用以下命令删除此全局范围:
MyModel::withoutGlobalScope('order')->get();