1
0
mirror of https://github.com/BookStackApp/BookStack.git synced 2026-01-03 23:42:28 +03:00

Sorting: Added book autosort logic

This commit is contained in:
Dan Brown
2025-02-05 16:52:20 +00:00
parent 7093daa49d
commit c13ce18837
6 changed files with 153 additions and 0 deletions

View File

@@ -16,6 +16,54 @@ class BookSorter
) {
}
/**
* Runs the auto-sort for a book if the book has a sort set applied to it.
* This does not consider permissions since the sort operations are centrally
* managed by admins so considered permitted if existing and assigned.
*/
public function runBookAutoSort(Book $book): void
{
$set = $book->sortSet;
if (!$set) {
return;
}
$sortFunctions = array_map(function (SortSetOperation $op) {
return $op->getSortFunction();
}, $set->getOperations());
$chapters = $book->chapters()
->with('pages:id,name,priority,created_at,updated_at')
->get(['id', 'name', 'priority', 'created_at', 'updated_at']);
/** @var (Chapter|Book)[] $topItems */
$topItems = [
...$book->directPages()->get(['id', 'name', 'priority', 'created_at', 'updated_at']),
...$chapters,
];
foreach ($sortFunctions as $sortFunction) {
usort($topItems, $sortFunction);
}
foreach ($topItems as $index => $topItem) {
$topItem->priority = $index + 1;
$topItem->save();
}
foreach ($chapters as $chapter) {
$pages = $chapter->pages->all();
foreach ($sortFunctions as $sortFunction) {
usort($pages, $sortFunction);
}
foreach ($pages as $index => $page) {
$page->priority = $index + 1;
$page->save();
}
}
}
/**
* Sort the books content using the given sort map.

View File

@@ -2,6 +2,9 @@
namespace BookStack\Sorting;
use Closure;
use Illuminate\Support\Str;
enum SortSetOperation: string
{
case NameAsc = 'name_asc';
@@ -33,6 +36,12 @@ enum SortSetOperation: string
return trim($label);
}
public function getSortFunction(): callable
{
$camelValue = Str::camel($this->value);
return SortSetOperationComparisons::$camelValue(...);
}
/**
* @return SortSetOperation[]
*/

View File

@@ -0,0 +1,69 @@
<?php
namespace BookStack\Sorting;
use BookStack\Entities\Models\Chapter;
use BookStack\Entities\Models\Entity;
/**
* Sort comparison function for each of the possible SortSetOperation values.
* Method names should be camelCase names for the SortSetOperation enum value.
* TODO - Test to cover each SortSetOperation enum value is covered.
*/
class SortSetOperationComparisons
{
public static function nameAsc(Entity $a, Entity $b): int
{
return $a->name <=> $b->name;
}
public static function nameDesc(Entity $a, Entity $b): int
{
return $b->name <=> $a->name;
}
public static function nameNumericAsc(Entity $a, Entity $b): int
{
$numRegex = '/^\d+(\.\d+)?/';
$aMatches = [];
$bMatches = [];
preg_match($numRegex, $a, $aMatches);
preg_match($numRegex, $b, $bMatches);
return ($aMatches[0] ?? 0) <=> ($bMatches[0] ?? 0);
}
public static function nameNumericDesc(Entity $a, Entity $b): int
{
return -(static::nameNumericAsc($a, $b));
}
public static function createdDateAsc(Entity $a, Entity $b): int
{
return $a->created_at->unix() <=> $b->created_at->unix();
}
public static function createdDateDesc(Entity $a, Entity $b): int
{
return $b->created_at->unix() <=> $a->created_at->unix();
}
public static function updatedDateAsc(Entity $a, Entity $b): int
{
return $a->updated_at->unix() <=> $b->updated_at->unix();
}
public static function updatedDateDesc(Entity $a, Entity $b): int
{
return $b->updated_at->unix() <=> $a->updated_at->unix();
}
public static function chaptersFirst(Entity $a, Entity $b): int
{
return ($b instanceof Chapter ? 1 : 0) - (($a instanceof Chapter) ? 1 : 0);
}
public static function chaptersLast(Entity $a, Entity $b): int
{
return ($a instanceof Chapter ? 1 : 0) - (($b instanceof Chapter) ? 1 : 0);
}
}