charm / recordset
一个用于过滤和排序来自不同数据源(如数据库表、数组、API 或 CSV 文件)的数据行的库。
Requires
- php: >=7.4
- ext-intl: *
Requires (Dev)
- phpunit/phpunit: ^9
Suggests
- ext-mbstring: To support internationalized character encodings
This package is auto-updated.
Last update: 2024-09-06 04:49:32 UTC
README
Charm/Recordset 是一个库,允许您使用几个不同的强大查询 API 从任何数据源定义数据集合。
功能
- 将任何数据源发布为具有分页、排序和过滤功能的 REST API。
- 使用标准 SQL(包括 JOIN)查询和连接这些数据源。
- 支持的数据源
- PDO 数据库查询
- Sqlite3 数据库表
- CSV 文件
- PHP 数组、生成器和迭代器
- 其他 REST API
- 自定义数据源适配器
- 完全支持 UTF,并带有区域设置排序。
通过单个 API 提供数据,无论数据存储在 CSV 文件、远程 API 或是由生成数据构建。
例如;此 API 允许您执行以下 SQL 查询的等效操作
SELECT * FROM ./countries.csv ORDER BY latitude
SELECT value FROM positive_integers WHERE value < 10
SELECT value FROM all_integers WHERE value > -10 AND value < 10
以上示例只需实现每个表的后端。
TLDR
您可以通过简单的查询 API 提供所有数据,而不是创建各种方法来获取特定类的对象
您可以通过强大的和可预测的查询 API 使用户使用,而不是创建大量的类方法,如 getByUserId(int $userId)
和 getByFirstName(string $name)
// $user = $users->getById(123);
// one of three approaches
$user = $users->eq('id', 123)->first(); // low level API
$user = $users->where('id=123')->first(); // query string API
$user = $users->where('id=?', 123)->first(); // query string API with bound and typed columns
这种方法在多个领域带来巨大好处
自动支持更强大的查询:'users where gender = "male" and registered_ts > 123'
更高的安全性;记录集可以在后端“预先过滤”,因此消费者只能查询有限子集的行。
能够在不更新后端适配器的情况下替换后端。
基于文件的后端可以使用版本控制系统更新,而不是通过数据库迁移。
记录集可以作为基于查询字符串过滤的 REST API 集合公开。
后端必须实现 Charm\Recordset\RecordsetInterface
。实现此接口的最简单方法是扩展 Charm\Recordset\AbstractRecordset
。
对于 CSV 文件、PDO 数据库表、数组和生成器,有一些预先制作的后端可用。
下面将展示一些使用示例和 CSV 后端 Country
集合的简单实现。
查询
查询的最紧凑方法是使用 Recordset::query()
方法。
以下示例是等效的
foreach (Country::all()
->where('name[gt]=t&name[lt]=z&latitude[gte]=50&latitude[lte]=80&$order=-name')
->page(0,100) as $country) {
echo $country->getCapital()."\n";
}
和
foreach (Country::all() // fetch a recordset
->gt('name', 't') // reduce the recordset to countries where name > 't'
->lt('name', 'z') // and where name < '<'
->gte('latitude', 50) // and where latitude >= 20
->lt('latitude', 80) // and where latitude <= 80
->order('name', true) // sort them in descending order by name
->page(0, 100) // fetch the 100 first rows
as
$country) {
echo $country->getCapital()."\n";
}
通过向记录集添加运算符表达式来执行查询。
$southernCountries = $countries->lt('latitude', 0);
$northernCountries = $countries->gte('latitude', 0);
请注意,记录集是不可变的。这意味着您可以使用运算符来限制对行的访问。
可以链式使用多个运算符
$countriesNearEquator = $countries->lt('latitude', 23.43)->gt('latitude', -23.43);
以下运算符受支持
运算符 | 方法 |
---|---|
= | Recordset::eq($key, $value) |
> | Recordset::gt($key, $value) |
>= | Recordset::gte($key, $value) |
< | Recordset::lt($key, $value) |
<= | Recordset::lte($key, $value) |
startsWith | `Recordset::startsWith('name', 'n') |
获取数据
从记录集中获取前 100 行
$iterator = $northernCountries->page(0, 100)
即使此请求需要 100 次后端 API 调用,对消费者来说也是不可见的。如果过滤是通过数据库引擎执行的,或者过滤是通过 PHP 代码执行的,这也是隐藏的。
迭代结果
要实际获取行,请使用 page
方法
foreach ($southernCountries->page(0, 100) as $country) {
if ($country instanceof Country) {
// This requires that the backend objects of this kind
}
}
国家收藏
<?php
use Charm\Recordset\CSVRecordset;
class Country {
public $code, name, $latitude, $longitude;
protected function __construct(string $code, string $name, float $latitude, float $longitude) {
$this->code = $code;
$this->name = $name;
$this->latitude = $latitude;
$this->longitude = $longitude;
}
public static function all() {
/**
* It is quite simple to create a custom data provider, but
* here we'll be using the CSVRecordset class.
*
* CSV file are not indexed, but there are ways to accelerate
* this, for example by using a CachingRecordset or by
* using a more powerful backend for your data.
*/
return new CSVRecordset(
// the filename where data is stored
'countries.csv',
// a function which will convert an array of arrays to an array of objects
function(array $rows) {
foreach ($rows as $i => $row) {
$rows[$i] = new Country($row[0], $row[3], $row[1], $row[2]);
}
return $rows;
}
});
}
}
按关键字选择
<?php
// get a particular country
$norway = Country::all()->eq('name', 'Norway');
// get countries sorted by latitude
$countries = Country::all()->order('latitude');
// get countries sorted by name where latitude is greater than 70
$countries = Country::all()->gt('latitude', 70)->order('name');