Completed
Pull Request — 4.0 (#48)
by Marc
05:40
created

TDBMDaoGenerator::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 6
Ratio 85.71 %

Importance

Changes 7
Bugs 1 Features 0
Metric Value
c 7
b 1
f 0
dl 6
loc 7
rs 9.4285
cc 1
eloc 5
nc 1
nop 3
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
        $beanDescriptor = new BeanDescriptor($table, $this->schemaAnalyzer, $this->schema, $this->tdbmSchemaAnalyzer);
120
121
        $this->generateBean($beanDescriptor, $beanName, $baseBeanName, $table, $beannamespace, $classNameMapper, $storeInUtc);
122
        $this->generateDao($beanDescriptor, $daoName, $baseDaoName, $beanName, $table, $daonamespace, $beannamespace, $classNameMapper);
123
    }
124
125
    /**
126
     * Returns the name of the bean class from the table name.
127
     *
128
     * @param $tableName
129
     *
130
     * @return string
131
     */
132
    public static function getBeanNameFromTableName($tableName)
133
    {
134
        return self::toSingular(self::toCamelCase($tableName)).'Bean';
135
    }
136
137
    /**
138
     * Returns the name of the DAO class from the table name.
139
     *
140
     * @param $tableName
141
     *
142
     * @return string
143
     */
144
    public static function getDaoNameFromTableName($tableName)
145
    {
146
        return self::toSingular(self::toCamelCase($tableName)).'Dao';
147
    }
148
149
    /**
150
     * Returns the name of the base bean class from the table name.
151
     *
152
     * @param $tableName
153
     *
154
     * @return string
155
     */
156
    public static function getBaseBeanNameFromTableName($tableName)
157
    {
158
        return self::toSingular(self::toCamelCase($tableName)).'BaseBean';
159
    }
160
161
    /**
162
     * Returns the name of the base DAO class from the table name.
163
     *
164
     * @param $tableName
165
     *
166
     * @return string
167
     */
168
    public static function getBaseDaoNameFromTableName($tableName)
169
    {
170
        return self::toSingular(self::toCamelCase($tableName)).'BaseDao';
171
    }
172
173
    /**
174
     * Writes the PHP bean file with all getters and setters from the table passed in parameter.
175
     *
176
     * @param BeanDescriptor  $beanDescriptor
177
     * @param string          $className       The name of the class
178
     * @param string          $baseClassName   The name of the base class which will be extended (name only, no directory)
179
     * @param Table           $table           The table
180
     * @param string          $beannamespace   The namespace of the bean
181
     * @param ClassNameMapper $classNameMapper
182
     *
183
     * @throws TDBMException
184
     */
185
    public function generateBean(BeanDescriptor $beanDescriptor, $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...
186
    {
187
        $str = $beanDescriptor->generatePhpCode($beannamespace);
188
189
        $possibleBaseFileNames = $classNameMapper->getPossibleFileNames($beannamespace.'\\'.$baseClassName);
190
        if (empty($possibleBaseFileNames)) {
191
            throw new TDBMException('Sorry, autoload namespace issue. The class "'.$beannamespace.'\\'.$baseClassName.'" is not autoloadable.');
192
        }
193
        $possibleBaseFileName = $this->rootPath.$possibleBaseFileNames[0];
194
195
        $this->ensureDirectoryExist($possibleBaseFileName);
196
        file_put_contents($possibleBaseFileName, $str);
197
        @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...
198
199
        $possibleFileNames = $classNameMapper->getPossibleFileNames($beannamespace.'\\'.$className);
200
        if (empty($possibleFileNames)) {
201
            // @codeCoverageIgnoreStart
202
            throw new TDBMException('Sorry, autoload namespace issue. The class "'.$beannamespace.'\\'.$className.'" is not autoloadable.');
203
            // @codeCoverageIgnoreEnd
204
        }
205
        $possibleFileName = $this->rootPath.$possibleFileNames[0];
206
207 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...
208
            $tableName = $table->getName();
209
210
            $str = "<?php
211
/*
212
 * This file has been automatically generated by TDBM.
213
 * You can edit this file as it will not be overwritten.
214
 */
215
216
namespace {$beannamespace};
217
218
/**
219
 * The $className class maps the '$tableName' table in database.
220
 */
221
class $className extends $baseClassName
222
{
223
224
}";
225
            $this->ensureDirectoryExist($possibleFileName);
226
            file_put_contents($possibleFileName, $str);
227
            @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...
228
        }
229
    }
230
231
    /**
232
     * Tries to find a @defaultSort annotation in one of the columns.
233
     *
234
     * @param Table $table
235
     *
236
     * @return array First item: column name, Second item: column order (asc/desc)
237
     */
238
    private function getDefaultSortColumnFromAnnotation(Table $table)
239
    {
240
        $defaultSort = null;
241
        $defaultSortDirection = null;
242
        foreach ($table->getColumns() as $column) {
243
            $comments = $column->getComment();
244
            $matches = [];
245
            if (preg_match('/@defaultSort(\((desc|asc)\))*/', $comments, $matches) != 0) {
246
                $defaultSort = $column->getName();
247
                if (count($matches) === 3) {
248
                    $defaultSortDirection = $matches[2];
249
                } else {
250
                    $defaultSortDirection = 'ASC';
251
                }
252
            }
253
        }
254
255
        return [$defaultSort, $defaultSortDirection];
256
    }
257
258
    /**
259
     * Writes the PHP bean DAO with simple functions to create/get/save objects.
260
     *
261
     * @param BeanDescriptor  $beanDescriptor
262
     * @param string          $className       The name of the class
263
     * @param string          $baseClassName
264
     * @param string          $beanClassName
265
     * @param Table           $table
266
     * @param string          $daonamespace
267
     * @param string          $beannamespace
268
     * @param ClassNameMapper $classNameMapper
269
     *
270
     * @throws TDBMException
271
     */
272
    public function generateDao(BeanDescriptor $beanDescriptor, $className, $baseClassName, $beanClassName, Table $table, $daonamespace, $beannamespace, ClassNameMapper $classNameMapper)
273
    {
274
        $tableName = $table->getName();
275
        $primaryKeyColumns = $table->getPrimaryKeyColumns();
276
277
        list($defaultSort, $defaultSortDirection) = $this->getDefaultSortColumnFromAnnotation($table);
278
279
        // FIXME: lowercase tables with _ in the name should work!
280
        $tableCamel = self::toSingular(self::toCamelCase($tableName));
281
282
        $beanClassWithoutNameSpace = $beanClassName;
283
        $beanClassName = $beannamespace.'\\'.$beanClassName;
284
285
        list($usedBeans, $findByDaoCode) = $beanDescriptor->generateFindByDaoCode($beannamespace, $beanClassWithoutNameSpace);
286
287
        $usedBeans[] = $beanClassName;
288
        // Let's suppress duplicates in used beans (if any)
289
        $usedBeans = array_flip(array_flip($usedBeans));
290
        $useStatements = array_map(function ($usedBean) {
291
            return "use $usedBean;\n";
292
        }, $usedBeans);
293
294
        $str = "<?php
295
296
/*
297
 * This file has been automatically generated by TDBM.
298
 * DO NOT edit this file, as it might be overwritten.
299
 * If you need to perform changes, edit the $className class instead!
300
 */
301
302
namespace {$daonamespace};
303
304
use Mouf\\Database\\TDBM\\TDBMService;
305
use Mouf\\Database\\TDBM\\ResultIterator;
306
use Mouf\\Database\\TDBM\\ArrayIterator;
307
".implode('', $useStatements)."
308
309
/**
310
 * The $baseClassName class will maintain the persistence of $beanClassWithoutNameSpace class into the $tableName table.
311
 *
312
 */
313
class $baseClassName
314
{
315
316
    /**
317
     * @var TDBMService
318
     */
319
    protected \$tdbmService;
320
321
    /**
322
     * The default sort column.
323
     *
324
     * @var string
325
     */
326
    private \$defaultSort = ".($defaultSort ? "'$defaultSort'" : 'null').";
327
328
    /**
329
     * The default sort direction.
330
     *
331
     * @var string
332
     */
333
    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...
334
335
    /**
336
     * Sets the TDBM service used by this DAO.
337
     *
338
     * @param TDBMService \$tdbmService
339
     */
340
    public function __construct(TDBMService \$tdbmService)
341
    {
342
        \$this->tdbmService = \$tdbmService;
343
    }
344
345
    /**
346
     * Persist the $beanClassWithoutNameSpace instance.
347
     *
348
     * @param $beanClassWithoutNameSpace \$obj The bean to save.
349
     */
350
    public function save($beanClassWithoutNameSpace \$obj)
351
    {
352
        \$this->tdbmService->save(\$obj);
353
    }
354
355
    /**
356
     * Get all $tableCamel records.
357
     *
358
     * @return {$beanClassWithoutNameSpace}[]|ResultIterator|ResultArray
359
     */
360
    public function findAll()
361
    {
362
        if (\$this->defaultSort) {
363
            \$orderBy = '$tableName.'.\$this->defaultSort.' '.\$this->defaultDirection;
364
        } else {
365
            \$orderBy = null;
366
        }
367
        return \$this->tdbmService->findObjects('$tableName',  null, [], \$orderBy);
368
    }
369
    ";
370
371
        if (count($primaryKeyColumns) === 1) {
372
            $primaryKeyColumn = $primaryKeyColumns[0];
373
            $str .= "
374
    /**
375
     * Get $beanClassWithoutNameSpace specified by its ID (its primary key)
376
     * If the primary key does not exist, an exception is thrown.
377
     *
378
     * @param string|int \$id
379
     * @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.
380
     * @return $beanClassWithoutNameSpace
381
     * @throws TDBMException
382
     */
383
    public function getById(\$id, \$lazyLoading = false)
384
    {
385
        return \$this->tdbmService->findObjectByPk('$tableName', ['$primaryKeyColumn' => \$id], [], \$lazyLoading);
386
    }
387
    ";
388
        }
389
        $str .= "
390
    /**
391
     * Deletes the $beanClassWithoutNameSpace passed in parameter.
392
     *
393
     * @param $beanClassWithoutNameSpace \$obj object to delete
394
     * @param bool \$cascade if true, it will delete all object linked to \$obj
395
     */
396
    public function delete($beanClassWithoutNameSpace \$obj, \$cascade = false)
397
    {
398
        if (\$cascade === true) {
399
            \$this->tdbmService->deleteCascade(\$obj);
400
        } else {
401
            \$this->tdbmService->delete(\$obj);
402
        }
403
    }
404
405
406
    /**
407
     * Get a list of $beanClassWithoutNameSpace specified by its filters.
408
     *
409
     * @param mixed \$filter The filter bag (see TDBMService::findObjects for complete description)
410
     * @param array \$parameters The parameters associated with the filter
411
     * @param mixed \$orderBy The order string
412
     * @param array \$additionalTablesFetch A list of additional tables to fetch (for performance improvement)
413
     * @param int \$mode Either TDBMService::MODE_ARRAY or TDBMService::MODE_CURSOR (for large datasets). Defaults to TDBMService::MODE_ARRAY.
414
     * @return {$beanClassWithoutNameSpace}[]|ResultIterator|ResultArray
415
     */
416
    protected function find(\$filter = null, array \$parameters = [], \$orderBy=null, array \$additionalTablesFetch = [], \$mode = null)
417
    {
418
        if (\$this->defaultSort && \$orderBy == null) {
419
            \$orderBy = '$tableName.'.\$this->defaultSort.' '.\$this->defaultDirection;
420
        }
421
        return \$this->tdbmService->findObjects('$tableName', \$filter, \$parameters, \$orderBy, \$additionalTablesFetch, \$mode);
422
    }
423
424
    /**
425
     * Get a single $beanClassWithoutNameSpace specified by its filters.
426
     *
427
     * @param mixed \$filter The filter bag (see TDBMService::findObjects for complete description)
428
     * @param array \$parameters The parameters associated with the filter
429
     * @return $beanClassWithoutNameSpace
430
     */
431
    protected function findOne(\$filter=null, array \$parameters = [])
432
    {
433
        return \$this->tdbmService->findObject('$tableName', \$filter, \$parameters);
434
    }
435
436
    /**
437
     * Sets the default column for default sorting.
438
     *
439
     * @param string \$defaultSort
440
     */
441
    public function setDefaultSort(\$defaultSort)
442
    {
443
        \$this->defaultSort = \$defaultSort;
444
    }
445
";
446
447
        $str .= $findByDaoCode;
448
        $str .= '}
449
';
450
451
        $possibleBaseFileNames = $classNameMapper->getPossibleFileNames($daonamespace.'\\'.$baseClassName);
452
        if (empty($possibleBaseFileNames)) {
453
            // @codeCoverageIgnoreStart
454
            throw new TDBMException('Sorry, autoload namespace issue. The class "'.$baseClassName.'" is not autoloadable.');
455
            // @codeCoverageIgnoreEnd
456
        }
457
        $possibleBaseFileName = $this->rootPath.$possibleBaseFileNames[0];
458
459
        $this->ensureDirectoryExist($possibleBaseFileName);
460
        file_put_contents($possibleBaseFileName, $str);
461
        @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...
462
463
        $possibleFileNames = $classNameMapper->getPossibleFileNames($daonamespace.'\\'.$className);
464
        if (empty($possibleFileNames)) {
465
            // @codeCoverageIgnoreStart
466
            throw new TDBMException('Sorry, autoload namespace issue. The class "'.$className.'" is not autoloadable.');
467
            // @codeCoverageIgnoreEnd
468
        }
469
        $possibleFileName = $this->rootPath.$possibleFileNames[0];
470
471
        // Now, let's generate the "editable" class
472 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...
473
            $str = "<?php
474
475
/*
476
 * This file has been automatically generated by TDBM.
477
 * You can edit this file as it will not be overwritten.
478
 */
479
480
namespace {$daonamespace};
481
482
/**
483
 * The $className class will maintain the persistence of $beanClassWithoutNameSpace class into the $tableName table.
484
 */
485
class $className extends $baseClassName
486
{
487
488
}
489
";
490
            $this->ensureDirectoryExist($possibleFileName);
491
            file_put_contents($possibleFileName, $str);
492
            @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...
493
        }
494
    }
495
496
    /**
497
     * Generates the factory bean.
498
     *
499
     * @param Table[] $tableList
500
     */
501
    private function generateFactory(array $tableList, $daoFactoryClassName, $daoNamespace, ClassNameMapper $classNameMapper)
502
    {
503
        // For each table, let's write a property.
504
505
        $str = "<?php
506
507
/*
508
 * This file has been automatically generated by TDBM.
509
 * DO NOT edit this file, as it might be overwritten.
510
 */
511
512
namespace {$daoNamespace};
513
514
/**
515
 * The $daoFactoryClassName provides an easy access to all DAOs generated by TDBM.
516
 *
517
 */
518
class $daoFactoryClassName
519
{
520
";
521
522
        foreach ($tableList as $table) {
523
            $tableName = $table->getName();
524
            $daoClassName = $this->getDaoNameFromTableName($tableName);
525
            $daoInstanceName = self::toVariableName($daoClassName);
526
527
            $str .= '    /**
528
     * @var '.$daoClassName.'
529
     */
530
    private $'.$daoInstanceName.';
531
532
    /**
533
     * Returns an instance of the '.$daoClassName.' class.
534
     *
535
     * @return '.$daoClassName.'
536
     */
537
    public function get'.$daoClassName.'()
538
    {
539
        return $this->'.$daoInstanceName.';
540
    }
541
542
    /**
543
     * Sets the instance of the '.$daoClassName.' class that will be returned by the factory getter.
544
     *
545
     * @param '.$daoClassName.' $'.$daoInstanceName.'
546
     */
547
    public function set'.$daoClassName.'('.$daoClassName.' $'.$daoInstanceName.') {
548
        $this->'.$daoInstanceName.' = $'.$daoInstanceName.';
549
    }
550
551
';
552
        }
553
554
        $str .= '
555
}
556
';
557
558
        $possibleFileNames = $classNameMapper->getPossibleFileNames($daoNamespace.'\\'.$daoFactoryClassName);
559
        if (empty($possibleFileNames)) {
560
            throw new TDBMException('Sorry, autoload namespace issue. The class "'.$daoNamespace.'\\'.$daoFactoryClassName.'" is not autoloadable.');
561
        }
562
        $possibleFileName = $this->rootPath.$possibleFileNames[0];
563
564
        $this->ensureDirectoryExist($possibleFileName);
565
        file_put_contents($possibleFileName, $str);
566
        @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...
567
    }
568
569
    /**
570
     * Transforms a string to camelCase (except the first letter will be uppercase too).
571
     * Underscores and spaces are removed and the first letter after the underscore is uppercased.
572
     *
573
     * @param $str string
574
     *
575
     * @return string
576
     */
577
    public static function toCamelCase($str)
578
    {
579
        $str = strtoupper(substr($str, 0, 1)).substr($str, 1);
580
        while (true) {
581
            if (strpos($str, '_') === false && strpos($str, ' ') === false) {
582
                break;
583
            }
584
585
            $pos = strpos($str, '_');
586
            if ($pos === false) {
587
                $pos = strpos($str, ' ');
588
            }
589
            $before = substr($str, 0, $pos);
590
            $after = substr($str, $pos + 1);
591
            $str = $before.strtoupper(substr($after, 0, 1)).substr($after, 1);
592
        }
593
594
        return $str;
595
    }
596
597
    /**
598
     * Tries to put string to the singular form (if it is plural).
599
     * We assume the table names are in english.
600
     *
601
     * @param $str string
602
     *
603
     * @return string
604
     */
605
    public static function toSingular($str)
606
    {
607
        return Inflector::singularize($str);
608
    }
609
610
    /**
611
     * Put the first letter of the string in lower case.
612
     * Very useful to transform a class name into a variable name.
613
     *
614
     * @param $str string
615
     *
616
     * @return string
617
     */
618
    public static function toVariableName($str)
619
    {
620
        return strtolower(substr($str, 0, 1)).substr($str, 1);
621
    }
622
623
    /**
624
     * Ensures the file passed in parameter can be written in its directory.
625
     *
626
     * @param string $fileName
627
     *
628
     * @throws TDBMException
629
     */
630
    private function ensureDirectoryExist($fileName)
631
    {
632
        $dirName = dirname($fileName);
633
        if (!file_exists($dirName)) {
634
            $old = umask(0);
635
            $result = mkdir($dirName, 0775, true);
636
            umask($old);
637
            if ($result === false) {
638
                throw new TDBMException("Unable to create directory: '".$dirName."'.");
639
            }
640
        }
641
    }
642
643
    /**
644
     * @param string $rootPath
645
     */
646
    public function setRootPath($rootPath)
647
    {
648
        $this->rootPath = $rootPath;
649
    }
650
651
    /**
652
     * @return string
653
     */
654
    public function getRootPath()
655
    {
656
        return $this->rootPath;
657
    }
658
    
659
    /**
660
     * Transforms a DBAL type into a PHP type (for PHPDoc purpose).
661
     *
662
     * @param Type $type The DBAL type
663
     *
664
     * @return string The PHP type
665
     */
666
    public static function dbalTypeToPhpType(Type $type)
667
    {
668
        $map = [
669
            Type::TARRAY => 'array',
670
            Type::SIMPLE_ARRAY => 'array',
671
            Type::JSON_ARRAY => 'array',
672
            Type::BIGINT => 'string',
673
            Type::BOOLEAN => 'bool',
674
            Type::DATETIME => '\DateTimeInterface',
675
            Type::DATETIMETZ => '\DateTimeInterface',
676
            Type::DATE => '\DateTimeInterface',
677
            Type::TIME => '\DateTimeInterface',
678
            Type::DECIMAL => 'float',
679
            Type::INTEGER => 'int',
680
            Type::OBJECT => 'string',
681
            Type::SMALLINT => 'int',
682
            Type::STRING => 'string',
683
            Type::TEXT => 'string',
684
            Type::BINARY => 'string',
685
            Type::BLOB => 'string',
686
            Type::FLOAT => 'float',
687
            Type::GUID => 'string',
688
        ];
689
690
        return isset($map[$type->getName()]) ? $map[$type->getName()] : $type->getName();
691
    }
692
693
    /**
694
     * @param string $beanNamespace
695
     *
696
     * @return \string[] Returns a map mapping table name to beans name
697
     */
698
    public function buildTableToBeanMap($beanNamespace)
699
    {
700
        $tableToBeanMap = [];
701
702
        $tables = $this->schema->getTables();
703
704
        foreach ($tables as $table) {
705
            $tableName = $table->getName();
706
            $tableToBeanMap[$tableName] = $beanNamespace.'\\'.self::getBeanNameFromTableName($tableName);
707
        }
708
709
        return $tableToBeanMap;
710
    }
711
}
712