rossaddison / data
数据提供者、分页及相关抽象
Requires
- php: ^8.1
- ext-mbstring: *
- yiisoft/arrays: ^3.0
Requires (Dev)
- maglnet/composer-require-checker: ^4.7
- phpunit/phpunit: ^10
- rector/rector: ^1.0
- roave/infection-static-analysis-plugin: ^1.34
- spatie/phpunit-watcher: ^1.23
- vimeo/psalm: ^5.20
This package is auto-updated.
Last update: 2024-09-25 14:32:11 UTC
README
Yii 数据
该包提供通用数据抽象。目标是隐藏读取、写入和处理数据操作中的存储方面。
特性包括
- 具有计数、排序、限制和偏移、读取条件过滤器以及后过滤器的数据读取器抽象。
- 包括偏移和键集实现的分页抽象。
- 数据写入器抽象。
- 数据处理器抽象。
要求
- PHP 8.1 或更高版本。
安装
该包可以使用 Composer 安装。
composer require yiisoft/data
通用用法
概念
- 每个数据集由项目组成。
- 每个项目有多个命名字段。
- 数据集中的所有项目都具有相同的结构。
读取数据
数据读取器的目的是从数据库、数组或 API 等存储中读取数据,并将其转换为简单的字段 => 值迭代器。
$reader = new MyDataReader(...); $result = $reader->read();
结果是 iterable
,因此可以在其上使用 foreach
。如果您需要一个数组,可以按以下方式实现
// using is foreach foreach ($result as $item) { // ... } // preparing array $dataArray = $result instanceof \Traversable ? iterator_to_array($result, true) : (array)$result;
限制读取的项目数量
您可以在迭代器中限制项目的数量
$reader = (new MyDataReader(...))->withLimit(10); foreach ($reader->read() as $item) { // ... }
计算项目总数
要获取实现 CountableDataInterface
的数据读取器中的项目总数
$reader = new MyDataReader(...); $total = count($reader);
过滤
数据过滤可以分两步完成
- 形成获取数据的条件。这是通过“过滤器”完成的。
- 通过迭代和检查每个项目来后过滤数据。这是通过带有过滤器的
IterableDataReader
完成的。
尽可能使用条件,因为通常它提供了更好的性能。
要在实现 FilterableDataInterface
的数据读取器中过滤数据,您需要向 withFilter()
方法提供过滤器
$filter = new All( new GreaterThan('id', 3), new Like('name', 'agent') ); $reader = (new MyDataReader(...)) ->withFilter($filter); $data = $reader->read();
过滤器可以组合
所有
任何
介于
等于
等于空
大于
大于等于
ILike
在
小于
小于等于
像
不是
使用数组进行过滤
所有
和 任何
过滤器都有 withCriteriaArray()
方法,允许您使用数组定义过滤器。
$dataReader->withFilter((new All())->withCriteriaArray([ ['=', 'id', 88], [ 'or', [ ['=', 'color', 'red'], ['=', 'state', 1], ] ] ]));
实现自己的过滤器
要拥有自己的过滤器
- 至少实现
FilterInterface
,它包括getOperator()
方法,它返回表示过滤操作的字符串。toArray()
方法,它返回包含过滤参数的数组。
- 如果您想为特定的数据读取器类型创建过滤器处理程序,则需要至少实现
FilterHandlerInterface
。它有一个单个的getOperator()
方法,该方法返回表示过滤操作的字符串。此外,每个数据读取器都指定一个扩展接口,用于处理或构建操作。例如,IterableDataFilter
定义了IterableFilterHandlerInterface
,它包含执行过滤操作的附加match()
方法。
您可以使用 withFilterHandlers()
方法将您自己的过滤器处理程序添加到数据读取器中。您可以将任何过滤器处理程序添加到读取器中。如果读取器无法使用过滤器,则过滤器将被忽略。
// own filter for filtering class OwnNotTwoFilter implenents FilterInterface { private $field; public function __construct($field) { $this->field = $field; } public static function getOperator(): string { return 'my!2'; } public function toArray(): array { return [static::getOperator(), $this->field]; } } // own iterable filter handler for matching class OwnIterableNotTwoFilterHandler implements IterableFilterHandlerInterface { public function getOperator(): string { return OwnNotTwoFilter::getOperator(); } public function match(array $item, array $arguments, array $filterHandlers): bool { [$field] = $arguments; return $item[$field] != 2; } } // and using it on a data reader $filter = new All( new LessThan('id', 8), new OwnNotTwoFilter('id'), ); $reader = (new MyDataReader(...)) ->withFilter($filter) ->withFilterHandlers( new OwnIterableNotTwoFilter() new OwnSqlNotTwoFilter() // for SQL // and for any supported readers... ); $data = $reader->read();
排序
要在实现SortableDataInterface
的数据读取器中对数据进行排序,您需要向withSort()
方法提供一个排序对象。
$sorting = Sort::only([ 'id', 'name' ]); $sorting = $sorting->withOrder(['name' => 'asc']); // or $sorting = $sorting->withOrderString('name'); $reader = (new MyDataReader(...)) ->withSort($sorting); $data = $reader->read();
Sort
的目标是将逻辑字段排序映射到实际数据集字段排序,并形成数据读取器的标准。逻辑字段是用户操作的字段。实际字段是在数据集中实际存在的字段。这种映射有助于您需要根据一个逻辑字段进行排序,而实际上该字段在底层数据集中由多个字段组成。例如,您为用户提供一个包含实际数据集中姓氏和名字字段的用户名。
要获取Sort
实例,您可以使用Sort::only()
或Sort::any()
。使用Sort::only()
时,会忽略用户指定的无配置的逻辑字段的顺序。Sort::any()
直接使用用户指定的无配置的逻辑字段名和顺序。
无论哪种方式,您都需要传递一个配置数组,指定哪些逻辑字段应该是可排序的,并且可选地提供这些字段如何映射到实际字段顺序的详细信息。
要应用当前顺序,请使用withOrder()
,您提供一个数组,其中键对应于逻辑字段名,值对应于顺序(asc
或desc
)。或者可以使用withOrderString()
。在这种情况下,顺序表示为一个包含逗号分隔的逻辑字段名的单个字符串。如果名称以-
开头,则顺序方向设置为desc
。
跳过一些项
如果您需要从实现OffsetableDataInterface
的数据读取器中跳过一些项。
$reader = (new MyDataReader(...))->withOffset(10);
实现您自己的数据读取器
要拥有您自己的数据读取器,您至少需要实现DataReaderInteface
。它有一个单一的read()
方法,该方法返回表示一组项的可迭代对象。
可以实现其他接口来支持不同的分页类型、排序和筛选。
CountableDataInterface
- 允许获取数据读取器中的项目总数。FilterableDataInterface
- 允许根据标准返回项目子集。LimitableDataInterface
- 允许返回有限的项目子集。SortableDataInterface
- 允许按一个或多个字段进行排序。OffsetableDataInterface
- 允许在读取数据时跳过前N个项。
请注意,在实现这些方法时,应该只定义在后续的read()
中使用的标准,而不是修改数据。
分页
分页允许获取有限的数据子集,这对于按页显示项目以及在大数据集上获得可接受的性能都很有用。
提供了两种分页类型:传统的偏移分页和键集分页。
偏移分页
偏移分页是一种常见的分页方法,它选择OFFSET + LIMIT项,然后跳过OFFSET项。
优点
- 可以获得总页数
- 可以到达特定的页面
- 数据可以无序
- 考虑了数据读取器中设置的限制
缺点
- 性能随着页码的增加而下降
- 数据中间的插入或删除会使结果不一致
使用方法如下
$reader = (new MyDataReader(...)); $paginator = (new OffsetPaginator($dataReader)) ->withPageSize(10) ->withCurrentPage(2); $total = $paginator->getTotalPages(); $data = $paginator->read();
键集分页
键集分页是一种替代的分页方法,适用于无限滚动和“加载更多”。它选择LIMIT个键字段值大于或小于(根据排序)指定值的项。
优点
- 性能不依赖于页码
- 无论插入和删除如何,结果都是一致的
缺点
- 无法获得总页数
- 无法访问特定页面,只有“上一页”和“下一页”
- 数据不能是无序的
- 数据读取器中设置的限制导致异常
使用方法如下
$sort = Sort::only(['id', 'name'])->withOrderString('id'); $dataReader = (new MyDataReader(...)) ->withSort($sort); $paginator = (new KeysetPaginator($dataReader)) ->withPageSize(10) ->withToken(PageToken::next('13'));
当使用withNextPageToken()
获取下一页时,使用最后显示的项目显示的第一页ID(或用于分页的其他字段名)
写入数据
$writer = new MyDataWriter(...); $writer->write($arrayOfItems);
处理数据
$processor = new MyDataProcessor(...); $processor->process($arrayOfItems);
文档
如果您需要帮助或有疑问,可以到Yii 论坛。您还可以查看其他Yii 社区资源。
许可协议
Yii 数据是免费软件。它根据BSD许可证发布。有关更多信息,请参阅LICENSE
。
由Yii 软件维护。