alexanevsky / output-normalizer-bundle
提供函数,允许通过在类中定义规范化规则,灵活地自定义对象和实体输出的数组或JSON。
Requires
- php: >=8.1
- alexanevsky/getter-setter-accessor-bundle: ^1.0
- doctrine/orm: ^2.6
- symfony/config: ^5.4|^6.0
- symfony/dependency-injection: ^5.4|^6.0
- symfony/http-kernel: ^5.4|^6.0
- symfony/string: ^5.4|^6.0
This package is auto-updated.
Last update: 2024-09-28 02:18:18 UTC
README
此库允许您通过在实现OutputInterface
的类中定义规范化规则,灵活地自定义对象和实体的输出为数组或JSON。
目录
基本示例
假设我们有一个模型或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; } }
我们只想向输出提供两个属性:id
和userName
。让我们描述我们的类
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']
注意:请注意属性名已转换为蛇形小写。
这是规范化的基本功能。我们将在下面更详细地探讨其功能。
输出规范化器的工作原理
- 规范化器将您的模型(实体)的公共属性和获取器映射到输出对象的公共属性和设置器。
- 规范化器将输出对象的公共属性和获取器转换为数组,并将键转换为蛇形小写。
- 规范化器调用调用修饰符。
首先,规范化器遍历公共属性,然后遍历获取器(或设置器,具体取决于操作)。
注意:如果公共属性有获取器(或设置器),它将具有优先权,即获取器的值将被采用(传递给设置器),而不是从属性中获取(而不是分配给属性)。您可以在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']]
祝你好运!