[Finder] make reverse sorting a bit more generic

This commit is contained in:
Nicolas Grekas 2018-10-10 05:11:49 -07:00
parent 631d718ae8
commit ce861d1861
5 changed files with 32 additions and 88 deletions

View File

@ -7,7 +7,7 @@ CHANGELOG
* added $useNaturalSort option to Finder::sortByName() method
* the `Finder::sortByName()` method will have a new `$useNaturalSort`
argument in version 5.0, not defining it is deprecated
* added `Finder::reverseSorting` to reverse the sorting
* added `Finder::reverseSorting()` to reverse the sorting
4.0.0
-----

View File

@ -750,13 +750,8 @@ class Finder implements \IteratorAggregate, \Countable
$iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $this->notPaths);
}
if ($this->sort) {
$iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
$iterator = $iteratorAggregate->getIterator();
}
if ($this->reverseSorting) {
$iteratorAggregate = new Iterator\ReverseSortingIterator($iterator);
if ($this->sort || $this->reverseSorting) {
$iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort, $this->reverseSorting);
$iterator = $iteratorAggregate->getIterator();
}

View File

@ -1,32 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Iterator;
/**
* Reverse the order of a previous iterator.
*
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*/
class ReverseSortingIterator implements \IteratorAggregate
{
private $iterator;
public function __construct(\Traversable $iterator)
{
$this->iterator = $iterator;
}
public function getIterator()
{
return new \ArrayIterator(array_reverse(iterator_to_array($this->iterator, true)));
}
}

View File

@ -18,6 +18,7 @@ namespace Symfony\Component\Finder\Iterator;
*/
class SortableIterator implements \IteratorAggregate
{
const SORT_BY_NONE = 0;
const SORT_BY_NAME = 1;
const SORT_BY_TYPE = 2;
const SORT_BY_ACCESSED_TIME = 3;
@ -34,40 +35,43 @@ class SortableIterator implements \IteratorAggregate
*
* @throws \InvalidArgumentException
*/
public function __construct(\Traversable $iterator, $sort)
public function __construct(\Traversable $iterator, $sort, bool $reverseOrder = false)
{
$this->iterator = $iterator;
$order = $reverseOrder ? -1 : 1;
if (self::SORT_BY_NAME === $sort) {
$this->sort = function ($a, $b) {
return strcmp($a->getRealpath() ?: $a->getPathname(), $b->getRealpath() ?: $b->getPathname());
$this->sort = function ($a, $b) use ($order) {
return $order * strcmp($a->getRealpath() ?: $a->getPathname(), $b->getRealpath() ?: $b->getPathname());
};
} elseif (self::SORT_BY_NAME_NATURAL === $sort) {
$this->sort = function ($a, $b) {
return strnatcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());
$this->sort = function ($a, $b) use ($order) {
return $order * strnatcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());
};
} elseif (self::SORT_BY_TYPE === $sort) {
$this->sort = function ($a, $b) {
$this->sort = function ($a, $b) use ($order) {
if ($a->isDir() && $b->isFile()) {
return -1;
return -$order;
} elseif ($a->isFile() && $b->isDir()) {
return 1;
return $order;
}
return strcmp($a->getRealpath() ?: $a->getPathname(), $b->getRealpath() ?: $b->getPathname());
return $order * strcmp($a->getRealpath() ?: $a->getPathname(), $b->getRealpath() ?: $b->getPathname());
};
} elseif (self::SORT_BY_ACCESSED_TIME === $sort) {
$this->sort = function ($a, $b) {
return $a->getATime() - $b->getATime();
$this->sort = function ($a, $b) use ($order) {
return $order * ($a->getATime() - $b->getATime());
};
} elseif (self::SORT_BY_CHANGED_TIME === $sort) {
$this->sort = function ($a, $b) {
return $a->getCTime() - $b->getCTime();
$this->sort = function ($a, $b) use ($order) {
return $order * ($a->getCTime() - $b->getCTime());
};
} elseif (self::SORT_BY_MODIFIED_TIME === $sort) {
$this->sort = function ($a, $b) {
return $a->getMTime() - $b->getMTime();
$this->sort = function ($a, $b) use ($order) {
return $order * ($a->getMTime() - $b->getMTime());
};
} elseif (self::SORT_BY_NONE === $sort) {
$this->sort = $order;
} elseif (\is_callable($sort)) {
$this->sort = $sort;
} else {
@ -77,8 +81,17 @@ class SortableIterator implements \IteratorAggregate
public function getIterator()
{
if (1 === $this->sort) {
return $this->iterator;
}
$array = iterator_to_array($this->iterator, true);
uasort($array, $this->sort);
if (-1 === $this->sort) {
$array = array_reverse($array);
} else {
uasort($array, $this->sort);
}
return new \ArrayIterator($array);
}

View File

@ -1,32 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Tests\Iterator;
use Symfony\Component\Finder\Iterator\ReverseSortingIterator;
class ReverseSortingIteratorTest extends IteratorTestCase
{
public function test()
{
$iterator = new ReverseSortingIterator(new MockFileListIterator(array(
'a.txt',
'b.yaml',
'c.php',
)));
$result = iterator_to_array($iterator);
$this->assertCount(3, $iterator);
$this->assertSame('c.php', $result[0]->getFilename());
$this->assertSame('b.yaml', $result[1]->getFilename());
$this->assertSame('a.txt', $result[2]->getFilename());
}
}