SortOrder
in package
エントリーの表示順の採番
表示順は「スコープ内で 1 から始まる連番」を正とする。スコープは表示順のカラムごとに異なり、 entry_sort はブログ、entry_user_sort はブログとユーザー、entry_category_sort はブログと カテゴリーで区切られる。
Table of Contents
Constants
- SORT_FIELDS = ['entry_sort', 'entry_user_sort', 'entry_category_sort']
- 表示順のカラム名とスコープの対応
Methods
-
buildUpdatePlan()
: array<int, array{type: "shift", delta: int, entryIds: list
}|array{type: "assign", values: array }> - 採番結果を、まとめて実行できる UPDATE の単位に分解する
- calculate() : array<int, int>
- 並べ替えの結果、スコープ内の各エントリーが取るべき表示順を求める
- reorder() : int
- 並べ替えを永続化する
Constants
SORT_FIELDS
表示順のカラム名とスコープの対応
public
mixed
SORT_FIELDS
= ['entry_sort', 'entry_user_sort', 'entry_category_sort']
Methods
buildUpdatePlan()
採番結果を、まとめて実行できる UPDATE の単位に分解する
public
buildUpdatePlan(array<int, array{id: int, sort: int}> $siblings, array<int, int> $assignments) : array<int, array{type: "shift", delta: int, entryIds: list}|array{type: "assign", values: array}>
差分(新しい値 - 元の値)が一定の連続した区間は「表示順に一定値を足す」1 本の UPDATE で 書ける。Rails の acts_as_list が increment_all / decrement_all で採っているのと同じ形で、 順位カラム方式では長距離移動や重複解消でこの形が支配的になる。実測でも、密な連番の ブログで重複を解消すると 582 行が 1 つの区間に畳まれる。
差分が揃わない行(壊れたデータの正規化など)は算術ではまとめられないため、CASE 式で 一括更新する側へ回す。
一時的に表示順が重複する順序で更新しても構わない。acts_as_list が 1 行ずつ更新する経路を 持つのは順位カラムに一意制約がある場合の制約違反を避けるためで、entry_sort 系には 一意制約が無いため区間の適用順は問わない。
Parameters
- $siblings : array<int, array{id: int, sort: int}>
-
calculate() に渡したものと同じ並び
- $assignments : array<int, int>
-
calculate() の戻り値
Return values
array<int, array{type: "shift", delta: int, entryIds: listcalculate()
並べ替えの結果、スコープ内の各エントリーが取るべき表示順を求める
public
calculate(array<int, array{id: int, sort: int}> $siblings, int $movedEntryId, int|null $prevEntryId, int|null $nextEntryId) : array<int, int>
兄弟リストの先頭から 1, 2, 3... と採番し直し、移動対象を $nextEntryId の手前 ($nextEntryId が無ければ $prevEntryId の直後)へ差し込む。既に正しい値が入っている行は 戻り値に含めないため、呼び出し側は差分だけを UPDATE すればよい。
移動対象を配置し終えたあと、既存の値が次の採番値以上になった時点で走査を打ち切る。 それ以降の行は押し出す必要が無いため、更新量が移動距離に比例する範囲に収まる。 打ち切り位置より後ろに残っている重複はここでは解消しない(データ修正ツールの担当)。
Parameters
- $siblings : array<int, array{id: int, sort: int}>
-
スコープ内の全エントリー。表示順・エントリーIDの昇順で渡すこと
- $movedEntryId : int
-
移動したエントリーのID
- $prevEntryId : int|null
-
移動先の直前に来るエントリーのID
- $nextEntryId : int|null
-
移動先の直後に来るエントリーのID
Return values
array<int, int> —更新が必要なエントリーID => 新しい表示順
reorder()
並べ替えを永続化する
public
reorder("entry_sort"|"entry_user_sort"|"entry_category_sort" $sortField, int $blogId, int|null $userId, int|null $categoryId, int $movedEntryId, int|null $prevEntryId, int|null $nextEntryId) : int
Parameters
- $sortField : "entry_sort"|"entry_user_sort"|"entry_category_sort"
- $blogId : int
- $userId : int|null
-
entry_user_sort のときのスコープ
- $categoryId : int|null
-
entry_category_sort のときのスコープ(カテゴリー未設定は null)
- $movedEntryId : int
- $prevEntryId : int|null
- $nextEntryId : int|null
Return values
int —更新したエントリー数