flyhjaelp/laravel-eloquent-orderable

通过在模型上使用可排序特性,使Eloquent模型可排序。当当前模型的排序更新或新模型插入或删除时,它将自动更新其组内所有其他模型的排序。

v1.2.0 2019-04-26 12:56 UTC

README

Laravel Eloquent Orderable 是一个帮助您使Eloquent模型可排序的包,无论是在组内还是在同一类的所有其他模型内。

安装

通过composer安装

composer require flyhjaelp/laravel-eloquent-orderable

数据库设置

如果要在模型上使用可排序功能,它必须有一个数据库列可以按其排序。默认情况下,该包将寻找名为 "order" 的列,但此名称可以重写。排序列应是无符号整数,可以是空值。示例

Schema::create('orderable_test_models', function (Blueprint $table) {
  $table->unsignedInteger('order')->nullable();
});

默认用法

<?php

use Flyhjaelp\LaravelEloquentOrderable\Interfaces\OrderableInterface;
use Flyhjaelp\LaravelEloquentOrderable\Traits\Orderable;
use Illuminate\Database\Eloquent\Model;

class Foobar extends Model implements OrderableInterface { //implement the orderable interface

   use Orderable; //use the orderable trait
   
}

创建一个没有指定排序的新模型

新实例将自动添加一个排序,默认情况下它们被添加为最后一个排序。

$foobarA = (new Foobar())->save();
$foobarB = (new Foobar())->save();
$foobarC = (new Foobar())->save();
Foobar::all()->pluck('order','id');
// will output [1 => 1, 2 => 2, 3 => 3]

创建一个具有指定排序的新模型

如果创建时指定了排序,则该排序将相应地更新已存在的排序。

$foobarD = new Foobar();
$foobarD->order = 2;
$foobarD->save();
Foobar::all()->pluck('order','id');
// will output [1 => 1, 4 => 2, 2 => 3, 3 => 4]

更新模型的排序

当更新模型的排序时,其他模型将自动相应地更新它们的排序。

$foobarC->order = 2;`
$foobarC->save();
Foobar::all()->pluck('order','id'); // will output [1 => 1, 3 => 2, 4 => 3, 2 => 3]

删除模型

当删除模型时,所有其他具有更高排序的模型的排序将减少一个。

$foobarA->delete();
Foobar::all()->pluck('order','id'); // will output [3 => 1, 4 => 2, 2 => 3]

分组使用

您可以在模型中创建一个组,排序只适用于该组。例如,您可能有一个名为MenuItem的模型,它应该按menu_id分组,排序应只适用于其组。要将组添加到模型中,您必须包含orderableWithinGroup特性并实现以下函数

  • scopeOrdered(Builder $query)
  • scopeWithinOrderGroup(Builder $query, OrderableInterface $orderableModel)
  • columnsAffectingOrderGroup()
<?php

use Flyhjaelp\LaravelEloquentOrderable\Interfaces\OrderableInterface;
use Flyhjaelp\LaravelEloquentOrderable\Traits\OrderableWithinGroup;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;

class MenuItem extends Model implements OrderableInterface { //implement the orderable interface

   use OrderableWithinGroup; //use the orderableWithinGroup trait
   
   public function scopeOrdered(Builder $query): void{
      $query->orderBy('menu_id')->orderBy('order');
   }
   
   public function scopeWithinOrderGroup(Builder $query, OrderableInterface $orderableModel): void{
      $query->where('menu_id',$orderableModel->menu_id);
   }
   
   public function columnsAffectingOrderGroup(): Collection{
      return collect(['menu_id']);
   }
   
}

模型现在在其组内排序

新实例将自动添加一个排序,默认情况下它们被添加为组内的最后一个排序。

<?php

$foobarA = new Foobar();
$foobarA->menu_id = 1;
$foobarA->save();
$foobarB= new Foobar();
$foobarB->menu_id = 1;
$foobarB->save();
$foobarC = new Foobar();
$foobarC->menu_id = 2;
$foobarC->save();
Foobar::all()->pluck('order','id');
// will output [1 => 1, 2 => 2, 3 => 1]

在关联模型中的使用

如果您希望能够在检索时对多对多关系进行排序,则可以创建可排序的关联模型。排序只能单向工作,这意味着如果您例如有一个包含多个检查点的旅程,则可以在检索旅程时使检查点按照正确的顺序显示,但不能反过来。

设置关联模型排序

为了使关联模型可排序,您必须在模型上使用PivotOrderable特性。还需要在关联关系表中有自增主键(通常是一个 "id")。此外,您必须实现以下提到的OrderableWithinGroup方法

<?php

use Flyhjaelp\LaravelEloquentOrderable\Interfaces\OrderableInterface;
use Flyhjaelp\LaravelEloquentOrderable\Traits\PivotOrderable;
use Illuminate\Database\Eloquent\Relations\Pivot;
use Illuminate\Database\Eloquent\Builder;

class JourneyCheckpointsRelationship extends Pivot implements OrderableInterface{

   use PivotOrderable;

   public $incrementing = true;
   
   public function scopeWithinOrderGroup($query, OrderableInterface $orderableModel)
   {
      return $query->where('journey_id', $orderableModel->journey_id);
   }

   public function scopeOrdered(Builder $query): void
   {
      $query->orderBy('journey_id')->orderBy($this->getOrderableColumn());
   }

   public function columnsAffectingOrderGroup(): Collection
   {
      return collect(['journey_id']);
   }
   
}

当从模型调用关系时,您必须在模型上定义关系时,在belongsToMany调用上链式使用using方法。此外,如果您希望在检索时对关系进行排序,还必须添加orderBy方法调用。

<?php

use Illuminate\Database\Eloquent\Model;

class Journey extends Model{

   public function checkpoints() {
      return $this
         ->belongsToMany(Checkpoint::class)
         ->using(JourneyCheckpointsRelationship::class)
         ->withPivot('order')
         ->orderBy('pivot_order');
   }

}

重写默认值

您必须更改用于存储排序的默认列以及默认排序作用域。

重写默认排序列

public function getOrderableColumn(): string {
  return 'non_default_order_column';
}

重写全局排序作用域

public function scopeOrdered(Builder $query): void{
  $query->orderBy('menu_id')->orderBy('order');
}

贡献

欢迎提交拉取请求。对于主要更改,请首先打开一个问题以讨论您想要更改的内容。

请确保根据需要更新测试。

许可

MIT