焦点/数据

用于处理非结构化数据(如JSON)的工具集合

3.1.0 2024-08-26 14:14 UTC

This package is auto-updated.

Last update: 2024-08-26 14:15:25 UTC


README

Minimum PHP Version Latest Stable Version CI Status Code Coverage

用于处理非结构化数据(如JSON)的工具集合

安装

安装并使用此包的最佳方式是使用 composer

composer require focus/data

用法

最基本的使用是 KeyedDataObject,它封装对象和 KeyedDataArray,它封装数组

use Focus\Data\KeyedData\KeyedDataFactory;

$value = [
    'user' => [
        'name' => 'Susan Smith',
        'email' => 'susan@example.com',
        'hobbies' => [
            'football',
            'swimming',
            'reading',
        ],
        'deactivated_at' => null,
    ],
];

// Will create either KeyedDataObject or KeyedDataArray, depending on the value
$data = KeyedDataFactory::from($value);

一旦您有一个数据实例,您可以通过使用点路径来访问值

$name = $data->get(path: 'user.name'); // Susan Smith
$email = $data->get(path: 'user.email'); // susan@example.com

不存在的值将返回为 null

$phone = $data->get(path: 'user.phone'); // null

支持使用 JMESPath 表达式,通过使用 search() 方法

$sports = $data->search(path: "user.hobbies[? contains(@, 'ball')]"); // ['football']

即使值是 null,也可以检查路径的存在

$deactivated = $data->has(path: 'user.deactivated_at'); // true

JSON 数据

JsonData 对象是一个代理,具有用于从 JSON 字符串以及 PSR-7 RequestInterfaceServerRequestInterfaceResponseInterface 对象创建数据实例的工厂方法

use Focus\Data\JsonData;

/** @var Psr\Http\Message\ServerRequestInterface $request */
$request = $app->request();

$data = JsonData::fromRequest($request);

JsonData 提供了三种工厂方法

  • fromString() 从 JSON 字符串创建数据
  • fromRequest() 从 PSR-7(服务器)请求创建数据
  • fromResponse() 从 PSR-7 响应创建数据

当使用 ServerRequestInterface 对象调用 JsonData::fromRequest() 时,默认会使用 getParsedBody() 的值。要禁用此行为,请使用

$data = JsonData::fromRequest($request, useParsedBody: false);

当使用 getParsedBody() 时,请记住,大多数 ServerRequestInterface 对象会使用 associative: true 解码请求体,生成一个数组。如果您希望 JsonData->value 是一个对象而不是数组,请将 ServerRequestInterface 配置为使用 associative: falsejson_decode() 的默认值)解码请求体

常见问题解答

这些是关于此包的使用和设计的常见问题。

为什么 has() 对 null 值返回 true?

这允许检测输入值,这些值不应该被覆盖。例如,如果应用程序将 deactivated_at 时间戳设置为表示用户已离职,它可能还需要能够通过设置 deactivated_at: null 来重新激活用户

if ($data->get(path: 'user.deactivated_at')) {
    $this->userRepository->deactivate(
        id: $data->get(path: 'user.id'),
        timestamp: $data->get(path: 'user.deactivated_at'),
    );
} elseif ($data->has(path: 'user.deactivated_at')) {
    $this->userRepository->activate(
        id: $data->get(path: 'user.id'),
    );
}

如果 has() 对 null 值不返回 true,则检测 null 值的存在将是不可能的,因为 get() 对于未定义的路径返回 null。

为什么存在数据接口?

细心的观察者会注意到 KeyedData 实现了一个 Data 接口,以及存在 DataProxy 抽象类的存在。这允许通过使用 代理对象 来定制实现,尽管 KeyedData 是一个 final readonly 类,以满足 开闭原则

默认情况下,DataProxy 对象会将所有调用直接转发到源 Data 对象。这允许自定义任何方法的行为,而无需实现完整的 Data 接口。例如,这将修改 get() 方法以将 false 值视为 null

use Focus\Data\Data;
use Focus\Data\DataProxy;

final class MyData extends DataProxy
{
    public function get(string $path): mixed
    {
        $value = $this->source()->get($path);
        
        if ($value === false) {
           return null;
        }
        
        return $value;
    }
}