EC-CUBE4 DBAL Types を増やす

## はじめに

商品クラスなどを拡張した際に、リレーションテーブルを使うするまでもないが、プロパティを文字列ではなく、オブジェクトで設定したいときの方法になります。
※ EC-CUBE 特有の機能ではなく、Symfony の機能です。

## 注意事項

ファイルのパスに制限はありません。

## ファイルの準備

```php:app/Customize/WrappingSetting.php
<?php

declare(strict_types=1);

namespace Customize;

class WrappingSetting implements ToScalarInterface
{
    private const WRAPPING_REQUIRED = 'required';
    private const WRAPPING_OPTIONAL = 'optional';
    private const WRAPPING_NONE = 'none';

    /** @var string */
    private $value;

    public static function getWrappingSettings(): array
    {
        return [
            self::WRAPPING_REQUIRED,
            self::WRAPPING_OPTIONAL,
            self::WRAPPING_NONE,
        ];
    }

    public static function reconstruct(string $value): WrappingSetting
    {
        $wrappingSetting = new self();
        $wrappingSetting->value = $value;

        return $wrappingSetting;
    }

    public function toScalar(): string
    {
        return $this->value;
    }

    public function isRequired(): bool
    {
        return $this->value === self::WRAPPING_REQUIRED;
    }

    public function isOptional(): bool
    {
        return $this->value === self::WRAPPING_OPTIONAL;
    }

    public function isNone(): bool
    {
        return $this->value === self::WRAPPING_NONE;
    }
}
```

```php:app/Customize/Types/WrappingSettingType.php
<?php

declare(strict_types=1);

namespace Customize\Types;

use Customize\WrappingSetting;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\Type;

class WrappingSettingType extends Type
{
    public function getSQLDeclaration(array $column, AbstractPlatform $platform): string
    {
        $column['length'] = 20;

        return $platform->getVarcharTypeDeclarationSQL($column);
    }

    public function getName(): string
    {
        return 'wrapping_setting_type';
    }

    public function convertToPHPValue($value, AbstractPlatform $platform): ?WrappingSetting
    {
        if ($value === null) {
            return null;
        }

        return WrappingSetting::reconstruct($value);
    }

    public function convertToDatabaseValue($value, AbstractPlatform $platform)
    {
        if ($value === null) {
            return null;
        }

        assert($value instanceof WrappingSetting);

        return $value->toScalar();
    }

    public function requiresSQLCommentHint(AbstractPlatform $platform): bool
    {
        return true;
    }
}
```


```php:app/Customize/Entity/ProductTrait.php
/**
 * @EntityExtension("Eccube\Entity\Product")
 */
trait ProductTrait
{
    /**
     * 包装紙の設定
     *
     * @var WrappingSetting|null
     *
     * @ORM\Column(name="wrapping_setting", type="wrapping_setting_type", length=20, nullable=true)
     */
    private $wrappingSetting;

    public function getWrappingSetting(): ?WrappingSetting
    {
        return $this->wrappingSetting;
    }
}
```

```diff_yaml:source/app/app/config/eccube/packages/doctrine.yaml
        types:
            datetime: 'Eccube\Doctrine\DBAL\Types\UTCDateTimeType'
            datetimetz: 'Eccube\Doctrine\DBAL\Types\UTCDateTimeTzType'
+             wrapping_setting_type: 'Customize\Types\WrappingSettingType'
```

## 適用

```bash
./bin/console doctrine:schema:update --dump-sql
./bin/console doctrine:schema:update --dump-sql --force
```

うまくいかない場合は、DB関連のキャッシュをクリアすると良いかもしれません。

```bash
./bin/console doctrine:cache:clear-metadata
./bin/console doctrine:cache:clear-query
./bin/console doctrine:cache:clear-result
```

## できあがり

![スクリーンショット 2022-01-24 14.39.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2019/858d93a6-5d17-8208-c506-62a0a660d1a4.png)