Skip to content

Commit

Permalink
added Finder::sortBy() & sortByName()
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed Feb 2, 2023
1 parent d422dd0 commit 18452e5
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 8 deletions.
52 changes: 44 additions & 8 deletions src/Utils/Finder.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ class Finder implements \IteratorAggregate
/** @var \Closure[] */
private array $descentFilters = [];
private bool $childFirst = false;

/** @var ?callable */
private $sort;
private int $maxDepth = -1;
private bool $ignoreUnreadableDirs = true;

Expand Down Expand Up @@ -163,6 +166,27 @@ public function ignoreUnreadableDirs(bool $state = true): static
}


/**
* Set a compare function for sorting directory entries. The function will be called to sort entries from the same directory.
* @param callable(FileInfo, FileInfo): int $callback
*/
public function sortBy(callable $callback): static
{
$this->sort = $callback;
return $this;
}


/**
* Sorts files in each directory naturally by name.
*/
public function sortByName(): static
{
$this->sort = fn(FileInfo $a, FileInfo $b): int => strnatcmp($a->getBasename(), $b->getBasename());
return $this;
}


/********************* filtering ****************d*g**/


Expand Down Expand Up @@ -307,16 +331,16 @@ private function traverseDir(string $dir, array $searches, array $subdirs = []):
throw new Nette\InvalidStateException($e->getMessage());
}
}
$absolute = FileSystem::isAbsolute($dir);

$relativePath = implode(DIRECTORY_SEPARATOR, $subdirs);
$files = $this->convertToFiles($pathNames, implode('/', $subdirs), FileSystem::isAbsolute($dir));

foreach ($pathNames as $pathName) {
if (!$absolute) {
$pathName = preg_replace('~\.?/~A', '', $pathName);
}
$pathName = FileSystem::platformSlashes($pathName);
$file = new FileInfo($pathName, $relativePath);
if ($this->sort) {
$files = iterator_to_array($files);
usort($files, $this->sort);
}

foreach ($files as $file) {
$pathName = $file->getPathname();
$cache = $subSearch = [];

if ($file->isDir()) {
Expand Down Expand Up @@ -350,6 +374,18 @@ private function traverseDir(string $dir, array $searches, array $subdirs = []):
}


private function convertToFiles(iterable $pathNames, string $relativePath, bool $absolute): \Generator
{
foreach ($pathNames as $pathName) {
if (!$absolute) {
$pathName = preg_replace('~\.?/~A', '', $pathName);
}
$pathName = FileSystem::platformSlashes($pathName);
yield new FileInfo($pathName, $relativePath);
}
}


private function proveFilters(array $filters, FileInfo $file, array &$cache): bool
{
foreach ($filters as $filter) {
Expand Down
69 changes: 69 additions & 0 deletions tests/Utils/Finder.sort.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

/**
* Test: Nette\Utils\Finder sorting.
*/

declare(strict_types=1);

use Nette\Utils\FileInfo;
use Nette\Utils\Finder;
use Tester\Assert;


require __DIR__ . '/../bootstrap.php';


function export($iterator)
{
$arr = [];
foreach ($iterator as $key => $value) {
$arr[] = strtr($key, '\\', '/');
}

return $arr;
}


test('byName', function () {
$finder = Finder::find('*')
->from('fixtures.finder')
->sortByName();

Assert::same([
'fixtures.finder/file.txt',
'fixtures.finder/images',
'fixtures.finder/images/logo.gif',
'fixtures.finder/subdir',
'fixtures.finder/subdir/file.txt',
'fixtures.finder/subdir/readme',
'fixtures.finder/subdir/subdir2',
'fixtures.finder/subdir/subdir2/file.txt',
], export($finder));

$finder->childFirst();
Assert::same([
'fixtures.finder/file.txt',
'fixtures.finder/images/logo.gif',
'fixtures.finder/images',
'fixtures.finder/subdir/file.txt',
'fixtures.finder/subdir/readme',
'fixtures.finder/subdir/subdir2/file.txt',
'fixtures.finder/subdir/subdir2',
'fixtures.finder/subdir',
], export($finder));
});

test('user func', function () {
$finder = Finder::findFiles('*')
->from('fixtures.finder')
->sortBy(fn(FileInfo $a, FileInfo $b) => substr((string) $a, -1) <=> substr((string) $b, -1));

Assert::same([
'fixtures.finder/subdir/subdir2/file.txt',
'fixtures.finder/subdir/readme',
'fixtures.finder/subdir/file.txt',
'fixtures.finder/images/logo.gif',
'fixtures.finder/file.txt',
], export($finder));
});

0 comments on commit 18452e5

Please sign in to comment.