From 94dfc1b6e2e71866eaa4d868204d97b048cda3b2 Mon Sep 17 00:00:00 2001 From: Arunas Skirius Date: Fri, 17 Oct 2025 10:49:56 +0300 Subject: [PATCH] Add unified sortUsing() method to collections Simplifies controller sorting logic by introducing a unified sortUsing(method, order) method. Existing sorting methods now delegate to this new method. No breaking changes. --- src/Http/Controllers/FilesController.php | 15 +---- src/Http/Controllers/FoldersController.php | 32 +--------- src/LogFileCollection.php | 43 ++++++++----- src/LogFolderCollection.php | 71 +++++++++++----------- tests/Unit/LogFileCollectionTest.php | 54 ++++++++++++++++ tests/Unit/LogFolderCollectionTest.php | 58 ++++++++++++++++++ 6 files changed, 178 insertions(+), 95 deletions(-) diff --git a/src/Http/Controllers/FilesController.php b/src/Http/Controllers/FilesController.php index d6ab3eae..6be7ecc0 100644 --- a/src/Http/Controllers/FilesController.php +++ b/src/Http/Controllers/FilesController.php @@ -18,20 +18,7 @@ public function index(Request $request) $sortingMethod = config('log-viewer.defaults.file_sorting_method', SortingMethod::ModifiedTime); $direction = $this->validateDirection($request->query('direction')); - if ($sortingMethod === SortingMethod::ModifiedTime) { - if ($direction === SortingOrder::Ascending) { - $files = $files->sortByEarliestFirst(); - } else { - $files = $files->sortByLatestFirst(); - } - - } else { - if ($direction === SortingOrder::Ascending) { - $files = $files->sortAlphabeticallyAsc(); - } else { - $files = $files->sortAlphabeticallyDesc(); - } - } + $files->sortUsing($sortingMethod, $direction); return LogFileResource::collection($files); } diff --git a/src/Http/Controllers/FoldersController.php b/src/Http/Controllers/FoldersController.php index f6d9dc70..a0bfb790 100644 --- a/src/Http/Controllers/FoldersController.php +++ b/src/Http/Controllers/FoldersController.php @@ -23,37 +23,9 @@ public function index(Request $request) $fileSortingMethod = config('log-viewer.defaults.file_sorting_method', SortingMethod::ModifiedTime); $fileSortingOrder = $this->validateDirection($request->query('direction')); - if ($sortingMethod === SortingMethod::Alphabetical) { - if ($sortingOrder === SortingOrder::Ascending) { - $folders = $folders->sortAlphabeticallyAsc(); - } else { - $folders = $folders->sortAlphabeticallyDesc(); - } - } else { // ModifiedTime - if ($fileSortingOrder === SortingOrder::Ascending) { - $folders = $folders->sortByEarliestFirst(); - } else { - $folders = $folders->sortByLatestFirst(); - } - } + $folders->sortUsing($sortingMethod, $sortingOrder); - // Sort files within folders after sorting folders - $folders->each(function ($folder) use ($fileSortingMethod, $fileSortingOrder) { - if ($fileSortingMethod === SortingMethod::ModifiedTime) { - if ($fileSortingOrder === SortingOrder::Ascending) { - $folder->files()->sortByEarliestFirst(); - } else { - $folder->files()->sortByLatestFirst(); - } - - } else { - if ($fileSortingOrder === SortingOrder::Ascending) { - $folder->files()->sortAlphabeticallyAsc(); - } else { - $folder->files()->sortAlphabeticallyDesc(); - } - } - }); + $folders->each(fn ($folder) => $folder->files()->sortUsing($fileSortingMethod, $fileSortingOrder)); return LogFolderResource::collection($folders->values()); } diff --git a/src/LogFileCollection.php b/src/LogFileCollection.php index 23a44ec5..474aa2bc 100644 --- a/src/LogFileCollection.php +++ b/src/LogFileCollection.php @@ -3,6 +3,8 @@ namespace Opcodes\LogViewer; use Illuminate\Support\Collection; +use Opcodes\LogViewer\Enums\SortingMethod; +use Opcodes\LogViewer\Enums\SortingOrder; use Opcodes\LogViewer\Readers\MultipleLogReader; /** @@ -10,36 +12,47 @@ */ class LogFileCollection extends Collection { - public function sortByEarliestFirst(): self + public function sortUsing(string $method, string $order): self { - $this->items = $this->sortBy(function (LogFile $file) { - return $file->earliestTimestamp().($file->name ?? ''); - }, SORT_NATURAL)->values()->all(); + if ($method === SortingMethod::ModifiedTime) { + if ($order === SortingOrder::Ascending) { + $this->items = $this->sortBy(function (LogFile $file) { + return $file->earliestTimestamp().($file->name ?? ''); + }, SORT_NATURAL)->values()->all(); + } else { + $this->items = $this->sortByDesc(function (LogFile $file) { + return $file->latestTimestamp().($file->name ?? ''); + }, SORT_NATURAL)->values()->all(); + } + } else { + if ($order === SortingOrder::Ascending) { + $this->items = $this->sortBy('name')->values()->all(); + } else { + $this->items = $this->sortByDesc('name')->values()->all(); + } + } return $this; } - public function sortByLatestFirst(): self + public function sortByEarliestFirst(): self { - $this->items = $this->sortByDesc(function (LogFile $file) { - return $file->latestTimestamp().($file->name ?? ''); - }, SORT_NATURAL)->values()->all(); + return $this->sortUsing(SortingMethod::ModifiedTime, SortingOrder::Ascending); + } - return $this; + public function sortByLatestFirst(): self + { + return $this->sortUsing(SortingMethod::ModifiedTime, SortingOrder::Descending); } public function sortAlphabeticallyAsc(): self { - $this->items = $this->sortBy('name')->values()->all(); - - return $this; + return $this->sortUsing(SortingMethod::Alphabetical, SortingOrder::Ascending); } public function sortAlphabeticallyDesc(): self { - $this->items = $this->sortByDesc('name')->values()->all(); - - return $this; + return $this->sortUsing(SortingMethod::Alphabetical, SortingOrder::Descending); } public function latest(): ?LogFile diff --git a/src/LogFolderCollection.php b/src/LogFolderCollection.php index 394f5038..a0897a17 100644 --- a/src/LogFolderCollection.php +++ b/src/LogFolderCollection.php @@ -3,9 +3,40 @@ namespace Opcodes\LogViewer; use Illuminate\Support\Collection; +use Opcodes\LogViewer\Enums\SortingMethod; +use Opcodes\LogViewer\Enums\SortingOrder; class LogFolderCollection extends Collection { + public function sortUsing(string $method, string $order): self + { + if ($method === SortingMethod::ModifiedTime) { + if ($order === SortingOrder::Ascending) { + $this->items = $this->sortBy->earliestTimestamp()->values()->all(); + } else { + $this->items = $this->sortByDesc->latestTimestamp()->values()->all(); + } + } else { + $this->items = collect($this->items) + ->sort(function (LogFolder $a, LogFolder $b) use ($order) { + if ($a->isRoot() && ! $b->isRoot()) { + return -1; + } + if (! $a->isRoot() && $b->isRoot()) { + return 1; + } + + return $order === SortingOrder::Ascending + ? strcmp($a->cleanPath(), $b->cleanPath()) + : strcmp($b->cleanPath(), $a->cleanPath()); + }) + ->values() + ->all(); + } + + return $this; + } + public static function fromFiles($files = []): LogFolderCollection { return new LogFolderCollection( @@ -18,16 +49,12 @@ public static function fromFiles($files = []): LogFolderCollection public function sortByEarliestFirst(): self { - $this->items = $this->sortBy->earliestTimestamp()->values()->all(); - - return $this; + return $this->sortUsing(SortingMethod::ModifiedTime, SortingOrder::Ascending); } public function sortByLatestFirst(): self { - $this->items = $this->sortByDesc->latestTimestamp()->values()->all(); - - return $this; + return $this->sortUsing(SortingMethod::ModifiedTime, SortingOrder::Descending); } public function sortByEarliestFirstIncludingFiles(): self @@ -48,39 +75,11 @@ public function sortByLatestFirstIncludingFiles(): self public function sortAlphabeticallyAsc(): self { - $this->items = collect($this->items) - ->sort(function (LogFolder $a, LogFolder $b) { - if ($a->isRoot() && ! $b->isRoot()) { - return -1; - } - if (! $a->isRoot() && $b->isRoot()) { - return 1; - } - - return strcmp($a->cleanPath(), $b->cleanPath()); - }) - ->values() - ->all(); - - return $this; + return $this->sortUsing(SortingMethod::Alphabetical, SortingOrder::Ascending); } public function sortAlphabeticallyDesc(): self { - $this->items = collect($this->items) - ->sort(function (LogFolder $a, LogFolder $b) { - if ($a->isRoot() && ! $b->isRoot()) { - return -1; - } - if (! $a->isRoot() && $b->isRoot()) { - return 1; - } - - return strcmp($b->cleanPath(), $a->cleanPath()); - }) - ->values() - ->all(); - - return $this; + return $this->sortUsing(SortingMethod::Alphabetical, SortingOrder::Descending); } } diff --git a/tests/Unit/LogFileCollectionTest.php b/tests/Unit/LogFileCollectionTest.php index 4fc63188..0a64fd0b 100644 --- a/tests/Unit/LogFileCollectionTest.php +++ b/tests/Unit/LogFileCollectionTest.php @@ -1,5 +1,7 @@ toBe($secondFile); }); + +test('LogFileCollection can sort by ModifiedTime ascending using sortUsing method', function () { + $firstFile = Mockery::mock(new LogFile('test.log')) + ->allows(['earliestTimestamp' => now()->subDay()->timestamp, 'name' => 'test.log']); + $secondFile = Mockery::mock(new LogFile('test2.log')) + ->allows(['earliestTimestamp' => now()->subDays(2)->timestamp, 'name' => 'test2.log']); + $collection = new LogFileCollection([$firstFile, $secondFile]); + + $collection->sortUsing(SortingMethod::ModifiedTime, SortingOrder::Ascending); + + expect($collection[0])->toBe($secondFile) + ->and($collection[1])->toBe($firstFile); +}); + +test('LogFileCollection can sort by ModifiedTime descending using sortUsing method', function () { + $firstFile = Mockery::mock(new LogFile('test.log')) + ->allows(['latestTimestamp' => now()->subDays(2)->timestamp, 'name' => 'test.log']); + $secondFile = Mockery::mock(new LogFile('test2.log')) + ->allows(['latestTimestamp' => now()->subDay()->timestamp, 'name' => 'test2.log']); + $collection = new LogFileCollection([$firstFile, $secondFile]); + + $collection->sortUsing(SortingMethod::ModifiedTime, SortingOrder::Descending); + + expect($collection[0])->toBe($secondFile) + ->and($collection[1])->toBe($firstFile); +}); + +test('LogFileCollection can sort alphabetically ascending using sortUsing method', function () { + $fileA = new LogFile('a.log'); + $fileB = new LogFile('b.log'); + $fileC = new LogFile('c.log'); + $collection = new LogFileCollection([$fileC, $fileA, $fileB]); + + $collection->sortUsing(SortingMethod::Alphabetical, SortingOrder::Ascending); + + expect($collection[0])->toBe($fileA) + ->and($collection[1])->toBe($fileB) + ->and($collection[2])->toBe($fileC); +}); + +test('LogFileCollection can sort alphabetically descending using sortUsing method', function () { + $fileA = new LogFile('a.log'); + $fileB = new LogFile('b.log'); + $fileC = new LogFile('c.log'); + $collection = new LogFileCollection([$fileA, $fileC, $fileB]); + + $collection->sortUsing(SortingMethod::Alphabetical, SortingOrder::Descending); + + expect($collection[0])->toBe($fileC) + ->and($collection[1])->toBe($fileB) + ->and($collection[2])->toBe($fileA); +}); diff --git a/tests/Unit/LogFolderCollectionTest.php b/tests/Unit/LogFolderCollectionTest.php index e219f1a0..9f1d91b9 100644 --- a/tests/Unit/LogFolderCollectionTest.php +++ b/tests/Unit/LogFolderCollectionTest.php @@ -1,5 +1,7 @@ and($collection[2])->toBe($bFolder) ->and($collection[3])->toBe($aFolder); }); + +test('LogFolderCollection can sort by ModifiedTime ascending using sortUsing method', function () { + $firstFolder = Mockery::mock(new LogFolder('folder', [])) + ->allows(['earliestTimestamp' => now()->subDay()->timestamp]); + $secondFolder = Mockery::mock(new LogFolder('folder2', [])) + ->allows(['earliestTimestamp' => now()->subDays(2)->timestamp]); + $collection = new LogFolderCollection([$firstFolder, $secondFolder]); + + $collection->sortUsing(SortingMethod::ModifiedTime, SortingOrder::Ascending); + + expect($collection[0])->toBe($secondFolder) + ->and($collection[1])->toBe($firstFolder); +}); + +test('LogFolderCollection can sort by ModifiedTime descending using sortUsing method', function () { + $firstFolder = Mockery::mock(new LogFolder('folder', [])) + ->allows(['latestTimestamp' => now()->subDays(2)->timestamp]); + $secondFolder = Mockery::mock(new LogFolder('folder2', [])) + ->allows(['latestTimestamp' => now()->subDay()->timestamp]); + $collection = new LogFolderCollection([$firstFolder, $secondFolder]); + + $collection->sortUsing(SortingMethod::ModifiedTime, SortingOrder::Descending); + + expect($collection[0])->toBe($secondFolder) + ->and($collection[1])->toBe($firstFolder); +}); + +test('LogFolderCollection can sort alphabetically ascending using sortUsing method, with root always on top', function () { + $rootFolder = Mockery::mock(new LogFolder('', []))->allows(['isRoot' => true, 'cleanPath' => LogFolder::rootPrefix()]); + $bFolder = Mockery::mock(new LogFolder('b', []))->allows(['isRoot' => false, 'cleanPath' => 'b']); + $aFolder = Mockery::mock(new LogFolder('a', []))->allows(['isRoot' => false, 'cleanPath' => 'a']); + $zFolder = Mockery::mock(new LogFolder('z', []))->allows(['isRoot' => false, 'cleanPath' => 'z']); + $collection = new LogFolderCollection([$zFolder, $rootFolder, $bFolder, $aFolder]); + + $collection->sortUsing(SortingMethod::Alphabetical, SortingOrder::Ascending); + + expect($collection[0])->toBe($rootFolder) + ->and($collection[1])->toBe($aFolder) + ->and($collection[2])->toBe($bFolder) + ->and($collection[3])->toBe($zFolder); +}); + +test('LogFolderCollection can sort alphabetically descending using sortUsing method, with root always on top', function () { + $rootFolder = Mockery::mock(new LogFolder('', []))->allows(['isRoot' => true, 'cleanPath' => LogFolder::rootPrefix()]); + $bFolder = Mockery::mock(new LogFolder('b', []))->allows(['isRoot' => false, 'cleanPath' => 'b']); + $aFolder = Mockery::mock(new LogFolder('a', []))->allows(['isRoot' => false, 'cleanPath' => 'a']); + $zFolder = Mockery::mock(new LogFolder('z', []))->allows(['isRoot' => false, 'cleanPath' => 'z']); + $collection = new LogFolderCollection([$aFolder, $zFolder, $rootFolder, $bFolder]); + + $collection->sortUsing(SortingMethod::Alphabetical, SortingOrder::Descending); + + expect($collection[0])->toBe($rootFolder) + ->and($collection[1])->toBe($zFolder) + ->and($collection[2])->toBe($bFolder) + ->and($collection[3])->toBe($aFolder); +});