acelaya/doctrine-enum-type

此包已被废弃,不再维护。未建议替代包。

一个自定义的 Doctrine 类型,使用 myclabs/php-enum 将列值映射到枚举对象

v2.5.0 2021-01-25 14:38 UTC

This package is auto-updated.

Last update: 2022-09-14 05:37:12 UTC


README

Build Status Code Coverage Latest Stable Version Total Downloads License Paypal Donate

⚠️ 此包已不再相关,因为 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版本开始,该库提供了一种定义钩子的方法,用于自定义值如何从数据库转换写入数据库的方式,通过使用枚举中的静态方法castValueIncastValueOut实现。

例如,让我们假设我们有一个枚举

<?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);
}