1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace Doctrine\ORM\Mapping\Driver; |
6
|
|
|
|
7
|
|
|
use Doctrine\Common\Util\Inflector; |
8
|
|
|
use Doctrine\DBAL\Schema\AbstractSchemaManager; |
9
|
|
|
use Doctrine\DBAL\Schema\Index; |
10
|
|
|
use Doctrine\DBAL\Schema\SchemaException; |
11
|
|
|
use Doctrine\DBAL\Schema\Table; |
12
|
|
|
use Doctrine\DBAL\Schema\Column; |
13
|
|
|
use Doctrine\DBAL\Types\Type; |
14
|
|
|
use Doctrine\ORM\Mapping; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* The DatabaseDriver reverse engineers the mapping metadata from a database. |
18
|
|
|
* |
19
|
|
|
* @link www.doctrine-project.org |
20
|
|
|
* @since 2.0 |
21
|
|
|
* @author Guilherme Blanco <[email protected]> |
22
|
|
|
* @author Jonathan Wage <[email protected]> |
23
|
|
|
* @author Benjamin Eberlei <[email protected]> |
24
|
|
|
*/ |
25
|
|
|
class DatabaseDriver implements MappingDriver |
26
|
|
|
{ |
27
|
|
|
/** |
28
|
|
|
* @var AbstractSchemaManager |
29
|
|
|
*/ |
30
|
|
|
private $sm; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* @var array|null |
34
|
|
|
*/ |
35
|
|
|
private $tables = null; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* @var array |
39
|
|
|
*/ |
40
|
|
|
private $classToTableNames = []; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* @var array |
44
|
|
|
*/ |
45
|
|
|
private $manyToManyTables = []; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* @var array |
49
|
|
|
*/ |
50
|
|
|
private $classNamesForTables = []; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @var array |
54
|
|
|
*/ |
55
|
|
|
private $fieldNamesForColumns = []; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* The namespace for the generated entities. |
59
|
|
|
* |
60
|
|
|
* @var string|null |
61
|
|
|
*/ |
62
|
|
|
private $namespace; |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* @param AbstractSchemaManager $schemaManager |
66
|
|
|
*/ |
67
|
|
|
public function __construct(AbstractSchemaManager $schemaManager) |
68
|
|
|
{ |
69
|
|
|
$this->sm = $schemaManager; |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* Set the namespace for the generated entities. |
74
|
|
|
* |
75
|
|
|
* @param string $namespace |
76
|
|
|
* |
77
|
|
|
* @return void |
78
|
|
|
*/ |
79
|
|
|
public function setNamespace($namespace) |
80
|
|
|
{ |
81
|
|
|
$this->namespace = $namespace; |
82
|
|
|
} |
83
|
|
|
|
84
|
2 |
|
/** |
85
|
|
|
* {@inheritDoc} |
86
|
2 |
|
*/ |
87
|
2 |
|
public function isTransient($className) |
88
|
|
|
{ |
89
|
|
|
return true; |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* {@inheritDoc} |
94
|
|
|
*/ |
95
|
|
|
public function getAllClassNames() |
96
|
|
|
{ |
97
|
|
|
$this->reverseEngineerMappingFromDatabase(); |
98
|
|
|
|
99
|
|
|
return array_keys($this->classToTableNames); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* Sets class name for a table. |
104
|
|
|
* |
105
|
|
|
* @param string $tableName |
106
|
|
|
* @param string $className |
107
|
|
|
* |
108
|
|
|
* @return void |
109
|
|
|
*/ |
110
|
|
|
public function setClassNameForTable($tableName, $className) |
111
|
|
|
{ |
112
|
2 |
|
$this->classNamesForTables[$tableName] = $className; |
113
|
|
|
} |
114
|
2 |
|
|
115
|
|
|
/** |
116
|
2 |
|
* Sets field name for a column on a specific table. |
117
|
|
|
* |
118
|
|
|
* @param string $tableName |
119
|
|
|
* @param string $columnName |
120
|
|
|
* @param string $fieldName |
121
|
|
|
* |
122
|
|
|
* @return void |
123
|
|
|
*/ |
124
|
|
|
public function setFieldNameForColumn($tableName, $columnName, $fieldName) |
125
|
|
|
{ |
126
|
|
|
$this->fieldNamesForColumns[$tableName][$columnName] = $fieldName; |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* Sets tables manually instead of relying on the reverse engineering capabilities of SchemaManager. |
131
|
|
|
* |
132
|
|
|
* @param array $entityTables |
133
|
|
|
* @param array $manyToManyTables |
134
|
|
|
* |
135
|
|
|
* @return void |
136
|
|
|
*/ |
137
|
|
|
public function setTables($entityTables, $manyToManyTables) |
138
|
|
|
{ |
139
|
|
|
$this->tables = $this->manyToManyTables = $this->classToTableNames = []; |
140
|
|
|
|
141
|
|
|
foreach ($entityTables as $table) { |
142
|
|
|
$className = $this->getClassNameForTable($table->getName()); |
143
|
|
|
|
144
|
|
|
$this->classToTableNames[$className] = $table->getName(); |
145
|
|
|
$this->tables[$table->getName()] = $table; |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
foreach ($manyToManyTables as $table) { |
149
|
|
|
$this->manyToManyTables[$table->getName()] = $table; |
150
|
|
|
} |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
/** |
154
|
2 |
|
* {@inheritDoc} |
155
|
|
|
*/ |
156
|
2 |
|
public function loadMetadataForClass( |
157
|
|
|
string $className, |
158
|
2 |
|
Mapping\ClassMetadata $metadata, |
159
|
2 |
|
Mapping\ClassMetadataBuildingContext $metadataBuildingContext |
160
|
|
|
) |
161
|
2 |
|
{ |
162
|
2 |
|
$this->reverseEngineerMappingFromDatabase(); |
163
|
|
|
|
164
|
|
|
if ( ! isset($this->classToTableNames[$className])) { |
165
|
2 |
|
throw new \InvalidArgumentException("Unknown class " . $className); |
166
|
1 |
|
} |
167
|
|
|
|
168
|
2 |
|
// @todo guilhermeblanco This should somehow disappear... =) |
169
|
|
|
$metadata->setClassName($className); |
170
|
|
|
|
171
|
|
|
$this->buildTable($metadata); |
172
|
|
|
$this->buildFieldMappings($metadata); |
173
|
2 |
|
$this->buildToOneAssociationMappings($metadata); |
174
|
|
|
|
175
|
2 |
|
$loweredTableName = strtolower($metadata->getTableName()); |
176
|
|
|
|
177
|
2 |
|
foreach ($this->manyToManyTables as $manyTable) { |
178
|
|
|
foreach ($manyTable->getForeignKeys() as $foreignKey) { |
179
|
|
|
// foreign key maps to the table of the current entity, many to many association probably exists |
180
|
|
|
if ( ! ($loweredTableName === strtolower($foreignKey->getForeignTableName()))) { |
181
|
2 |
|
continue; |
182
|
|
|
} |
183
|
2 |
|
|
184
|
2 |
|
$myFk = $foreignKey; |
185
|
|
|
$otherFk = null; |
186
|
2 |
|
|
187
|
2 |
|
foreach ($manyTable->getForeignKeys() as $manyTableForeignKey) { |
188
|
2 |
|
if ($manyTableForeignKey !== $myFk) { |
189
|
|
|
$otherFk = $manyTableForeignKey; |
190
|
2 |
|
|
191
|
1 |
|
break; |
192
|
|
|
} |
193
|
1 |
|
} |
194
|
1 |
|
|
195
|
|
|
if ( ! $otherFk) { |
196
|
|
|
// the definition of this many to many table does not contain |
197
|
1 |
|
// enough foreign key information to continue reverse engineering. |
198
|
1 |
|
continue; |
199
|
|
|
} |
200
|
1 |
|
|
201
|
1 |
|
$localColumn = current($myFk->getColumns()); |
202
|
|
|
|
203
|
1 |
|
$associationMapping = []; |
204
|
|
|
$associationMapping['fieldName'] = $this->getFieldNameForColumn($manyTable->getName(), current($otherFk->getColumns()), true); |
205
|
|
|
$associationMapping['targetEntity'] = $this->getClassNameForTable($otherFk->getForeignTableName()); |
206
|
|
|
|
207
|
1 |
|
if (current($manyTable->getColumns())->getName() === $localColumn) { |
208
|
|
|
$associationMapping['inversedBy'] = $this->getFieldNameForColumn($manyTable->getName(), current($myFk->getColumns()), true); |
209
|
|
|
$associationMapping['joinTable'] = new Mapping\JoinTableMetadata(); |
210
|
1 |
|
|
211
|
|
|
$joinTable = $associationMapping['joinTable']; |
212
|
|
|
$joinTable->setName(strtolower($manyTable->getName())); |
213
|
|
|
|
214
|
|
|
$fkCols = $myFk->getForeignColumns(); |
215
|
|
|
$cols = $myFk->getColumns(); |
216
|
|
|
|
217
|
|
View Code Duplication |
for ($i = 0, $l = count($cols); $i < $l; $i++) { |
|
|
|
|
218
|
|
|
$joinColumn = new Mapping\JoinColumnMetadata(); |
219
|
|
|
|
220
|
|
|
$joinColumn->setColumnName($cols[$i]); |
221
|
|
|
$joinColumn->setReferencedColumnName($fkCols[$i]); |
222
|
|
|
|
223
|
|
|
$joinTable->addJoinColumn($joinColumn); |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
$fkCols = $otherFk->getForeignColumns(); |
227
|
|
|
$cols = $otherFk->getColumns(); |
228
|
|
|
|
229
|
|
View Code Duplication |
for ($i = 0, $l = count($cols); $i < $l; $i++) { |
|
|
|
|
230
|
|
|
$joinColumn = new Mapping\JoinColumnMetadata(); |
231
|
|
|
|
232
|
|
|
$joinColumn->setColumnName($cols[$i]); |
233
|
|
|
$joinColumn->setReferencedColumnName($fkCols[$i]); |
234
|
|
|
|
235
|
|
|
$joinTable->addInverseJoinColumn($joinColumn); |
236
|
|
|
} |
237
|
|
|
} else { |
238
|
|
|
$associationMapping['mappedBy'] = $this->getFieldNameForColumn($manyTable->getName(), current($myFk->getColumns()), true); |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
$metadata->addProperty($associationMapping); |
|
|
|
|
242
|
|
|
|
243
|
|
|
break; |
244
|
|
|
} |
245
|
|
|
} |
246
|
|
|
} |
247
|
|
|
|
248
|
|
|
/** |
249
|
|
|
* @return void |
250
|
|
|
* |
251
|
|
|
* @throws Mapping\MappingException |
252
|
1 |
|
*/ |
253
|
|
|
private function reverseEngineerMappingFromDatabase() |
254
|
|
|
{ |
255
|
2 |
|
if ($this->tables !== null) { |
256
|
|
|
return; |
257
|
|
|
} |
258
|
|
|
|
259
|
|
|
$tables = []; |
260
|
|
|
|
261
|
|
|
foreach ($this->sm->listTableNames() as $tableName) { |
262
|
2 |
|
$tables[$tableName] = $this->sm->listTableDetails($tableName); |
263
|
|
|
} |
264
|
2 |
|
|
265
|
2 |
|
$this->tables = $this->manyToManyTables = $this->classToTableNames = []; |
266
|
|
|
|
267
|
|
|
foreach ($tables as $tableName => $table) { |
268
|
|
|
$foreignKeys = ($this->sm->getDatabasePlatform()->supportsForeignKeyConstraints()) |
269
|
|
|
? $table->getForeignKeys() |
270
|
|
|
: []; |
271
|
|
|
|
272
|
|
|
$allForeignKeyColumns = []; |
273
|
|
|
|
274
|
|
|
foreach ($foreignKeys as $foreignKey) { |
275
|
|
|
$allForeignKeyColumns = array_merge($allForeignKeyColumns, $foreignKey->getLocalColumns()); |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
if ( ! $table->hasPrimaryKey()) { |
279
|
|
|
throw new Mapping\MappingException( |
280
|
|
|
"Table " . $table->getName() . " has no primary key. Doctrine does not ". |
281
|
|
|
"support reverse engineering from tables that don't have a primary key." |
282
|
|
|
); |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
$pkColumns = $table->getPrimaryKey()->getColumns(); |
286
|
|
|
|
287
|
|
|
sort($pkColumns); |
288
|
|
|
sort($allForeignKeyColumns); |
289
|
|
|
|
290
|
|
|
if ($pkColumns == $allForeignKeyColumns && count($foreignKeys) == 2) { |
291
|
|
|
$this->manyToManyTables[$tableName] = $table; |
292
|
|
|
} else { |
293
|
|
|
// lower-casing is necessary because of Oracle Uppercase Tablenames, |
294
|
|
|
// assumption is lower-case + underscore separated. |
295
|
|
|
$className = $this->getClassNameForTable($tableName); |
296
|
|
|
|
297
|
|
|
$this->tables[$tableName] = $table; |
298
|
|
|
$this->classToTableNames[$className] = $tableName; |
299
|
|
|
} |
300
|
|
|
} |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
/** |
304
|
|
|
* Build table from a class metadata. |
305
|
|
|
* |
306
|
|
|
* @param Mapping\ClassMetadata $metadata |
307
|
|
|
*/ |
308
|
|
|
private function buildTable(Mapping\ClassMetadata $metadata) |
309
|
|
|
{ |
310
|
|
|
$tableName = $this->classToTableNames[$metadata->getClassName()]; |
311
|
|
|
$indexes = $this->tables[$tableName]->getIndexes(); |
312
|
|
|
$tableMetadata = new Mapping\TableMetadata(); |
313
|
|
|
|
314
|
|
|
$tableMetadata->setName($this->classToTableNames[$metadata->getClassName()]); |
315
|
|
|
|
316
|
|
|
foreach ($indexes as $index) { |
317
|
2 |
|
/** @var Index $index */ |
318
|
|
|
if ($index->isPrimary()) { |
319
|
2 |
|
continue; |
320
|
2 |
|
} |
321
|
|
|
|
322
|
2 |
|
$tableMetadata->addIndex([ |
323
|
2 |
|
'name' => $index->getName(), |
324
|
2 |
|
'columns' => $index->getColumns(), |
325
|
|
|
'unique' => $index->isUnique(), |
326
|
|
|
'options' => $index->getOptions(), |
327
|
1 |
|
'flags' => $index->getFlags(), |
328
|
1 |
|
]); |
329
|
1 |
|
} |
330
|
|
|
|
331
|
1 |
|
$metadata->setTable($tableMetadata); |
332
|
|
|
} |
333
|
1 |
|
|
334
|
|
|
/** |
335
|
2 |
|
* Build field mapping from class metadata. |
336
|
|
|
* |
337
|
|
|
* @param Mapping\ClassMetadata $metadata |
338
|
|
|
*/ |
339
|
|
|
private function buildFieldMappings(Mapping\ClassMetadata $metadata) |
340
|
|
|
{ |
341
|
|
|
$tableName = $metadata->getTableName(); |
342
|
2 |
|
$columns = $this->tables[$tableName]->getColumns(); |
343
|
|
|
$primaryKeys = $this->getTablePrimaryKeys($this->tables[$tableName]); |
344
|
2 |
|
$foreignKeys = $this->getTableForeignKeys($this->tables[$tableName]); |
345
|
2 |
|
$allForeignKeys = []; |
346
|
2 |
|
|
347
|
2 |
|
foreach ($foreignKeys as $foreignKey) { |
348
|
2 |
|
$allForeignKeys = array_merge($allForeignKeys, $foreignKey->getLocalColumns()); |
349
|
|
|
} |
350
|
2 |
|
|
351
|
|
|
$ids = []; |
352
|
|
|
|
353
|
|
|
foreach ($columns as $column) { |
354
|
2 |
|
if (in_array($column->getName(), $allForeignKeys)) { |
355
|
|
|
continue; |
356
|
2 |
|
} |
357
|
2 |
|
|
358
|
|
|
$fieldName = $this->getFieldNameForColumn($tableName, $column->getName(), false); |
359
|
|
|
$fieldMetadata = $this->convertColumnAnnotationToFieldMetadata($tableName, $column, $fieldName); |
360
|
|
|
|
361
|
2 |
|
if ($primaryKeys && in_array($column->getName(), $primaryKeys)) { |
|
|
|
|
362
|
2 |
|
$fieldMetadata->setPrimaryKey(true); |
363
|
|
|
|
364
|
2 |
|
$ids[] = $fieldMetadata; |
365
|
2 |
|
} |
366
|
|
|
|
367
|
2 |
|
$metadata->addProperty($fieldMetadata); |
368
|
|
|
} |
369
|
|
|
|
370
|
2 |
|
// We need to check for the columns here, because we might have associations as id as well. |
371
|
|
|
if ($ids && count($primaryKeys) === 1) { |
|
|
|
|
372
|
|
|
$ids[0]->setValueGenerator(new Mapping\ValueGeneratorMetadata(Mapping\GeneratorType::AUTO)); |
373
|
|
|
} |
374
|
2 |
|
} |
375
|
2 |
|
|
376
|
|
|
/** |
377
|
2 |
|
* Parse the given Column as FieldMetadata |
378
|
|
|
* |
379
|
|
|
* @param string $tableName |
380
|
|
|
* @param Column $column |
381
|
|
|
* @param string $fieldName |
382
|
|
|
* |
383
|
|
|
* @return Mapping\FieldMetadata |
384
|
|
|
*/ |
385
|
|
|
private function convertColumnAnnotationToFieldMetadata(string $tableName, Column $column, string $fieldName) |
386
|
|
|
{ |
387
|
2 |
|
$options = []; |
388
|
|
|
$fieldMetadata = new Mapping\FieldMetadata($fieldName); |
389
|
|
|
|
390
|
2 |
|
$fieldMetadata->setType($column->getType()); |
391
|
2 |
|
$fieldMetadata->setTableName($tableName); |
392
|
|
|
$fieldMetadata->setColumnName($column->getName()); |
393
|
|
|
|
394
|
|
|
// Type specific elements |
395
|
2 |
|
switch ($column->getType()->getName()) { |
396
|
2 |
|
case Type::TARRAY: |
397
|
2 |
|
case Type::BLOB: |
398
|
2 |
|
case Type::GUID: |
399
|
2 |
|
case Type::JSON_ARRAY: |
400
|
2 |
|
case Type::OBJECT: |
401
|
2 |
|
case Type::SIMPLE_ARRAY: |
402
|
2 |
|
case Type::STRING: |
403
|
2 |
|
case Type::TEXT: |
404
|
1 |
|
if ($column->getLength()) { |
|
|
|
|
405
|
1 |
|
$fieldMetadata->setLength($column->getLength()); |
406
|
1 |
|
} |
407
|
|
|
|
408
|
2 |
|
$options['fixed'] = $column->getFixed(); |
409
|
2 |
|
break; |
410
|
|
|
|
411
|
|
|
case Type::DECIMAL: |
412
|
|
|
case Type::FLOAT: |
413
|
|
|
$fieldMetadata->setScale($column->getScale()); |
414
|
2 |
|
$fieldMetadata->setPrecision($column->getPrecision()); |
415
|
|
|
break; |
416
|
|
|
|
417
|
2 |
|
case Type::INTEGER: |
418
|
2 |
|
case Type::BIGINT: |
419
|
|
|
case Type::SMALLINT: |
420
|
|
|
$options['unsigned'] = $column->getUnsigned(); |
421
|
|
|
break; |
422
|
2 |
|
} |
423
|
|
|
|
424
|
|
|
// Comment |
425
|
|
|
if (($comment = $column->getComment()) !== null) { |
426
|
|
|
$options['comment'] = $comment; |
427
|
2 |
|
} |
428
|
|
|
|
429
|
|
|
// Default |
430
|
|
|
if (($default = $column->getDefault()) !== null) { |
431
|
2 |
|
$options['default'] = $default; |
432
|
|
|
} |
433
|
|
|
|
434
|
|
|
$fieldMetadata->setOptions($options); |
435
|
|
|
|
436
|
|
|
return $fieldMetadata; |
437
|
|
|
} |
438
|
|
|
|
439
|
2 |
|
/** |
440
|
|
|
* Build to one (one to one, many to one) association mapping from class metadata. |
441
|
2 |
|
* |
442
|
2 |
|
* @param Mapping\ClassMetadata $metadata |
443
|
2 |
|
*/ |
444
|
|
|
private function buildToOneAssociationMappings(Mapping\ClassMetadata $metadata) |
445
|
2 |
|
{ |
446
|
|
|
$tableName = $metadata->getTableName(); |
447
|
|
|
$primaryKeys = $this->getTablePrimaryKeys($this->tables[$tableName]); |
448
|
|
|
$foreignKeys = $this->getTableForeignKeys($this->tables[$tableName]); |
449
|
|
|
|
450
|
|
|
foreach ($foreignKeys as $foreignKey) { |
451
|
|
|
$foreignTableName = $foreignKey->getForeignTableName(); |
452
|
|
|
$fkColumns = $foreignKey->getColumns(); |
453
|
|
|
$fkForeignColumns = $foreignKey->getForeignColumns(); |
454
|
|
|
$localColumn = current($fkColumns); |
455
|
|
|
$associationMapping = [ |
456
|
|
|
'fieldName' => $this->getFieldNameForColumn($tableName, $localColumn, true), |
457
|
|
|
'targetEntity' => $this->getClassNameForTable($foreignTableName), |
458
|
|
|
]; |
459
|
|
|
|
460
|
|
|
if ($metadata->getProperty($associationMapping['fieldName'])) { |
461
|
|
|
$associationMapping['fieldName'] .= '2'; // "foo" => "foo2" |
|
|
|
|
462
|
|
|
} |
463
|
|
|
|
464
|
|
|
if ($primaryKeys && in_array($localColumn, $primaryKeys)) { |
|
|
|
|
465
|
|
|
$associationMapping['id'] = true; |
466
|
|
|
} |
467
|
|
|
|
468
|
|
View Code Duplication |
for ($i = 0, $l = count($fkColumns); $i < $l; $i++) { |
|
|
|
|
469
|
|
|
$joinColumn = new Mapping\JoinColumnMetadata(); |
470
|
|
|
|
471
|
|
|
$joinColumn->setColumnName($fkColumns[$i]); |
472
|
|
|
$joinColumn->setReferencedColumnName($fkForeignColumns[$i]); |
473
|
|
|
|
474
|
|
|
$associationMapping['joinColumns'][] = $joinColumn; |
475
|
|
|
} |
476
|
|
|
|
477
|
2 |
|
// Here we need to check if $fkColumns are the same as $primaryKeys |
478
|
|
|
if ( ! array_diff($fkColumns, $primaryKeys)) { |
479
|
|
|
$metadata->addProperty($associationMapping); |
|
|
|
|
480
|
|
|
} else { |
481
|
|
|
$metadata->addProperty($associationMapping); |
|
|
|
|
482
|
|
|
} |
483
|
|
|
} |
484
|
|
|
} |
485
|
|
|
|
486
|
2 |
|
/** |
487
|
|
|
* Retrieve schema table definition foreign keys. |
488
|
2 |
|
* |
489
|
|
|
* @param \Doctrine\DBAL\Schema\Table $table |
490
|
2 |
|
* |
491
|
|
|
* @return array |
492
|
|
|
*/ |
493
|
|
|
private function getTableForeignKeys(Table $table) |
494
|
|
|
{ |
495
|
|
|
return ($this->sm->getDatabasePlatform()->supportsForeignKeyConstraints()) |
496
|
|
|
? $table->getForeignKeys() |
497
|
|
|
: []; |
498
|
|
|
} |
499
|
|
|
|
500
|
2 |
|
/** |
501
|
|
|
* Retrieve schema table definition primary keys. |
502
|
|
|
* |
503
|
2 |
|
* @param \Doctrine\DBAL\Schema\Table $table |
504
|
|
|
* |
505
|
|
|
* @return array |
506
|
|
|
*/ |
507
|
|
|
private function getTablePrimaryKeys(Table $table) |
508
|
|
|
{ |
509
|
|
|
try { |
510
|
|
|
return $table->getPrimaryKey()->getColumns(); |
511
|
|
|
} catch (SchemaException $e) { |
512
|
|
|
// Do nothing |
513
|
|
|
} |
514
|
|
|
|
515
|
|
|
return []; |
516
|
|
|
} |
517
|
|
|
|
518
|
2 |
|
/** |
519
|
|
|
* Returns the mapped class name for a table if it exists. Otherwise return "classified" version. |
520
|
2 |
|
* |
521
|
|
|
* @param string $tableName |
522
|
|
|
* |
523
|
|
|
* @return string |
524
|
2 |
|
*/ |
525
|
|
|
private function getClassNameForTable($tableName) |
526
|
|
|
{ |
527
|
|
|
if (isset($this->classNamesForTables[$tableName])) { |
528
|
|
|
return $this->namespace . $this->classNamesForTables[$tableName]; |
529
|
|
|
} |
530
|
|
|
|
531
|
|
|
return $this->namespace . Inflector::classify(strtolower($tableName)); |
532
|
|
|
} |
533
|
|
|
|
534
|
|
|
/** |
535
|
|
|
* Return the mapped field name for a column, if it exists. Otherwise return camelized version. |
536
|
2 |
|
* |
537
|
|
|
* @param string $tableName |
538
|
2 |
|
* @param string $columnName |
539
|
|
|
* @param boolean $fk Whether the column is a foreignkey or not. |
540
|
|
|
* |
541
|
|
|
* @return string |
542
|
2 |
|
*/ |
543
|
|
|
private function getFieldNameForColumn($tableName, $columnName, $fk = false) |
544
|
|
|
{ |
545
|
2 |
|
if (isset($this->fieldNamesForColumns[$tableName]) && isset($this->fieldNamesForColumns[$tableName][$columnName])) { |
546
|
|
|
return $this->fieldNamesForColumns[$tableName][$columnName]; |
547
|
|
|
} |
548
|
|
|
|
549
|
2 |
|
$columnName = strtolower($columnName); |
550
|
|
|
|
551
|
|
|
// Replace _id if it is a foreignkey column |
552
|
|
|
if ($fk) { |
553
|
|
|
$columnName = str_replace('_id', '', $columnName); |
554
|
|
|
} |
555
|
|
|
|
556
|
|
|
return Inflector::camelize($columnName); |
557
|
|
|
} |
558
|
|
|
} |
559
|
|
|
|
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.