acelaya / doctrine-enum-type
一个自定义的 Doctrine 类型,使用 myclabs/php-enum 将列值映射到枚举对象
Requires
- php: ^7.4 || ^8.0
- doctrine/dbal: ^2.12 || ^3.0
- myclabs/php-enum: ^1.7
Requires (Dev)
- infection/infection: ^0.20
- phpspec/prophecy-phpunit: ^2.0
- phpstan/phpstan: ^0.12.52
- phpunit/phpunit: ^9.4
- roave/security-advisories: dev-master
- shlinkio/php-coding-standard: ~2.1.1
README
⚠️ 此包已不再相关,因为 PHP 现在已具有原生的枚举,并且 doctrine 正式支持它们
https://www.doctrine-project.org/2022/01/11/orm-2.11.html
此包提供了一个基类实现,用于定义 doctrine 实体列类型,这些类型映射到 MyCLabs\Enum\Enum
对象。该类在myclabs/php-enum 包中定义。
安装
推荐安装方法是使用 composer
composer require acelaya/doctrine-enum-type
使用
此包提供了一个 Acelaya\Doctrine\Type\PhpEnumType
类,该类扩展了 Doctrine\DBAL\Types\Type
。您可以使用它轻松地将类型名称映射到具体的 Enums。
PhpEnumType
类将被用作每个枚举属性的 doctrine 类型。
让我们假设我们有两个枚举。
<?php declare(strict_types=1); namespace Acelaya\Enum; use MyCLabs\Enum\Enum; class Action extends Enum { public const CREATE = 'create'; public const READ = 'read'; public const UPDATE = 'update'; public const DELETE = 'delete'; }
<?php declare(strict_types=1); namespace Acelaya\Enum; use MyCLabs\Enum\Enum; class Gender extends Enum { public const MALE = 'male'; public const FEMALE = 'female'; }
以及这个实体,具有每种实体类型的列。
<?php declare(strict_types=1); namespace Acelaya\Entity; use Acelaya\Enum\Action; use Acelaya\Enum\Gender; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity() * @ORM\Table(name="users") */ class User { /** * @var int * * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @var string * * @ORM\Column() */ protected $name; /** * @var Action * * @ORM\Column(type=Action::class, length=10) */ protected $action; /** * @var Gender * * @ORM\Column(type="php_enum_gender") */ protected $gender; // Getters and setters... }
操作属性的列类型是 Action
枚举的 FQCN,性别列的类型是 php_enum_gender。要使它工作,您必须使用 Acelaya\Doctrine\Type\PhpEnumType::registerEnumType
静态方法注册具体的列类型。
<?php declare(strict_types=1); // in bootstrapping code // ... use Acelaya\Doctrine\Type\PhpEnumType; use Acelaya\Enum\Action; use Acelaya\Enum\Gender; // ... // Register my types PhpEnumType::registerEnumType(Action::class); PhpEnumType::registerEnumType('php_enum_gender', Gender::class); // Don't forget to register the enums for schema operations $platform = $em->getConnection()->getDatabasePlatform(); $platform->registerDoctrineTypeMapping('VARCHAR', Action::class); $platform->registerDoctrineTypeMapping('VARCHAR', 'php_enum_gender');
这将内部注册一个自定义的 doctrine 类型。如您所见,您可以仅传递枚举的 FQCN,使类型使用它作为名称,但您也可以提供不同的名称。
或者,您可以使用 Acelaya\Doctrine\Type\PhpEnumType::registerEnumTypes
,它期望一个要注册的枚举数组。
<?php declare(strict_types=1); // ... use Acelaya\Doctrine\Type\PhpEnumType; use Acelaya\Enum\Action; use Acelaya\Enum\Gender; PhpEnumType::registerEnumTypes([ Action::class, 'php_enum_gender' => Gender::class, ]);
使用此方法,具有字符串键的元素将使用该名称注册,而具有整数键的元素将使用值作为类型名称。
为每个要注册的具体枚举执行相同的操作。
如果您需要有关自定义 doctrine 列类型的更多信息,请参阅http://doctrine-orm.readthedocs.io/en/latest/cookbook/custom-mapping-types.html
自定义 SQL 声明
默认情况下,Acelaya\Doctrine\Type\PhpEnumType
类将所有枚举定义为类似 VARCHAR 的类型
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) { return $platform->getVarcharTypeDeclarationSQL($fieldDeclaration); }
这意味着您可以自定义 length
(默认为 255),但不能自定义列类型。
如果您想要更具体的东西,例如 MySQL 枚举,只需扩展 PhpEnumType
并用如下方式覆盖 getSQLDeclaration()
方法。
<?php declare(strict_types=1); namespace App\Type; use Acelaya\Doctrine\Type\PhpEnumType; use Doctrine\DBAL\Platforms\AbstractPlatform; use function call_user_func; use function implode; use function sprintf; class MyPhpEnumType extends PhpEnumType { public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform): string { $values = call_user_func([$this->enumClass, 'toArray']); return sprintf( 'ENUM("%s") COMMENT "%s"', implode('", "', $values), $this->getName() ); } }
然后请记住使用您自己的类注册枚举。
<?php declare(strict_types=1); // ... use Acelaya\Enum\Action; use Acelaya\Enum\Gender; use App\Type\MyPhpEnumType; MyPhpEnumType::registerEnumTypes([ Action::class, 'php_enum_gender' => Gender::class, ]);
自定义值转换
库假设枚举的所有值都是字符串,但这可能并不总是如此。
从v2.2.0版本开始,该库提供了一种定义钩子的方法,用于自定义值如何从数据库转换和写入数据库的方式,通过使用枚举中的静态方法castValueIn
和castValueOut
实现。
例如,让我们假设我们有一个枚举
<?php declare(strict_types=1); namespace Acelaya\Enum; use MyCLabs\Enum\Enum; class Status extends Enum { public const SUCCESS = 1; public const ERROR = 2; }
使用泛型PhpEnumType
在从数据库转换值时会导致错误,因为它会被反序列化为字符串。
为了使其正常工作,您必须在枚举中添加castValueIn
静态方法
<?php declare(strict_types=1); namespace Acelaya\Enum; use MyCLabs\Enum\Enum; class Status extends Enum { public const SUCCESS = 1; public const ERROR = 2; public static function castValueIn($value): int { return (int) $value; } }
此方法在检查值是否有效并创建枚举实例之前自动调用。
同样,可以定义一个castValueOut
方法来修改在将值持久化到数据库之前。
<?php declare(strict_types=1); namespace Acelaya\Enum; use MyCLabs\Enum\Enum; use function strtolower; class Gender extends Enum { public const MALE = 'male'; public const FEMALE = 'female'; public static function castValueOut(self $value): string { return strtolower((string) $value); } }
这些方法还可以用于自定义值。例如,如果您以前使用的是带有下划线的值,想要用破折号替换它们,您可以在枚举中定义这些方法,以保持向后兼容性。
<?php // ... public static function castValueIn($value): string { return \str_replace('_', '-', $value); } public static function castValueOut(self $value): string { return \str_replace('-', '_', (string) $value); }