FieldMetadataBuilder   A
last analyzed

Complexity

Total Complexity 28

Size/Duplication

Total Lines 196
Duplicated Lines 0 %

Test Coverage

Coverage 87.78%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 90
c 2
b 0
f 0
dl 0
loc 196
ccs 79
cts 90
cp 0.8778
rs 10
wmc 28

10 Methods

Rating   Name   Duplication   Size   Complexity  
A withColumnAnnotation() 0 5 1
A withComponentMetadata() 0 5 1
A withVersionAnnotation() 0 5 1
A withIdAnnotation() 0 5 1
A __construct() 0 6 2
A withFieldName() 0 5 1
A withGeneratedValueAnnotation() 0 5 1
D build() 0 100 18
A withCustomIdGeneratorAnnotation() 0 5 1
A withSequenceGeneratorAnnotation() 0 5 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ORM\Mapping\Builder;
6
7
use Doctrine\DBAL\Types\Type;
8
use Doctrine\ORM\Annotation;
9
use Doctrine\ORM\Mapping;
10
use function array_merge;
11
use function assert;
12
13
class FieldMetadataBuilder
14
{
15
    /** @var Mapping\ClassMetadataBuildingContext */
16
    private $metadataBuildingContext;
17
18
    /** @var ValueGeneratorMetadataBuilder */
19
    private $valueGeneratorMetadataBuilder;
20
21
    /** @var Mapping\ClassMetadata */
22
    private $componentMetadata;
23
24
    /** @var string */
25
    private $fieldName;
26
27
    /** @var Annotation\Column */
28
    private $columnAnnotation;
29
30
    /** @var Annotation\Id|null */
31
    private $idAnnotation;
32
33
    /** @var Annotation\Version|null */
34
    private $versionAnnotation;
35
36
    /** @var Annotation\GeneratedValue|null */
37
    private $generatedValueAnnotation;
38
39
    /** @var Annotation\SequenceGenerator|null */
40
    private $sequenceGeneratorAnnotation;
41
42
    /** @var Annotation\CustomIdGenerator|null */
43
    private $customIdGeneratorAnnotation;
44
45 408
    public function __construct(
46
        Mapping\ClassMetadataBuildingContext $metadataBuildingContext,
47
        ?ValueGeneratorMetadataBuilder $valueGeneratorMetadataBuilder = null
48
    ) {
49 408
        $this->metadataBuildingContext       = $metadataBuildingContext;
50 408
        $this->valueGeneratorMetadataBuilder = $valueGeneratorMetadataBuilder ?: new ValueGeneratorMetadataBuilder($metadataBuildingContext);
51 408
    }
52
53 407
    public function withComponentMetadata(Mapping\ClassMetadata $componentMetadata) : FieldMetadataBuilder
54
    {
55 407
        $this->componentMetadata = $componentMetadata;
56
57 407
        return $this;
58
    }
59
60 407
    public function withFieldName(string $fieldName) : FieldMetadataBuilder
61
    {
62 407
        $this->fieldName = $fieldName;
63
64 407
        return $this;
65
    }
66
67 398
    public function withColumnAnnotation(Annotation\Column $columnAnnotation) : FieldMetadataBuilder
68
    {
69 398
        $this->columnAnnotation = $columnAnnotation;
70
71 398
        return $this;
72
    }
73
74 407
    public function withIdAnnotation(?Annotation\Id $idAnnotation) : FieldMetadataBuilder
75
    {
76 407
        $this->idAnnotation = $idAnnotation;
77
78 407
        return $this;
79
    }
80
81 407
    public function withVersionAnnotation(?Annotation\Version $versionAnnotation) : FieldMetadataBuilder
82
    {
83 407
        $this->versionAnnotation = $versionAnnotation;
84
85 407
        return $this;
86
    }
87
88 401
    public function withGeneratedValueAnnotation(?Annotation\GeneratedValue $generatedValueAnnotation) : FieldMetadataBuilder
89
    {
90 401
        $this->generatedValueAnnotation = $generatedValueAnnotation;
91
92 401
        return $this;
93
    }
94
95 401
    public function withSequenceGeneratorAnnotation(?Annotation\SequenceGenerator $sequenceGeneratorAnnotation) : FieldMetadataBuilder
96
    {
97 401
        $this->sequenceGeneratorAnnotation = $sequenceGeneratorAnnotation;
98
99 401
        return $this;
100
    }
101
102 401
    public function withCustomIdGeneratorAnnotation(?Annotation\CustomIdGenerator $customIdGeneratorAnnotation) : FieldMetadataBuilder
103
    {
104 401
        $this->customIdGeneratorAnnotation = $customIdGeneratorAnnotation;
105
106 401
        return $this;
107
    }
108
109 398
    public function build() : Mapping\FieldMetadata
110
    {
111
        // Validate required fields
112 398
        assert($this->componentMetadata !== null);
113 398
        assert($this->columnAnnotation !== null);
114 398
        assert($this->fieldName !== null);
115
116 398
        $componentClassName = $this->componentMetadata->getClassName();
117 398
        $namingStrategy     = $this->metadataBuildingContext->getNamingStrategy();
118 398
        $columnName         = $this->columnAnnotation->name
119 398
            ?? $namingStrategy->propertyToColumnName($this->fieldName, $componentClassName);
120 398
        $fieldMetadata      = new Mapping\FieldMetadata($this->fieldName);
121
122
        // For PHP 7.4+, we could potentially infer from property type
123 398
        if ($this->columnAnnotation->type === null) {
124
            throw Mapping\MappingException::propertyTypeIsRequired($componentClassName, $this->fieldName);
125
        }
126
127 398
        $fieldType    = Type::getType($this->columnAnnotation->type);
128 398
        $fieldOptions = $this->columnAnnotation->options ?? [];
129
130
        // Check for primary key
131 398
        if ($this->idAnnotation !== null) {
132 392
            $fieldMetadata->setPrimaryKey(true);
133
134 392
            if ($fieldType->canRequireSQLConversion()) {
135
                throw Mapping\MappingException::sqlConversionNotAllowedForPrimaryKeyProperties(
136
                    $componentClassName,
137
                    $this->fieldName,
138
                    $fieldType->getName()
139
                );
140
            }
141
142
            // Check for value generator
143 392
            $valueGeneratorMetadata = $this->valueGeneratorMetadataBuilder
144 392
                ->withComponentMetadata($this->componentMetadata)
145 392
                ->withFieldName($this->fieldName)
146 392
                ->withFieldType($fieldType)
147 392
                ->withGeneratedValueAnnotation($this->generatedValueAnnotation)
148 392
                ->withSequenceGeneratorAnnotation($this->sequenceGeneratorAnnotation)
149 392
                ->withCustomIdGeneratorAnnotation($this->customIdGeneratorAnnotation)
150 392
                ->build();
151
152 392
            $fieldMetadata->setValueGenerator($valueGeneratorMetadata);
153
        }
154
155
        // Check for version
156 398
        if ($this->versionAnnotation !== null) {
157
            // Determine default option for versioned field
158 20
            switch ($fieldType->getName()) {
159 20
                case 'integer':
160 2
                case 'bigint':
161 2
                case 'smallint':
162 19
                    $fieldOptions = array_merge(['default' => 1], $fieldOptions);
163 19
                    break;
164
165 2
                case 'datetime':
166 1
                case 'datetime_immutable':
167
                case 'datetimetz':
168
                case 'datetimetz_immutable':
169 2
                    $fieldOptions = array_merge(['default' => 'CURRENT_TIMESTAMP'], $fieldOptions);
170 2
                    break;
171
172
                default:
173
                    if (! isset($fieldOptions['default'])) {
174
                        throw Mapping\MappingException::unsupportedOptimisticLockingType($fieldType);
175
                    }
176
177
                    break;
178
            }
179
180 20
            $fieldMetadata->setVersioned(true);
181
        }
182
183
        // Prevent PK and version on same field
184 398
        if ($fieldMetadata->isPrimaryKey() && $fieldMetadata->isVersioned()) {
185
            throw Mapping\MappingException::cannotVersionIdField($componentClassName, $this->fieldName);
186
        }
187
188 398
        $fieldMetadata->setColumnName($columnName);
189 398
        $fieldMetadata->setType($fieldType);
190 398
        $fieldMetadata->setOptions($fieldOptions);
191 398
        $fieldMetadata->setScale($this->columnAnnotation->scale);
192 398
        $fieldMetadata->setPrecision($this->columnAnnotation->precision);
193 398
        $fieldMetadata->setNullable($this->columnAnnotation->nullable);
194 398
        $fieldMetadata->setUnique($this->columnAnnotation->unique);
195
196 398
        if (! $this->componentMetadata->isMappedSuperclass) {
197 391
            $fieldMetadata->setTableName($this->componentMetadata->getTableName());
198
        }
199
200 398
        if (! empty($this->columnAnnotation->columnDefinition)) {
201 8
            $fieldMetadata->setColumnDefinition($this->columnAnnotation->columnDefinition);
202
        }
203
204 398
        if (! empty($this->columnAnnotation->length)) {
205 398
            $fieldMetadata->setLength($this->columnAnnotation->length);
206
        }
207
208 398
        return $fieldMetadata;
209
    }
210
}
211