承接 maiorano84/object-hydrator 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

maiorano84/object-hydrator

Composer 安装命令:

composer require maiorano84/object-hydrator

包简介

Hydration package for PHP Objects

README 文档

README

A small utility to streamline Object Hydration

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

Requirements

Object Hydrator requires PHP 8.1 or greater.

Composer

This package may be installed as a Composer dependency by running the following command:

composer require maiorano84/object-hydrator

If you would like to use the latest unstable version, you can run:

composer require maiorano84/object-hydrator:dev-master

Usage

This is a small set of concepts to facilitate the orchestration of object hydration based on varying strategies.

There are 3 concepts that the default Hydration class uses in order to determine how a given input is applied to an object:

  • Hydration Keys - These are simple strings that are used to indicate the name of the input that is used. When an input key is matched to a Hydration Key, the value is passed through to the underlying mapping.
  • Hydration Mappings - These are objects that store a reference to a given key and a reflection object that points to either a Property or a Method. When a mapping is matched by a given strategy, it will be passed a value that it can use to hydrate the object property.
  • Hydration Strategies - These are objects that define the logic used to determine how an input key and value is mapped. Even further, these objects may also determine if a given key and value should be processed recursively by the Hydrator.

Hydration Keys and Hydration Strategies are both set up as Attributes, which may be used to decorate any given class structure marked for Hydration. In this way, you may customize how a given class is Hydrated.

Multiple Hydration Strategies may be applied to a single given class.

Why?

A common task that many REST APIs and ORMs require is the ability to fill arbitary objects with structured data in bulk. The criteria used for setting these values can vary wildly from class to class, and designating a unified interface by which class hydration may occur predictably can prove to be challenging.

The simplest and most common approach would be to have each object implement a given interface that is responsible for the hydration of that entity. The problem with this approach is that it violates the Single-Responsibility principle, and adds extra business logic that the entity itself doesn't really need to be handling.

This removes much of the boilerplate code needed for handling custom hydration rules, while also providing a simple interface by which classes may define their own rules and the order in which they're applied.

Usage

Given a User Entity:

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);
    }
}

Hydration of a User entity can be as simple as the following:

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>
)
 */

By default, classes with no strategy defined will use a combination of the Reflection\PropertiesStrategy and Reflection\MethodsStrategy in that order. The result will be all keys that match a public property name, and all keys that match a property setter will be used to hydrate the entity. Note in the above example that the public $username was hydrated with the value maiorano84, and the private $password was hydrated via the setPassword setter.

More complex structures may also be hydrated like so:

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);
    }
}

There are a number of things going on here:

  • An ArrayStrategy may be used to explicitly map certain input keys to properties or methods.
  • We are chaining PropertiesStrategy and MethodsStrategy fallbacks to default to the appropriate public properties/setters behaviors for keys that aren't defined in the ArrayStrategy
  • The UserAvatar class is allowing both private and public properties to be set for its implementation of the PropertiesStrategy
  • HydrationKey is used to override the input keys in certain areas that would otherwise be difficult to determine through reflection

Hydration can be done similarly as before:

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
        )
)
*/

The Hydrator

The Hydrator can be thought of as an orchestration tool. It doesn't really do any property setting or method invocations itself, but rather loops through all of the key/value pairs and determines the best Strategy to use.

Hydration Strategies

Hydration Strategies encapsulate the logic to determine how input keys and values are mapped to properties or methods. Every Hydration Strategy will expose an underlying Mapping Interface that can be used to define the relationship between a given key and its associated property/method.

Other methods are used to determine if a given key is available within a strategy, or if a value can be considered recursive.

See the Maiorano\ObjectHydrator\Strategies\HydrationStrategyInterface for more details.

Hydration Mappings

Mappings carry both a Hydration Key as well as a Reflection Object containing information about the associated property or method. A mapping serves primarily to store a given association, as well as to complete the appropriate hydration invocation.

See the Maiorano\ObjectHydrator\Mappings\HydrationMappingInterface for more details.

Hydration Keys

Hydration Keys serve as indicators for input. All input for a given hydration attempt is expected to be a structured associative array, with all keys of the array representing an expected Hydration Key.

The default Reflection Strategies will look first to any Properties/Methods with an explicit HydrationKey decorator.

If no Attributes are found, then the Reflection Strategies will try to determine one by name:

  • In the case of Properties, matching names will be considered an association and a Mapping will be created.
  • In the case of Methods, if the method starts with set and the rest of its name matches a given property, then a Mapping will be created using that key.
  • The Reflection Strategies default only to public properties or methods. This may be overriden using the HydrationStrategy decorator.

Other Notes

Possible points of improvement:

  • Method Reflection is currently limited only to one parameter for recursion.
  • Additional attributes may be needed to flesh out possible exclusion logic to prevent mapping on public properties

maiorano84/object-hydrator 适用场景与选型建议

maiorano84/object-hydrator 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 4 次下载、GitHub Stars 达 0, 最近一次更新时间为 2022 年 03 月 28 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「entities」 「hydration」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 maiorano84/object-hydrator 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 maiorano84/object-hydrator 我们能提供哪些服务?
定制开发 / 二次开发

基于 maiorano84/object-hydrator 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 4
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 3
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 1
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2022-03-28