Skip to content

Commit 861eced

Browse files
authored
Merge pull request #97 from dunglas/uuid_support
Add support for UUIDs and various ID generation strategies
2 parents 34966b8 + aad94c7 commit 861eced

16 files changed

+352
-44
lines changed

src/AnnotationGenerator/ConstraintAnnotationGenerator.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ public function generateFieldAnnotations(string $className, string $fieldName):
3030
$field = $this->classes[$className]['fields'][$fieldName];
3131

3232
if ($field['isId']) {
33+
if ('uuid' === $this->config['id']['generationStrategy']) {
34+
return ['@Assert\Uuid'];
35+
}
36+
3337
return [];
3438
}
3539

src/AnnotationGenerator/DoctrineMongoDBAnnotationGenerator.php

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,10 @@ public function generateClassAnnotations(string $className): array
4848
*/
4949
public function generateFieldAnnotations(string $className, string $fieldName): array
5050
{
51-
$this->classes[$className];
5251
$field = $this->classes[$className]['fields'][$fieldName];
52+
if ($field['isId']) {
53+
return $this->generateIdAnnotations();
54+
}
5355

5456
$annotations = [];
5557

@@ -85,17 +87,15 @@ public function generateFieldAnnotations(string $className, string $fieldName):
8587
}
8688

8789
if (isset($type)) {
88-
if (!$field['isId']) {
89-
$annotation = '@MongoDB\Field';
90+
$annotation = '@MongoDB\Field';
9091

91-
if ($field['isArray']) {
92-
$type = 'collection';
93-
}
92+
if ($field['isArray']) {
93+
$type = 'collection';
94+
}
9495

95-
$annotation .= sprintf('(type="%s")', $type);
96+
$annotation .= sprintf('(type="%s")', $type);
9697

97-
$annotations[] = $annotation;
98-
}
98+
$annotations[] = $annotation;
9999
} else {
100100
if ($field['cardinality'] === CardinalitiesExtractor::CARDINALITY_0_1
101101
|| $field['cardinality'] === CardinalitiesExtractor::CARDINALITY_1_1
@@ -109,10 +109,6 @@ public function generateFieldAnnotations(string $className, string $fieldName):
109109
}
110110
}
111111

112-
if ($field['isId']) {
113-
$annotations[] = '@MongoDB\Id';
114-
}
115-
116112
return $annotations;
117113
}
118114

@@ -138,4 +134,22 @@ private function getRelationName(string $range): string
138134

139135
return $class[$range]['interfaceName'] ?? $class['name'];
140136
}
137+
138+
private function generateIdAnnotations(): array
139+
{
140+
switch ($this->config['id']['generationStrategy']) {
141+
case 'uuid':
142+
if ($this->config['id']['writable']) {
143+
return ['@MongoDB\Id(strategy="NONE", type="bin_uuid")'];
144+
}
145+
146+
return ['@MongoDB\Id(strategy="UUID")'];
147+
case 'auto':
148+
return ['@MongoDB\Id(strategy="INCREMENT")'];
149+
case 'mongoid':
150+
return ['@MongoDB\Id'];
151+
default:
152+
return ['@MongoDB\Id(strategy="NONE", type="string")'];
153+
}
154+
}
141155
}

src/AnnotationGenerator/DoctrineOrmAnnotationGenerator.php

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,17 @@ public function generateClassAnnotations(string $className): array
5656
*/
5757
public function generateFieldAnnotations(string $className, string $fieldName): array
5858
{
59-
$this->classes[$className];
6059
$field = $this->classes[$className]['fields'][$fieldName];
60+
if ($field['isId']) {
61+
return $this->generateIdAnnotations();
62+
}
63+
64+
$annotations = [];
6165

6266
$field['relationTableName'] = null;
63-
if (!$field['isId'] && isset($this->config['types'][$className]['properties'][$fieldName])) {
67+
if (isset($this->config['types'][$className]['properties'][$fieldName])) {
6468
$field['relationTableName'] = $this->config['types'][$className]['properties'][$fieldName]['relationTableName'];
6569
}
66-
$annotations = [];
6770

6871
if ($field['isEnum']) {
6972
$type = $field['isArray'] ? 'simple_array' : 'string';
@@ -82,17 +85,15 @@ public function generateFieldAnnotations(string $className, string $fieldName):
8285
$type = 'time';
8386
break;
8487
case 'Number':
85-
// No break
8688
case 'Float':
8789
$type = 'float';
8890
break;
8991
case 'Integer':
9092
$type = 'integer';
9193
break;
9294
case 'Text':
93-
// No break
9495
case 'URL':
95-
$type = 'string';
96+
$type = 'text';
9697
break;
9798
}
9899
}
@@ -102,7 +103,7 @@ public function generateFieldAnnotations(string $className, string $fieldName):
102103
$isColumnHasProperties = false;
103104

104105
if ($field['ormColumn']) {
105-
$annotation .= '('.$field['ormColumn'].')';
106+
$annotation .= sprintf('(%s)', $field['ormColumn']);
106107
} else {
107108
if ($type !== 'string' || $field['isNullable'] || $field['isUnique']) {
108109
$isColumnHasProperties = true;
@@ -182,11 +183,6 @@ public function generateFieldAnnotations(string $className, string $fieldName):
182183
}
183184
}
184185

185-
if ($field['isId']) {
186-
$annotations[] = '@ORM\Id';
187-
$annotations[] = '@ORM\GeneratedValue(strategy="AUTO")';
188-
}
189-
190186
return $annotations;
191187
}
192188

@@ -203,6 +199,30 @@ public function generateUses(string $className): array
203199
return $typeIsEnum ? [] : ['Doctrine\ORM\Mapping as ORM'];
204200
}
205201

202+
private function generateIdAnnotations(): array
203+
{
204+
$annotations = ['@ORM\Id'];
205+
if ('none' !== $this->config['id']['generationStrategy'] && !$this->config['id']['writable']) {
206+
$annotations[] = sprintf('@ORM\GeneratedValue(strategy="%s")', strtoupper($this->config['id']['generationStrategy']));
207+
}
208+
209+
switch ($this->config['id']['generationStrategy']) {
210+
case 'uuid':
211+
$type = 'guid';
212+
break;
213+
case 'auto':
214+
$type = 'integer';
215+
break;
216+
default:
217+
$type = 'string';
218+
break;
219+
}
220+
221+
$annotations[] = sprintf('@ORM\Column(type="%s")', $type);
222+
223+
return $annotations;
224+
}
225+
206226
/**
207227
* Gets class or interface name to use in relations.
208228
*/

src/AnnotationGenerator/PhpDocAnnotationGenerator.php

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ public function generateFieldAnnotations(string $className, string $fieldName):
7878
$comment = $field['resource'] ? $field['resource']->get('rdfs:comment') : '';
7979

8080
$annotations = $this->formatDoc((string) $comment, true);
81-
$annotations[0] = sprintf('@var %s %s', $this->toPhpType($field), $annotations[0]);
81+
82+
$annotations[0] = sprintf('@var %s %s', $this->toPhpDocType($field), $annotations[0]);
8283
$annotations[] = '';
8384

8485
return $annotations;
@@ -93,7 +94,7 @@ public function generateGetterAnnotations(string $className, string $fieldName):
9394
return [];
9495
}
9596

96-
return [sprintf('@return %s', $this->toPhpType($this->classes[$className]['fields'][$fieldName]))];
97+
return [sprintf('@return %s', $this->toPhpDocType($this->classes[$className]['fields'][$fieldName]))];
9798
}
9899

99100
/**
@@ -105,7 +106,7 @@ public function generateSetterAnnotations(string $className, string $fieldName):
105106
return [];
106107
}
107108

108-
return [sprintf('@param %s $%s', $this->toPhpType($this->classes[$className]['fields'][$fieldName]), $fieldName)];
109+
return [sprintf('@param %s $%s', $this->toPhpDocType($this->classes[$className]['fields'][$fieldName]), $fieldName)];
109110
}
110111

111112
/**
@@ -179,4 +180,14 @@ private function formatDoc(string $doc, bool $indent = false): array
179180

180181
return $doc;
181182
}
183+
184+
private function toPhpDocType(array $field): string
185+
{
186+
$type = $this->toPhpType($field);
187+
if ($field['isNullable']) {
188+
$type .= '|null';
189+
}
190+
191+
return $type;
192+
}
182193
}

src/TypesGenerator.php

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -293,28 +293,55 @@ public function generate(array $config): void
293293
}
294294

295295
// Generate ID
296-
if ($config['generateId']) {
296+
if ($config['id']['generate']) {
297297
foreach ($classes as &$class) {
298298
if ($class['hasChild'] || $class['isEnum'] || $class['embeddable']) {
299299
continue;
300300
}
301301

302+
switch ($config['id']['generationStrategy']) {
303+
case 'auto':
304+
$range = 'Integer';
305+
$typeHint = 'int';
306+
$writable = false;
307+
$nullable = true;
308+
break;
309+
case 'uuid':
310+
$range = 'Text';
311+
$typeHint = 'string';
312+
$writable = $config['id']['writable'];
313+
$nullable = !$writable;
314+
break;
315+
case 'mongoid':
316+
$range = 'Text';
317+
$typeHint = 'string';
318+
$writable = false;
319+
$nullable = true;
320+
break;
321+
default:
322+
$range = 'Text';
323+
$typeHint = 'string';
324+
$writable = true;
325+
$nullable = false;
326+
break;
327+
}
328+
302329
$class['fields'] = [
303330
'id' => [
304331
'name' => 'id',
305332
'resource' => null,
306-
'range' => 'Integer',
333+
'range' => $range,
307334
'cardinality' => CardinalitiesExtractor::CARDINALITY_1_1,
308335
'ormColumn' => null,
309336
'isArray' => false,
310337
'isReadable' => true,
311-
'isWritable' => false,
312-
'isNullable' => false,
338+
'isWritable' => $writable,
339+
'isNullable' => $nullable,
313340
'isUnique' => false,
314341
'isCustom' => true,
315342
'isEnum' => false,
316343
'isId' => true,
317-
'typeHint' => 'int',
344+
'typeHint' => $typeHint,
318345
],
319346
] + $class['fields'];
320347
}

src/TypesGeneratorConfiguration.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,15 @@ function ($rdfa) {
7070
->prototype('scalar')->end()
7171
->end()
7272
->booleanNode('debug')->defaultFalse()->info('Debug mode')->end()
73-
->booleanNode('generateId')->defaultTrue()->info('Automatically add an id field to entities')->end()
73+
->arrayNode('id')
74+
->addDefaultsIfNotSet()
75+
->info('IDs configuration')
76+
->children()
77+
->booleanNode('generate')->defaultTrue()->info('Automatically add an id field to entities')->end()
78+
->enumNode('generationStrategy')->defaultValue('auto')->values(['auto', 'none', 'uuid', 'mongoid'])->info('The ID generation strategy to use ("none" to not let the database generate IDs).')->end()
79+
->booleanNode('writable')->defaultFalse()->info('Is the ID writable? Only applicable if "generationStrategy" is "uuid".')->end()
80+
->end()
81+
->end()
7482
->booleanNode('useInterface')->defaultFalse()->info('Generate interfaces and use Doctrine\'s Resolve Target Entity feature')->end()
7583
->booleanNode('checkIsGoodRelations')->defaultFalse()->info('Emit a warning if a property is not derived from GoodRelations')->end()
7684
->scalarNode('header')->defaultFalse()->info('A license or any text to use as header of generated files')->example('// (c) Kévin Dunglas <[email protected]>')->end()

tests/Command/DumpConfigurationTest.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,17 @@ public function testDumpConfiguration()
5050
# Debug mode
5151
debug: false
5252
53-
# Automatically add an id field to entities
54-
generateId: true
53+
# IDs configuration
54+
id:
55+
56+
# Automatically add an id field to entities
57+
generate: true
58+
59+
# The ID generation strategy to use ("none" to not let the database generate IDs).
60+
generationStrategy: auto # One of "auto"; "none"; "uuid"; "mongoid"
61+
62+
# Is the ID writable? Only applicable if "generationStrategy" is "uuid".
63+
writable: false
5564
5665
# Generate interfaces and use Doctrine's Resolve Target Entity feature
5766
useInterface: false

0 commit comments

Comments
 (0)