Test Failed
Pull Request — 4.2 (#140)
by David
04:46
created

TDBMDaoGenerator::generateBean()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 37
Code Lines 18

Duplication

Lines 23
Ratio 62.16 %

Importance

Changes 0
Metric Value
dl 23
loc 37
rs 8.8571
c 0
b 0
f 0
cc 2
eloc 18
nc 2
nop 4
1
<?php
2
3
namespace Mouf\Database\TDBM\Utils;
4
5
use Doctrine\Common\Inflector\Inflector;
6
use Doctrine\DBAL\Schema\Schema;
7
use Doctrine\DBAL\Schema\Table;
8
use Doctrine\DBAL\Types\Type;
9
use Mouf\Database\TDBM\ConfigurationInterface;
10
use Mouf\Database\TDBM\TDBMException;
11
use Mouf\Database\TDBM\TDBMSchemaAnalyzer;
12
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
13
14
/**
15
 * This class generates automatically DAOs and Beans for TDBM.
16
 */
17
class TDBMDaoGenerator
18
{
19
    /**
20
     * @var Schema
21
     */
22
    private $schema;
23
24
    /**
25
     * The root directory of the project.
26
     *
27
     * @var string
28
     */
29
    private $rootPath;
30
31
    /**
32
     * Name of composer file.
33
     *
34
     * @var string
35
     */
36
    private $composerFile;
37
38
    /**
39
     * @var TDBMSchemaAnalyzer
40
     */
41
    private $tdbmSchemaAnalyzer;
42
43
    /**
44
     * @var EventDispatcherInterface
45
     */
46
    private $eventDispatcher;
47
48
    /**
49
     * @var NamingStrategyInterface
50
     */
51
    private $namingStrategy;
52
    /**
53
     * @var ConfigurationInterface
54
     */
55
    private $configuration;
56
57
    /**
58
     * Constructor.
59
     *
60
     * @param ConfigurationInterface $configuration
61
     * @param TDBMSchemaAnalyzer $tdbmSchemaAnalyzer
62
     */
63
    public function __construct(ConfigurationInterface $configuration, TDBMSchemaAnalyzer $tdbmSchemaAnalyzer)
64
    {
65
        $this->configuration = $configuration;
66
        $this->schema = $tdbmSchemaAnalyzer->getSchema();
67
        $this->tdbmSchemaAnalyzer = $tdbmSchemaAnalyzer;
68
        $this->rootPath = __DIR__.'/../../../../../../../../';
69
        $this->namingStrategy = $configuration->getNamingStrategy();
70
        $this->eventDispatcher = $configuration->getGeneratorEventDispatcher();
0 ignored issues
show
Documentation Bug introduced by
It seems like $configuration->getGeneratorEventDispatcher() of type object<Mouf\Database\TDB...ratorListenerInterface> is incompatible with the declared type object<Symfony\Component...entDispatcherInterface> of property $eventDispatcher.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
71
    }
72
73
    /**
74
     * Generates all the daos and beans.
75
     *
76
     * @throws TDBMException
77
     */
78
    public function generateAllDaosAndBeans(): void
79
    {
80
        // TODO: check that no class name ends with "Base". Otherwise, there will be name clash.
81
82
        $tableList = $this->schema->getTables();
83
84
        // Remove all beans and daos from junction tables
85
        $junctionTables = $this->configuration->getSchemaAnalyzer()->detectJunctionTables(true);
86
        $junctionTableNames = array_map(function (Table $table) {
87
            return $table->getName();
88
        }, $junctionTables);
89
90
        $tableList = array_filter($tableList, function (Table $table) use ($junctionTableNames) {
91
            return !in_array($table->getName(), $junctionTableNames);
92
        });
93
94
        $beanDescriptors = [];
95
96
        foreach ($tableList as $table) {
97
            $beanDescriptors[] = $this->generateDaoAndBean($table);
98
        }
99
100
101
        $this->generateFactory($tableList);
102
103
        // Let's call the list of listeners
104
        $this->eventDispatcher->onGenerate($this->configuration, $beanDescriptors);
0 ignored issues
show
Bug introduced by
The method onGenerate() does not seem to exist on object<Symfony\Component...entDispatcherInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
105
    }
106
107
    /**
108
     * Generates in one method call the daos and the beans for one table.
109
     *
110
     * @param Table $table
111
     *
112
     * @return BeanDescriptor
113
     * @throws TDBMException
114
     */
115
    private function generateDaoAndBean(Table $table) : BeanDescriptor
116
    {
117
        // TODO: $storeInUtc is NOT USED.
118
        $tableName = $table->getName();
119
        $daoName = $this->namingStrategy->getDaoClassName($tableName);
120
        $beanName = $this->namingStrategy->getBeanClassName($tableName);
121
        $baseBeanName = $this->namingStrategy->getBaseBeanClassName($tableName);
122
        $baseDaoName = $this->namingStrategy->getBaseDaoClassName($tableName);
123
124
        $beanDescriptor = new BeanDescriptor($table, $this->configuration->getSchemaAnalyzer(), $this->schema, $this->tdbmSchemaAnalyzer, $this->namingStrategy);
125
        $this->generateBean($beanDescriptor, $beanName, $baseBeanName, $table);
126
        $this->generateDao($beanDescriptor, $daoName, $baseDaoName, $beanName, $table);
127
        return $beanDescriptor;
128
    }
129
130
    /**
131
     * Writes the PHP bean file with all getters and setters from the table passed in parameter.
132
     *
133
     * @param BeanDescriptor  $beanDescriptor
134
     * @param string          $className       The name of the class
135
     * @param string          $baseClassName   The name of the base class which will be extended (name only, no directory)
136
     * @param Table           $table           The table
137
     *
138
     * @throws TDBMException
139
     */
140
    public function generateBean(BeanDescriptor $beanDescriptor, $className, $baseClassName, Table $table)
141
    {
142
        $beannamespace = $this->configuration->getBeanNamespace();
143
        $str = $beanDescriptor->generatePhpCode($beannamespace);
144
145
        $possibleBaseFileName = $this->configuration->getPathFinder()->getPath($beannamespace.'\\Generated\\'.$baseClassName)->getPathname();
146
147
        $this->ensureDirectoryExist($possibleBaseFileName);
148
        file_put_contents($possibleBaseFileName, $str);
149
        @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...
150
151
        $possibleFileName = $this->configuration->getPathFinder()->getPath($beannamespace.'\\'.$className)->getPathname();
152
153 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...
154
            $tableName = $table->getName();
155
            $str = "<?php
156
/*
157
 * This file has been automatically generated by TDBM.
158
 * You can edit this file as it will not be overwritten.
159
 */
160
161
namespace {$beannamespace};
162
163
use {$beannamespace}\\Generated\\{$baseClassName};
164
165
/**
166
 * The $className class maps the '$tableName' table in database.
167
 */
168
class $className extends $baseClassName
169
{
170
}
171
";
172
            $this->ensureDirectoryExist($possibleFileName);
173
            file_put_contents($possibleFileName, $str);
174
            @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...
175
        }
176
    }
177
178
    /**
179
     * Tries to find a @defaultSort annotation in one of the columns.
180
     *
181
     * @param Table $table
182
     *
183
     * @return array First item: column name, Second item: column order (asc/desc)
184
     */
185
    private function getDefaultSortColumnFromAnnotation(Table $table)
186
    {
187
        $defaultSort = null;
188
        $defaultSortDirection = null;
189
        foreach ($table->getColumns() as $column) {
190
            $comments = $column->getComment();
191
            $matches = [];
192
            if (preg_match('/@defaultSort(\((desc|asc)\))*/', $comments, $matches) != 0) {
193
                $defaultSort = $column->getName();
194
                if (count($matches) === 3) {
195
                    $defaultSortDirection = $matches[2];
196
                } else {
197
                    $defaultSortDirection = 'ASC';
198
                }
199
            }
200
        }
201
202
        return [$defaultSort, $defaultSortDirection];
203
    }
204
205
    /**
206
     * Writes the PHP bean DAO with simple functions to create/get/save objects.
207
     *
208
     * @param BeanDescriptor  $beanDescriptor
209
     * @param string          $className       The name of the class
210
     * @param string          $baseClassName
211
     * @param string          $beanClassName
212
     * @param Table           $table
213
     *
214
     * @throws TDBMException
215
     */
216
    private function generateDao(BeanDescriptor $beanDescriptor, string $className, string $baseClassName, string $beanClassName, Table $table)
217
    {
218
        $daonamespace = $this->configuration->getDaoNamespace();
219
        $beannamespace = $this->configuration->getBeanNamespace();
220
        $tableName = $table->getName();
221
        $primaryKeyColumns = $table->getPrimaryKeyColumns();
222
223
        list($defaultSort, $defaultSortDirection) = $this->getDefaultSortColumnFromAnnotation($table);
224
225
        // FIXME: lowercase tables with _ in the name should work!
226
        $tableCamel = self::toSingular(self::toCamelCase($tableName));
227
228
        $beanClassWithoutNameSpace = $beanClassName;
229
        $beanClassName = $beannamespace.'\\'.$beanClassName;
230
231
        list($usedBeans, $findByDaoCode) = $beanDescriptor->generateFindByDaoCode($beannamespace, $beanClassWithoutNameSpace);
232
233
        $usedBeans[] = $beanClassName;
234
        // Let's suppress duplicates in used beans (if any)
235
        $usedBeans = array_flip(array_flip($usedBeans));
236
        $useStatements = array_map(function ($usedBean) {
237
            return "use $usedBean;\n";
238
        }, $usedBeans);
239
240
        $str = "<?php
241
242
/*
243
 * This file has been automatically generated by TDBM.
244
 * DO NOT edit this file, as it might be overwritten.
245
 * If you need to perform changes, edit the $className class instead!
246
 */
247
248
namespace {$daonamespace}\\Generated;
249
250
use Mouf\\Database\\TDBM\\TDBMService;
251
use Mouf\\Database\\TDBM\\ResultIterator;
252
use Mouf\\Database\\TDBM\\ArrayIterator;
253
".implode('', $useStatements)."
254
/**
255
 * The $baseClassName class will maintain the persistence of $beanClassWithoutNameSpace class into the $tableName table.
256
 *
257
 */
258
class $baseClassName
259
{
260
261
    /**
262
     * @var TDBMService
263
     */
264
    protected \$tdbmService;
265
266
    /**
267
     * The default sort column.
268
     *
269
     * @var string
270
     */
271
    private \$defaultSort = ".($defaultSort ? "'$defaultSort'" : 'null').';
272
273
    /**
274
     * The default sort direction.
275
     *
276
     * @var string
277
     */
278
    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...
279
280
    /**
281
     * Sets the TDBM service used by this DAO.
282
     *
283
     * @param TDBMService \$tdbmService
284
     */
285
    public function __construct(TDBMService \$tdbmService)
286
    {
287
        \$this->tdbmService = \$tdbmService;
288
    }
289
290
    /**
291
     * Persist the $beanClassWithoutNameSpace instance.
292
     *
293
     * @param $beanClassWithoutNameSpace \$obj The bean to save.
294
     */
295
    public function save($beanClassWithoutNameSpace \$obj)
296
    {
297
        \$this->tdbmService->save(\$obj);
298
    }
299
300
    /**
301
     * Get all $tableCamel records.
302
     *
303
     * @return {$beanClassWithoutNameSpace}[]|ResultIterator|ResultArray
304
     */
305
    public function findAll() : iterable
306
    {
307
        if (\$this->defaultSort) {
308
            \$orderBy = '$tableName.'.\$this->defaultSort.' '.\$this->defaultDirection;
309
        } else {
310
            \$orderBy = null;
311
        }
312
        return \$this->tdbmService->findObjects('$tableName', null, [], \$orderBy);
313
    }
314
    ";
315
316
        if (count($primaryKeyColumns) === 1) {
317
            $primaryKeyColumn = $primaryKeyColumns[0];
318
            $primaryKeyPhpType = self::dbalTypeToPhpType($table->getColumn($primaryKeyColumn)->getType());
319
            $str .= "
320
    /**
321
     * Get $beanClassWithoutNameSpace specified by its ID (its primary key)
322
     * If the primary key does not exist, an exception is thrown.
323
     *
324
     * @param string|int \$id
325
     * @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.
326
     * @return $beanClassWithoutNameSpace
327
     * @throws TDBMException
328
     */
329
    public function getById($primaryKeyPhpType \$id, \$lazyLoading = false) : $beanClassWithoutNameSpace
330
    {
331
        return \$this->tdbmService->findObjectByPk('$tableName', ['$primaryKeyColumn' => \$id], [], \$lazyLoading);
332
    }
333
    ";
334
        }
335
        $str .= "
336
    /**
337
     * Deletes the $beanClassWithoutNameSpace passed in parameter.
338
     *
339
     * @param $beanClassWithoutNameSpace \$obj object to delete
340
     * @param bool \$cascade if true, it will delete all object linked to \$obj
341
     */
342
    public function delete($beanClassWithoutNameSpace \$obj, \$cascade = false) : void
343
    {
344
        if (\$cascade === true) {
345
            \$this->tdbmService->deleteCascade(\$obj);
346
        } else {
347
            \$this->tdbmService->delete(\$obj);
348
        }
349
    }
350
351
352
    /**
353
     * Get a list of $beanClassWithoutNameSpace specified by its filters.
354
     *
355
     * @param mixed \$filter The filter bag (see TDBMService::findObjects for complete description)
356
     * @param array \$parameters The parameters associated with the filter
357
     * @param mixed \$orderBy The order string
358
     * @param array \$additionalTablesFetch A list of additional tables to fetch (for performance improvement)
359
     * @param int \$mode Either TDBMService::MODE_ARRAY or TDBMService::MODE_CURSOR (for large datasets). Defaults to TDBMService::MODE_ARRAY.
360
     * @return {$beanClassWithoutNameSpace}[]|ResultIterator|ResultArray
361
     */
362
    protected function find(\$filter = null, array \$parameters = [], \$orderBy=null, array \$additionalTablesFetch = [], \$mode = null) : iterable
363
    {
364
        if (\$this->defaultSort && \$orderBy == null) {
365
            \$orderBy = '$tableName.'.\$this->defaultSort.' '.\$this->defaultDirection;
366
        }
367
        return \$this->tdbmService->findObjects('$tableName', \$filter, \$parameters, \$orderBy, \$additionalTablesFetch, \$mode);
368
    }
369
370
    /**
371
     * Get a list of $beanClassWithoutNameSpace specified by its filters.
372
     * Unlike the `find` method that guesses the FROM part of the statement, here you can pass the \$from part.
373
     *
374
     * You should not put an alias on the main table name. So your \$from variable should look like:
375
     *
376
     *   \"$tableName JOIN ... ON ...\"
377
     *
378
     * @param string \$from The sql from statement
379
     * @param mixed \$filter The filter bag (see TDBMService::findObjects for complete description)
380
     * @param array \$parameters The parameters associated with the filter
381
     * @param mixed \$orderBy The order string
382
     * @param int \$mode Either TDBMService::MODE_ARRAY or TDBMService::MODE_CURSOR (for large datasets). Defaults to TDBMService::MODE_ARRAY.
383
     * @return {$beanClassWithoutNameSpace}[]|ResultIterator|ResultArray
384
     */
385
    protected function findFromSql(\$from, \$filter = null, array \$parameters = [], \$orderBy = null, \$mode = null) : iterable
386
    {
387
        if (\$this->defaultSort && \$orderBy == null) {
388
            \$orderBy = '$tableName.'.\$this->defaultSort.' '.\$this->defaultDirection;
389
        }
390
        return \$this->tdbmService->findObjectsFromSql('$tableName', \$from, \$filter, \$parameters, \$orderBy, \$mode);
391
    }
392
393
    /**
394
     * Get a single $beanClassWithoutNameSpace specified by its filters.
395
     *
396
     * @param mixed \$filter The filter bag (see TDBMService::findObjects for complete description)
397
     * @param array \$parameters The parameters associated with the filter
398
     * @param array \$additionalTablesFetch A list of additional tables to fetch (for performance improvement)
399
     * @return $beanClassWithoutNameSpace|null
400
     */
401
    protected function findOne(\$filter = null, array \$parameters = [], array \$additionalTablesFetch = []) : ?$beanClassWithoutNameSpace
402
    {
403
        return \$this->tdbmService->findObject('$tableName', \$filter, \$parameters, \$additionalTablesFetch);
404
    }
405
406
    /**
407
     * Get a single $beanClassWithoutNameSpace specified by its filters.
408
     * Unlike the `find` method that guesses the FROM part of the statement, here you can pass the \$from part.
409
     *
410
     * You should not put an alias on the main table name. So your \$from variable should look like:
411
     *
412
     *   \"$tableName JOIN ... ON ...\"
413
     *
414
     * @param string \$from The sql from statement
415
     * @param mixed \$filter The filter bag (see TDBMService::findObjects for complete description)
416
     * @param array \$parameters The parameters associated with the filter
417
     * @return $beanClassWithoutNameSpace|null
418
     */
419
    protected function findOneFromSql(\$from, \$filter = null, array \$parameters = []) : ?$beanClassWithoutNameSpace
420
    {
421
        return \$this->tdbmService->findObjectFromSql('$tableName', \$from, \$filter, \$parameters);
422
    }
423
424
    /**
425
     * Sets the default column for default sorting.
426
     *
427
     * @param string \$defaultSort
428
     */
429
    public function setDefaultSort(string \$defaultSort) : void
430
    {
431
        \$this->defaultSort = \$defaultSort;
432
    }
433
";
434
435
        $str .= $findByDaoCode;
436
        $str .= '}
437
';
438
439
        $possibleBaseFileName = $this->configuration->getPathFinder()->getPath($daonamespace.'\\Generated\\'.$baseClassName)->getPathname();
440
441
        $this->ensureDirectoryExist($possibleBaseFileName);
442
        file_put_contents($possibleBaseFileName, $str);
443
        @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...
444
445
        $possibleFileName = $this->configuration->getPathFinder()->getPath($daonamespace.'\\'.$className)->getPathname();
446
447
        // Now, let's generate the "editable" class
448 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...
449
            $str = "<?php
450
451
/*
452
 * This file has been automatically generated by TDBM.
453
 * You can edit this file as it will not be overwritten.
454
 */
455
456
namespace {$daonamespace};
457
458
use {$daonamespace}\\Generated\\{$baseClassName};
459
460
/**
461
 * The $className class will maintain the persistence of $beanClassWithoutNameSpace class into the $tableName table.
462
 */
463
class $className extends $baseClassName
464
{
465
}
466
";
467
            $this->ensureDirectoryExist($possibleFileName);
468
            file_put_contents($possibleFileName, $str);
469
            @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...
470
        }
471
    }
472
473
    /**
474
     * Generates the factory bean.
475
     *
476
     * @param Table[] $tableList
477
     * @throws TDBMException
478
     */
479
    private function generateFactory(array $tableList) : void
480
    {
481
        $daoNamespace = $this->configuration->getDaoNamespace();
482
        $daoFactoryClassName = $this->namingStrategy->getDaoFactoryClassName();
483
484
        // For each table, let's write a property.
485
486
        $str = "<?php
487
488
/*
489
 * This file has been automatically generated by TDBM.
490
 * DO NOT edit this file, as it might be overwritten.
491
 */
492
493
namespace {$daoNamespace}\\Generated;
494
495
";
496
        foreach ($tableList as $table) {
497
            $tableName = $table->getName();
498
            $daoClassName = $this->namingStrategy->getDaoClassName($tableName);
499
            $str .= "use {$daoNamespace}\\".$daoClassName.";\n";
500
        }
501
502
        $str .= "
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->namingStrategy->getDaoClassName($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.'() : '.$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.') : void
537
    {
538
        $this->'.$daoInstanceName.' = $'.$daoInstanceName.';
539
    }';
540
        }
541
542
        $str .= '
543
}
544
';
545
546
        $possibleFileName = $this->configuration->getPathFinder()->getPath($daoNamespace.'\\Generated\\'.$daoFactoryClassName)->getPathname();
547
548
        $this->ensureDirectoryExist($possibleFileName);
549
        file_put_contents($possibleFileName, $str);
550
        @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...
551
    }
552
553
    /**
554
     * Transforms a string to camelCase (except the first letter will be uppercase too).
555
     * Underscores and spaces are removed and the first letter after the underscore is uppercased.
556
     *
557
     * @param $str string
558
     *
559
     * @return string
560
     */
561
    public static function toCamelCase($str)
562
    {
563
        $str = strtoupper(substr($str, 0, 1)).substr($str, 1);
564
        while (true) {
565
            if (strpos($str, '_') === false && strpos($str, ' ') === false) {
566
                break;
567
            }
568
569
            $pos = strpos($str, '_');
570
            if ($pos === false) {
571
                $pos = strpos($str, ' ');
572
            }
573
            $before = substr($str, 0, $pos);
574
            $after = substr($str, $pos + 1);
575
            $str = $before.strtoupper(substr($after, 0, 1)).substr($after, 1);
576
        }
577
578
        return $str;
579
    }
580
581
    /**
582
     * Tries to put string to the singular form (if it is plural).
583
     * We assume the table names are in english.
584
     *
585
     * @param $str string
586
     *
587
     * @return string
588
     */
589
    public static function toSingular($str)
590
    {
591
        return Inflector::singularize($str);
592
    }
593
594
    /**
595
     * Put the first letter of the string in lower case.
596
     * Very useful to transform a class name into a variable name.
597
     *
598
     * @param $str string
599
     *
600
     * @return string
601
     */
602
    public static function toVariableName($str)
603
    {
604
        return strtolower(substr($str, 0, 1)).substr($str, 1);
605
    }
606
607
    /**
608
     * Ensures the file passed in parameter can be written in its directory.
609
     *
610
     * @param string $fileName
611
     *
612
     * @throws TDBMException
613
     */
614
    private function ensureDirectoryExist($fileName)
615
    {
616
        $dirName = dirname($fileName);
617
        if (!file_exists($dirName)) {
618
            $old = umask(0);
619
            $result = mkdir($dirName, 0775, true);
620
            umask($old);
621
            if ($result === false) {
622
                throw new TDBMException("Unable to create directory: '".$dirName."'.");
623
            }
624
        }
625
    }
626
627
    /**
628
     * Absolute path to composer json file.
629
     *
630
     * @param string $composerFile
631
     */
632
    /*public function setComposerFile($composerFile)
0 ignored issues
show
Unused Code Comprehensibility introduced by
53% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
633
    {
634
        $this->rootPath = dirname($composerFile).'/';
635
        $this->composerFile = basename($composerFile);
636
    }*/
637
638
    /**
639
     * Transforms a DBAL type into a PHP type (for PHPDoc purpose).
640
     *
641
     * @param Type $type The DBAL type
642
     *
643
     * @return string The PHP type
644
     */
645
    public static function dbalTypeToPhpType(Type $type)
646
    {
647
        $map = [
648
            Type::TARRAY => 'array',
649
            Type::SIMPLE_ARRAY => 'array',
650
            'json' => 'array',  // 'json' is supported from Doctrine DBAL 2.6 only.
651
            Type::JSON_ARRAY => 'array',
652
            Type::BIGINT => 'string',
653
            Type::BOOLEAN => 'bool',
654
            Type::DATETIME => '\DateTimeInterface',
655
            Type::DATETIMETZ => '\DateTimeInterface',
656
            Type::DATE => '\DateTimeInterface',
657
            Type::TIME => '\DateTimeInterface',
658
            Type::DECIMAL => 'float',
659
            Type::INTEGER => 'int',
660
            Type::OBJECT => 'string',
661
            Type::SMALLINT => 'int',
662
            Type::STRING => 'string',
663
            Type::TEXT => 'string',
664
            Type::BINARY => 'string',
665
            Type::BLOB => 'string',
666
            Type::FLOAT => 'float',
667
            Type::GUID => 'string',
668
        ];
669
670
        return isset($map[$type->getName()]) ? $map[$type->getName()] : $type->getName();
671
    }
672
}
673