Completed
Pull Request — 3.4 (#46)
by David
22:22 queued 03:02
created

TDBMDaoGenerator::toVariableName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 3
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
namespace Mouf\Database\TDBM\Utils;
3
4
use Doctrine\Common\Inflector\Inflector;
5
use Doctrine\DBAL\Driver\Connection;
6
use Doctrine\DBAL\Schema\Column;
7
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
8
use Doctrine\DBAL\Schema\Schema;
9
use Doctrine\DBAL\Schema\Table;
10
use Doctrine\DBAL\Types\Type;
11
use Mouf\Composer\ClassNameMapper;
12
use Mouf\Database\SchemaAnalyzer\SchemaAnalyzer;
13
use Mouf\Database\TDBM\TDBMException;
14
use Mouf\Database\TDBM\TDBMSchemaAnalyzer;
15
16
17
/**
18
 * This class generates automatically DAOs and Beans for TDBM.
19
 *
20
 */
21
class TDBMDaoGenerator {
22
23
    /**
24
     * 
25
     * @var SchemaAnalyzer
26
     */
27
    private $schemaAnalyzer;
28
29
    /**
30
     *
31
     * @var Schema
32
     */
33
    private $schema;
34
35
    /**
36
     * The root directory of the project.
37
     *
38
     * @var string
39
     */
40
    private $rootPath;
41
42
    /**
43
     * @var TDBMSchemaAnalyzer
44
     */
45
    private $tdbmSchemaAnalyzer;
46
47
    /**
48
     * Constructor.
49
     *
50
     * @param Connection $dbConnection The connection to the database.
0 ignored issues
show
Bug introduced by
There is no parameter named $dbConnection. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
51
     */
52 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...
53
        $this->schemaAnalyzer = $schemaAnalyzer;
54
        $this->schema = $schema;
55
        $this->tdbmSchemaAnalyzer = $tdbmSchemaAnalyzer;
56
        $this->rootPath = __DIR__."/../../../../../../../../";
57
    }
58
59
    /**
60
     * Generates all the daos and beans.
61
     *
62
     * @param string $daoFactoryClassName The classe name of the DAO factory
63
     * @param string $daonamespace The namespace for the DAOs, without trailing \
64
     * @param string $beannamespace The Namespace for the beans, without trailing \
65
     * @param bool $storeInUtc If the generated daos should store the date in UTC timezone instead of user's timezone.
66
     * @return \string[] the list of tables
67
     * @throws TDBMException
68
     */
69
    public function generateAllDaosAndBeans($daoFactoryClassName, $daonamespace, $beannamespace, $storeInUtc) {
70
        // TODO: extract ClassNameMapper in its own package!
71
        $classNameMapper = ClassNameMapper::createFromComposerFile($this->rootPath.'composer.json');
72
73
        // TODO: check that no class name ends with "Base". Otherwise, there will be name clash.
74
75
        $tableList = $this->schema->getTables();
76
77
        // Remove all beans and daos from junction tables
78
        $junctionTables = $this->schemaAnalyzer->detectJunctionTables();
79
        $junctionTableNames = array_map(function(Table $table) {
80
            return $table->getName();
81
        }, $junctionTables);
82
83
        $tableList = array_filter($tableList, function(Table $table) use ($junctionTableNames) {
84
            return !in_array($table->getName(), $junctionTableNames);
85
        });
86
87
        foreach ($tableList as $table) {
88
            $this->generateDaoAndBean($table, $daonamespace, $beannamespace, $classNameMapper, $storeInUtc);
89
        }
90
        
91
        $this->generateFactory($tableList, $daoFactoryClassName, $daonamespace, $classNameMapper);
92
93
        // Ok, let's return the list of all tables.
94
        // These will be used by the calling script to create Mouf instances.
95
        
96
        return array_map(function(Table $table) { return $table->getName(); },$tableList);
97
    }
98
    
99
    /**
100
     * Generates in one method call the daos and the beans for one table.
101
     * 
102
     * @param $tableName
103
     */
104
    public function generateDaoAndBean(Table $table, $daonamespace, $beannamespace, ClassNameMapper $classNameMapper, $storeInUtc) {
105
		$tableName = $table->getName();
106
        $daoName = $this->getDaoNameFromTableName($tableName);
107
        $beanName = $this->getBeanNameFromTableName($tableName);
108
        $baseBeanName = $this->getBaseBeanNameFromTableName($tableName);
109
        $baseDaoName = $this->getBaseDaoNameFromTableName($tableName);
110
111
        $this->generateBean($beanName, $baseBeanName, $table, $beannamespace, $classNameMapper, $storeInUtc);
112
        $this->generateDao($daoName, $baseDaoName, $beanName, $table, $daonamespace, $beannamespace, $classNameMapper);
113
    }
114
    
115
    /**
116
     * Returns the name of the bean class from the table name.
117
     * 
118
     * @param $tableName
119
     * @return string
120
     */
121
    public static function getBeanNameFromTableName($tableName) {
122
        return TDBMDaoGenerator::toSingular(TDBMDaoGenerator::toCamelCase($tableName))."Bean";
123
    }
124
    
125
    /**
126
     * Returns the name of the DAO class from the table name.
127
     * 
128
     * @param $tableName
129
     * @return string
130
     */
131
    public static function getDaoNameFromTableName($tableName) {
132
        return TDBMDaoGenerator::toSingular(TDBMDaoGenerator::toCamelCase($tableName))."Dao";
133
    }
134
    
135
    /**
136
     * Returns the name of the base bean class from the table name.
137
     * 
138
     * @param $tableName
139
     * @return string
140
     */
141
    public static function getBaseBeanNameFromTableName($tableName) {
142
        return TDBMDaoGenerator::toSingular(TDBMDaoGenerator::toCamelCase($tableName))."BaseBean";
143
    }
144
145
    /**
146
     * Returns the name of the base DAO class from the table name.
147
     *
148
     * @param $tableName
149
     * @return string
150
     */
151
    public static function getBaseDaoNameFromTableName($tableName) {
152
        return TDBMDaoGenerator::toSingular(TDBMDaoGenerator::toCamelCase($tableName))."BaseDao";
153
    }
154
155
    /**
156
     * Writes the PHP bean file with all getters and setters from the table passed in parameter.
157
     *
158
     * @param string $className The name of the class
159
     * @param string $baseClassName The name of the base class which will be extended (name only, no directory)
160
     * @param Table $table The table
161
     * @param string $beannamespace The namespace of the bean
162
     * @param ClassNameMapper $classNameMapper
163
     * @throws TDBMException
164
     */
165
    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...
166
167
        $beanDescriptor = new BeanDescriptor($table, $this->schemaAnalyzer, $this->schema, $this->tdbmSchemaAnalyzer);
168
169
        $str = $beanDescriptor->generatePhpCode($beannamespace);
170
171
        $possibleBaseFileNames = $classNameMapper->getPossibleFileNames($beannamespace."\\".$baseClassName);
172
        if (!$possibleBaseFileNames) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $possibleBaseFileNames of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
173
            throw new TDBMException('Sorry, autoload namespace issue. The class "'.$beannamespace."\\".$baseClassName.'" is not autoloadable.');
174
        }
175
        $possibleBaseFileName = $this->rootPath.$possibleBaseFileNames[0];
176
177
        $this->ensureDirectoryExist($possibleBaseFileName);
178
        file_put_contents($possibleBaseFileName, $str);
179
        @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...
180
181
182
183
        $possibleFileNames = $classNameMapper->getPossibleFileNames($beannamespace."\\".$className);
184
        if (!$possibleFileNames) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $possibleFileNames of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
185
            // @codeCoverageIgnoreStart
186
            throw new TDBMException('Sorry, autoload namespace issue. The class "'.$beannamespace."\\".$className.'" is not autoloadable.');
187
            // @codeCoverageIgnoreEnd
188
        }
189
        $possibleFileName = $this->rootPath.$possibleFileNames[0];
190
191 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...
192
            $tableName = $table->getName();
193
194
            $str = "<?php
195
/*
196
 * This file has been automatically generated by TDBM.
197
 * You can edit this file as it will not be overwritten.
198
 */
199
200
namespace {$beannamespace};
201
 
202
/**
203
 * The $className class maps the '$tableName' table in database.
204
 */
205
class $className extends $baseClassName 
206
{
207
208
}";
209
            $this->ensureDirectoryExist($possibleFileName);
210
            file_put_contents($possibleFileName ,$str);
211
            @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...
212
        }
213
    }
214
215
    /**
216
     * Writes the PHP bean DAO with simple functions to create/get/save objects.
217
     *
218
     * @param string $fileName The file that will be written (without the directory)
0 ignored issues
show
Bug introduced by
There is no parameter named $fileName. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
219
     * @param string $className The name of the class
220
     * @param string $tableName The name of the table
0 ignored issues
show
Bug introduced by
There is no parameter named $tableName. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
221
     */
222
    public function generateDao($className, $baseClassName, $beanClassName, Table $table, $daonamespace, $beannamespace, ClassNameMapper $classNameMapper) {
223
        $tableName = $table->getName();
224
        $primaryKeyColumns = $table->getPrimaryKeyColumns();
225
226
        $defaultSort = null;
227
        foreach ($table->getColumns() as $column) {
228
            $comments = $column->getComment();
229
            $matches = array();
230
            if (preg_match('/@defaultSort(\((desc|asc)\))*/', $comments, $matches) != 0){
231
                $defaultSort = $data['column_name'];
0 ignored issues
show
Bug introduced by
The variable $data does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
232
                if (count($matches == 3)){
233
                    $defaultSortDirection = $matches[2];
234
                }else{
235
                    $defaultSortDirection = 'ASC';
236
                }
237
            }
238
        }
239
240
        // FIXME: lowercase tables with _ in the name should work!
241
        $tableCamel = self::toSingular(self::toCamelCase($tableName));
242
        
243
        $beanClassWithoutNameSpace = $beanClassName;
244
        $beanClassName = $beannamespace."\\".$beanClassName;
245
        
246
        $str = "<?php
247
248
/*
249
 * This file has been automatically generated by TDBM.
250
 * DO NOT edit this file, as it might be overwritten.
251
 * If you need to perform changes, edit the $className class instead!
252
 */
253
254
namespace {$daonamespace};
255
256
use Mouf\\Database\\TDBM\\TDBMService;
257
use Mouf\\Database\\TDBM\\ResultIterator;
258
use Mouf\\Database\\TDBM\\ArrayIterator;
259
use $beanClassName;
260
261
/**
262
 * The $baseClassName class will maintain the persistence of $beanClassWithoutNameSpace class into the $tableName table.
263
 * 
264
 */
265
class $baseClassName
266
{
267
268
    /**
269
     * @var TDBMService
270
     */
271
    protected \$tdbmService;
272
    
273
    /**
274
     * The default sort column.
275
     *
276
     * @var string
277
     */
278
    private \$defaultSort = ".($defaultSort ? "'$defaultSort'" : 'null').";
279
    
280
    /**
281
     * The default sort direction.
282
     *
283
     * @var string
284
     */
285
    private \$defaultDirection = ".($defaultSort && $defaultSortDirection ? "'$defaultSortDirection'" : "'asc'").";
0 ignored issues
show
Bug introduced by
The variable $defaultSortDirection does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
286
    
287
    /**
288
     * Sets the TDBM service used by this DAO.
289
     *
290
     * @param TDBMService \$tdbmService
291
     */
292
    public function __construct(TDBMService \$tdbmService)
293
    {
294
        \$this->tdbmService = \$tdbmService;
295
    }
296
297
    /**
298
     * Return a new instance of $beanClassWithoutNameSpace object, that will be persisted in database.
299
     *
300
     * @return $beanClassWithoutNameSpace
301
     */// TODO!
302
    /*public function create()
303
    {
304
        return \$this->tdbmService->getNewObject('$tableName', true);
305
    }*/
306
    
307
    /**
308
     * Persist the $beanClassWithoutNameSpace instance.
309
     *
310
     * @param $beanClassWithoutNameSpace \$obj The bean to save.
311
     */
312
    public function save($beanClassWithoutNameSpace \$obj)
313
    {
314
        \$this->tdbmService->save(\$obj);
315
    }
316
317
    /**
318
     * Get all $tableCamel records. 
319
     *
320
     * @return {$beanClassWithoutNameSpace}[]|ResultIterator|ResultArray
321
     */
322
    public function findAll()
323
    {
324
        if (\$this->defaultSort) {
325
            \$orderBy = '$tableName.'.\$this->defaultSort.' '.\$this->defaultDirection;
326
        } else {
327
            \$orderBy = null;
328
        }
329
        return \$this->tdbmService->findObjects('$tableName',  null, [], \$orderBy);
330
    }
331
    ";
332
333
        if (count($primaryKeyColumns) === 1) {
334
            $primaryKeyColumn = $primaryKeyColumns[0];
335
            $str .= "
336
    /**
337
     * Get $beanClassWithoutNameSpace specified by its ID (its primary key)
338
     * If the primary key does not exist, an exception is thrown.
339
     *
340
     * @param string|int \$id
341
     * @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.
342
     * @return $beanClassWithoutNameSpace
343
     * @throws TDBMException
344
     */
345
    public function getById(\$id, \$lazyLoading = false)
346
    {
347
        return \$this->tdbmService->findObjectByPk('$tableName', ['$primaryKeyColumn' => \$id], [], \$lazyLoading);
348
    }
349
    ";
350
        }
351
        $str .= "
352
    /**
353
     * Deletes the $beanClassWithoutNameSpace passed in parameter.
354
     *
355
     * @param $beanClassWithoutNameSpace \$obj object to delete
356
     * @param bool \$cascade if true, it will delete all object linked to \$obj
357
     */
358
    public function delete($beanClassWithoutNameSpace \$obj, \$cascade = false)
359
    {
360
        if (\$cascade === true) {
361
            \$this->tdbmService->deleteCascade(\$obj);
362
        } else {
363
            \$this->tdbmService->delete(\$obj);
364
        }
365
    }
366
367
368
    /**
369
     * Get a list of $beanClassWithoutNameSpace specified by its filters.
370
     *
371
     * @param mixed \$filter The filter bag (see TDBMService::findObjects for complete description)
372
     * @param array \$parameters The parameters associated with the filter
373
     * @param mixed \$orderby The order string
374
     * @param array \$additionalTablesFetch A list of additional tables to fetch (for performance improvement)
375
     * @param string \$mode Either TDBMService::MODE_ARRAY or TDBMService::MODE_CURSOR (for large datasets). Defaults to TDBMService::MODE_ARRAY.
376
     * @return {$beanClassWithoutNameSpace}[]|ResultIterator|ResultArray
377
     */
378
    protected function find(\$filter=null, array \$parameters = [], \$orderby=null, array \$additionalTablesFetch = array(), \$mode = null)
379
    {
380
        if (\$this->defaultSort && \$orderby == null) {
381
            \$orderby = '$tableName.'.\$this->defaultSort.' '.\$this->defaultDirection;
382
        }
383
        return \$this->tdbmService->findObjects('$tableName', \$filter, \$parameters, \$orderby, \$additionalTablesFetch, \$mode);
384
    }
385
386
    /**
387
     * Get a single $beanClassWithoutNameSpace specified by its filters.
388
     *
389
     * @param mixed \$filter The filter bag (see TDBMService::findObjects for complete description)
390
     * @param array \$parameters The parameters associated with the filter
391
     * @return $beanClassWithoutNameSpace
392
     */
393
    protected function findOne(\$filter=null, array \$parameters = [])
394
    {
395
        return \$this->tdbmService->findObject('$tableName', \$filter, \$parameters);
396
    }
397
    
398
    /**
399
     * Sets the default column for default sorting.
400
     *
401
     * @param string \$defaultSort
402
     */
403
    public function setDefaultSort(\$defaultSort)
404
    {
405
        \$this->defaultSort = \$defaultSort;
406
    }
407
    ";
408
409
$str .= "
410
}
411
";
412
413
        $possibleBaseFileNames = $classNameMapper->getPossibleFileNames($daonamespace."\\".$baseClassName);
414
        if (!$possibleBaseFileNames) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $possibleBaseFileNames of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
415
            // @codeCoverageIgnoreStart
416
            throw new TDBMException('Sorry, autoload namespace issue. The class "'.$baseClassName.'" is not autoloadable.');
417
            // @codeCoverageIgnoreEnd
418
        }
419
        $possibleBaseFileName = $this->rootPath.$possibleBaseFileNames[0];
420
421
        $this->ensureDirectoryExist($possibleBaseFileName);
422
        file_put_contents($possibleBaseFileName ,$str);
423
        @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...
424
425
        $possibleFileNames = $classNameMapper->getPossibleFileNames($daonamespace."\\".$className);
426
        if (!$possibleFileNames) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $possibleFileNames of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
427
            // @codeCoverageIgnoreStart
428
            throw new TDBMException('Sorry, autoload namespace issue. The class "'.$className.'" is not autoloadable.');
429
            // @codeCoverageIgnoreEnd
430
        }
431
        $possibleFileName = $this->rootPath.$possibleFileNames[0];
432
        
433
        // Now, let's generate the "editable" class
434 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...
435
            $str = "<?php
436
437
/*
438
 * This file has been automatically generated by TDBM.
439
 * You can edit this file as it will not be overwritten.
440
 */
441
442
namespace {$daonamespace};
443
444
/**
445
 * The $className class will maintain the persistence of $beanClassWithoutNameSpace class into the $tableName table.
446
 */
447
class $className extends $baseClassName
448
{
449
450
}
451
";
452
            $this->ensureDirectoryExist($possibleFileName);
453
            file_put_contents($possibleFileName ,$str);
454
            @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...
455
        }
456
    }
457
458
459
460
    /**
461
     * Generates the factory bean.
462
     * 
463
     * @param Table[] $tableList
464
     */
465
    private function generateFactory(array $tableList, $daoFactoryClassName, $daoNamespace, ClassNameMapper $classNameMapper) {
466
        // For each table, let's write a property.
467
        
468
        $str = "<?php
469
470
/*
471
 * This file has been automatically generated by TDBM.
472
 * DO NOT edit this file, as it might be overwritten.
473
 */
474
475
namespace {$daoNamespace};
476
        
477
/**
478
 * The $daoFactoryClassName provides an easy access to all DAOs generated by TDBM.
479
 *
480
 */
481
class $daoFactoryClassName 
482
{
483
";
484
485
        foreach ($tableList as $table) {
486
            $tableName = $table->getName();
487
            $daoClassName = $this->getDaoNameFromTableName($tableName);
488
            $daoInstanceName = self::toVariableName($daoClassName);
489
            
490
            $str .= '    /**
491
     * @var '.$daoClassName.'
492
     */
493
    private $'.$daoInstanceName.';
494
495
    /**
496
     * Returns an instance of the '.$daoClassName.' class.
497
     * 
498
     * @return '.$daoClassName.'
499
     */
500
    public function get'.$daoClassName.'()
501
    {
502
        return $this->'.$daoInstanceName.';
503
    }
504
    
505
    /**
506
     * Sets the instance of the '.$daoClassName.' class that will be returned by the factory getter.
507
     *
508
     * @param '.$daoClassName.' $'.$daoInstanceName.'
509
     */
510
    public function set'.$daoClassName.'('.$daoClassName.' $'.$daoInstanceName.') {
511
        $this->'.$daoInstanceName.' = $'.$daoInstanceName.';
512
    }
513
    
514
';
515
        }
516
        
517
        
518
        $str .= '
519
}
520
';
521
522
        $possibleFileNames = $classNameMapper->getPossibleFileNames($daoNamespace."\\".$daoFactoryClassName);
523
        if (!$possibleFileNames) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $possibleFileNames of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
524
            throw new TDBMException('Sorry, autoload namespace issue. The class "'.$daoNamespace."\\".$daoFactoryClassName.'" is not autoloadable.');
525
        }
526
        $possibleFileName = $this->rootPath.$possibleFileNames[0];
527
528
        $this->ensureDirectoryExist($possibleFileName);
529
        file_put_contents($possibleFileName ,$str);
530
        @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...
531
    }
532
533
    /**
534
     * Transforms a string to camelCase (except the first letter will be uppercase too).
535
     * Underscores and spaces are removed and the first letter after the underscore is uppercased.
536
     * 
537
     * @param $str string
538
     * @return string
539
     */
540
    public static function toCamelCase($str) {
541
        $str = strtoupper(substr($str,0,1)).substr($str,1);
542
        while (true) {
543
            if (strpos($str, "_") === false && strpos($str, " ") === false) {
544
                break;
545
			}
546
                
547
            $pos = strpos($str, "_");
548
            if ($pos === false) {
549
                $pos = strpos($str, " ");
550
            }
551
            $before = substr($str,0,$pos);
552
            $after = substr($str,$pos+1);
553
            $str = $before.strtoupper(substr($after,0,1)).substr($after,1);
554
        }
555
        return $str;
556
    }
557
    
558
    /**
559
     * Tries to put string to the singular form (if it is plural).
560
     * We assume the table names are in english.
561
     *
562
     * @param $str string
563
     * @return string
564
     */
565
    public static function toSingular($str) {
566
        return Inflector::singularize($str);
567
    }
568
    
569
    /**
570
     * Put the first letter of the string in lower case.
571
     * Very useful to transform a class name into a variable name.
572
     * 
573
     * @param $str string
574
     * @return string
575
     */
576
    public static function toVariableName($str) {
577
        return strtolower(substr($str, 0, 1)).substr($str, 1);
578
    }
579
580
    /**
581
     * Ensures the file passed in parameter can be written in its directory.
582
     * @param string $fileName
583
     * @throws TDBMException
584
     */
585
    private function ensureDirectoryExist($fileName) {
586
        $dirName = dirname($fileName);
587
        if (!file_exists($dirName)) {
588
            $old = umask(0);
589
            $result = mkdir($dirName, 0775, true);
590
            umask($old);
591
            if ($result === false) {
592
                throw new TDBMException("Unable to create directory: '".$dirName."'.");
593
            }
594
        }
595
    }
596
597
    /**
598
     * @param string $rootPath
599
     */
600
    public function setRootPath($rootPath)
601
    {
602
        $this->rootPath = $rootPath;
603
    }
604
605
    /**
606
     * Transforms a DBAL type into a PHP type (for PHPDoc purpose)
607
     *
608
     * @param Type $type The DBAL type
609
     * @return string The PHP type
610
     */
611
    public static function dbalTypeToPhpType(Type $type) {
612
        $map = [
613
            Type::TARRAY => 'array',
614
            Type::SIMPLE_ARRAY => 'array',
615
            Type::JSON_ARRAY => 'array',
616
            Type::BIGINT => 'string',
617
            Type::BOOLEAN => 'bool',
618
            Type::DATETIME => '\DateTimeInterface',
619
            Type::DATETIMETZ => '\DateTimeInterface',
620
            Type::DATE => '\DateTimeInterface',
621
            Type::TIME => '\DateTimeInterface',
622
            Type::DECIMAL => 'float',
623
            Type::INTEGER => 'int',
624
            Type::OBJECT => 'string',
625
            Type::SMALLINT => 'int',
626
            Type::STRING => 'string',
627
            Type::TEXT => 'string',
628
            Type::BINARY => 'string',
629
            Type::BLOB => 'string',
630
            Type::FLOAT => 'float',
631
            Type::GUID => 'string'
632
        ];
633
634
        return isset($map[$type->getName()])?$map[$type->getName()]:$type->getName();
635
    }
636
637
    /**
638
     *
639
     * @param string $beanNamespace
640
     * @return \string[] Returns a map mapping table name to beans name
641
     */
642
    public function buildTableToBeanMap($beanNamespace) {
643
        $tableToBeanMap = [];
644
645
        $tables = $this->schema->getTables();
646
647
        foreach ($tables as $table) {
648
            $tableName = $table->getName();
649
            $tableToBeanMap[$tableName] = $beanNamespace . "\\" . self::getBeanNameFromTableName($tableName);
650
        }
651
        return $tableToBeanMap;
652
    }
653
}
654