-
-
Notifications
You must be signed in to change notification settings - Fork 27
/
AbstractEnumType.php
155 lines (130 loc) · 3.91 KB
/
AbstractEnumType.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
<?php
declare(strict_types=1);
/*
* This file is part of the "elao/enum" package.
*
* Copyright (C) Elao
*
* @author Elao <contact@elao.com>
*/
namespace Elao\Enum\Bridge\Doctrine\DBAL\Types;
use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\Type;
use Elao\Enum\Exception\InvalidArgumentException;
abstract class AbstractEnumType extends Type
{
private bool $isIntBackedEnum;
/**
* The enum FQCN for which we should make the DBAL conversion.
*
* @psalm-return class-string<\BackedEnum>
*/
abstract protected function getEnumClass(): string;
/**
* What should be returned on null value from the database.
*/
protected function onNullFromDatabase(): ?\BackedEnum
{
return null;
}
/**
* What should be returned on null value from PHP.
*/
protected function onNullFromPhp(): int|string|null
{
return null;
}
/**
* {@inheritdoc}
*
* @param \BackedEnum|int|string|null $value
*/
public function convertToDatabaseValue($value, AbstractPlatform $platform): string|int|null
{
if ($value !== null && !is_a($value, $this->getEnumClass())) {
$throwException = true;
if ($this->checkIfValueMatchesBackedEnumType($value)) {
$value = $this->getEnumClass()::tryFrom($this->cast($value));
if ($value !== null) {
$throwException = false;
}
}
if ($throwException) {
throw new InvalidArgumentException(sprintf(
'Expected an instance of a %s. %s given.',
$this->getEnumClass(),
get_debug_type($value),
));
}
}
if (null === $value) {
return $this->onNullFromPhp();
}
return $value->value;
}
/**
* {@inheritdoc}
*
* @param int|string|null $value The value to convert.
*/
public function convertToPHPValue($value, AbstractPlatform $platform): ?\BackedEnum
{
if (null === $value) {
return $this->onNullFromDatabase();
}
return $this->getEnumClass()::from($this->cast($value));
}
/**
* {@inheritdoc}
*/
public function getSQLDeclaration(array $column, AbstractPlatform $platform): string
{
if ($this->isIntBackedEnum()) {
return $platform->getIntegerTypeDeclarationSQL($column);
}
if (empty($column['length'])) {
$column['length'] = 255;
}
return method_exists($platform, 'getStringTypeDeclarationSQL') ?
$platform->getStringTypeDeclarationSQL($column) :
$platform->getVarcharTypeDeclarationSQL($column);
}
/**
* {@inheritdoc}
*/
public function requiresSQLCommentHint(AbstractPlatform $platform): bool
{
return true;
}
/**
* {@inheritdoc}
*/
public function getBindingType(): int
{
return $this->isIntBackedEnum() ? ParameterType::INTEGER : ParameterType::STRING;
}
/**
* Cast the value from database to proper enumeration internal type.
*/
private function cast(int|string $value): int|string
{
return $this->isIntBackedEnum() ? (int) $value : (string) $value;
}
private function checkIfValueMatchesBackedEnumType(mixed $value): bool
{
return ($this->isIntBackedEnum() && \is_int($value)) || (!$this->isIntBackedEnum() && \is_string($value));
}
private function isIntBackedEnum(): bool
{
if (!isset($this->isIntBackedEnum)) {
$r = new \ReflectionEnum($this->getEnumClass());
$this->isIntBackedEnum = 'int' === (string) $r->getBackingType();
}
return $this->isIntBackedEnum;
}
public function getName(): string
{
return $this->getEnumClass();
}
}