alexanevsky/output-normalizer-bundle

提供函数,允许通过在类中定义规范化规则,灵活地自定义对象和实体输出的数组或JSON。

安装: 32

依赖项: 0

建议者: 0

安全: 0

星星: 1

关注者: 1

分支: 0

开放问题: 0

类型:symfony-bundle

1.0.1 2023-05-27 23:20 UTC

This package is auto-updated.

Last update: 2024-09-28 02:18:18 UTC


README

此库允许您通过在实现OutputInterface的类中定义规范化规则,灵活地自定义对象和实体的输出为数组或JSON。

目录

  1. 基本示例
  2. 输出规范化器的工作原理
  3. 使用获取器
  4. 使用设置器
  5. 对象规范化
  6. 对象规范化的全局描述
  7. 实体标识符输出
  8. 使用输出修饰符

基本示例

假设我们有一个模型或Doctrine实体,如下所示

class User
{
    private int $id = 1;

    private string $userName = 'John Doe';

    private string $skippedProperty = 'Lorem Ipsum';

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

    public function getUserName(): string
    {
        return $this->userName;
    }

    public function getSkippedProperty(): string
    {
        return $this->skippedProperty;
    }
}

我们只想向输出提供两个属性:iduserName。让我们描述我们的类

use Alexanevsky\OutputNormalizerBundle\Output\OutputInterface;

class UserOutput implements OutputInterface
{
    public int $id;

    public string $userName;
}

OutputNormalizer添加到控制器或服务的构造函数中

use Alexanevsky\OutputNormalizerBundle\OutputNormalizer;

public function __construct(
    private OutputNormalizer $outputNormalizer
) {}

然后我们调用normalize方法,传入User实体和UserOutput类名

$output = $this->outputNormalizer->normalize($user, UserOutput::class);

结果,在$output中我们将得到这个

['id' => 1, 'user_name' => 'John Doe']

注意:请注意属性名已转换为蛇形小写。

这是规范化的基本功能。我们将在下面更详细地探讨其功能。

输出规范化器的工作原理

  1. 规范化器将您的模型(实体)的公共属性和获取器映射到输出对象的公共属性和设置器。
  2. 规范化器将输出对象的公共属性和获取器转换为数组,并将键转换为蛇形小写。
  3. 规范化器调用调用修饰符。

首先,规范化器遍历公共属性,然后遍历获取器(或设置器,具体取决于操作)。

注意:如果公共属性有获取器(或设置器),它将具有优先权,即获取器的值将被采用(传递给设置器),而不是从属性中获取(而不是分配给属性)。您可以在alexanevsky/getter-setter-accessor中了解更多关于如何在库中使用获取器和设置器的信息。

使用获取器

假设这个模型

class User
{
    private string $phone = '8002752273';

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

要仅输出电话,我们只需将此属性添加到我们的Output类中

class UserOutput implements OutputInterface
{
    public string $phone;
}

我们的结果将像这样

['phone' => '8002752273']

但是,如果我们向输出添加一个执行某些修改的电话获取器,它将在规范化期间被调用

class UserOutput implements OutputInterface
{
    public string $phone;

    public function getPhone(): string
    {
        return '+1' . $this->phone;
    }
}

结果将是

['phone' => '+18002752273']

使用设置器

我们不需要在我们的输出中使用公共属性,我们可以像我们通常在其他地方的项目中那样使用设置器和获取器。一切都会像预期的那样工作

use Alexanevsky\OutputNormalizerBundle\Output\OutputInterface;

class UserOutput implements OutputInterface
{
    private int $id;

    public function setId(int $id): void
    {
        $this->id = $id;
    }

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

对象规范化

想象一下,对于电话,我们使用一个字符串而不是一个类

class Phone
{
    private string $prefix = '+1';

    private string $number = '8002752273';

    private string $country = 'USA';

    // Getters and setters of prefix, number and country...
}

在用户模型中

class User
{
    private Phone $phone;
}

在输出中,我们也必须使用这个模型

class UserOutput implements OutputInterface
{
    public Phone $phone;
}

对象将通过其公共属性和获取器进行规范化,就像Symphony规范化器通常所做的那样

['phone' => ['prefix' => '+1', 'number' => '8002752273', 'country' => 'USA']]

我们也可以使用PhoneOutput而不是Phone,它也实现了OutputInterface,在其中我们只定义我们需要的属性

class PhoneOutput implements OutputInterface
{
    private string $prefix = '+1';

    private string $number = '8002752273';
}

class UserOutput implements OutputInterface
{
    public PhoneOutput $phone;
}

结果,我们将只得到我们需要的属性

['phone' => ['prefix' => '+1', 'number' => '8002752273']]

然而,请记住,我们可以像上面的例子一样使用获取器来输出修改后的结果

class UserOutput implements OutputInterface
{
    public Phone $phone;

    public function getPhone(): string
    {
        return $this->phone->getPrefix() . $this->phone->getNumber();
    }
}

结果将是

['phone' => '+18002752273']

对象规范化的全局描述

我们可以全局描述我们想要如何规范化一些对象。为此,我们需要创建一个从 ObjectNormalizerInterface 继承的类,并将其放置在我们的项目中的任何位置

use Alexanevsky\OutputNormalizerBundle\ObjectNormalizer\ObjectNormalizerInterface;

class PhoneNormalizer implements ObjectNormalizerInterface
{
    public function supports(object $object): bool
    {
        return $object instanceof Phone;
    }

    public function normalize(object $object): string
    {
        return $phone->getPrefix() . $phone->getNumber();
    }
}

现在我们只需在我们的输出中指定 Phone,它将根据上述规则进行规范化

class UserOutput implements OutputInterface
{
    public Phone $phone;
}

我们将得到这个结果

['phone' => '+18002752273']

实体标识符输出

想象一下,我们的实体有一个属性包含另一个实体

class City
{
    private int $id = 1;

    private string $name = 'Los Angeles';

    // Getters and setters of id and name...
}

class User
{
    private City $city;

    public function getCity(): City
    {
        return $this->city;
    }
}

为了不规范化 City 的所有属性,而只规范化其标识符,我们必须添加 EntityToId 属性

use Alexanevsky\OutputNormalizerBundle\Output\Attribute\EntityToId;

class UserOutput implements OutputInterface
{
    #[EntityToId]
    public City $city;
}

然后我们得到这个结果

['city_id' => 1]

如果我们模型中有多对一的关系,我们可以以相同的方式显示所有标识符

class User
{
    private Collection $cities;

    public function getCities(): Collection
    {
        return $this->cities;
    }
}

class UserOutput implements OutputInterface
{
    #[EntityToId]
    public Collection|array $cities;
}

输出将附加 s 到键,因为我们正在输出一个集合

['cities_ids' => [1]]

如果实体标识符与 id 不同,则必须将其作为 EntityToId 的第一个参数传递

class Airport
{
    private string $code = 'LAX';

    private string $name = 'Los Angeles';

    // Getters and setters of code and name...
}

class User
{
    private Airport $airport;

    public function getAirport(): Airport
    {
        return $this->airport;
    }
}

class UserOutput implements OutputInterface
{
    #[EntityToId('code')]
    public Airport $airport;
}

我们的结果将是

['airport_code' => 'LAX']

如果我们想覆盖输出数组键添加的后缀,我们必须将其作为 EntityToId 的第二个参数传递

class UserOutput implements OutputInterface
{
    #[EntityToId('code', 'identifier')]
    public Airport $airport;
}

我们的结果将是

['airport_identifier' => 'LAX']

如果我们根本不想添加后缀,我们必须将 false 作为 EntityToId 的第二个参数传递

class UserOutput implements OutputInterface
{
    #[EntityToId('code', false)]
    public Airport $airport;
}

我们的结果将是

['airport' => 'LAX']

使用输出修饰符

如果我们想以某种方式改变我们规范化到数组中的数据,我们必须使用 OutputModifierInterface。它修改我们的 OutputInterface 数据。

让我们想象以下实体

class User
{
    private array $roles = ['ROLE_USER', 'ROLE_ADMIN'];

    // Getter and setter of roles
}

class UserOutput implements OutputInterface
{
    public array $roles;
}

假设我们想要从输出中移除 ROLE_USER 角色,并打印除了它之外的所有角色。我们可以使用 OutputModifierInterface 来实现这一点。只需将其放置在我们的项目中的任何位置即可

use Alexanevsky\OutputNormalizerBundle\OutputModifier\OutputModifierInterface;

class UserOutputModifier extends OutputModifierInterface
{
    public function supports(object $output, object $source): bool
    {
        return $output instanceof UserOutput;
    }

    /**
     * @param UserOutput $output;
     */
    public function modify(OutputInterface $output, object $source): void
    {
        $output->roles = array_diff($output->roles, ['ROLE_USER']);
    }
}

规范化器本身调用修饰符,并使用那些在规范化器传递给修饰符的模型和输出类的 supports 方法中返回 true 的修饰符。

我们的输出将像这样

['roles' => ['ROLE_ADMIN']]

祝你好运!