Completed
Push — 4.0 ( b1b9bd...e1def4 )
by David
21:09
created

TDBMDaoGenerator::generateDao()   C

Complexity

Conditions 8
Paths 64

Size

Total Lines 214
Code Lines 59

Duplication

Lines 22
Ratio 10.28 %

Importance

Changes 21
Bugs 1 Features 3
Metric Value
c 21
b 1
f 3
dl 22
loc 214
rs 5.2676
cc 8
eloc 59
nc 64
nop 7

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Mouf\Database\TDBM\Utils;
4
5
use Doctrine\Common\Inflector\Inflector;
6
use Doctrine\DBAL\Schema\Column;
7
use Doctrine\DBAL\Schema\Schema;
8
use Doctrine\DBAL\Schema\Table;
9
use Doctrine\DBAL\Types\Type;
10
use Mouf\Composer\ClassNameMapper;
11
use Mouf\Database\SchemaAnalyzer\SchemaAnalyzer;
12
use Mouf\Database\TDBM\TDBMException;
13
use Mouf\Database\TDBM\TDBMSchemaAnalyzer;
14
15
/**
16
 * This class generates automatically DAOs and Beans for TDBM.
17
 */
18
class TDBMDaoGenerator
19
{
20
    /**
21
     * @var SchemaAnalyzer
22
     */
23
    private $schemaAnalyzer;
24
25
    /**
26
     * @var Schema
27
     */
28
    private $schema;
29
30
    /**
31
     * The root directory of the project.
32
     *
33
     * @var string
34
     */
35
    private $rootPath;
36
37
    /**
38
     * @var TDBMSchemaAnalyzer
39
     */
40
    private $tdbmSchemaAnalyzer;
41
42
    /**
43
     * Constructor.
44
     *
45
     * @param SchemaAnalyzer     $schemaAnalyzer
46
     * @param Schema             $schema
47
     * @param TDBMSchemaAnalyzer $tdbmSchemaAnalyzer
48
     */
49 View Code Duplication
    public function __construct(SchemaAnalyzer $schemaAnalyzer, Schema $schema, TDBMSchemaAnalyzer $tdbmSchemaAnalyzer)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
50
    {
51
        $this->schemaAnalyzer = $schemaAnalyzer;
52
        $this->schema = $schema;
53
        $this->tdbmSchemaAnalyzer = $tdbmSchemaAnalyzer;
54
        $this->rootPath = __DIR__.'/../../../../../../../../';
55
    }
56
57
    /**
58
     * Generates all the daos and beans.
59
     *
60
     * @param string $daoFactoryClassName The classe name of the DAO factory
61
     * @param string $daonamespace        The namespace for the DAOs, without trailing \
62
     * @param string $beannamespace       The Namespace for the beans, without trailing \
63
     * @param bool   $storeInUtc          If the generated daos should store the date in UTC timezone instead of user's timezone.
64
     *
65
     * @return \string[] the list of tables
66
     *
67
     * @throws TDBMException
68
     */
69
    public function generateAllDaosAndBeans($daoFactoryClassName, $daonamespace, $beannamespace, $storeInUtc)
70
    {
71
        // TODO: extract ClassNameMapper in its own package!
72
        $classNameMapper = ClassNameMapper::createFromComposerFile($this->rootPath.'composer.json');
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->schemaAnalyzer->detectJunctionTables();
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
        foreach ($tableList as $table) {
89
            $this->generateDaoAndBean($table, $daonamespace, $beannamespace, $classNameMapper, $storeInUtc);
90
        }
91
92
        $this->generateFactory($tableList, $daoFactoryClassName, $daonamespace, $classNameMapper);
93
94
        // Ok, let's return the list of all tables.
95
        // These will be used by the calling script to create Mouf instances.
96
97
        return array_map(function (Table $table) { return $table->getName(); }, $tableList);
98
    }
99
100
    /**
101
     * Generates in one method call the daos and the beans for one table.
102
     *
103
     * @param Table           $table
104
     * @param string          $daonamespace
105
     * @param string          $beannamespace
106
     * @param ClassNameMapper $classNameMapper
107
     * @param bool            $storeInUtc
108
     *
109
     * @throws TDBMException
110
     */
111
    public function generateDaoAndBean(Table $table, $daonamespace, $beannamespace, ClassNameMapper $classNameMapper, $storeInUtc)
112
    {
113
        $tableName = $table->getName();
114
        $daoName = $this->getDaoNameFromTableName($tableName);
115
        $beanName = $this->getBeanNameFromTableName($tableName);
116
        $baseBeanName = $this->getBaseBeanNameFromTableName($tableName);
117
        $baseDaoName = $this->getBaseDaoNameFromTableName($tableName);
118
119
        $this->generateBean($beanName, $baseBeanName, $table, $beannamespace, $classNameMapper, $storeInUtc);
120
        $this->generateDao($daoName, $baseDaoName, $beanName, $table, $daonamespace, $beannamespace, $classNameMapper);
121
    }
122
123
    /**
124
     * Returns the name of the bean class from the table name.
125
     *
126
     * @param $tableName
127
     *
128
     * @return string
129
     */
130
    public static function getBeanNameFromTableName($tableName)
131
    {
132
        return self::toSingular(self::toCamelCase($tableName)).'Bean';
133
    }
134
135
    /**
136
     * Returns the name of the DAO class from the table name.
137
     *
138
     * @param $tableName
139
     *
140
     * @return string
141
     */
142
    public static function getDaoNameFromTableName($tableName)
143
    {
144
        return self::toSingular(self::toCamelCase($tableName)).'Dao';
145
    }
146
147
    /**
148
     * Returns the name of the base bean class from the table name.
149
     *
150
     * @param $tableName
151
     *
152
     * @return string
153
     */
154
    public static function getBaseBeanNameFromTableName($tableName)
155
    {
156
        return self::toSingular(self::toCamelCase($tableName)).'BaseBean';
157
    }
158
159
    /**
160
     * Returns the name of the base DAO class from the table name.
161
     *
162
     * @param $tableName
163
     *
164
     * @return string
165
     */
166
    public static function getBaseDaoNameFromTableName($tableName)
167
    {
168
        return self::toSingular(self::toCamelCase($tableName)).'BaseDao';
169
    }
170
171
    /**
172
     * Writes the PHP bean file with all getters and setters from the table passed in parameter.
173
     *
174
     * @param string          $className       The name of the class
175
     * @param string          $baseClassName   The name of the base class which will be extended (name only, no directory)
176
     * @param Table           $table           The table
177
     * @param string          $beannamespace   The namespace of the bean
178
     * @param ClassNameMapper $classNameMapper
179
     *
180
     * @throws TDBMException
181
     */
182
    public function generateBean($className, $baseClassName, Table $table, $beannamespace, ClassNameMapper $classNameMapper, $storeInUtc)
0 ignored issues
show
Unused Code introduced by
The parameter $storeInUtc is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
183
    {
184
        $beanDescriptor = new BeanDescriptor($table, $this->schemaAnalyzer, $this->schema, $this->tdbmSchemaAnalyzer);
185
186
        $str = $beanDescriptor->generatePhpCode($beannamespace);
187
188
        $possibleBaseFileNames = $classNameMapper->getPossibleFileNames($beannamespace.'\\'.$baseClassName);
189
        if (empty($possibleBaseFileNames)) {
190
            throw new TDBMException('Sorry, autoload namespace issue. The class "'.$beannamespace.'\\'.$baseClassName.'" is not autoloadable.');
191
        }
192
        $possibleBaseFileName = $this->rootPath.$possibleBaseFileNames[0];
193
194
        $this->ensureDirectoryExist($possibleBaseFileName);
195
        file_put_contents($possibleBaseFileName, $str);
196
        @chmod($possibleBaseFileName, 0664);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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...
197
198
        $possibleFileNames = $classNameMapper->getPossibleFileNames($beannamespace.'\\'.$className);
199
        if (empty($possibleFileNames)) {
200
            // @codeCoverageIgnoreStart
201
            throw new TDBMException('Sorry, autoload namespace issue. The class "'.$beannamespace.'\\'.$className.'" is not autoloadable.');
202
            // @codeCoverageIgnoreEnd
203
        }
204
        $possibleFileName = $this->rootPath.$possibleFileNames[0];
205
206 View Code Duplication
        if (!file_exists($possibleFileName)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
207
            $tableName = $table->getName();
208
209
            $str = "<?php
210
/*
211
 * This file has been automatically generated by TDBM.
212
 * You can edit this file as it will not be overwritten.
213
 */
214
215
namespace {$beannamespace};
216
217
/**
218
 * The $className class maps the '$tableName' table in database.
219
 */
220
class $className extends $baseClassName
221
{
222
223
}";
224
            $this->ensureDirectoryExist($possibleFileName);
225
            file_put_contents($possibleFileName, $str);
226
            @chmod($possibleFileName, 0664);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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...
227
        }
228
    }
229
230
    /**
231
     * Tries to find a @defaultSort annotation in one of the columns.
232
     *
233
     * @param Table $table
234
     *
235
     * @return array First item: column name, Second item: column order (asc/desc)
236
     */
237
    private function getDefaultSortColumnFromAnnotation(Table $table)
238
    {
239
        $defaultSort = null;
240
        $defaultSortDirection = null;
241
        foreach ($table->getColumns() as $column) {
242
            $comments = $column->getComment();
243
            $matches = array();
244
            if (preg_match('/@defaultSort(\((desc|asc)\))*/', $comments, $matches) != 0) {
245
                $defaultSort = $column->getName();
246
                if (count($matches) === 3) {
247
                    $defaultSortDirection = $matches[2];
248
                } else {
249
                    $defaultSortDirection = 'ASC';
250
                }
251
            }
252
        }
253
254
        return [$defaultSort, $defaultSortDirection];
255
    }
256
257
    /**
258
     * Writes the PHP bean DAO with simple functions to create/get/save objects.
259
     *
260
     * @param string          $className       The name of the class
261
     * @param string          $baseClassName
262
     * @param string          $beanClassName
263
     * @param Table           $table
264
     * @param string          $daonamespace
265
     * @param string          $beannamespace
266
     * @param ClassNameMapper $classNameMapper
267
     *
268
     * @throws TDBMException
269
     */
270
    public function generateDao($className, $baseClassName, $beanClassName, Table $table, $daonamespace, $beannamespace, ClassNameMapper $classNameMapper)
271
    {
272
        $tableName = $table->getName();
273
        $primaryKeyColumns = $table->getPrimaryKeyColumns();
274
275
        list($defaultSort, $defaultSortDirection) = $this->getDefaultSortColumnFromAnnotation($table);
276
277
        // FIXME: lowercase tables with _ in the name should work!
278
        $tableCamel = self::toSingular(self::toCamelCase($tableName));
279
280
        $beanClassWithoutNameSpace = $beanClassName;
281
        $beanClassName = $beannamespace.'\\'.$beanClassName;
282
283
        $str = "<?php
284
285
/*
286
 * This file has been automatically generated by TDBM.
287
 * DO NOT edit this file, as it might be overwritten.
288
 * If you need to perform changes, edit the $className class instead!
289
 */
290
291
namespace {$daonamespace};
292
293
use Mouf\\Database\\TDBM\\TDBMService;
294
use Mouf\\Database\\TDBM\\ResultIterator;
295
use Mouf\\Database\\TDBM\\ArrayIterator;
296
use $beanClassName;
297
298
/**
299
 * The $baseClassName class will maintain the persistence of $beanClassWithoutNameSpace class into the $tableName table.
300
 *
301
 */
302
class $baseClassName
303
{
304
305
    /**
306
     * @var TDBMService
307
     */
308
    protected \$tdbmService;
309
310
    /**
311
     * The default sort column.
312
     *
313
     * @var string
314
     */
315
    private \$defaultSort = ".($defaultSort ? "'$defaultSort'" : 'null').";
316
317
    /**
318
     * The default sort direction.
319
     *
320
     * @var string
321
     */
322
    private \$defaultDirection = ".($defaultSort && $defaultSortDirection ? "'$defaultSortDirection'" : "'asc'").";
0 ignored issues
show
Bug Best Practice introduced by
The expression $defaultSort of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
Bug Best Practice introduced by
The expression $defaultSortDirection of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
323
324
    /**
325
     * Sets the TDBM service used by this DAO.
326
     *
327
     * @param TDBMService \$tdbmService
328
     */
329
    public function __construct(TDBMService \$tdbmService)
330
    {
331
        \$this->tdbmService = \$tdbmService;
332
    }
333
334
    /**
335
     * Persist the $beanClassWithoutNameSpace instance.
336
     *
337
     * @param $beanClassWithoutNameSpace \$obj The bean to save.
338
     */
339
    public function save($beanClassWithoutNameSpace \$obj)
340
    {
341
        \$this->tdbmService->save(\$obj);
342
    }
343
344
    /**
345
     * Get all $tableCamel records.
346
     *
347
     * @return {$beanClassWithoutNameSpace}[]|ResultIterator|ResultArray
348
     */
349
    public function findAll()
350
    {
351
        if (\$this->defaultSort) {
352
            \$orderBy = '$tableName.'.\$this->defaultSort.' '.\$this->defaultDirection;
353
        } else {
354
            \$orderBy = null;
355
        }
356
        return \$this->tdbmService->findObjects('$tableName',  null, [], \$orderBy);
357
    }
358
    ";
359
360
        if (count($primaryKeyColumns) === 1) {
361
            $primaryKeyColumn = $primaryKeyColumns[0];
362
            $str .= "
363
    /**
364
     * Get $beanClassWithoutNameSpace specified by its ID (its primary key)
365
     * If the primary key does not exist, an exception is thrown.
366
     *
367
     * @param string|int \$id
368
     * @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.
369
     * @return $beanClassWithoutNameSpace
370
     * @throws TDBMException
371
     */
372
    public function getById(\$id, \$lazyLoading = false)
373
    {
374
        return \$this->tdbmService->findObjectByPk('$tableName', ['$primaryKeyColumn' => \$id], [], \$lazyLoading);
375
    }
376
    ";
377
        }
378
        $str .= "
379
    /**
380
     * Deletes the $beanClassWithoutNameSpace passed in parameter.
381
     *
382
     * @param $beanClassWithoutNameSpace \$obj object to delete
383
     * @param bool \$cascade if true, it will delete all object linked to \$obj
384
     */
385
    public function delete($beanClassWithoutNameSpace \$obj, \$cascade = false)
386
    {
387
        if (\$cascade === true) {
388
            \$this->tdbmService->deleteCascade(\$obj);
389
        } else {
390
            \$this->tdbmService->delete(\$obj);
391
        }
392
    }
393
394
395
    /**
396
     * Get a list of $beanClassWithoutNameSpace specified by its filters.
397
     *
398
     * @param mixed \$filter The filter bag (see TDBMService::findObjects for complete description)
399
     * @param array \$parameters The parameters associated with the filter
400
     * @param mixed \$orderby The order string
401
     * @param array \$additionalTablesFetch A list of additional tables to fetch (for performance improvement)
402
     * @param string \$mode Either TDBMService::MODE_ARRAY or TDBMService::MODE_CURSOR (for large datasets). Defaults to TDBMService::MODE_ARRAY.
403
     * @return {$beanClassWithoutNameSpace}[]|ResultIterator|ResultArray
404
     */
405
    protected function find(\$filter=null, array \$parameters = [], \$orderby=null, array \$additionalTablesFetch = array(), \$mode = null)
406
    {
407
        if (\$this->defaultSort && \$orderby == null) {
408
            \$orderby = '$tableName.'.\$this->defaultSort.' '.\$this->defaultDirection;
409
        }
410
        return \$this->tdbmService->findObjects('$tableName', \$filter, \$parameters, \$orderby, \$additionalTablesFetch, \$mode);
411
    }
412
413
    /**
414
     * Get a single $beanClassWithoutNameSpace specified by its filters.
415
     *
416
     * @param mixed \$filter The filter bag (see TDBMService::findObjects for complete description)
417
     * @param array \$parameters The parameters associated with the filter
418
     * @return $beanClassWithoutNameSpace
419
     */
420
    protected function findOne(\$filter=null, array \$parameters = [])
421
    {
422
        return \$this->tdbmService->findObject('$tableName', \$filter, \$parameters);
423
    }
424
425
    /**
426
     * Sets the default column for default sorting.
427
     *
428
     * @param string \$defaultSort
429
     */
430
    public function setDefaultSort(\$defaultSort)
431
    {
432
        \$this->defaultSort = \$defaultSort;
433
    }
434
    ";
435
436
        $str .= '
437
}
438
';
439
440
        $possibleBaseFileNames = $classNameMapper->getPossibleFileNames($daonamespace.'\\'.$baseClassName);
441
        if (empty($possibleBaseFileNames)) {
442
            // @codeCoverageIgnoreStart
443
            throw new TDBMException('Sorry, autoload namespace issue. The class "'.$baseClassName.'" is not autoloadable.');
444
            // @codeCoverageIgnoreEnd
445
        }
446
        $possibleBaseFileName = $this->rootPath.$possibleBaseFileNames[0];
447
448
        $this->ensureDirectoryExist($possibleBaseFileName);
449
        file_put_contents($possibleBaseFileName, $str);
450
        @chmod($possibleBaseFileName, 0664);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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...
451
452
        $possibleFileNames = $classNameMapper->getPossibleFileNames($daonamespace.'\\'.$className);
453
        if (empty($possibleFileNames)) {
454
            // @codeCoverageIgnoreStart
455
            throw new TDBMException('Sorry, autoload namespace issue. The class "'.$className.'" is not autoloadable.');
456
            // @codeCoverageIgnoreEnd
457
        }
458
        $possibleFileName = $this->rootPath.$possibleFileNames[0];
459
460
        // Now, let's generate the "editable" class
461 View Code Duplication
        if (!file_exists($possibleFileName)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
462
            $str = "<?php
463
464
/*
465
 * This file has been automatically generated by TDBM.
466
 * You can edit this file as it will not be overwritten.
467
 */
468
469
namespace {$daonamespace};
470
471
/**
472
 * The $className class will maintain the persistence of $beanClassWithoutNameSpace class into the $tableName table.
473
 */
474
class $className extends $baseClassName
475
{
476
477
}
478
";
479
            $this->ensureDirectoryExist($possibleFileName);
480
            file_put_contents($possibleFileName, $str);
481
            @chmod($possibleFileName, 0664);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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...
482
        }
483
    }
484
485
    /**
486
     * Generates the factory bean.
487
     *
488
     * @param Table[] $tableList
489
     */
490
    private function generateFactory(array $tableList, $daoFactoryClassName, $daoNamespace, ClassNameMapper $classNameMapper)
491
    {
492
        // For each table, let's write a property.
493
494
        $str = "<?php
495
496
/*
497
 * This file has been automatically generated by TDBM.
498
 * DO NOT edit this file, as it might be overwritten.
499
 */
500
501
namespace {$daoNamespace};
502
503
/**
504
 * The $daoFactoryClassName provides an easy access to all DAOs generated by TDBM.
505
 *
506
 */
507
class $daoFactoryClassName
508
{
509
";
510
511
        foreach ($tableList as $table) {
512
            $tableName = $table->getName();
513
            $daoClassName = $this->getDaoNameFromTableName($tableName);
514
            $daoInstanceName = self::toVariableName($daoClassName);
515
516
            $str .= '    /**
517
     * @var '.$daoClassName.'
518
     */
519
    private $'.$daoInstanceName.';
520
521
    /**
522
     * Returns an instance of the '.$daoClassName.' class.
523
     *
524
     * @return '.$daoClassName.'
525
     */
526
    public function get'.$daoClassName.'()
527
    {
528
        return $this->'.$daoInstanceName.';
529
    }
530
531
    /**
532
     * Sets the instance of the '.$daoClassName.' class that will be returned by the factory getter.
533
     *
534
     * @param '.$daoClassName.' $'.$daoInstanceName.'
535
     */
536
    public function set'.$daoClassName.'('.$daoClassName.' $'.$daoInstanceName.') {
537
        $this->'.$daoInstanceName.' = $'.$daoInstanceName.';
538
    }
539
540
';
541
        }
542
543
        $str .= '
544
}
545
';
546
547
        $possibleFileNames = $classNameMapper->getPossibleFileNames($daoNamespace.'\\'.$daoFactoryClassName);
548
        if (empty($possibleFileNames)) {
549
            throw new TDBMException('Sorry, autoload namespace issue. The class "'.$daoNamespace.'\\'.$daoFactoryClassName.'" is not autoloadable.');
550
        }
551
        $possibleFileName = $this->rootPath.$possibleFileNames[0];
552
553
        $this->ensureDirectoryExist($possibleFileName);
554
        file_put_contents($possibleFileName, $str);
555
        @chmod($possibleFileName, 0664);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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...
556
    }
557
558
    /**
559
     * Transforms a string to camelCase (except the first letter will be uppercase too).
560
     * Underscores and spaces are removed and the first letter after the underscore is uppercased.
561
     *
562
     * @param $str string
563
     *
564
     * @return string
565
     */
566
    public static function toCamelCase($str)
567
    {
568
        $str = strtoupper(substr($str, 0, 1)).substr($str, 1);
569
        while (true) {
570
            if (strpos($str, '_') === false && strpos($str, ' ') === false) {
571
                break;
572
            }
573
574
            $pos = strpos($str, '_');
575
            if ($pos === false) {
576
                $pos = strpos($str, ' ');
577
            }
578
            $before = substr($str, 0, $pos);
579
            $after = substr($str, $pos + 1);
580
            $str = $before.strtoupper(substr($after, 0, 1)).substr($after, 1);
581
        }
582
583
        return $str;
584
    }
585
586
    /**
587
     * Tries to put string to the singular form (if it is plural).
588
     * We assume the table names are in english.
589
     *
590
     * @param $str string
591
     *
592
     * @return string
593
     */
594
    public static function toSingular($str)
595
    {
596
        return Inflector::singularize($str);
597
    }
598
599
    /**
600
     * Put the first letter of the string in lower case.
601
     * Very useful to transform a class name into a variable name.
602
     *
603
     * @param $str string
604
     *
605
     * @return string
606
     */
607
    public static function toVariableName($str)
608
    {
609
        return strtolower(substr($str, 0, 1)).substr($str, 1);
610
    }
611
612
    /**
613
     * Ensures the file passed in parameter can be written in its directory.
614
     *
615
     * @param string $fileName
616
     *
617
     * @throws TDBMException
618
     */
619
    private function ensureDirectoryExist($fileName)
620
    {
621
        $dirName = dirname($fileName);
622
        if (!file_exists($dirName)) {
623
            $old = umask(0);
624
            $result = mkdir($dirName, 0775, true);
625
            umask($old);
626
            if ($result === false) {
627
                throw new TDBMException("Unable to create directory: '".$dirName."'.");
628
            }
629
        }
630
    }
631
632
    /**
633
     * @param string $rootPath
634
     */
635
    public function setRootPath($rootPath)
636
    {
637
        $this->rootPath = $rootPath;
638
    }
639
640
    /**
641
     * Transforms a DBAL type into a PHP type (for PHPDoc purpose).
642
     *
643
     * @param Type $type The DBAL type
644
     *
645
     * @return string The PHP type
646
     */
647
    public static function dbalTypeToPhpType(Type $type)
648
    {
649
        $map = [
650
            Type::TARRAY => 'array',
651
            Type::SIMPLE_ARRAY => 'array',
652
            Type::JSON_ARRAY => 'array',
653
            Type::BIGINT => 'string',
654
            Type::BOOLEAN => 'bool',
655
            Type::DATETIME => '\DateTimeInterface',
656
            Type::DATETIMETZ => '\DateTimeInterface',
657
            Type::DATE => '\DateTimeInterface',
658
            Type::TIME => '\DateTimeInterface',
659
            Type::DECIMAL => 'float',
660
            Type::INTEGER => 'int',
661
            Type::OBJECT => 'string',
662
            Type::SMALLINT => 'int',
663
            Type::STRING => 'string',
664
            Type::TEXT => 'string',
665
            Type::BINARY => 'string',
666
            Type::BLOB => 'string',
667
            Type::FLOAT => 'float',
668
            Type::GUID => 'string',
669
        ];
670
671
        return isset($map[$type->getName()]) ? $map[$type->getName()] : $type->getName();
672
    }
673
674
    /**
675
     * @param string $beanNamespace
676
     *
677
     * @return \string[] Returns a map mapping table name to beans name
678
     */
679
    public function buildTableToBeanMap($beanNamespace)
680
    {
681
        $tableToBeanMap = [];
682
683
        $tables = $this->schema->getTables();
684
685
        foreach ($tables as $table) {
686
            $tableName = $table->getName();
687
            $tableToBeanMap[$tableName] = $beanNamespace.'\\'.self::getBeanNameFromTableName($tableName);
688
        }
689
690
        return $tableToBeanMap;
691
    }
692
}
693