在Symfony中处理ids值对象

安装次数: 25,660

依赖者: 2

建议者: 0

安全性: 0

星标: 4

关注者: 0

分支: 6

开放性问题: 0

类型:symfony-bundle

v1.2.1 2024-08-03 05:09 UTC

README

一个用于在Symfony中处理id和id列表值对象的Symfony包。它包括用于自动归一化和反归一化的Symfony规范化和Doctrine类型,可以直接在数据库中存储ids和id列表。

由于它是应用程序的核心部分,因此经过彻底测试(包括突变测试)。

Latest Stable Version PHP Version Require codecov Packagist Downloads Packagist License

安装和配置

通过composer安装包

composer require digital-craftsman/ids

建议安装uuid PHP扩展以获得更好的id创建和验证性能。symfony/polyfill-uuid用作后备。您可以在安装PHP扩展后防止安装polyfill

处理ids

创建新的id

大部分逻辑在Id类中。创建新的id就像创建一个新的final readonly class并从中扩展一样,如下所示

<?php

declare(strict_types=1);

namespace App\ValueObject;

use DigitalCraftsman\Ids\ValueObject\Id;

final readonly class UserId extends Id
{
}

现在您已经可以在代码中使用它了,如下所示

$userId = UserId::generateRandom();
if ($userId->isEqualTo($command->userId)) {
    ...
}

防止无效使用

$requestingUser->userId->mustNotBeEqualTo($command->targetUserId);

或使用自定义异常

$requestingUser->userId->mustNotBeEqualTo(
    $command->targetUserId,
    static fn () => new Exception\UserCanNotTargetItself(),
);

Symfony序列化器

如果您直接注入SerializerInterface,则无需执行任何操作。id的反序列化器将自动注册。

namespace App\DTO;

final readonly class UserPayload
{
    public function __construct(
        public UserId $userId,
        public string $firstName,
        public string $lastName,
    ) {
    }
}
public function __construct(
    private SerializerInterface $serializer,
) {
}

public function handle(UserPayload $userPayload): string
{
    return $this->serializer->serialize($userPayload, JsonEncoder::FORMAT);
}
{
  "userId": "15d6208b-7cf2-49e5-a193-301d594d98a7",
  "firstName": "Tomas",
  "lastName": "Bauer"
}

这可以与CQRS包结合使用,以便在序列化id中。

Doctrine类型

要在实体中使用id,您只需为id注册一个新的类型。创建一个新的类来表示新的id,如下所示

<?php

declare(strict_types=1);

namespace App\Doctrine;

use App\ValueObject\UserId;
use DigitalCraftsman\Ids\Doctrine\IdType;

final class UserIdType extends IdType
{
    public static function getTypeName(): string
    {
        return 'user_id';
    }

    public static function getClass(): string
    {
        return UserId::class;
    }
}

然后,在您的config/packages/doctrine.yaml文件中注册新类型

doctrine:
  dbal:
    types:
      user_id: App\Doctrine\UserIdType

或者,您还可以添加编译器传递以自动注册类型

然后您就可以将其添加到实体中,如下所示

<?php

declare(strict_types=1);

namespace App\Entity;

use App\ValueObject\UserId;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;

#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\Table(name: '`user`')]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
    #[ORM\Id]
    #[ORM\Column(name: 'id', type: 'user_id')]
    public UserId $id;
    
    ...
}

处理id列表

id列表是id数组的包装器。它包含一些实用函数和改进的类型安全。

IdList是不可变的。因此,突变方法(如addremove等)始终返回列表的新实例。

创建新的id列表

大部分逻辑在IdList类中。创建新的id列表就像创建一个新的final readonly class并从中扩展一样,如下所示

<?php

declare(strict_types=1);

namespace App\ValueObject;

use DigitalCraftsman\Ids\ValueObject\IdList;

/** @extends IdList<UserId> */
final readonly class UserIdList extends IdLIst
{
    public static function handlesIdClass(): string
    {
        return UserId::class;
    }
}

现在您已经可以在代码中使用它了,如下所示

$userIdList = new UserIdList($userIds);
if ($idsOfEnabledUsers->contains($command->userId)) {
    ...
}

防止无效使用

$idsOfEnabledUsers->mustContainId($command->targetUserId);

或使用自定义异常

$idsOfEnabledUsers->mustContainId(
    $command->targetUserId,
    static fn () => new Exception\UserIsNotEnabled(),
);

Symfony序列化器

如果您直接注入SerializerInterface,则无需执行任何操作。id列表的反序列化器将自动注册。

Doctrine类型

要在实体中使用id列表,您只需为id列表注册一个新的类型。创建一个新的类来表示新的id列表,如下所示

<?php

declare(strict_types=1);

namespace App\Doctrine;

use App\ValueObject\UserId;
use App\ValueObject\UserIdList;
use DigitalCraftsman\Ids\Doctrine\IdListType;

final class UserIdListType extends IdListType
{
    protected function getTypeName(): string
    {
        return 'user_id_list';
    }

    protected function getIdListClass(): string
    {
        return UserIdList::class;
    }
    
    protected function getIdClass(): string
    {
        return UserId::class;
    }
}

然后,在您的config/packages/doctrine.yaml文件中注册新类型

doctrine:
  dbal:
    types:
      user_id_list: App\Doctrine\UserIdListType

然后您就可以将其添加到实体中,如下所示

<?php

declare(strict_types=1);

namespace App\Entity;

use App\ValueObject\UserIdList;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: InvestorRepository::class)]
#[ORM\Table(name: 'investor')]
class Investor
{
    #[ORM\Column(name: 'ids_of_users_with_access', type: 'user_id_list')]
    public UserIdList $idsOfUsersWithAccess;
    
    ...
}

附加文档