EnumType::getSQLDeclaration()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 6
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Zlikavac32\DoctrineEnum\DBAL\Types;
6
7
use Doctrine\DBAL\Platforms\AbstractPlatform;
8
use Doctrine\DBAL\Types\ConversionException;
9
use Doctrine\DBAL\Types\Type;
10
use LogicException;
11
use function Zlikavac32\Enum\assertFqnIsEnumClass;
12
use Zlikavac32\Enum\Enum;
13
use Zlikavac32\Enum\EnumNotFoundException;
14
15
abstract class EnumType extends Type
16
{
17
    /**
18
     * @var string|Enum
19
     */
20
    private $enumClass;
21
22
    private bool $checkedForNameLengths = false;
23
24
    final public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform): string
25
    {
26
        $this->ensureStateIsValid();
27
28
        return $platform->getVarcharTypeDeclarationSQL([
29
            'length' => $this->columnLength()
30
        ]);
31
    }
32
33
    final public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string
34
    {
35
        $this->ensureStateIsValid();
36
37
        if (null === $value) {
38
            return null;
39
        }
40
41
        if (false === ($value instanceof $this->enumClass)) {
42
            throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', $this->enumClass]);
43
        }
44
45
        return $this->enumToDatabaseValue($value);
46
    }
47
48
    final public function convertToPHPValue($value, AbstractPlatform $platform): ?Enum
49
    {
50
        $this->ensureStateIsValid();
51
52
        if (null === $value) {
53
            return null;
54
        }
55
56
        if (false === is_string($value)) {
57
            throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'string']);
58
        }
59
60
        return $this->databaseValueToEnum($value);
61
    }
62
63
    protected function enumToDatabaseValue(Enum $enum): string
64
    {
65
        return $enum->name();
66
    }
67
68
    /**
69
     * @throws ConversionException
70
     */
71
    protected function databaseValueToEnum(string $value): Enum
72
    {
73
        try {
74
            return $this->enumClass::valueOf($value);
75
        } catch (EnumNotFoundException $e) {
76
            throw ConversionException::conversionFailed($value, $this->getName());
77
        }
78
    }
79
80
    final public function requiresSQLCommentHint(AbstractPlatform $platform)
81
    {
82
        $this->ensureStateIsValid();
83
84
        return true;
85
    }
86
87
    private function ensureStateIsValid(): void
88
    {
89
        $this->ensureEnumClassIsSetAndValid();
90
        $this->ensureEnumLengthsAreValid();
91
    }
92
93
    private function ensureEnumClassIsSetAndValid(): void
94
    {
95
        if (is_string($this->enumClass)) {
96
            return ;
97
        }
98
99
        $enumClass = $this->enumClass();
100
101
        assertFqnIsEnumClass($enumClass);
102
103
        $this->enumClass = $enumClass;
104
    }
105
106
    private function ensureEnumLengthsAreValid(): void
107
    {
108
        if ($this->checkedForNameLengths) {
109
            return ;
110
        }
111
112
        $columnLength = $this->columnLength();
113
114
        foreach ($this->enumClass::values() as $element) {
115
            $this->assertElementNameLengthIsValid($element, $columnLength);
116
        }
117
    }
118
119
    private function assertElementNameLengthIsValid(Enum $element, int $columnLength): void
120
    {
121
        $elementName = $this->enumToDatabaseValue($element);
122
123
        if (strlen($elementName) <= $columnLength) {
124
            return ;
125
        }
126
127
        throw new LogicException(
128
            sprintf(
129
                '%s::%s() is longer than %d characters',
130
                $this->enumClass,
131
                $elementName,
132
                $columnLength
133
            )
134
        );
135
    }
136
137
    abstract protected function enumClass(): string;
138
139
    /**
140
     * Column length used for variable character column definition that will hold the enum name as a value. Override
141
     * if 32 is to big or to small.
142
     */
143
    protected function columnLength(): int
144
    {
145
        return 32;
146
    }
147
}
148