stratadox / sorting
v0.3.1
2019-11-27 19:40 UTC
Requires
- php: >=7.0
- stratadox/sorting-contracts: ^0.3
Requires (Dev)
- php-coveralls/php-coveralls: ^2.2
- phpstan/phpstan: ^0.9.2
- phpunit/phpunit: ^7.1
README
排序包包含用于对表格或对象集合等数据结构进行排序的工具。
排序指令是对象,因此可以作为参数轻松传递。可以通过链式调用多个指令以按多个字段进行排序。
安装
使用composer安装
composer require stratadox/sorting
基本用法
二维数组
当对一个关联数组集合进行排序时,使用
<?php use Stratadox\Sorting\ArraySorter; use Stratadox\Sorting\Sort; $table = [ ['name' => 'Foo', 'rating' => 3], ['name' => 'Bar', 'rating' => 1], ['name' => 'Baz', 'rating' => 2], ]; $sorter = new ArraySorter(); $table = $sorter->sort($table, Sort::descendingBy('rating')); assert($table === [ ['name' => 'Foo', 'rating' => 3], ['name' => 'Baz', 'rating' => 2], ['name' => 'Bar', 'rating' => 1], ]);
对象
如果集合由对象组成,排序定义保持不变。在这种情况下,使用ObjectSorter而不是ArraySorter来获取排序需求。
<?php use Stratadox\Sorting\ObjectSorter; use Stratadox\Sorting\Sort; class SomeObject { private $name; private $rating; public function __construct(string $name, int $rating) { $this->name = $name; $this->rating = $rating; } public function name(): string { return $this->name; } public function rating(): int { return $this->rating; } } $objects = [ new SomeObject('Foo', 3), new SomeObject('Bar', 1), new SomeObject('Baz', 2), ]; $sorter = new ObjectSorter(); $objects = $sorter->sort($objects, Sort::ascendingBy('rating')); assert($objects == [ new SomeObject('Bar', 1), new SomeObject('Baz', 2), new SomeObject('Foo', 3), ]);
方法映射
当方法名称与字段名称不匹配,或需要使用自定义方法来确定排序权重时,可以给ObjectSorter提供一个映射。
<?php use Stratadox\Sorting\ObjectSorter; use Stratadox\Sorting\Sort; class SomeObject { private $name; private $rating; public function __construct(string $name, int $rating) { $this->name = $name; $this->rating = $rating; } public function getName(): string { return $this->name; } public function getTheRating(): int { return $this->rating; } } $objects = [ new SomeObject('Foo', 3), new SomeObject('Bar', 1), new SomeObject('Baz', 2), ]; $sorter = new ObjectSorter([ 'name' => 'getName', 'rating' => 'getTheRating', ]); $objects = $sorter->sort($objects, Sort::ascendingBy('rating')); assert($objects == [ new SomeObject('Bar', 1), new SomeObject('Baz', 2), new SomeObject('Foo', 3), ]);
嵌套数组
如果要排序的结构由嵌套数组列表组成,可以使用NestedArraySorter。
<?php use Stratadox\Sorting\NestedArraySorter; use Stratadox\Sorting\Sort; $unsorted = [ ['result' => ['index' => 3, 'label' => 'bar']], ['result' => ['index' => 2, 'label' => 'qux']], ['result' => ['index' => 1, 'label' => 'baz']], ['result' => ['index' => 2, 'label' => 'foo']], ]; $sorter = new NestedArraySorter(); $result = $sorter->sort($unsorted, Sort::ascendingBy('result.index')); assert($result === [ ['result' => ['index' => 1, 'label' => 'baz']], ['result' => ['index' => 2, 'label' => 'qux']], ['result' => ['index' => 2, 'label' => 'foo']], ['result' => ['index' => 3, 'label' => 'bar']], ]);
按多个字段排序
<?php use Stratadox\Sorting\ArraySorter; use Stratadox\Sorting\Sort; $table = [ ['name' => 'Bar', 'rating' => 1], ['name' => 'Foo', 'rating' => 3], ['name' => 'Baz', 'rating' => 1], ]; $sorter = new ArraySorter(); $table = $sorter->sort($table, Sort::descendingBy('rating', Sort::descendingBy('name')) ); assert($table == [ ['name' => 'Foo', 'rating' => 3], ['name' => 'Baz', 'rating' => 1], ['name' => 'Bar', 'rating' => 1], ]);
或者
<?php use Stratadox\Sorting\ArraySorter; use Stratadox\Sorting\Sort; $table = [ ['name' => 'Bar', 'rating' => 1], ['name' => 'Foo', 'rating' => 3], ['name' => 'Baz', 'rating' => 1], ]; $sorter = new ArraySorter(); $table = $sorter->sort($table, Sort::descendingBy('rating')->andThenDescendingBy('name') ); assert($table == [ ['name' => 'Foo', 'rating' => 3], ['name' => 'Baz', 'rating' => 1], ['name' => 'Bar', 'rating' => 1], ]);
或者
<?php use Stratadox\Sorting\ArraySorter; use Stratadox\Sorting\Sorted; $table = [ ['name' => 'Bar', 'rating' => 1], ['name' => 'Foo', 'rating' => 3], ['name' => 'Baz', 'rating' => 1], ]; $sorter = new ArraySorter(); $table = $sorter->sort($table, Sorted::by([ 'rating' => false, 'name' => false, ])); assert($table == [ ['name' => 'Foo', 'rating' => 3], ['name' => 'Baz', 'rating' => 1], ['name' => 'Bar', 'rating' => 1], ]);
结构
排序包包含两个核心概念
- 排序定义,用于声明排序需求,
- 排序器,根据给定定义对元素进行排序。
保持这种分离是为了将排序意图与被排序的数据结构解耦。
例如,排序定义 Sort::ascendingBy('name')
可以应用于关联数组集合或对象集合 - 请求排序的客户端不需要知道要排序的元素内部结构。
在设计允许排序的接口时,一个方法可能接受一个排序定义,例如 public function getSorted(Sorting $definition): array
。此接口的实现者可以使用他们认为合适的任何排序器,只要他们产生预期的结果。
某些实现甚至可能不使用任何排序器,而是直接使用排序定义以不同的方式生成排序后的结果列表。此类用法的示例可能是一个具有内存和SQL实现的存储库。
<?php use Stratadox\Sorting\Contracts\Sorting; use Stratadox\Sorting\ObjectSorter; use Stratadox\Sorting\OrderByParser; class SomeEntity { // ... } interface SomeRepository { /** @return SomeEntity[] */ public function all(Sorting $sorting): array; } class SomeInMemoryRepository implements SomeRepository { private $sorter; private $entities; public function __construct(SomeEntity ...$entities) { $this->sorter = new ObjectSorter(); $this->entities = $entities; } public function all(Sorting $sorting): array { return $this->sorter->sort($this->entities, $sorting); } } class SomeDatabaseRepository implements SomeRepository { private $connection; private $orderByParser; private $deserializer; public function __construct(PDO $connection, DeserializesObjects $deserializer) { $this->connection = $connection; $this->orderByParser = OrderByParser::allowing('foo', 'bar'); $this->deserializer = $deserializer; } public function all(Sorting $sorting): array { $query = $this->connection->query( 'SELECT * FROM some_table ' . $this->orderByParser->parse($sorting) ); $entities = []; foreach ($query->fetchAll(PDO::FETCH_ASSOC) as $row) { $entities[] = $this->deserializer->from($row); } return $entities; } }