Completed
Push — master ( fc3773...aef6e2 )
by David
13s
created

getDefaultSortColumnFromAnnotation()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 18
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 12
nc 4
nop 1
1
<?php
2
declare(strict_types=1);
3
4
namespace TheCodingMachine\TDBM\Utils;
5
6
use Doctrine\Common\Inflector\Inflector;
7
use Doctrine\DBAL\Schema\Schema;
8
use Doctrine\DBAL\Schema\Table;
9
use Doctrine\DBAL\Types\Type;
10
use TheCodingMachine\TDBM\ConfigurationInterface;
11
use TheCodingMachine\TDBM\TDBMException;
12
use TheCodingMachine\TDBM\TDBMSchemaAnalyzer;
13
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
14
use Symfony\Component\Filesystem\Filesystem;
15
16
/**
17
 * This class generates automatically DAOs and Beans for TDBM.
18
 */
19
class TDBMDaoGenerator
20
{
21
    /**
22
     * @var Schema
23
     */
24
    private $schema;
25
26
    /**
27
     * Name of composer file.
28
     *
29
     * @var string
30
     */
31
    private $composerFile;
0 ignored issues
show
introduced by
The private property $composerFile is not used, and could be removed.
Loading history...
32
33
    /**
34
     * @var TDBMSchemaAnalyzer
35
     */
36
    private $tdbmSchemaAnalyzer;
37
38
    /**
39
     * @var GeneratorListenerInterface
40
     */
41
    private $eventDispatcher;
42
43
    /**
44
     * @var NamingStrategyInterface
45
     */
46
    private $namingStrategy;
47
    /**
48
     * @var ConfigurationInterface
49
     */
50
    private $configuration;
51
52
    /**
53
     * Constructor.
54
     *
55
     * @param ConfigurationInterface $configuration
56
     * @param TDBMSchemaAnalyzer $tdbmSchemaAnalyzer
57
     */
58
    public function __construct(ConfigurationInterface $configuration, TDBMSchemaAnalyzer $tdbmSchemaAnalyzer)
59
    {
60
        $this->configuration = $configuration;
61
        $this->schema = $tdbmSchemaAnalyzer->getSchema();
62
        $this->tdbmSchemaAnalyzer = $tdbmSchemaAnalyzer;
63
        $this->namingStrategy = $configuration->getNamingStrategy();
64
        $this->eventDispatcher = $configuration->getGeneratorEventDispatcher();
65
    }
66
67
    /**
68
     * Generates all the daos and beans.
69
     *
70
     * @throws TDBMException
71
     */
72
    public function generateAllDaosAndBeans(): void
73
    {
74
        // TODO: check that no class name ends with "Base". Otherwise, there will be name clash.
75
76
        $tableList = $this->schema->getTables();
77
78
        // Remove all beans and daos from junction tables
79
        $junctionTables = $this->configuration->getSchemaAnalyzer()->detectJunctionTables(true);
80
        $junctionTableNames = array_map(function (Table $table) {
81
            return $table->getName();
82
        }, $junctionTables);
83
84
        $tableList = array_filter($tableList, function (Table $table) use ($junctionTableNames) {
85
            return !in_array($table->getName(), $junctionTableNames);
86
        });
87
88
        $beanDescriptors = [];
89
90
        foreach ($tableList as $table) {
91
            $beanDescriptors[] = $this->generateDaoAndBean($table);
92
        }
93
94
95
        $this->generateFactory($tableList);
96
97
        // Let's call the list of listeners
98
        $this->eventDispatcher->onGenerate($this->configuration, $beanDescriptors);
99
    }
100
101
    /**
102
     * Generates in one method call the daos and the beans for one table.
103
     *
104
     * @param Table $table
105
     *
106
     * @return BeanDescriptor
107
     * @throws TDBMException
108
     */
109
    private function generateDaoAndBean(Table $table) : BeanDescriptor
110
    {
111
        $tableName = $table->getName();
112
        $daoName = $this->namingStrategy->getDaoClassName($tableName);
113
        $beanName = $this->namingStrategy->getBeanClassName($tableName);
114
        $baseBeanName = $this->namingStrategy->getBaseBeanClassName($tableName);
115
        $baseDaoName = $this->namingStrategy->getBaseDaoClassName($tableName);
116
117
        $beanDescriptor = new BeanDescriptor($table, $this->configuration->getBeanNamespace(), $this->configuration->getBeanNamespace().'\\Generated', $this->configuration->getSchemaAnalyzer(), $this->schema, $this->tdbmSchemaAnalyzer, $this->namingStrategy);
118
        $this->generateBean($beanDescriptor, $beanName, $baseBeanName, $table);
119
        $this->generateDao($beanDescriptor, $daoName, $baseDaoName, $beanName, $table);
120
        return $beanDescriptor;
121
    }
122
123
    /**
124
     * Writes the PHP bean file with all getters and setters from the table passed in parameter.
125
     *
126
     * @param BeanDescriptor  $beanDescriptor
127
     * @param string          $className       The name of the class
128
     * @param string          $baseClassName   The name of the base class which will be extended (name only, no directory)
129
     * @param Table           $table           The table
130
     *
131
     * @throws TDBMException
132
     */
133
    public function generateBean(BeanDescriptor $beanDescriptor, $className, $baseClassName, Table $table)
134
    {
135
        $beannamespace = $this->configuration->getBeanNamespace();
136
        $str = $beanDescriptor->generatePhpCode();
137
138
        $possibleBaseFileName = $this->configuration->getPathFinder()->getPath($beannamespace.'\\Generated\\'.$baseClassName)->getPathname();
139
140
        $this->dumpFile($possibleBaseFileName, $str);
141
142
        $possibleFileName = $this->configuration->getPathFinder()->getPath($beannamespace.'\\'.$className)->getPathname();
143
144
        if (!file_exists($possibleFileName)) {
145
            $tableName = $table->getName();
146
            $str = "<?php
147
/*
148
 * This file has been automatically generated by TDBM.
149
 * You can edit this file as it will not be overwritten.
150
 */
151
152
declare(strict_types=1);
153
154
namespace {$beannamespace};
155
156
use {$beannamespace}\\Generated\\{$baseClassName};
157
158
/**
159
 * The $className class maps the '$tableName' table in database.
160
 */
161
class $className extends $baseClassName
162
{
163
}
164
";
165
166
            $this->dumpFile($possibleFileName, $str);
167
        }
168
    }
169
170
    /**
171
     * Tries to find a @defaultSort annotation in one of the columns.
172
     *
173
     * @param Table $table
174
     *
175
     * @return array First item: column name, Second item: column order (asc/desc)
176
     */
177
    private function getDefaultSortColumnFromAnnotation(Table $table)
178
    {
179
        $defaultSort = null;
180
        $defaultSortDirection = null;
181
        foreach ($table->getColumns() as $column) {
182
            $comments = $column->getComment();
183
            $matches = [];
184
            if ($comments !== null && preg_match('/@defaultSort(\((desc|asc)\))*/', $comments, $matches) != 0) {
185
                $defaultSort = $column->getName();
186
                if (count($matches) === 3) {
187
                    $defaultSortDirection = $matches[2];
188
                } else {
189
                    $defaultSortDirection = 'ASC';
190
                }
191
            }
192
        }
193
194
        return [$defaultSort, $defaultSortDirection];
195
    }
196
197
    /**
198
     * Writes the PHP bean DAO with simple functions to create/get/save objects.
199
     *
200
     * @param BeanDescriptor  $beanDescriptor
201
     * @param string          $className       The name of the class
202
     * @param string          $baseClassName
203
     * @param string          $beanClassName
204
     * @param Table           $table
205
     *
206
     * @throws TDBMException
207
     */
208
    private function generateDao(BeanDescriptor $beanDescriptor, string $className, string $baseClassName, string $beanClassName, Table $table)
209
    {
210
        $daonamespace = $this->configuration->getDaoNamespace();
211
        $beannamespace = $this->configuration->getBeanNamespace();
212
        $tableName = $table->getName();
213
        $primaryKeyColumns = self::getPrimaryKeyColumnsOrFail($table);
214
215
        list($defaultSort, $defaultSortDirection) = $this->getDefaultSortColumnFromAnnotation($table);
216
217
        $beanClassWithoutNameSpace = $beanClassName;
218
        $beanClassName = $beannamespace.'\\'.$beanClassName;
219
220
        list($usedBeans, $findByDaoCode) = $beanDescriptor->generateFindByDaoCode($beannamespace, $beanClassWithoutNameSpace);
221
222
        $usedBeans[] = $beanClassName;
223
        // Let's suppress duplicates in used beans (if any)
224
        $usedBeans = array_flip(array_flip($usedBeans));
225
        $useStatements = array_map(function ($usedBean) {
226
            return "use $usedBean;\n";
227
        }, $usedBeans);
228
229
        $str = "<?php
230
/*
231
 * This file has been automatically generated by TDBM.
232
 * DO NOT edit this file, as it might be overwritten.
233
 * If you need to perform changes, edit the $className class instead!
234
 */
235
236
declare(strict_types=1);
237
238
namespace {$daonamespace}\\Generated;
239
240
use TheCodingMachine\\TDBM\\TDBMService;
241
use TheCodingMachine\\TDBM\\ResultIterator;
242
".implode('', $useStatements)."
243
/**
244
 * The $baseClassName class will maintain the persistence of $beanClassWithoutNameSpace class into the $tableName table.
245
 *
246
 */
247
class $baseClassName
248
{
249
250
    /**
251
     * @var TDBMService
252
     */
253
    protected \$tdbmService;
254
255
    /**
256
     * The default sort column.
257
     *
258
     * @var string
259
     */
260
    private \$defaultSort = ".($defaultSort ? "'$defaultSort'" : 'null').';
261
262
    /**
263
     * The default sort direction.
264
     *
265
     * @var string
266
     */
267
    private $defaultDirection = '.($defaultSort && $defaultSortDirection ? "'$defaultSortDirection'" : "'asc'").";
268
269
    /**
270
     * Sets the TDBM service used by this DAO.
271
     *
272
     * @param TDBMService \$tdbmService
273
     */
274
    public function __construct(TDBMService \$tdbmService)
275
    {
276
        \$this->tdbmService = \$tdbmService;
277
    }
278
279
    /**
280
     * Persist the $beanClassWithoutNameSpace instance.
281
     *
282
     * @param $beanClassWithoutNameSpace \$obj The bean to save.
283
     */
284
    public function save($beanClassWithoutNameSpace \$obj)
285
    {
286
        \$this->tdbmService->save(\$obj);
287
    }
288
289
    /**
290
     * Get all $beanClassWithoutNameSpace records.
291
     *
292
     * @return {$beanClassWithoutNameSpace}[]|ResultIterator
293
     */
294
    public function findAll() : iterable
295
    {
296
        if (\$this->defaultSort) {
297
            \$orderBy = '$tableName.'.\$this->defaultSort.' '.\$this->defaultDirection;
298
        } else {
299
            \$orderBy = null;
300
        }
301
        return \$this->tdbmService->findObjects('$tableName', null, [], \$orderBy);
302
    }
303
    ";
304
305
        if (count($primaryKeyColumns) === 1) {
306
            $primaryKeyColumn = $primaryKeyColumns[0];
307
            $primaryKeyPhpType = self::dbalTypeToPhpType($table->getColumn($primaryKeyColumn)->getType());
308
            $str .= "
309
    /**
310
     * Get $beanClassWithoutNameSpace specified by its ID (its primary key)
311
     * If the primary key does not exist, an exception is thrown.
312
     *
313
     * @param $primaryKeyPhpType \$id
314
     * @param bool \$lazyLoading If set to true, the object will not be loaded right away. Instead, it will be loaded when you first try to access a method of the object.
315
     * @return $beanClassWithoutNameSpace
316
     * @throws TDBMException
317
     */
318
    public function getById($primaryKeyPhpType \$id, \$lazyLoading = false) : $beanClassWithoutNameSpace
319
    {
320
        return \$this->tdbmService->findObjectByPk('$tableName', ['$primaryKeyColumn' => \$id], [], \$lazyLoading);
321
    }
322
    ";
323
        }
324
        $str .= "
325
    /**
326
     * Deletes the $beanClassWithoutNameSpace passed in parameter.
327
     *
328
     * @param $beanClassWithoutNameSpace \$obj object to delete
329
     * @param bool \$cascade if true, it will delete all object linked to \$obj
330
     */
331
    public function delete($beanClassWithoutNameSpace \$obj, \$cascade = false) : void
332
    {
333
        if (\$cascade === true) {
334
            \$this->tdbmService->deleteCascade(\$obj);
335
        } else {
336
            \$this->tdbmService->delete(\$obj);
337
        }
338
    }
339
340
341
    /**
342
     * Get a list of $beanClassWithoutNameSpace specified by its filters.
343
     *
344
     * @param mixed \$filter The filter bag (see TDBMService::findObjects for complete description)
345
     * @param array \$parameters The parameters associated with the filter
346
     * @param mixed \$orderBy The order string
347
     * @param array \$additionalTablesFetch A list of additional tables to fetch (for performance improvement)
348
     * @param int \$mode Either TDBMService::MODE_ARRAY or TDBMService::MODE_CURSOR (for large datasets). Defaults to TDBMService::MODE_ARRAY.
349
     * @return {$beanClassWithoutNameSpace}[]|ResultIterator
350
     */
351
    protected function find(\$filter = null, array \$parameters = [], \$orderBy=null, array \$additionalTablesFetch = [], \$mode = null) : iterable
352
    {
353
        if (\$this->defaultSort && \$orderBy == null) {
354
            \$orderBy = '$tableName.'.\$this->defaultSort.' '.\$this->defaultDirection;
355
        }
356
        return \$this->tdbmService->findObjects('$tableName', \$filter, \$parameters, \$orderBy, \$additionalTablesFetch, \$mode);
357
    }
358
359
    /**
360
     * Get a list of $beanClassWithoutNameSpace specified by its filters.
361
     * Unlike the `find` method that guesses the FROM part of the statement, here you can pass the \$from part.
362
     *
363
     * You should not put an alias on the main table name. So your \$from variable should look like:
364
     *
365
     *   \"$tableName JOIN ... ON ...\"
366
     *
367
     * @param string \$from The sql from statement
368
     * @param mixed \$filter The filter bag (see TDBMService::findObjects for complete description)
369
     * @param array \$parameters The parameters associated with the filter
370
     * @param mixed \$orderBy The order string
371
     * @param int \$mode Either TDBMService::MODE_ARRAY or TDBMService::MODE_CURSOR (for large datasets). Defaults to TDBMService::MODE_ARRAY.
372
     * @return {$beanClassWithoutNameSpace}[]|ResultIterator
373
     */
374
    protected function findFromSql(\$from, \$filter = null, array \$parameters = [], \$orderBy = null, \$mode = null) : iterable
375
    {
376
        if (\$this->defaultSort && \$orderBy == null) {
377
            \$orderBy = '$tableName.'.\$this->defaultSort.' '.\$this->defaultDirection;
378
        }
379
        return \$this->tdbmService->findObjectsFromSql('$tableName', \$from, \$filter, \$parameters, \$orderBy, \$mode);
380
    }
381
382
    /**
383
     * Get a list of $beanClassWithoutNameSpace from a SQL query.
384
     * Unlike the `find` and `findFromSql` methods, here you can pass the whole \$sql query.
385
     *
386
     * You should not put an alias on the main table name, and select its columns using `*`. So the SELECT part of you \$sql should look like:
387
     *
388
     *   \"SELECT $tableName.* FROM ...\"
389
     *
390
     * @param string \$sql The sql query
391
     * @param array \$parameters The parameters associated with the filter
392
     * @param string \$countSql The count sql query (automatically computed if not provided)
393
     * @param int \$mode Either TDBMService::MODE_ARRAY or TDBMService::MODE_CURSOR (for large datasets). Defaults to TDBMService::MODE_ARRAY.
394
     * @return {$beanClassWithoutNameSpace}[]|ResultIterator
395
     */
396
    protected function findFromRawSql(\$sql, array \$parameters = [], \$countSql = null, \$mode = null) : iterable
397
    {
398
        return \$this->tdbmService->findObjectsFromRawSql('$tableName', \$sql, \$parameters, \$mode, null, \$countSql);
399
    }
400
401
    /**
402
     * Get a single $beanClassWithoutNameSpace specified by its filters.
403
     *
404
     * @param mixed \$filter The filter bag (see TDBMService::findObjects for complete description)
405
     * @param array \$parameters The parameters associated with the filter
406
     * @param array \$additionalTablesFetch A list of additional tables to fetch (for performance improvement)
407
     * @return $beanClassWithoutNameSpace|null
408
     */
409
    protected function findOne(\$filter = null, array \$parameters = [], array \$additionalTablesFetch = []) : ?$beanClassWithoutNameSpace
410
    {
411
        return \$this->tdbmService->findObject('$tableName', \$filter, \$parameters, \$additionalTablesFetch);
412
    }
413
414
    /**
415
     * Get a single $beanClassWithoutNameSpace specified by its filters.
416
     * Unlike the `find` method that guesses the FROM part of the statement, here you can pass the \$from part.
417
     *
418
     * You should not put an alias on the main table name. So your \$from variable should look like:
419
     *
420
     *   \"$tableName JOIN ... ON ...\"
421
     *
422
     * @param string \$from The sql from statement
423
     * @param mixed \$filter The filter bag (see TDBMService::findObjects for complete description)
424
     * @param array \$parameters The parameters associated with the filter
425
     * @return $beanClassWithoutNameSpace|null
426
     */
427
    protected function findOneFromSql(\$from, \$filter = null, array \$parameters = []) : ?$beanClassWithoutNameSpace
428
    {
429
        return \$this->tdbmService->findObjectFromSql('$tableName', \$from, \$filter, \$parameters);
430
    }
431
432
    /**
433
     * Sets the default column for default sorting.
434
     *
435
     * @param string \$defaultSort
436
     */
437
    public function setDefaultSort(string \$defaultSort) : void
438
    {
439
        \$this->defaultSort = \$defaultSort;
440
    }
441
";
442
443
        $str .= $findByDaoCode;
444
        $str .= '}
445
';
446
447
        $possibleBaseFileName = $this->configuration->getPathFinder()->getPath($daonamespace.'\\Generated\\'.$baseClassName)->getPathname();
448
449
        $this->dumpFile($possibleBaseFileName, $str);
450
451
        $possibleFileName = $this->configuration->getPathFinder()->getPath($daonamespace.'\\'.$className)->getPathname();
452
453
        // Now, let's generate the "editable" class
454
        if (!file_exists($possibleFileName)) {
455
            $str = "<?php
456
/*
457
 * This file has been automatically generated by TDBM.
458
 * You can edit this file as it will not be overwritten.
459
 */
460
461
declare(strict_types=1);
462
463
namespace {$daonamespace};
464
465
use {$daonamespace}\\Generated\\{$baseClassName};
466
467
/**
468
 * The $className class will maintain the persistence of $beanClassWithoutNameSpace class into the $tableName table.
469
 */
470
class $className extends $baseClassName
471
{
472
}
473
";
474
            $this->dumpFile($possibleFileName, $str);
475
        }
476
    }
477
478
    /**
479
     * Generates the factory bean.
480
     *
481
     * @param Table[] $tableList
482
     * @throws TDBMException
483
     */
484
    private function generateFactory(array $tableList) : void
485
    {
486
        $daoNamespace = $this->configuration->getDaoNamespace();
487
        $daoFactoryClassName = $this->namingStrategy->getDaoFactoryClassName();
488
489
        // For each table, let's write a property.
490
491
        $str = "<?php
492
declare(strict_types=1);
493
494
/*
495
 * This file has been automatically generated by TDBM.
496
 * DO NOT edit this file, as it might be overwritten.
497
 */
498
499
namespace {$daoNamespace}\\Generated;
500
501
";
502
        foreach ($tableList as $table) {
503
            $tableName = $table->getName();
504
            $daoClassName = $this->namingStrategy->getDaoClassName($tableName);
505
            $str .= "use {$daoNamespace}\\".$daoClassName.";\n";
506
        }
507
508
        $str .= "
509
/**
510
 * The $daoFactoryClassName provides an easy access to all DAOs generated by TDBM.
511
 *
512
 */
513
class $daoFactoryClassName
514
{
515
";
516
517
        foreach ($tableList as $table) {
518
            $tableName = $table->getName();
519
            $daoClassName = $this->namingStrategy->getDaoClassName($tableName);
520
            $daoInstanceName = self::toVariableName($daoClassName);
521
522
            $str .= '    /**
523
     * @var '.$daoClassName.'
524
     */
525
    private $'.$daoInstanceName.';
526
527
    /**
528
     * Returns an instance of the '.$daoClassName.' class.
529
     *
530
     * @return '.$daoClassName.'
531
     */
532
    public function get'.$daoClassName.'() : '.$daoClassName.'
533
    {
534
        return $this->'.$daoInstanceName.';
535
    }
536
537
    /**
538
     * Sets the instance of the '.$daoClassName.' class that will be returned by the factory getter.
539
     *
540
     * @param '.$daoClassName.' $'.$daoInstanceName.'
541
     */
542
    public function set'.$daoClassName.'('.$daoClassName.' $'.$daoInstanceName.') : void
543
    {
544
        $this->'.$daoInstanceName.' = $'.$daoInstanceName.';
545
    }';
546
        }
547
548
        $str .= '
549
}
550
';
551
552
        $possibleFileName = $this->configuration->getPathFinder()->getPath($daoNamespace.'\\Generated\\'.$daoFactoryClassName)->getPathname();
553
554
        $this->dumpFile($possibleFileName, $str);
555
    }
556
557
    /**
558
     * Transforms a string to camelCase (except the first letter will be uppercase too).
559
     * Underscores and spaces are removed and the first letter after the underscore is uppercased.
560
     * Quoting is removed if present.
561
     *
562
     * @param string $str
563
     *
564
     * @return string
565
     */
566
    public static function toCamelCase($str) : string
567
    {
568
        $str = str_replace(array('`', '"', '[', ']'), '', $str);
569
570
        $str = strtoupper(substr($str, 0, 1)).substr($str, 1);
571
        while (true) {
572
            if (strpos($str, '_') === false && strpos($str, ' ') === false) {
573
                break;
574
            }
575
576
            $pos = strpos($str, '_');
577
            if ($pos === false) {
578
                $pos = strpos($str, ' ');
579
            }
580
            $before = substr($str, 0, $pos);
581
            $after = substr($str, $pos + 1);
582
            $str = $before.strtoupper(substr($after, 0, 1)).substr($after, 1);
583
        }
584
585
        return $str;
586
    }
587
588
    /**
589
     * Tries to put string to the singular form (if it is plural).
590
     * We assume the table names are in english.
591
     *
592
     * @param string $str
593
     *
594
     * @return string
595
     */
596
    public static function toSingular($str)
597
    {
598
        return Inflector::singularize($str);
599
    }
600
601
    /**
602
     * Put the first letter of the string in lower case.
603
     * Very useful to transform a class name into a variable name.
604
     *
605
     * @param string $str
606
     *
607
     * @return string
608
     */
609
    public static function toVariableName($str)
610
    {
611
        return strtolower(substr($str, 0, 1)).substr($str, 1);
612
    }
613
614
    /**
615
     * Ensures the file passed in parameter can be written in its directory.
616
     *
617
     * @param string $fileName
618
     *
619
     * @throws TDBMException
620
     */
621
    private function ensureDirectoryExist(string $fileName)
622
    {
623
        $dirName = dirname($fileName);
624
        if (!file_exists($dirName)) {
625
            $old = umask(0);
626
            $result = mkdir($dirName, 0775, true);
627
            umask($old);
628
            if ($result === false) {
629
                throw new TDBMException("Unable to create directory: '".$dirName."'.");
630
            }
631
        }
632
    }
633
634
    private function dumpFile(string $fileName, string $content) : void
635
    {
636
        $this->ensureDirectoryExist($fileName);
637
        $fileSystem = new Filesystem();
638
        $fileSystem->dumpFile($fileName, $content);
639
        @chmod($fileName, 0664);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chmod(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

639
        /** @scrutinizer ignore-unhandled */ @chmod($fileName, 0664);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
640
    }
641
642
    /**
643
     * Transforms a DBAL type into a PHP type (for PHPDoc purpose).
644
     *
645
     * @param Type $type The DBAL type
646
     *
647
     * @return string The PHP type
648
     */
649
    public static function dbalTypeToPhpType(Type $type) : string
650
    {
651
        $map = [
652
            Type::TARRAY => 'array',
653
            Type::SIMPLE_ARRAY => 'array',
654
            'json' => 'array',  // 'json' is supported from Doctrine DBAL 2.6 only.
655
            Type::JSON_ARRAY => 'array',
656
            Type::BIGINT => 'string',
657
            Type::BOOLEAN => 'bool',
658
            Type::DATETIME_IMMUTABLE => '\DateTimeImmutable',
659
            Type::DATETIMETZ_IMMUTABLE => '\DateTimeImmutable',
660
            Type::DATE_IMMUTABLE => '\DateTimeImmutable',
661
            Type::TIME_IMMUTABLE => '\DateTimeImmutable',
662
            Type::DECIMAL => 'float',
663
            Type::INTEGER => 'int',
664
            Type::OBJECT => 'string',
665
            Type::SMALLINT => 'int',
666
            Type::STRING => 'string',
667
            Type::TEXT => 'string',
668
            Type::BINARY => 'resource',
669
            Type::BLOB => 'resource',
670
            Type::FLOAT => 'float',
671
            Type::GUID => 'string',
672
        ];
673
674
        return isset($map[$type->getName()]) ? $map[$type->getName()] : $type->getName();
675
    }
676
677
    /**
678
     * @param Table $table
679
     * @return string[]
680
     * @throws TDBMException
681
     */
682
    public static function getPrimaryKeyColumnsOrFail(Table $table): array {
683
        if ($table->getPrimaryKey() === null) {
684
            // Security check: a table MUST have a primary key
685
            throw new TDBMException(sprintf('Table "%s" does not have any primary key', $table->getName()));
686
        }
687
        return $table->getPrimaryKey()->getUnquotedColumns();
688
    }
689
}
690