Passed
Pull Request — master (#116)
by David
04:56
created

BeanDescriptor::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 11
dl 0
loc 13
rs 9.9
c 0
b 0
f 0
cc 1
nc 1
nop 10

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
declare(strict_types=1);
3
4
namespace TheCodingMachine\TDBM\Utils;
5
6
use Doctrine\DBAL\Schema\Column;
7
use Doctrine\DBAL\Schema\Index;
8
use Doctrine\DBAL\Schema\Schema;
9
use Doctrine\DBAL\Schema\Table;
10
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
11
use JsonSerializable;
12
use Mouf\Database\SchemaAnalyzer\SchemaAnalyzer;
13
use PhpParser\Comment\Doc;
14
use Ramsey\Uuid\Uuid;
15
use TheCodingMachine\TDBM\AbstractTDBMObject;
16
use TheCodingMachine\TDBM\AlterableResultIterator;
17
use TheCodingMachine\TDBM\ResultIterator;
18
use TheCodingMachine\TDBM\SafeFunctions;
19
use TheCodingMachine\TDBM\TDBMException;
20
use TheCodingMachine\TDBM\TDBMSchemaAnalyzer;
21
use TheCodingMachine\TDBM\TDBMService;
22
use TheCodingMachine\TDBM\Utils\Annotation\AnnotationParser;
23
use Zend\Code\Generator\ClassGenerator;
24
use Zend\Code\Generator\DocBlock\Tag\ParamTag;
25
use Zend\Code\Generator\DocBlock\Tag\ReturnTag;
26
use Zend\Code\Generator\DocBlock\Tag\ThrowsTag;
27
use Zend\Code\Generator\DocBlock\Tag\VarTag;
28
use Zend\Code\Generator\DocBlockGenerator;
29
use Zend\Code\Generator\FileGenerator;
30
use Zend\Code\Generator\MethodGenerator;
31
use Zend\Code\Generator\ParameterGenerator;
32
use Zend\Code\Generator\PropertyGenerator;
33
34
/**
35
 * This class represents a bean.
36
 */
37
class BeanDescriptor implements BeanDescriptorInterface
38
{
39
    /**
40
     * @var Table
41
     */
42
    private $table;
43
44
    /**
45
     * @var SchemaAnalyzer
46
     */
47
    private $schemaAnalyzer;
48
49
    /**
50
     * @var Schema
51
     */
52
    private $schema;
53
54
    /**
55
     * @var AbstractBeanPropertyDescriptor[]
56
     */
57
    private $beanPropertyDescriptors = [];
58
59
    /**
60
     * @var TDBMSchemaAnalyzer
61
     */
62
    private $tdbmSchemaAnalyzer;
63
64
    /**
65
     * @var NamingStrategyInterface
66
     */
67
    private $namingStrategy;
68
    /**
69
     * @var string
70
     */
71
    private $beanNamespace;
72
    /**
73
     * @var string
74
     */
75
    private $generatedBeanNamespace;
76
    /**
77
     * @var AnnotationParser
78
     */
79
    private $annotationParser;
80
    /**
81
     * @var string
82
     */
83
    private $daoNamespace;
84
    /**
85
     * @var string
86
     */
87
    private $generatedDaoNamespace;
88
89
    public function __construct(Table $table, string $beanNamespace, string $generatedBeanNamespace, string $daoNamespace, string $generatedDaoNamespace, SchemaAnalyzer $schemaAnalyzer, Schema $schema, TDBMSchemaAnalyzer $tdbmSchemaAnalyzer, NamingStrategyInterface $namingStrategy, AnnotationParser $annotationParser)
90
    {
91
        $this->table = $table;
92
        $this->beanNamespace = $beanNamespace;
93
        $this->generatedBeanNamespace = $generatedBeanNamespace;
94
        $this->daoNamespace = $daoNamespace;
95
        $this->generatedDaoNamespace = $generatedDaoNamespace;
96
        $this->schemaAnalyzer = $schemaAnalyzer;
97
        $this->schema = $schema;
98
        $this->tdbmSchemaAnalyzer = $tdbmSchemaAnalyzer;
99
        $this->namingStrategy = $namingStrategy;
100
        $this->annotationParser = $annotationParser;
101
        $this->initBeanPropertyDescriptors();
102
    }
103
104
    private function initBeanPropertyDescriptors(): void
105
    {
106
        $this->beanPropertyDescriptors = $this->getProperties($this->table);
107
    }
108
109
    /**
110
     * Returns the foreign-key the column is part of, if any. null otherwise.
111
     *
112
     * @param Table  $table
113
     * @param Column $column
114
     *
115
     * @return ForeignKeyConstraint|null
116
     */
117
    private function isPartOfForeignKey(Table $table, Column $column) : ?ForeignKeyConstraint
118
    {
119
        $localColumnName = $column->getName();
120
        foreach ($table->getForeignKeys() as $foreignKey) {
121
            foreach ($foreignKey->getUnquotedLocalColumns() as $columnName) {
122
                if ($columnName === $localColumnName) {
123
                    return $foreignKey;
124
                }
125
            }
126
        }
127
128
        return null;
129
    }
130
131
    /**
132
     * @return AbstractBeanPropertyDescriptor[]
133
     */
134
    public function getBeanPropertyDescriptors(): array
135
    {
136
        return $this->beanPropertyDescriptors;
137
    }
138
139
    /**
140
     * Returns the list of columns that are not nullable and not autogenerated for a given table and its parent.
141
     *
142
     * @return AbstractBeanPropertyDescriptor[]
143
     */
144
    public function getConstructorProperties(): array
145
    {
146
        $constructorProperties = array_filter($this->beanPropertyDescriptors, function (AbstractBeanPropertyDescriptor $property) {
147
            return $property->isCompulsory();
148
        });
149
150
        return $constructorProperties;
151
    }
152
153
    /**
154
     * Returns the list of columns that have default values for a given table.
155
     *
156
     * @return AbstractBeanPropertyDescriptor[]
157
     */
158
    public function getPropertiesWithDefault(): array
159
    {
160
        $properties = $this->getPropertiesForTable($this->table);
161
        $defaultProperties = array_filter($properties, function (AbstractBeanPropertyDescriptor $property) {
162
            return $property->hasDefault();
163
        });
164
165
        return $defaultProperties;
166
    }
167
168
    /**
169
     * Returns the list of properties exposed as getters and setters in this class.
170
     *
171
     * @return AbstractBeanPropertyDescriptor[]
172
     */
173
    public function getExposedProperties(): array
174
    {
175
        $exposedProperties = array_filter($this->beanPropertyDescriptors, function (AbstractBeanPropertyDescriptor $property) {
176
            return $property->getTable()->getName() == $this->table->getName();
177
        });
178
179
        return $exposedProperties;
180
    }
181
182
    /**
183
     * Returns the list of properties for this table (including parent tables).
184
     *
185
     * @param Table $table
186
     *
187
     * @return AbstractBeanPropertyDescriptor[]
188
     */
189
    private function getProperties(Table $table): array
190
    {
191
        // Security check: a table MUST have a primary key
192
        TDBMDaoGenerator::getPrimaryKeyColumnsOrFail($table);
193
194
        $parentRelationship = $this->schemaAnalyzer->getParentRelationship($table->getName());
195
        if ($parentRelationship) {
196
            $parentTable = $this->schema->getTable($parentRelationship->getForeignTableName());
197
            $properties = $this->getProperties($parentTable);
198
            // we merge properties by overriding property names.
199
            $localProperties = $this->getPropertiesForTable($table);
200
            foreach ($localProperties as $name => $property) {
201
                // We do not override properties if this is a primary key!
202
                if ($property->isPrimaryKey()) {
203
                    continue;
204
                }
205
                $properties[$name] = $property;
206
            }
207
        } else {
208
            $properties = $this->getPropertiesForTable($table);
209
        }
210
211
        return $properties;
212
    }
213
214
    /**
215
     * Returns the list of properties for this table (ignoring parent tables).
216
     *
217
     * @param Table $table
218
     *
219
     * @return AbstractBeanPropertyDescriptor[]
220
     */
221
    private function getPropertiesForTable(Table $table): array
222
    {
223
        $parentRelationship = $this->schemaAnalyzer->getParentRelationship($table->getName());
224
        if ($parentRelationship) {
225
            $ignoreColumns = $parentRelationship->getUnquotedLocalColumns();
226
        } else {
227
            $ignoreColumns = [];
228
        }
229
230
        $beanPropertyDescriptors = [];
231
        foreach ($table->getColumns() as $column) {
232
            if (array_search($column->getName(), $ignoreColumns) !== false) {
233
                continue;
234
            }
235
236
            $fk = $this->isPartOfForeignKey($table, $column);
237
            if ($fk !== null) {
238
                // Check that previously added descriptors are not added on same FK (can happen with multi key FK).
239
                foreach ($beanPropertyDescriptors as $beanDescriptor) {
240
                    if ($beanDescriptor instanceof ObjectBeanPropertyDescriptor && $beanDescriptor->getForeignKey() === $fk) {
241
                        continue 2;
242
                    }
243
                }
244
                // Check that this property is not an inheritance relationship
245
                $parentRelationship = $this->schemaAnalyzer->getParentRelationship($table->getName());
246
                if ($parentRelationship === $fk) {
247
                    continue;
248
                }
249
250
                $beanPropertyDescriptors[] = new ObjectBeanPropertyDescriptor($table, $fk, $this->namingStrategy, $this->beanNamespace);
251
            } else {
252
                $beanPropertyDescriptors[] = new ScalarBeanPropertyDescriptor($table, $column, $this->namingStrategy, $this->annotationParser);
253
            }
254
        }
255
256
        // Now, let's get the name of all properties and let's check there is no duplicate.
257
        /* @var $names AbstractBeanPropertyDescriptor[] */
258
        $names = [];
259
        foreach ($beanPropertyDescriptors as $beanDescriptor) {
260
            $name = $beanDescriptor->getGetterName();
261
            if (isset($names[$name])) {
262
                $names[$name]->useAlternativeName();
263
                $beanDescriptor->useAlternativeName();
264
            } else {
265
                $names[$name] = $beanDescriptor;
266
            }
267
        }
268
269
        // Final check (throw exceptions if problem arises)
270
        $names = [];
271
        foreach ($beanPropertyDescriptors as $beanDescriptor) {
272
            $name = $beanDescriptor->getGetterName();
273
            if (isset($names[$name])) {
274
                throw new TDBMException('Unsolvable name conflict while generating method name');
275
            } else {
276
                $names[$name] = $beanDescriptor;
277
            }
278
        }
279
280
        // Last step, let's rebuild the list with a map:
281
        $beanPropertyDescriptorsMap = [];
282
        foreach ($beanPropertyDescriptors as $beanDescriptor) {
283
            $beanPropertyDescriptorsMap[$beanDescriptor->getVariableName()] = $beanDescriptor;
284
        }
285
286
        return $beanPropertyDescriptorsMap;
287
    }
288
289
    private function generateBeanConstructor() : MethodGenerator
290
    {
291
        $constructorProperties = $this->getConstructorProperties();
292
293
        $constructor = new MethodGenerator('__construct', [], MethodGenerator::FLAG_PUBLIC);
294
        $constructor->setDocBlock('The constructor takes all compulsory arguments.');
295
296
        $assigns = [];
297
        $parentConstructorArguments = [];
298
299
        foreach ($constructorProperties as $property) {
300
            $parameter = new ParameterGenerator(ltrim($property->getVariableName(), '$'));
301
            if ($property->isTypeHintable()) {
302
                $parameter->setType($property->getPhpType());
303
            }
304
            $constructor->setParameter($parameter);
305
306
            $constructor->getDocBlock()->setTag($property->getParamAnnotation());
307
308
            if ($property->getTable()->getName() === $this->table->getName()) {
309
                $assigns[] = $property->getConstructorAssignCode()."\n";
310
            } else {
311
                $parentConstructorArguments[] = $property->getVariableName();
312
            }
313
        }
314
315
        $parentConstructorCode = sprintf("parent::__construct(%s);\n", implode(', ', $parentConstructorArguments));
316
317
        foreach ($this->getPropertiesWithDefault() as $property) {
318
            $assigns[] = $property->assignToDefaultCode()."\n";
319
        }
320
321
        $body = $parentConstructorCode . implode('', $assigns);
322
323
        $constructor->setBody($body);
324
325
        return $constructor;
326
    }
327
328
    /**
329
     * Returns the descriptors of one-to-many relationships (the foreign keys pointing on this beans)
330
     *
331
     * @return DirectForeignKeyMethodDescriptor[]
332
     */
333
    private function getDirectForeignKeysDescriptors(): array
334
    {
335
        $fks = $this->tdbmSchemaAnalyzer->getIncomingForeignKeys($this->table->getName());
336
337
        $descriptors = [];
338
339
        foreach ($fks as $fk) {
340
            $descriptors[] = new DirectForeignKeyMethodDescriptor($fk, $this->table, $this->namingStrategy);
341
        }
342
343
        return $descriptors;
344
    }
345
346
    /**
347
     * @return PivotTableMethodsDescriptor[]
348
     */
349
    private function getPivotTableDescriptors(): array
350
    {
351
        $descs = [];
352
        foreach ($this->schemaAnalyzer->detectJunctionTables(true) as $table) {
353
            // There are exactly 2 FKs since this is a pivot table.
354
            $fks = array_values($table->getForeignKeys());
355
356
            if ($fks[0]->getForeignTableName() === $this->table->getName()) {
357
                list($localFk, $remoteFk) = $fks;
358
            } elseif ($fks[1]->getForeignTableName() === $this->table->getName()) {
359
                list($remoteFk, $localFk) = $fks;
360
            } else {
361
                continue;
362
            }
363
364
            $descs[] = new PivotTableMethodsDescriptor($table, $localFk, $remoteFk, $this->namingStrategy, $this->beanNamespace);
365
        }
366
367
        return $descs;
368
    }
369
370
    /**
371
     * Returns the list of method descriptors (and applies the alternative name if needed).
372
     *
373
     * @return MethodDescriptorInterface[]
374
     */
375
    public function getMethodDescriptors(): array
376
    {
377
        $directForeignKeyDescriptors = $this->getDirectForeignKeysDescriptors();
378
        $pivotTableDescriptors = $this->getPivotTableDescriptors();
379
380
        $descriptors = array_merge($directForeignKeyDescriptors, $pivotTableDescriptors);
381
382
        // Descriptors by method names
383
        $descriptorsByMethodName = [];
384
385
        foreach ($descriptors as $descriptor) {
386
            $descriptorsByMethodName[$descriptor->getName()][] = $descriptor;
387
        }
388
389
        foreach ($descriptorsByMethodName as $descriptorsForMethodName) {
390
            if (count($descriptorsForMethodName) > 1) {
391
                foreach ($descriptorsForMethodName as $descriptor) {
392
                    $descriptor->useAlternativeName();
393
                }
394
            }
395
        }
396
397
        return $descriptors;
398
    }
399
400
    public function generateJsonSerialize(): MethodGenerator
401
    {
402
        $tableName = $this->table->getName();
403
        $parentFk = $this->schemaAnalyzer->getParentRelationship($tableName);
404
        if ($parentFk !== null) {
405
            $initializer = '$array = parent::jsonSerialize($stopRecursion);';
406
        } else {
407
            $initializer = '$array = [];';
408
        }
409
410
        $method = new MethodGenerator('jsonSerialize');
411
        $method->setDocBlock('Serializes the object for JSON encoding.');
412
        $method->getDocBlock()->setTag(new ParamTag('$stopRecursion', ['bool'], 'Parameter used internally by TDBM to stop embedded objects from embedding other objects.'));
413
        $method->getDocBlock()->setTag(new ReturnTag(['array']));
414
        $method->setParameter(new ParameterGenerator('stopRecursion', 'bool', false));
415
416
        $str = '%s
417
%s
418
%s
419
return $array;
420
';
421
422
        $propertiesCode = '';
423
        foreach ($this->getExposedProperties() as $beanPropertyDescriptor) {
424
            $propertiesCode .= $beanPropertyDescriptor->getJsonSerializeCode();
425
        }
426
427
        // Many2many relationships
428
        $methodsCode = '';
429
        foreach ($this->getMethodDescriptors() as $methodDescriptor) {
430
            $methodsCode .= $methodDescriptor->getJsonSerializeCode();
431
        }
432
433
        $method->setBody(sprintf($str, $initializer, $propertiesCode, $methodsCode));
434
435
        return $method;
436
    }
437
438
    /**
439
     * Returns as an array the class we need to extend from and the list of use statements.
440
     *
441
     * @param ForeignKeyConstraint|null $parentFk
442
     * @return string[]
443
     */
444
    private function generateExtendsAndUseStatements(ForeignKeyConstraint $parentFk = null): array
445
    {
446
        $classes = [];
447
        if ($parentFk !== null) {
448
            $extends = $this->namingStrategy->getBeanClassName($parentFk->getForeignTableName());
449
            $classes[] = $extends;
450
        }
451
452
        foreach ($this->getBeanPropertyDescriptors() as $beanPropertyDescriptor) {
453
            $className = $beanPropertyDescriptor->getClassName();
454
            if (null !== $className) {
455
                $classes[] = $className;
456
            }
457
        }
458
459
        foreach ($this->getMethodDescriptors() as $descriptor) {
460
            $classes = array_merge($classes, $descriptor->getUsedClasses());
461
        }
462
463
        $classes = array_unique($classes);
464
465
        return $classes;
466
    }
467
468
    /**
469
     * Returns the representation of the PHP bean file with all getters and setters.
470
     *
471
     * @return FileGenerator
472
     */
473
    public function generatePhpCode(): FileGenerator
474
    {
475
476
        $file = new FileGenerator();
477
        $class = new ClassGenerator();
478
        $file->setClass($class);
479
        $file->setNamespace($this->generatedBeanNamespace);
480
481
        $tableName = $this->table->getName();
482
        $baseClassName = $this->namingStrategy->getBaseBeanClassName($tableName);
483
        $className = $this->namingStrategy->getBeanClassName($tableName);
484
        $parentFk = $this->schemaAnalyzer->getParentRelationship($this->table->getName());
485
486
        $classes = $this->generateExtendsAndUseStatements($parentFk);
487
488
        foreach ($classes as $useClass) {
489
            $file->setUse($this->beanNamespace.'\\'.$useClass);
490
        }
491
492
        /*$uses = array_map(function ($className) {
493
            return 'use '.$this->beanNamespace.'\\'.$className.";\n";
494
        }, $classes);
495
        $use = implode('', $uses);*/
496
497
        $extends = $this->getExtendedBeanClassName();
498
        if ($extends === null) {
499
            $class->setExtendedClass(AbstractTDBMObject::class);
500
            $file->setUse(AbstractTDBMObject::class);
501
        } else {
502
            $class->setExtendedClass($extends);
503
        }
504
505
        $file->setUse(ResultIterator::class);
506
        $file->setUse(AlterableResultIterator::class);
507
        $file->setUse(Uuid::class);
508
        $file->setUse(JsonSerializable::class);
509
510
        $class->setName($baseClassName);
511
        $class->setAbstract(true);
512
513
        $file->setDocBlock(new DocBlockGenerator('This file has been automatically generated by TDBM.', <<<EOF
514
DO NOT edit this file, as it might be overwritten.
515
If you need to perform changes, edit the $className class instead!
516
EOF
517
        ));
518
519
        $class->setDocBlock(new DocBlockGenerator("The $baseClassName class maps the '$tableName' table in database."));
520
        $class->setImplementedInterfaces([ JsonSerializable::class ]);
521
522
523
        $class->addMethodFromGenerator($this->generateBeanConstructor());
524
525
        foreach ($this->getExposedProperties() as $property) {
526
            foreach ($property->getGetterSetterCode() as $generator) {
527
                $class->addMethodFromGenerator($generator);
528
            }
529
        }
530
531
        foreach ($this->getMethodDescriptors() as $methodDescriptor) {
532
            foreach ($methodDescriptor->getCode() as $generator) {
533
                $class->addMethodFromGenerator($generator);
534
            }
535
        }
536
537
        $class->addMethodFromGenerator($this->generateJsonSerialize());
538
        $class->addMethodFromGenerator($this->generateGetUsedTablesCode());
539
        $onDeleteCode = $this->generateOnDeleteCode();
540
        if ($onDeleteCode) {
541
            $class->addMethodFromGenerator($onDeleteCode);
542
        }
543
        $cloneCode = $this->generateCloneCode();
544
        if ($cloneCode) {
0 ignored issues
show
introduced by
$cloneCode is of type Zend\Code\Generator\MethodGenerator, thus it always evaluated to true.
Loading history...
545
            $class->addMethodFromGenerator($cloneCode);
546
        }
547
548
        return $file;
549
    }
550
551
    /**
552
     * Writes the representation of the PHP DAO file.
553
     *
554
     * @return FileGenerator
555
     */
556
    public function generateDaoPhpCode(): FileGenerator
557
    {
558
        $file = new FileGenerator();
559
        $class = new ClassGenerator();
560
        $file->setClass($class);
561
        $file->setNamespace($this->generatedDaoNamespace);
562
563
        $tableName = $this->table->getName();
564
565
        $primaryKeyColumns = TDBMDaoGenerator::getPrimaryKeyColumnsOrFail($this->table);
566
567
        list($defaultSort, $defaultSortDirection) = $this->getDefaultSortColumnFromAnnotation($this->table);
568
569
        $className = $this->namingStrategy->getDaoClassName($tableName);
570
        $baseClassName = $this->namingStrategy->getBaseDaoClassName($tableName);
571
        $beanClassWithoutNameSpace = $this->namingStrategy->getBeanClassName($tableName);
572
        $beanClassName = $this->beanNamespace.'\\'.$beanClassWithoutNameSpace;
573
574
        $findByDaoCodeMethods = $this->generateFindByDaoCode($this->beanNamespace, $beanClassWithoutNameSpace);
575
576
        $usedBeans[] = $beanClassName;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$usedBeans was never initialized. Although not strictly required by PHP, it is generally a good practice to add $usedBeans = array(); before regardless.
Loading history...
577
        // Let's suppress duplicates in used beans (if any)
578
        $usedBeans = array_flip(array_flip($usedBeans));
579
        foreach ($usedBeans as $usedBean) {
580
            $class->addUse($usedBean);
581
        }
582
583
        $file->setDocBlock(new DocBlockGenerator(<<<EOF
584
This file has been automatically generated by TDBM.
585
DO NOT edit this file, as it might be overwritten.
586
If you need to perform changes, edit the $className class instead!
587
EOF
588
        ));
589
590
        $file->setNamespace($this->generatedDaoNamespace);
591
592
        $class->addUse(TDBMService::class);
593
        $class->addUse(ResultIterator::class);
594
        $class->addUse(TDBMException::class);
595
596
        $class->setName($baseClassName);
597
598
        $class->setDocBlock(new DocBlockGenerator("The $baseClassName class will maintain the persistence of $beanClassWithoutNameSpace class into the $tableName table."));
599
600
        $tdbmServiceProperty = new PropertyGenerator('tdbmService');
601
        $tdbmServiceProperty->setDocBlock(new DocBlockGenerator(null, null, [new VarTag(null, [TDBMService::class])]));
602
        $class->addPropertyFromGenerator($tdbmServiceProperty);
603
604
        $defaultSortProperty = new PropertyGenerator('defaultSort', $defaultSort);
605
        $defaultSortProperty->setDocBlock(new DocBlockGenerator('The default sort column.', null, [new VarTag(null, ['string', 'null'])]));
606
        $class->addPropertyFromGenerator($defaultSortProperty);
607
608
        $defaultSortPropertyDirection = new PropertyGenerator('defaultDirection', $defaultSort && $defaultSortDirection ? $defaultSortDirection : 'asc');
609
        $defaultSortPropertyDirection->setDocBlock(new DocBlockGenerator('The default sort direction.', null, [new VarTag(null, ['string'])]));
610
        $class->addPropertyFromGenerator($defaultSortPropertyDirection);
611
612
        $class->addMethod(
613
            '__construct',
614
            [ new ParameterGenerator('tdbmService', TDBMService::class) ],
615
            MethodGenerator::FLAG_PUBLIC,
616
            '$this->tdbmService = $tdbmService;',
617
            new DocBlockGenerator('Sets the TDBM service used by this DAO.')
0 ignored issues
show
Bug introduced by
new Zend\Code\Generator\...ice used by this DAO.') of type Zend\Code\Generator\DocBlockGenerator is incompatible with the type string expected by parameter $docBlock of Zend\Code\Generator\ClassGenerator::addMethod(). ( Ignorable by Annotation )

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

617
            /** @scrutinizer ignore-type */ new DocBlockGenerator('Sets the TDBM service used by this DAO.')
Loading history...
618
        );
619
620
        $saveMethod = new MethodGenerator(
621
            'save',
622
            [ new ParameterGenerator('obj', $beanClassName) ],
623
            MethodGenerator::FLAG_PUBLIC,
624
            '$this->tdbmService->save($obj);',
625
            new DocBlockGenerator("Persist the $beanClassWithoutNameSpace instance.",
626
                null,
627
                [
628
                    new ParamTag('obj', [$beanClassWithoutNameSpace], 'The bean to save.')
629
                ]));
630
        $saveMethod->setReturnType('void');
631
632
        $class->addMethodFromGenerator($saveMethod);
633
634
        $findAllBody = <<<EOF
635
if (\$this->defaultSort) {
636
    \$orderBy = '$tableName.'.\$this->defaultSort.' '.\$this->defaultDirection;
637
} else {
638
    \$orderBy = null;
639
}
640
return \$this->tdbmService->findObjects('$tableName', null, [], \$orderBy);
641
EOF;
642
643
        $findAllMethod = new MethodGenerator(
644
            'findAll',
645
            [],
646
            MethodGenerator::FLAG_PUBLIC,
647
            $findAllBody,
648
            new DocBlockGenerator("Get all $beanClassWithoutNameSpace records.",
649
                null,
650
                [
651
                    new ReturnTag([ $beanClassName.'[]', ResultIterator::class ])
652
                ])
653
        );
654
        $findAllMethod->setReturnType('iterable');
655
        $class->addMethodFromGenerator($findAllMethod);
656
657
        if (count($primaryKeyColumns) === 1) {
658
            $primaryKeyColumn = $primaryKeyColumns[0];
659
            $primaryKeyPhpType = TDBMDaoGenerator::dbalTypeToPhpType($this->table->getColumn($primaryKeyColumn)->getType());
660
661
            $getByIdMethod = new MethodGenerator(
662
                'getById',
663
                [
664
                    new ParameterGenerator('id', $primaryKeyPhpType),
665
                    new ParameterGenerator('lazyLoading', 'bool', false)
666
                ],
667
                MethodGenerator::FLAG_PUBLIC,
668
                "return \$this->tdbmService->findObjectByPk('$tableName', ['$primaryKeyColumn' => \$id], [], \$lazyLoading);",
669
                new DocBlockGenerator("Get $beanClassWithoutNameSpace specified by its ID (its primary key).",
670
                    'If the primary key does not exist, an exception is thrown.',
671
                    [
672
                        new ParamTag('id', [$primaryKeyPhpType]),
673
                        new ParamTag('lazyLoading', ['bool'], '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.'),
674
                        new ReturnTag([$beanClassName . '[]', ResultIterator::class]),
675
                        new ThrowsTag(TDBMException::class)
676
                    ])
677
            );
678
            $class->addMethodFromGenerator($getByIdMethod);
679
        }
680
681
        $deleteMethodBody = <<<EOF
682
if (\$cascade === true) {
683
    \$this->tdbmService->deleteCascade(\$obj);
684
} else {
685
    \$this->tdbmService->delete(\$obj);
686
}
687
EOF;
688
689
690
        $deleteMethod = new MethodGenerator(
691
            'delete',
692
            [
693
                new ParameterGenerator('obj', $beanClassName),
694
                new ParameterGenerator('cascade', 'bool', false)
695
            ],
696
            MethodGenerator::FLAG_PUBLIC,
697
            $deleteMethodBody,
698
            new DocBlockGenerator("Get all $beanClassWithoutNameSpace records.",
699
                null,
700
                [
701
                    new ParamTag('obj', [$beanClassName], 'The object to delete'),
702
                    new ParamTag('cascade', ['bool'], 'If true, it will delete all objects linked to $obj'),
703
                ])
704
        );
705
        $deleteMethod->setReturnType('void');
706
        $class->addMethodFromGenerator($deleteMethod);
707
708
        $findMethodBody = <<<EOF
709
if (\$this->defaultSort && \$orderBy == null) {
710
    \$orderBy = '$tableName.'.\$this->defaultSort.' '.\$this->defaultDirection;
711
}
712
return \$this->tdbmService->findObjects('$tableName', \$filter, \$parameters, \$orderBy, \$additionalTablesFetch, \$mode);
713
EOF;
714
715
716
        $findMethod = new MethodGenerator(
717
            'find',
718
            [
719
                (new ParameterGenerator('filter'))->setDefaultValue(null),
720
                new ParameterGenerator('parameters', 'array', []),
721
                (new ParameterGenerator('orderBy'))->setDefaultValue(null),
722
                new ParameterGenerator('additionalTablesFetch', 'array', []),
723
                (new ParameterGenerator('mode', '?int'))->setDefaultValue(null),
724
            ],
725
            MethodGenerator::FLAG_PUBLIC,
726
            $findMethodBody,
727
            new DocBlockGenerator("Get all $beanClassWithoutNameSpace records.",
728
                null,
729
                [
730
                    new ParamTag('filter', ['mixed'], 'The filter bag (see TDBMService::findObjects for complete description)'),
731
                    new ParamTag('parameters', ['mixed[]'], 'The parameters associated with the filter'),
732
                    new ParamTag('orderBy', ['mixed'], 'The order string'),
733
                    new ParamTag('additionalTablesFetch', ['string[]'], 'A list of additional tables to fetch (for performance improvement)'),
734
                    new ParamTag('mode', ['int', 'null'], 'Either TDBMService::MODE_ARRAY or TDBMService::MODE_CURSOR (for large datasets). Defaults to TDBMService::MODE_ARRAY.'),
735
                    new ReturnTag([$beanClassName . '[]', ResultIterator::class])
736
                ])
737
        );
738
        $findMethod->setReturnType('iterable');
739
        $class->addMethodFromGenerator($findMethod);
740
741
742
        $findFromSqlMethodBody = <<<EOF
743
if (\$this->defaultSort && \$orderBy == null) {
744
    \$orderBy = '$tableName.'.\$this->defaultSort.' '.\$this->defaultDirection;
745
}
746
return \$this->tdbmService->findObjectsFromSql('$tableName', \$from, \$filter, \$parameters, \$orderBy, \$mode);
747
EOF;
748
749
        $findFromSqlMethod = new MethodGenerator(
750
            'findFromSql',
751
            [
752
                new ParameterGenerator('from', 'string'),
753
                (new ParameterGenerator('filter'))->setDefaultValue(null),
754
                new ParameterGenerator('parameters', 'array', []),
755
                (new ParameterGenerator('orderBy'))->setDefaultValue(null),
756
                new ParameterGenerator('additionalTablesFetch', 'array', []),
757
                (new ParameterGenerator('mode', '?int'))->setDefaultValue(null),
758
            ],
759
            MethodGenerator::FLAG_PUBLIC,
760
            $findFromSqlMethodBody,
761
            new DocBlockGenerator("Get a list of $beanClassWithoutNameSpace specified by its filters.",
762
                "Unlike the `find` method that guesses the FROM part of the statement, here you can pass the \$from part.
763
764
You should not put an alias on the main table name. So your \$from variable should look like:
765
766
   \"$tableName JOIN ... ON ...\"",
767
                [
768
                    new ParamTag('from', ['string'], 'The sql from statement'),
769
                    new ParamTag('filter', ['mixed'], 'The filter bag (see TDBMService::findObjects for complete description)'),
770
                    new ParamTag('parameters', ['mixed[]'], 'The parameters associated with the filter'),
771
                    new ParamTag('orderBy', ['mixed'], 'The order string'),
772
                    new ParamTag('additionalTablesFetch', ['string[]'], 'A list of additional tables to fetch (for performance improvement)'),
773
                    new ParamTag('mode', ['int', 'null'], 'Either TDBMService::MODE_ARRAY or TDBMService::MODE_CURSOR (for large datasets). Defaults to TDBMService::MODE_ARRAY.'),
774
                    new ReturnTag([$beanClassName . '[]', ResultIterator::class])
775
                ])
776
        );
777
        $findFromSqlMethod->setReturnType('iterable');
778
        $class->addMethodFromGenerator($findFromSqlMethod);
779
780
781
782
783
        $findFromRawSqlMethodBody = <<<EOF
784
return \$this->tdbmService->findObjectsFromRawSql('$tableName', \$sql, \$parameters, \$mode, null, \$countSql);
785
EOF;
786
787
        $findFromRawSqlMethod = new MethodGenerator(
788
            'findFromRawSql',
789
            [
790
                new ParameterGenerator('sql', 'string'),
791
                new ParameterGenerator('parameters', 'array', []),
792
                (new ParameterGenerator('countSql', '?string'))->setDefaultValue(null),
793
                (new ParameterGenerator('mode', '?int'))->setDefaultValue(null),
794
            ],
795
            MethodGenerator::FLAG_PUBLIC,
796
            $findFromRawSqlMethodBody,
797
            new DocBlockGenerator("Get a list of $beanClassWithoutNameSpace from a SQL query.",
798
                "Unlike the `find` and `findFromSql` methods, here you can pass the whole \$sql query.
799
800
You should not put an alias on the main table name, and select its columns using `*`. So the SELECT part of you \$sql should look like:
801
802
   \"SELECT $tableName .* FROM ...\"",
803
                [
804
                    new ParamTag('sql', ['string'], 'The sql query'),
805
                    new ParamTag('parameters', ['mixed[]'], 'The parameters associated with the query'),
806
                    new ParamTag('countSql', ['string', 'null'], 'The sql query that provides total count of rows (automatically computed if not provided)'),
807
                    new ParamTag('mode', ['int', 'null'], 'Either TDBMService::MODE_ARRAY or TDBMService::MODE_CURSOR (for large datasets). Defaults to TDBMService::MODE_ARRAY.'),
808
                    new ReturnTag([$beanClassName . '[]', ResultIterator::class])
809
                ])
810
        );
811
        $findFromRawSqlMethod->setReturnType('iterable');
812
        $class->addMethodFromGenerator($findFromRawSqlMethod);
813
814
815
816
        $findOneMethodBody = <<<EOF
817
return \$this->tdbmService->findObject('$tableName', \$filter, \$parameters, \$additionalTablesFetch);
818
EOF;
819
820
821
        $findOneMethod = new MethodGenerator(
822
            'findOne',
823
            [
824
                (new ParameterGenerator('filter'))->setDefaultValue(null),
825
                new ParameterGenerator('parameters', 'array', []),
826
                new ParameterGenerator('additionalTablesFetch', 'array', []),
827
            ],
828
            MethodGenerator::FLAG_PUBLIC,
829
            $findOneMethodBody,
830
            new DocBlockGenerator("Get a single $beanClassWithoutNameSpace specified by its filters.",
831
                null,
832
                [
833
                    new ParamTag('filter', ['mixed'], 'The filter bag (see TDBMService::findObjects for complete description)'),
834
                    new ParamTag('parameters', ['mixed[]'], 'The parameters associated with the filter'),
835
                    new ParamTag('additionalTablesFetch', ['string[]'], 'A list of additional tables to fetch (for performance improvement)'),
836
                    new ReturnTag([$beanClassName, 'null'])
837
                ])
838
        );
839
        $findOneMethod->setReturnType("?$beanClassName");
840
        $class->addMethodFromGenerator($findOneMethod);
841
842
843
        $findOneFromSqlMethodBody = <<<EOF
844
return \$this->tdbmService->findObjectFromSql('$tableName', \$from, \$filter, \$parameters);
845
EOF;
846
847
        $findOneFromSqlMethod = new MethodGenerator(
848
            'findOneFromSql',
849
            [
850
                new ParameterGenerator('from', 'string'),
851
                (new ParameterGenerator('filter'))->setDefaultValue(null),
852
                new ParameterGenerator('parameters', 'array', []),
853
            ],
854
            MethodGenerator::FLAG_PUBLIC,
855
            $findOneFromSqlMethodBody,
856
            new DocBlockGenerator("Get a single $beanClassWithoutNameSpace specified by its filters.",
857
                "Unlike the `findOne` method that guesses the FROM part of the statement, here you can pass the \$from part.
858
859
You should not put an alias on the main table name. So your \$from variable should look like:
860
861
    \"$tableName JOIN ... ON ...\"",
862
                [
863
                    new ParamTag('from', ['string'], 'The sql from statement'),
864
                    new ParamTag('filter', ['mixed'], 'The filter bag (see TDBMService::findObjects for complete description)'),
865
                    new ParamTag('parameters', ['mixed[]'], 'The parameters associated with the filter'),
866
                    new ReturnTag([$beanClassName, 'null'])
867
                ])
868
        );
869
        $findOneFromSqlMethod->setReturnType("?$beanClassName");
870
        $class->addMethodFromGenerator($findOneFromSqlMethod);
871
872
873
        $setDefaultSortMethod = new MethodGenerator(
874
            'setDefaultSort',
875
            [
876
                new ParameterGenerator('defaultSort', 'string'),
877
            ],
878
            MethodGenerator::FLAG_PUBLIC,
879
            '$this->defaultSort = $defaultSort;',
880
            new DocBlockGenerator("Sets the default column for default sorting.",
881
            null,
882
                [
883
                    new ParamTag('defaultSort', ['string']),
884
                ])
885
        );
886
        $setDefaultSortMethod->setReturnType('void');
887
        $class->addMethodFromGenerator($setDefaultSortMethod);
888
889
        foreach ($findByDaoCodeMethods as $method) {
890
            $class->addMethodFromGenerator($method);
891
        }
892
893
        return $file;
894
    }
895
896
    /**
897
     * Tries to find a @defaultSort annotation in one of the columns.
898
     *
899
     * @param Table $table
900
     *
901
     * @return mixed[] First item: column name, Second item: column order (asc/desc)
902
     */
903
    private function getDefaultSortColumnFromAnnotation(Table $table): array
904
    {
905
        $defaultSort = null;
906
        $defaultSortDirection = null;
907
        foreach ($table->getColumns() as $column) {
908
            $comments = $column->getComment();
909
            $matches = [];
910
            if ($comments !== null && preg_match('/@defaultSort(\((desc|asc)\))*/', $comments, $matches) != 0) {
911
                $defaultSort = $column->getName();
912
                if (count($matches) === 3) {
913
                    $defaultSortDirection = $matches[2];
914
                } else {
915
                    $defaultSortDirection = 'ASC';
916
                }
917
            }
918
        }
919
920
        return [$defaultSort, $defaultSortDirection];
921
    }
922
923
    /**
924
     * @param string $beanNamespace
925
     * @param string $beanClassName
926
     *
927
     * @return MethodGenerator[]
928
     */
929
    private function generateFindByDaoCode(string $beanNamespace, string $beanClassName): array
930
    {
931
        $methods = [];
932
        foreach ($this->removeDuplicateIndexes($this->table->getIndexes()) as $index) {
933
            if (!$index->isPrimary()) {
934
                $method = $this->generateFindByDaoCodeForIndex($index, $beanNamespace, $beanClassName);
935
                if ($method !== null) {
936
                    $methods[] = $method;
937
                }
938
            }
939
        }
940
941
        return $methods;
942
    }
943
944
    /**
945
     * Remove identical indexes (indexes on same columns)
946
     *
947
     * @param Index[] $indexes
948
     * @return Index[]
949
     */
950
    private function removeDuplicateIndexes(array $indexes): array
951
    {
952
        $indexesByKey = [];
953
        foreach ($indexes as $index) {
954
            $indexesByKey[implode('__`__', $index->getUnquotedColumns())] = $index;
955
        }
956
957
        return array_values($indexesByKey);
958
    }
959
960
    /**
961
     * @param Index  $index
962
     * @param string $beanNamespace
963
     * @param string $beanClassName
964
     *
965
     * @return MethodGenerator|null
966
     */
967
    private function generateFindByDaoCodeForIndex(Index $index, string $beanNamespace, string $beanClassName): ?MethodGenerator
968
    {
969
        $columns = $index->getColumns();
970
        $usedBeans = [];
971
972
        /**
973
         * The list of elements building this index (expressed as columns or foreign keys)
974
         * @var AbstractBeanPropertyDescriptor[]
975
         */
976
        $elements = [];
977
978
        foreach ($columns as $column) {
979
            $fk = $this->isPartOfForeignKey($this->table, $this->table->getColumn($column));
980
            if ($fk !== null) {
981
                if (!in_array($fk, $elements)) {
982
                    $elements[] = new ObjectBeanPropertyDescriptor($this->table, $fk, $this->namingStrategy, $this->beanNamespace);
983
                }
984
            } else {
985
                $elements[] = new ScalarBeanPropertyDescriptor($this->table, $this->table->getColumn($column), $this->namingStrategy, $this->annotationParser);
986
            }
987
        }
988
989
        // If the index is actually only a foreign key, let's bypass it entirely.
990
        if (count($elements) === 1 && $elements[0] instanceof ObjectBeanPropertyDescriptor) {
991
            return null;
992
        }
993
994
        $parameters = [];
995
        //$functionParameters = [];
996
        $first = true;
997
        foreach ($elements as $element) {
998
            $parameter = new ParameterGenerator(ltrim($element->getVariableName(), '$'));
999
            if (!$first) {
1000
                $parameterType = '?';
1001
                //$functionParameter = '?';
1002
            } else {
1003
                $parameterType = '';
1004
                //$functionParameter = '';
1005
            }
1006
            $parameterType .= $element->getPhpType();
1007
            $parameter->setType($parameterType);
1008
            if (!$first) {
1009
                $parameter->setDefaultValue(null);
1010
            }
1011
            //$functionParameter .= $element->getPhpType();
1012
            $elementClassName = $element->getClassName();
1013
            if ($elementClassName) {
1014
                $usedBeans[] = $beanNamespace.'\\'.$elementClassName;
1015
            }
1016
            //$functionParameter .= ' '.$element->getVariableName();
1017
            if ($first) {
1018
                $first = false;
1019
            } /*else {
1020
                $functionParameter .= ' = null';
1021
            }*/
1022
            //$functionParameters[] = $functionParameter;
1023
            $parameters[] = $parameter;
1024
        }
1025
1026
        //$functionParametersString = implode(', ', $functionParameters);
1027
1028
        $count = 0;
1029
1030
        $params = [];
1031
        $filterArrayCode = '';
1032
        $commentArguments = [];
1033
        $first = true;
1034
        foreach ($elements as $element) {
1035
            $params[] = $element->getParamAnnotation();
1036
            if ($element instanceof ScalarBeanPropertyDescriptor) {
1037
                $filterArrayCode .= '            '.var_export($element->getColumnName(), true).' => '.$element->getVariableName().",\n";
1038
            } elseif ($element instanceof ObjectBeanPropertyDescriptor) {
1039
                $foreignKey = $element->getForeignKey();
1040
                $columns = SafeFunctions::arrayCombine($foreignKey->getLocalColumns(), $foreignKey->getForeignColumns());
1041
                ++$count;
1042
                $foreignTable = $this->schema->getTable($foreignKey->getForeignTableName());
1043
                foreach ($columns as $localColumn => $foreignColumn) {
1044
                    // TODO: a foreign key could point to another foreign key. In this case, there is no getter for the pointed column. We don't support this case.
1045
                    $targetedElement = new ScalarBeanPropertyDescriptor($foreignTable, $foreignTable->getColumn($foreignColumn), $this->namingStrategy, $this->annotationParser);
1046
                    if ($first) {
1047
                        // First parameter for index is not nullable
1048
                        $filterArrayCode .= '            '.var_export($localColumn, true).' => '.$element->getVariableName().'->'.$targetedElement->getGetterName()."(),\n";
1049
                    } else {
1050
                        // Other parameters for index is not nullable
1051
                        $filterArrayCode .= '            '.var_export($localColumn, true).' => ('.$element->getVariableName().' !== null) ? '.$element->getVariableName().'->'.$targetedElement->getGetterName()."() : null,\n";
1052
                    }
1053
                }
1054
            }
1055
            $commentArguments[] = substr($element->getVariableName(), 1);
1056
            if ($first) {
1057
                $first = false;
1058
            }
1059
        }
1060
1061
        //$paramsString = implode("\n", $params);
1062
1063
1064
        $methodName = $this->namingStrategy->getFindByIndexMethodName($index, $elements);
1065
1066
        $method = new MethodGenerator($methodName);
1067
1068
        if ($index->isUnique()) {
1069
            $parameters[] = new ParameterGenerator('additionalTablesFetch', 'array', []);
1070
            $params[] = new ParamTag('additionalTablesFetch', [ 'string[]' ], 'A list of additional tables to fetch (for performance improvement)');
1071
            $params[] = new ReturnTag([ $beanClassName, 'null' ]);
1072
1073
            $docBlock = new DocBlockGenerator("Get a $beanClassName filtered by ".implode(', ', $commentArguments). '.', null, $params);
1074
1075
            $body = "\$filter = [
1076
".$filterArrayCode."        ];
1077
return \$this->findOne(\$filter, [], \$additionalTablesFetch);
1078
";
1079
        } else {
1080
            $parameters[] = (new ParameterGenerator('orderBy'))->setDefaultValue(null);
1081
            $params[] = new ParamTag('orderBy', [ 'mixed' ], 'The order string');
1082
            $parameters[] = new ParameterGenerator('additionalTablesFetch', 'array', []);
1083
            $params[] = new ParamTag('additionalTablesFetch', [ 'string[]' ], 'A list of additional tables to fetch (for performance improvement)');
1084
            $parameters[] = (new ParameterGenerator('mode', '?int'))->setDefaultValue(null);
1085
            $params[] = new ParamTag('mode', [ 'int', 'null' ], 'Either TDBMService::MODE_ARRAY or TDBMService::MODE_CURSOR (for large datasets). Defaults to TDBMService::MODE_ARRAY.');
1086
            $params[] = new ReturnTag([ $beanClassName.'[]', ResultIterator::class ]);
1087
1088
            $docBlock = new DocBlockGenerator("Get a list of $beanClassName filtered by ".implode(', ', $commentArguments).".", null, $params);
1089
1090
            $body = "\$filter = [
1091
".$filterArrayCode."        ];
1092
return \$this->find(\$filter, [], \$orderBy, \$additionalTablesFetch, \$mode);
1093
";
1094
        }
1095
1096
        $method->setParameters($parameters);
1097
        $method->setDocBlock($docBlock);
1098
        $method->setBody($body);
1099
1100
        return $method;
1101
    }
1102
1103
    /**
1104
     * Generates the code for the getUsedTable protected method.
1105
     *
1106
     * @return MethodGenerator
1107
     */
1108
    private function generateGetUsedTablesCode(): MethodGenerator
1109
    {
1110
        $hasParentRelationship = $this->schemaAnalyzer->getParentRelationship($this->table->getName()) !== null;
1111
        if ($hasParentRelationship) {
1112
            $code = sprintf('$tables = parent::getUsedTables();
1113
$tables[] = %s;
1114
1115
return $tables;', var_export($this->table->getName(), true));
1116
        } else {
1117
            $code = sprintf('        return [ %s ];', var_export($this->table->getName(), true));
1118
        }
1119
1120
        $method = new MethodGenerator('getUsedTables');
1121
        $method->setDocBlock('Returns an array of used tables by this bean (from parent to child relationship).');
1122
        $method->getDocBlock()->setTag(new ReturnTag(['string[]']));
1123
        $method->setReturnType('array');
1124
        $method->setBody($code);
1125
1126
        return $method;
1127
    }
1128
1129
    private function generateOnDeleteCode(): ?MethodGenerator
1130
    {
1131
        $code = '';
1132
        $relationships = $this->getPropertiesForTable($this->table);
1133
        foreach ($relationships as $relationship) {
1134
            if ($relationship instanceof ObjectBeanPropertyDescriptor) {
1135
                $code .= sprintf('$this->setRef('.var_export($relationship->getForeignKey()->getName(), true).', null, '.var_export($this->table->getName(), true).");\n");
1136
            }
1137
        }
1138
1139
        if (!$code) {
1140
            return null;
1141
        }
1142
1143
        $method = new MethodGenerator('onDelete');
1144
        $method->setDocBlock('Method called when the bean is removed from database.');
1145
        $method->setReturnType('void');
1146
        $method->setBody('parent::onDelete();
1147
'.$code);
1148
1149
        return $method;
1150
    }
1151
1152
    private function generateCloneCode(): ?MethodGenerator
1153
    {
1154
        $code = '';
1155
1156
        foreach ($this->beanPropertyDescriptors as $beanPropertyDescriptor) {
1157
            $code .= $beanPropertyDescriptor->getCloneRule();
1158
        }
1159
1160
        $method = new MethodGenerator('__clone');
1161
        $method->setBody('parent::__clone();
1162
'.$code);
1163
1164
        return $method;
1165
    }
1166
1167
    /**
1168
     * Returns the bean class name (without the namespace).
1169
     *
1170
     * @return string
1171
     */
1172
    public function getBeanClassName() : string
1173
    {
1174
        return $this->namingStrategy->getBeanClassName($this->table->getName());
1175
    }
1176
1177
    /**
1178
     * Returns the base bean class name (without the namespace).
1179
     *
1180
     * @return string
1181
     */
1182
    public function getBaseBeanClassName() : string
1183
    {
1184
        return $this->namingStrategy->getBaseBeanClassName($this->table->getName());
1185
    }
1186
1187
    /**
1188
     * Returns the DAO class name (without the namespace).
1189
     *
1190
     * @return string
1191
     */
1192
    public function getDaoClassName() : string
1193
    {
1194
        return $this->namingStrategy->getDaoClassName($this->table->getName());
1195
    }
1196
1197
    /**
1198
     * Returns the base DAO class name (without the namespace).
1199
     *
1200
     * @return string
1201
     */
1202
    public function getBaseDaoClassName() : string
1203
    {
1204
        return $this->namingStrategy->getBaseDaoClassName($this->table->getName());
1205
    }
1206
1207
    /**
1208
     * Returns the table used to build this bean.
1209
     *
1210
     * @return Table
1211
     */
1212
    public function getTable(): Table
1213
    {
1214
        return $this->table;
1215
    }
1216
1217
    /**
1218
     * Returns the extended bean class name (without the namespace), or null if the bean is not extended.
1219
     *
1220
     * @return string
1221
     */
1222
    public function getExtendedBeanClassName(): ?string
1223
    {
1224
        $parentFk = $this->schemaAnalyzer->getParentRelationship($this->table->getName());
1225
        if ($parentFk !== null) {
1226
            return $this->namingStrategy->getBeanClassName($parentFk->getForeignTableName());
1227
        } else {
1228
            return null;
1229
        }
1230
    }
1231
1232
    /**
1233
     * @return string
1234
     */
1235
    public function getBeanNamespace(): string
1236
    {
1237
        return $this->beanNamespace;
1238
    }
1239
1240
    /**
1241
     * @return string
1242
     */
1243
    public function getGeneratedBeanNamespace(): string
1244
    {
1245
        return $this->generatedBeanNamespace;
1246
    }
1247
}
1248