morebec / domain-normalizer
此包已被弃用,不再维护。未建议替代包。
域对象规范器
0.4.0
2020-06-05 16:08 UTC
Requires
Requires (Dev)
- friendsofphp/php-cs-fixer: ^2.16
- phpunit/phpunit: ^9.0
- symfony/var-dumper: ^5.0
README
DomainNormalizer 是一个 Orkestra 组件,用于通过流畅的接口轻松规范域对象。它具有将序列化/持久化关注点从域类中移出的优点,同时提供了一种快速简便的方式来定义域类的原始映射信息。
它包含序列化和反序列化(通过规范化)的功能。
规范化
规范化是将域对象实例转换为原始值(int、string、float、bool、数组)数组表示的过程。这种数组表示称为规范化形式。
给定如下类结构
class Order { /** @var string */ private $id; /** @var int */ private $createdAt; /** @var array<OrderLineItem> */ private $lineItems; } class OrderLineItem { /** * @var string */ private $productId; /** * @var int */ private $quantity; public function __construct(ProductId $productId, int $quantity) { $this->productId = $productId; $this->quantity = $quantity; } } class ProductId { /** * @var string */ private $id; public function __construct(string $id) { $this->id = $id; } public function __toString() { return $this->id; } }
使用以下定义
use DateTime; use Morebec\DomainNormalizer\Normalization\Configuration\NormalizerConfiguration; use Morebec\DomainNormalizer\Normalization\Configuration\ObjectNormalizationDefinitionFactory as DefinitionFactory; use Morebec\DomainNormalizer\Normalization\Configuration\ObjectNormalizationDefinition as Definition; use Morebec\DomainNormalizer\Normalization\Normalizer; use Morebec\DomainNormalizer\Normalization\NormalizationContext; $config = new NormalizerConfiguration(); $config->registerDefinition(DefinitionFactory::forClass( Order::class, static function (Definition $d) { $d->property('id') ->renamedTo('ID') ->asString(); $d->property('createdAt')->as(static function (NormalizationContext $context) { $value = $context->getValue(); return (new DateTime("@$value"))->format('Y-m-d'); }); $d->property('lineItems') ->asArrayOfTransformed(OrderLineItem::class); $d->createProperty('nbLineItems') ->as(static function(NormalizationContext $context) { return count($context->getObject()->getLineItems()); } ); }) ); $config->registerDefinition(DefinitionFactory::forClass( OrderLineItem::class, static function (Definition $d) { $d->property('quantity'); $d->property('productId')->asString(); }) ); $normalizer = new Normalizer($config); $obj = new Order(); $data = $normalizer->normalize($obj);
将返回以下规范化形式
[ "id" => "id5e5716cf048284.16614551", "createdAt" => "2020-02-27", "lineItems" => [ 0 => [ "quantity" => 5, "productId" => "5e5716cf0485b7.29093456", ], 1 => [ "quantity" => 5, "productId" => "5e5716cf048606.07838602" ] ] ];
也可以在类内部包含您的定义
use Morebec\DomainNormalizer\Normalization\Configuration\ObjectNormalizationDefinition; class OrderDefinition extends ObjectNormalizationDefinition { public function __construct() { parent::__construct(Order::class); $this->property('id') ->renamedTo('ID') ->asString(); $this->property('createdAt')->as(static function (TransformationContext $context) { $value = $context->getValue(); return (new DateTime("@$value"))->format('Y-m-d'); }); $this->property('lineItems') ->asArrayOfTransformed(OrderLineItem::class); $this->createProperty('nbLineItems') ->as(static function(TransformationContext $context) { return count($context->getObject()->getLineItems()); } ); } }
规则很简单
- 如果规范器无法找到给定对象的定义
- 它将在其注册表中查找是否有可用的定义,用于对象的父类。
- 否则:将抛出异常
- 定义遵循显式声明方法
- 如果实例上存在属性但不属于定义的一部分,则不会进行规范化。将被忽略。
- 如果实例上不存在属性但属于定义的一部分
- 除非它是“绑定”属性,否则规范器将抛出异常。
- 在绑定属性的情况下,它们将被添加到结果规范化形式中。(这可以通过使用定义工厂时的
bound
定义或通过createProperty
来定义)
反规范化
反规范化的过程是规范化的逆过程:将规范化形式转换为域对象实例。
在反规范化定义中,我们不是定义属性,而是定义键。
规则与规范化类似,但预设了一些细微的差异
- 定义也遵循显式声明方法
- 如果键存在于规范化形式中但不属于定义的一部分,则不会进行反规范化。
- 每个嵌套的规范化形式都必须有一个相关的定义。
- 如果没有找到,反规范器将抛出异常。
- 如果存在键定义但关联的数据不存在
- 将应用配置的缺失转换器,这通常是要么抛出错误,要么提供默认值。
- 默认情况下是抛出错误
- 将应用配置的缺失转换器,这通常是要么抛出错误,要么提供默认值。
- 如果存在键定义,但类上没有相应的属性
- 抛出异常。
class OrderDenormalizationDefinition extends ObjectDenormalizationDefinition { public function __construct() { parent::_construct(Order::class); $this->key('ID') ->renamedTo('id') ->as(static function (TransformationContext $context) { return new ProductId($context->getValue()); } ); $this->key('createdAt')->as(static function (TransformationContext $context) { return strtotime($context->getValue()); }); $this->key('newKey')->defaultsTo('test'); $this->key('lineItems') ->asArrayOfTransformed(OrderLineItem::class); } }
自动反/规范化
尽管我们推荐使用显式定义,但也可以使用自动规范化和反规范化。
这在与简单的 DTO 进行规范化和反规范化处理时很有用。
new AutomaticNormalizationDefinition(Order::class); new AutomaticDenormalizationDefinition(Order::class);