【Laravel】Eloquentをソート順に並び替える
Eloquentを使用しているLaravelのモデルに並び順を追加・操作する機能を付与したい場合には、spatie/eloquent-sortableが非常に便利だったので紹介します。
インストール
$ composer require spatie/eloquent-sortable
モデルの定義
インストールが完了したら、ソートしたいモデルにimplements Sortable
, use SortableTrait
及びpublic $sortable
を追加します。
<?php
use Spatie\EloquentSortable\Sortable;
use Spatie\EloquentSortable\SortableTrait;
class MyModel extends Model implements Sortable
{
use SortableTrait;
public $sortable = [
'order_column_name' => 'order_column',
'sort_when_creating' => true,
];
...
}
データの取得は以下のように行います。
$orderedRecords = MyModel::ordered()->get();
デフォルトでソートを適用する場合は、以下のようなコードを追加します。
protected static function boot()
{
parent::boot();
static::addGlobalScope('ordered', static function (Builder $builder) {
$builder->ordered();
});
}
ソートを解除してデータを取得することも可能です。
$orderedRecords = MyModel::withoutGlobalScope()->get();
並び替え
ソート順の変更は以下のように行います。
並び替え
MyModel::setNewOrder([3,1,2]);
上に移動
$myModel->moveOrderUp();
下に移動
$myModel->moveOrderDown();
一番最初に移動
$myModel->moveToStart();
一番最後に移動
$myModel->moveToEnd();
順番を入れ替える
MyModel::swapOrder($myModel, $anotherModel);
グルーピング
外部キーごとにソート番号を管理したい場合は、モデルに以下のようなコードを追加することで実装できます。
public function buildSortQuery()
{
return static::query()->where('user_id', $this->user_id);
}
タイムスタンプ
デフォルトでは、並び替え順を変更した際にupdated_at
のようなタイムスタンプが更新されてしまいます。
更新を防ぐには以下のコードをモデルに追加してください。
<?php
class MyModel extends Model
{
// flag
protected static $ignoreTimestamps = false;
// setter
public static function ignoreTimestamps(bool $ignore = true)
{
static::$ignoreTimestamps = $ignore;
}
// override the method in the HasAttributes trait to also check for the custom flag
public function usesTimestamps()
{
return parent::usesTimestamps() && !static::$ignoreTimestamps;
}
// ...
}
並び替え変更時
MyModel::ignoreTimestamps();
MyModel::setNewOrder($order);
MyModel::ignoreTimestamps(false);