maiorano84/object-hydrator

PHP对象的激活包

v1.0.0 2022-03-29 04:37 UTC

This package is auto-updated.

Last update: 2024-08-29 05:56:15 UTC


README

一个用于简化对象激活的小工具

Author Latest Stable Version Total Downloads License Build Status Code Coverage Scrutinizer Code Quality StyleCI

要求

Object Hydrator 需要 PHP 8.1 或更高版本。

Composer

可以通过运行以下命令将此包作为 Composer 依赖项安装:

composer require maiorano84/object-hydrator

如果您想使用最新不稳定版本,可以运行:

composer require maiorano84/object-hydrator:dev-master

用法

这是一组小概念,用于基于不同策略简化对象激活的编排。

默认的激活类使用以下 3 个概念来决定如何将给定的输入应用于对象:

  • 激活键 - 这些是简单的字符串,用于表示输入的名称。当输入键与激活键匹配时,值将通过底层映射传递。
  • 激活映射 - 这些是存储对给定键的引用以及指向属性或方法的反射对象的对象。当映射与给定的策略匹配时,它将传递一个值,该值可用于激活对象属性。
  • 激活策略 - 这些是定义如何将输入键和值映射的逻辑的对象。更进一步,这些对象还可以确定是否应该递归地处理由激活器处理的给定键和值。

激活键和激活策略都设置为属性,可用来装饰标记为激活的任何给定类结构。这样,您可以自定义给定类的激活方式。

可以将多个激活策略应用于单个给定类。

为什么?

许多 REST API 和 ORM 需要的一个常见任务是能够批量填充任意对象中的结构化数据。用于设置这些值的条件可以从一个类到另一个类有很大的不同,通过指定一个统一的接口来预测地发生类激活可能会很具挑战性。

最简单和最常见的方法是让每个对象实现一个负责该实体激活的给定接口。这种方法的问题在于它违反了单一职责原则,并为实体本身不需要处理的额外业务逻辑添加了。

这消除了处理自定义激活规则所需的大量样板代码,同时提供了一个简单的接口,通过该接口类可以定义自己的规则及其应用顺序。

用法

给定一个用户实体

namespace App;

class SimpleUser {
    public string $username;
    private string $password;

    public function getPassword(): string
    {
        return $this->password;
    }

    public function setPassword(string $password): void
    {
        $this->password = password_hash($password, PASSWORD_DEFAULT);
    }
}

用户实体的激活可以像以下这样简单

use App\SimpleUser;
use Maiorano\ObjectHydrator\Hydrator;

$hydrator = new Hydrator;
$user = $hydrator->hydrate(SimpleUser::class, [
    'username' => 'maiorano84',
    'password' => 'secret',
]);
print_r($user);
/*
App\SimpleUser Object
(
    [username] => maiorano84
    [password:App\SimpleUser:private] => <hashedPassword>
)
 */

默认情况下,未定义策略的类将按顺序使用 Reflection\PropertiesStrategyReflection\MethodsStrategy 的组合。结果将使用所有匹配公共属性名称的键,以及所有匹配属性设置器的键用于激活实体。注意在上面的示例中,公共 $username 使用 maiorano84 值激活,私有 $password 通过 setPassword 设置器激活。

更复杂的结构也可以这样激活

namespace App;

use Maiorano\ObjectHydrator\Attributes\HydrationKey;
use Maiorano\ObjectHydrator\Attributes\HydrationStrategy;
use Maiorano\ObjectHydrator\Strategies\ArrayStrategy;
use Maiorano\ObjectHydrator\Strategies\Reflection\MethodsStrategy;
use Maiorano\ObjectHydrator\Strategies\Reflection\PropertiesStrategy;

#[HydrationStrategy(ArrayStrategy::class, ['_id' => 'id', '_email' => 'email'])]
#[HydrationStrategy(PropertiesStrategy::class)]
#[HydrationStrategy(MethodsStrategy::class)]
class ComplexUser {
    private int $id;
    public string $username;
    private string $email;
    private string $password;
    private UserAvatar $avatar;

    public function getId(): int
    {
        return $this->id;
    }

    public function getEmail(): string
    {
        return $this->email;
    }

    public function getUserPassword(): string
    {
        return $this->password;
    }

    #[HydrationKey('_password')]
    public function setUserPassword(string $password): void
    {
        $this->password = password_hash($password, PASSWORD_DEFAULT);
    }

    public function getAvatar(): UserAvatar
    {
        return $this->avatar;
    }

    public function setAvatar(UserAvatar $avatar): void
    {
        $this->avatar = $avatar;
    }
}

#[HydrationStrategy(PropertiesStrategy::class, ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PRIVATE)]
class UserAvatar {
    #[HydrationKey('_id')]
    private int $id;
    public string $name;
    private string $filePath;

    public function getUrl(): string
    {
        return sprintf('https://mydomain.com/images/%s/%d-%s', $this->filePath, $this->id, $this->name);
    }
}

这里发生了很多事情

  • 可以使用 ArrayStrategy 显式地将某些输入键映射到属性或方法。
  • 我们将 PropertiesStrategyMethodsStrategy 的后备链接起来,以默认为未在 ArrayStrategy 中定义的键的适当公共属性/设置器行为。
  • UserAvatar 类允许为其 PropertiesStrategy 实现设置私有和公共属性。
  • HydrationKey 用于覆盖某些难以通过反射确定的区域中的输入键。

注水可以像以前一样进行。

use App\ComplexUser;
use Maiorano\ObjectHydrator\Hydrator;

$hydrator = new Hydrator;
$user = $this->hydrator->hydrate(ComplexUser::class, [
    '_id' => 1,
    '_email' => 'maiorano84@gmail.com',
    '_password' => 'secret',
    'username' => 'maiorano84',
    'avatar' => [
        '_id' => 123,
        'name' => 'maiorano84.jpg',
        'filePath' => 'path/to/avatars'
    ],
]);
print_r($user);
/*
App\ComplexUser Object
(
    [username] => maiorano84
    [id:App\ComplexUser:private] => 1
    [email:App\ComplexUser:private] => maiorano84@gmail.com
    [password:App\ComplexUser:private] => <hashedPassword>
    [avatar:App\ComplexUser:private] => App\UserAvatar Object
        (
            [name] => maiorano84.jpg
            [id:App\UserAvatar:private] => 123
            [filePath:App\UserAvatar:private] => path/to/avatars
        )
)
*/

注水器

可以将注水器视为一种编排工具。它本身并不真正进行任何属性设置或方法调用,而是遍历所有的键/值对,并确定最佳策略。

注水策略

注水策略封装了确定输入键和值如何映射到属性或方法的逻辑。每个注水策略都将公开一个底层映射接口,可用于定义给定键与其关联属性/方法之间的关系。

其他方法用于确定给定键是否在策略中可用,或者值是否可以被认为是递归的。

有关详细信息,请参阅 Maiorano\ObjectHydrator\Strategies\HydrationStrategyInterface

注水映射

映射包含一个注水键以及一个包含有关关联属性或方法信息的反射对象。映射主要用来存储给定的关联,以及完成适当的注水调用。

有关详细信息,请参阅 Maiorano\ObjectHydrator\Mappings\HydrationMappingInterface

注水键

注水键作为输入的指示器。对于给定的注水尝试的所有输入都应是一个结构化的关联数组,数组的所有键都表示一个期望的注水键。

默认的反射策略首先查找任何带有显式 HydrationKey 装饰器的属性/方法。

如果没有找到属性,则反射策略将尝试通过名称确定一个。

  • 对于属性,匹配的名称将被认为是关联,并创建一个映射。
  • 对于方法,如果方法以 set 开头并且其名称的其余部分与给定的属性匹配,则将使用该键创建一个映射。
  • 默认情况下,反射策略仅适用于 public 属性或方法。这可以使用 HydrationStrategy 装饰器来覆盖。

其他说明

可能的改进点

  • 方法反射目前仅限于一个参数进行递归。
  • 可能需要额外的属性来充实可能的排除逻辑,以防止在公共属性上进行映射。