Failed Conditions
Push — master ( fa7802...d60694 )
by Guilherme
09:27
created

withCustomIdGeneratorAnnotation()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 6
ccs 3
cts 3
cp 1
crap 1
rs 10
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 401
    public function __construct(
46
        Mapping\ClassMetadataBuildingContext $metadataBuildingContext,
47
        ?ValueGeneratorMetadataBuilder $valueGeneratorMetadataBuilder = null
48
    ) {
49 401
        $this->metadataBuildingContext       = $metadataBuildingContext;
50 401
        $this->valueGeneratorMetadataBuilder = $valueGeneratorMetadataBuilder ?: new ValueGeneratorMetadataBuilder($metadataBuildingContext);
51 401
    }
52
53 401
    public function withComponentMetadata(Mapping\ClassMetadata $componentMetadata) : FieldMetadataBuilder
54
    {
55 401
        $this->componentMetadata = $componentMetadata;
56
57 401
        return $this;
58
    }
59
60 397
    public function withFieldName(string $fieldName) : FieldMetadataBuilder
61
    {
62 397
        $this->fieldName = $fieldName;
63
64 397
        return $this;
65
    }
66
67 397
    public function withColumnAnnotation(Annotation\Column $columnAnnotation) : FieldMetadataBuilder
68
    {
69 397
        $this->columnAnnotation = $columnAnnotation;
70
71 397
        return $this;
72
    }
73
74 397
    public function withIdAnnotation(?Annotation\Id $idAnnotation) : FieldMetadataBuilder
75
    {
76 397
        $this->idAnnotation = $idAnnotation;
77
78 397
        return $this;
79
    }
80
81 397
    public function withVersionAnnotation(?Annotation\Version $versionAnnotation) : FieldMetadataBuilder
82
    {
83 397
        $this->versionAnnotation = $versionAnnotation;
84
85 397
        return $this;
86
    }
87
88 395
    public function withGeneratedValueAnnotation(
89
        ?Annotation\GeneratedValue $generatedValueAnnotation
90
    ) : FieldMetadataBuilder {
91 395
        $this->generatedValueAnnotation = $generatedValueAnnotation;
92
93 395
        return $this;
94
    }
95
96 395
    public function withSequenceGeneratorAnnotation(
97
        ?Annotation\SequenceGenerator $sequenceGeneratorAnnotation
98
    ) : FieldMetadataBuilder {
99 395
        $this->sequenceGeneratorAnnotation = $sequenceGeneratorAnnotation;
100
101 395
        return $this;
102
    }
103
104 395
    public function withCustomIdGeneratorAnnotation(
105
        ?Annotation\CustomIdGenerator $customIdGeneratorAnnotation
106
    ) : FieldMetadataBuilder {
107 395
        $this->customIdGeneratorAnnotation = $customIdGeneratorAnnotation;
108
109 395
        return $this;
110
    }
111
112 397
    public function build() : Mapping\FieldMetadata
113
    {
114
        // Validate required fields
115 397
        assert($this->componentMetadata !== null);
116 397
        assert($this->columnAnnotation !== null);
117 397
        assert($this->fieldName !== null);
118
119 397
        $componentClassName = $this->componentMetadata->getClassName();
120 397
        $namingStrategy     = $this->metadataBuildingContext->getNamingStrategy();
121 397
        $columnName         = $this->columnAnnotation->name
122 397
            ?? $namingStrategy->propertyToColumnName($this->fieldName, $componentClassName);
123 397
        $fieldMetadata      = new Mapping\FieldMetadata($this->fieldName);
124
125
        // For PHP 7.4+, we could potentially infer from property type
126 397
        if ($this->columnAnnotation->type === null) {
127
            throw Mapping\MappingException::propertyTypeIsRequired($componentClassName, $this->fieldName);
128
        }
129
130 397
        $fieldType    = Type::getType($this->columnAnnotation->type);
131 397
        $fieldOptions = $this->columnAnnotation->options ?? [];
132
133
        // Check for primary key
134 397
        if ($this->idAnnotation !== null) {
135 391
            $fieldMetadata->setPrimaryKey(true);
136
137 391
            if ($fieldType->canRequireSQLConversion()) {
138
                throw Mapping\MappingException::sqlConversionNotAllowedForPrimaryKeyProperties(
139
                    $componentClassName,
140
                    $this->fieldName,
141
                    $fieldType->getName()
142
                );
143
            }
144
145
            // Check for value generator
146 391
            $valueGeneratorMetadata = $this->valueGeneratorMetadataBuilder
147 391
                ->withComponentMetadata($this->componentMetadata)
148 391
                ->withFieldName($this->fieldName)
149 391
                ->withFieldType($fieldType)
150 391
                ->withGeneratedValueAnnotation($this->generatedValueAnnotation)
151 391
                ->withSequenceGeneratorAnnotation($this->sequenceGeneratorAnnotation)
152 391
                ->withCustomIdGeneratorAnnotation($this->customIdGeneratorAnnotation)
153 391
                ->build();
154
155 391
            $fieldMetadata->setValueGenerator($valueGeneratorMetadata);
156
        }
157
158
        // Check for version
159 397
        if ($this->versionAnnotation !== null) {
160
            // Determine default option for versioned field
161 20
            switch ($fieldType->getName()) {
162 20
                case 'integer':
163 2
                case 'bigint':
164 2
                case 'smallint':
165 19
                    $fieldOptions = array_merge(['default' => 1], $fieldOptions);
166 19
                    break;
167
168 2
                case 'datetime':
169 1
                case 'datetime_immutable':
170
                case 'datetimetz':
171
                case 'datetimetz_immutable':
172 2
                    $fieldOptions = array_merge(['default' => 'CURRENT_TIMESTAMP'], $fieldOptions);
173 2
                    break;
174
175
                default:
176
                    if (! isset($fieldOptions['default'])) {
177
                        throw Mapping\MappingException::unsupportedOptimisticLockingType($fieldType);
178
                    }
179
180
                    break;
181
            }
182
183 20
            $fieldMetadata->setVersioned(true);
184
        }
185
186
        // Prevent PK and version on same field
187 397
        if ($fieldMetadata->isPrimaryKey() && $fieldMetadata->isVersioned()) {
188
            throw Mapping\MappingException::cannotVersionIdField($componentClassName, $this->fieldName);
189
        }
190
191 397
        $fieldMetadata->setColumnName($columnName);
192 397
        $fieldMetadata->setType($fieldType);
193 397
        $fieldMetadata->setOptions($fieldOptions);
194 397
        $fieldMetadata->setScale($this->columnAnnotation->scale);
195 397
        $fieldMetadata->setPrecision($this->columnAnnotation->precision);
196 397
        $fieldMetadata->setNullable($this->columnAnnotation->nullable);
197 397
        $fieldMetadata->setUnique($this->columnAnnotation->unique);
198
199 397
        if (! $this->componentMetadata->isMappedSuperclass) {
200 390
            $fieldMetadata->setTableName($this->componentMetadata->getTableName());
201
        }
202
203 397
        if (! empty($this->columnAnnotation->columnDefinition)) {
204 8
            $fieldMetadata->setColumnDefinition($this->columnAnnotation->columnDefinition);
205
        }
206
207 397
        if (! empty($this->columnAnnotation->length)) {
208 397
            $fieldMetadata->setLength($this->columnAnnotation->length);
209
        }
210
211 397
        return $fieldMetadata;
212
    }
213
}
214