|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
declare(strict_types=1); |
|
4
|
|
|
|
|
5
|
|
|
/* |
|
6
|
|
|
* This file is part of the Explicit Architecture POC, |
|
7
|
|
|
* which is created on top of the Symfony Demo application. |
|
8
|
|
|
* |
|
9
|
|
|
* (c) Herberto Graça <[email protected]> |
|
10
|
|
|
* |
|
11
|
|
|
* For the full copyright and license information, please view the LICENSE |
|
12
|
|
|
* file that was distributed with this source code. |
|
13
|
|
|
*/ |
|
14
|
|
|
|
|
15
|
|
|
namespace Acme\App\Infrastructure\Persistence\Doctrine\Type; |
|
16
|
|
|
|
|
17
|
|
|
use Acme\PhpExtension\Helper\ClassHelper; |
|
18
|
|
|
use Acme\PhpExtension\Helper\StringHelper; |
|
19
|
|
|
use Acme\PhpExtension\ScalarObjectInterface; |
|
20
|
|
|
use Doctrine\DBAL\Platforms\AbstractPlatform; |
|
21
|
|
|
|
|
22
|
|
|
trait TypeTrait |
|
23
|
|
|
{ |
|
24
|
|
|
abstract protected function getMappedClass(): string; |
|
25
|
|
|
|
|
26
|
|
View Code Duplication |
public function convertToPHPValue($value, AbstractPlatform $platform) |
|
|
|
|
|
|
27
|
|
|
{ |
|
28
|
|
|
$value = parent::convertToPHPValue($value, $platform); |
|
29
|
|
|
|
|
30
|
|
|
if ($value === null) { |
|
31
|
|
|
return null; |
|
32
|
|
|
} |
|
33
|
|
|
|
|
34
|
|
|
return $this->createSpecificObject($value); |
|
35
|
|
|
} |
|
36
|
|
|
|
|
37
|
|
|
/** |
|
38
|
|
|
* @param AbstractPlatform $platform This needs to be here in order to comply to the Type class method signature |
|
39
|
|
|
*/ |
|
40
|
|
|
public function convertToDatabaseValue($value, AbstractPlatform $platform) |
|
|
|
|
|
|
41
|
|
|
{ |
|
42
|
|
|
if ($value === null && $this->allowsNullValues()) { |
|
43
|
|
|
return null; |
|
44
|
|
|
} |
|
45
|
|
|
|
|
46
|
|
|
if ($value instanceof ScalarObjectInterface) { |
|
|
|
|
|
|
47
|
|
|
return $value->toScalar(); |
|
48
|
|
|
} |
|
49
|
|
|
|
|
50
|
|
|
return $value; |
|
51
|
|
|
} |
|
52
|
|
|
|
|
53
|
|
|
/** |
|
54
|
|
|
* This is used to generate a DC2Type:<whatever_type> comment for the field |
|
55
|
|
|
* and allow doctrine diff to match the types instead of assuming |
|
56
|
|
|
* it's an integer type (id). |
|
57
|
|
|
* |
|
58
|
|
|
* The value outputted here is what is used as key in config/packages/doctrine.yaml:doctrine|dbal|types |
|
59
|
|
|
* |
|
60
|
|
|
* By convention, we use the canonical class name in snake case. If at some point we get a collision, |
|
61
|
|
|
* we can override this method in the collision type mapper. |
|
62
|
|
|
* |
|
63
|
|
|
* @return string |
|
64
|
|
|
* |
|
65
|
|
|
* NOTE: We can not have return type type hinted because it needs to be compatible with |
|
66
|
|
|
* Doctrine\DBAL\Types\Type::getName() |
|
67
|
|
|
*/ |
|
68
|
|
|
public function getName() |
|
69
|
|
|
{ |
|
70
|
|
|
return StringHelper::toSnakeCase( |
|
71
|
|
|
ClassHelper::extractCanonicalClassName($this->getMappedClass()) |
|
72
|
|
|
); |
|
73
|
|
|
} |
|
74
|
|
|
|
|
75
|
|
|
/** |
|
76
|
|
|
* @param AbstractPlatform $platform This needs to be here in order to comply to the Type class method signature |
|
77
|
|
|
*/ |
|
78
|
|
|
public function requiresSQLCommentHint(AbstractPlatform $platform): bool |
|
|
|
|
|
|
79
|
|
|
{ |
|
80
|
|
|
return true; |
|
81
|
|
|
} |
|
82
|
|
|
|
|
83
|
|
|
protected function createSpecificObject($value) |
|
84
|
|
|
{ |
|
85
|
|
|
$class = $this->getMappedClass(); |
|
86
|
|
|
|
|
87
|
|
|
return new $class($value); |
|
88
|
|
|
} |
|
89
|
|
|
|
|
90
|
|
|
/** |
|
91
|
|
|
* In general an Enum is required and should have a value, but in some cases, because of Doctrine's implementation, |
|
92
|
|
|
* we cannot enforce this:. |
|
93
|
|
|
* |
|
94
|
|
|
* When we have a case of table inheritance, if we query an entity by the top table then Doctrine joins all the |
|
95
|
|
|
* inheritance tables and tries to hydrate all of their fields, including the ones from types |
|
96
|
|
|
* that don't belong to the entity we fetch for the database. |
|
97
|
|
|
* |
|
98
|
|
|
* This means that when we fetch a entity, doctrine will try to hydrate the sister entities fields as well, |
|
99
|
|
|
* and as we have enums in the sister entities, doctrine will try to create an enum for them. Of course |
|
100
|
|
|
* for the entity we care about this value will be NULL, so we need to do a null check in all Doctrine Enums |
|
101
|
|
|
* that we use in combination with a superclass. |
|
102
|
|
|
* |
|
103
|
|
|
* When we don't have a superclass (most cases) we should not allow null values. |
|
104
|
|
|
*/ |
|
105
|
|
|
protected function allowsNullValues(): bool |
|
106
|
|
|
{ |
|
107
|
|
|
return false; |
|
108
|
|
|
} |
|
109
|
|
|
} |
|
110
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.