xthiago / id-value-object
对象标识(ID)的值对象(VO)。包括用于持久化的Doctrine DBAL类型。
Requires
- php: >= 7.2
- ext-json: *
- ramsey/uuid: ^4.1
Requires (Dev)
- doctrine/coding-standard: ^9.0
- doctrine/dbal: ^2.13.1 || ^3.1
- phpunit/phpunit: ^8.5.16 || ^9.5
- symfony/serializer: ^5|^6
- vimeo/psalm: ^5.12
Suggests
- doctrine/dbal: To persist the Id instances into a relational database
README
PHP 库,用于使处理对象标识(ID)更加容易和有趣!
简而言之:你不应该依赖数据库机制来生成 ID。同样,你不应该在应用程序中操作标量值(通常是 int)。无论何时需要生成 ID,请使用此 ID 值对象。
功能
UUID v4
该库会自动生成 UUID v4 作为 ID。你将不会依赖持久化机制和刷新操作来生成标识。
与 Doctrine 集成
该库包含一个 Doctrine DBAL 类型,允许你将 ID 值对象映射为 Doctrine 实体属性。
需求
此库需要 PHP >= 7.2。
安装
使用 composer 安装此库。
composer install xthiago/id-value-object
Doctrine
为了使用此包提供的 Doctrine 持久化集成,你必须配置 Doctrine DBAL 类型。
独立 Doctrine
你必须在应用程序启动时注册 DBAL 类型,如下所示
<?php \Doctrine\DBAL\Types\Type::addType( 'xthiago_id', \Xthiago\ValueObject\Id\Persistence\DoctrineDbalType::class );
Symfony 框架
如果你使用的是 Symfony,你只需要编辑以下 Doctrine 配置,添加以下内容
doctrine: dbal: types: xthiago_id: Xthiago\ValueObject\Id\Persistence\DoctrineDbalType
使用
基本示例
<?php namespace YourApp; use Xthiago\ValueObject\Id\Id; // Generate a new ID (UUID v4): $generatedId = Id::generate(); echo $generatedId; // prints something like `b18c7bbe-da70-4c86-8b8f-145abb21a7c7`. // Create an ID from string: $parsedId = Id::fromString('Foo'); echo $parsedId; // prints 'Foo'. // Comparing two instances of Id: var_dump($generatedId->isEqualTo($parsedId)); // prints: `false` var_dump($parsedId->isEqualTo(Id::fromString('Foo'))); // prints: `true`
在实体类中映射 ID(例如 Product)
<?php namespace YourApp; use Doctrine\ORM\Mapping as ORM; use Xthiago\ValueObject\Id\Id; /** * @ORM\Entity() */ class Product { /** * @ORM\Id * @ORM\Column(type="xthiago_id", name="id") * * @var Id * @psalm-var Id<Product> */ private $id; // other attributes goes here. public function __construct(Id $id) { $this->id = $id; } /** @psalm-return Id<Product> */ public function id(): Id { return $this->id(); } }
创建自定义 ID 类
对于所有实体,你不应该依赖于通用的 Id
类,你可以为每个实体创建特定的值对象。
例如,如果你有一个 Product
实体,你可以按照以下方式创建一个 ProductId
值对象
class ProductId extends Id { }
然后你需要映射这种新类型。你可以按照以下方式扩展 DoctrineDbalType
class ProductIdDbalType extends DoctrineDbalType { public const NAME = 'product_id'; public function getConcreteIdClass(): string { return ProductId::class; } }
然后你配置这种新类型(例如 Type::addType(ProductIdDbalType::NAME, ProductIdDbalType::class);
)并开始在模型中使用它(这次我将使用 PHP 属性来展示映射)
<?php namespace YourApp; use Doctrine\ORM\Mapping as ORM; #[ ORM\Entity, ORM\Table('product') ] class Product { public function __construct( #[ ORM\Column(name: 'id', type: ProductIdDbalType::NAME), ORM\Id ] private ProductId $id, ) {} }
Symfony 序列化
此库包含一个类 IdInterfaceNormalizer
,能够序列化和反序列化 Id
值对象实例。
要使用此序列化器,你需要将其作为参数传递给 Serializer
类的构造函数
$serializer = new Serializer( normalizers: [ new IdInterfaceNormalizer(), // <--- // others normalizers... ], encoders: [new JsonEncoder()] );
FreezesUuidTrait
工具用于测试
在创建测试时,我们可能希望提前知道生成的 ID 的值。这让我们能够编写更简单的断言。此库提供了一个 trait FreezesUuidTrait
,可以用来冻结 UUID v4 生成或设置已知序列。
class MyAwesomeTest extends Testcase { use FreezesUuidTrait; protected function setUp(): void { // we could freeze the uuids here :) } protected function tearDown(): void { $this->unfreezeUuid(); // <-- This is important to unfreeze the uuid generation. } public function test_fixed_uuid(): void { // Fixing the uuid value (this can also be set on `setUp()` method): $this->freezeUuidV4WithFixedValue('866cc948-b6de-4cdc-8f5e-3b53a58a9f63'); // All generated Id will have the same uuid value. $this->assertSame('866cc948-b6de-4cdc-8f5e-3b53a58a9f63', (string) Id::generate()); $this->assertSame('866cc948-b6de-4cdc-8f5e-3b53a58a9f63', (string) Id::generate()); $this->assertSame('866cc948-b6de-4cdc-8f5e-3b53a58a9f63', (string) Id::generate()); } public function test_fixed_uuid_sequence(): void { // Fixing the uuid value with a known sequence: $this->freezeUuidV4WithKnownSequence( 'e2d5d0fd-a719-4da7-976d-b5cd184fa615' '4c98d212-19ed-4c41-9ea2-4b2d48d7410d' '2acfaf05-25c3-4db9-9fea-5d71a0c3f909' ); // Each new Id instance will assume one uuid from the known sequence: $this->assertSame('e2d5d0fd-a719-4da7-976d-b5cd184fa615', (string) Id::generate()); $this->assertSame('4c98d212-19ed-4c41-9ea2-4b2d48d7410d', (string) Id::generate()); $this->assertSame('2acfaf05-25c3-4db9-9fea-5d71a0c3f909', (string) Id::generate()); // If we call again Id::generate(), it will throw RuntimeException because there is no remaining uuid in the // available list. $this->assertException(RunTimeException::class); Id::generate(); $this->fail('The expected exception was not thrown.'); } }
贡献
欢迎提交拉取请求。对于重大更改,请先打开一个问题来讨论你想要进行的更改。
请确保根据需要更新测试。