BeanDescriptor   F
last analyzed

Complexity

Total Complexity 78

Size/Duplication

Total Lines 640
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 15

Importance

Changes 0
Metric Value
wmc 78
lcom 1
cbo 15
dl 0
loc 640
rs 1.9436
c 0
b 0
f 0

20 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
A initBeanPropertyDescriptors() 0 4 1
A isPartOfForeignKey() 0 13 4
A getBeanPropertyDescriptors() 0 4 1
A getConstructorProperties() 0 8 1
A getPropertiesWithDefault() 0 9 1
A getExposedProperties() 0 8 1
A getProperties() 0 21 4
D getPropertiesForTable() 0 68 14
B generateBeanConstructor() 0 42 5
A getDirectForeignKeysDescriptors() 0 12 2
A getPivotTableDescriptors() 0 20 4
B getMethodDescriptors() 0 24 5
B generateJsonSerialize() 0 39 4
B generateExtendsAndUseStatements() 0 23 5
B generatePhpCode() 0 61 4
A generateFindByDaoCode() 0 14 3
D generateFindByDaoCodeForIndex() 0 93 12
B generateGetUsedTablesCode() 0 24 2
B generateOnDeleteCode() 0 25 4

How to fix   Complexity   

Complex Class

Complex classes like BeanDescriptor often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use BeanDescriptor, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Mouf\Database\TDBM\Utils;
4
5
use Doctrine\DBAL\Schema\Column;
6
use Doctrine\DBAL\Schema\Index;
7
use Doctrine\DBAL\Schema\Schema;
8
use Doctrine\DBAL\Schema\Table;
9
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
10
use Mouf\Database\SchemaAnalyzer\SchemaAnalyzer;
11
use Mouf\Database\TDBM\TDBMException;
12
use Mouf\Database\TDBM\TDBMSchemaAnalyzer;
13
14
/**
15
 * This class represents a bean.
16
 */
17
class BeanDescriptor
18
{
19
    /**
20
     * @var Table
21
     */
22
    private $table;
23
24
    /**
25
     * @var SchemaAnalyzer
26
     */
27
    private $schemaAnalyzer;
28
29
    /**
30
     * @var Schema
31
     */
32
    private $schema;
33
34
    /**
35
     * @var AbstractBeanPropertyDescriptor[]
36
     */
37
    private $beanPropertyDescriptors = [];
38
39
    /**
40
     * @var TDBMSchemaAnalyzer
41
     */
42
    private $tdbmSchemaAnalyzer;
43
44
    public function __construct(Table $table, SchemaAnalyzer $schemaAnalyzer, Schema $schema, TDBMSchemaAnalyzer $tdbmSchemaAnalyzer)
45
    {
46
        $this->table = $table;
47
        $this->schemaAnalyzer = $schemaAnalyzer;
48
        $this->schema = $schema;
49
        $this->tdbmSchemaAnalyzer = $tdbmSchemaAnalyzer;
50
        $this->initBeanPropertyDescriptors();
51
    }
52
53
    private function initBeanPropertyDescriptors()
54
    {
55
        $this->beanPropertyDescriptors = $this->getProperties($this->table);
56
    }
57
58
    /**
59
     * Returns the foreign-key the column is part of, if any. null otherwise.
60
     *
61
     * @param Table  $table
62
     * @param Column $column
63
     *
64
     * @return ForeignKeyConstraint|null
65
     */
66
    private function isPartOfForeignKey(Table $table, Column $column)
67
    {
68
        $localColumnName = $column->getName();
69
        foreach ($table->getForeignKeys() as $foreignKey) {
70
            foreach ($foreignKey->getColumns() as $columnName) {
71
                if ($columnName === $localColumnName) {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $columnName (integer) and $localColumnName (string) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
72
                    return $foreignKey;
73
                }
74
            }
75
        }
76
77
        return;
78
    }
79
80
    /**
81
     * @return AbstractBeanPropertyDescriptor[]
82
     */
83
    public function getBeanPropertyDescriptors()
84
    {
85
        return $this->beanPropertyDescriptors;
86
    }
87
88
    /**
89
     * Returns the list of columns that are not nullable and not autogenerated for a given table and its parent.
90
     *
91
     * @return AbstractBeanPropertyDescriptor[]
92
     */
93
    public function getConstructorProperties()
94
    {
95
        $constructorProperties = array_filter($this->beanPropertyDescriptors, function (AbstractBeanPropertyDescriptor $property) {
96
            return $property->isCompulsory();
97
        });
98
99
        return $constructorProperties;
100
    }
101
102
    /**
103
     * Returns the list of columns that have default values for a given table.
104
     *
105
     * @return AbstractBeanPropertyDescriptor[]
106
     */
107
    public function getPropertiesWithDefault()
108
    {
109
        $properties = $this->getPropertiesForTable($this->table);
110
        $defaultProperties = array_filter($properties, function (AbstractBeanPropertyDescriptor $property) {
111
            return $property->hasDefault();
112
        });
113
114
        return $defaultProperties;
115
    }
116
117
    /**
118
     * Returns the list of properties exposed as getters and setters in this class.
119
     *
120
     * @return AbstractBeanPropertyDescriptor[]
121
     */
122
    public function getExposedProperties()
123
    {
124
        $exposedProperties = array_filter($this->beanPropertyDescriptors, function (AbstractBeanPropertyDescriptor $property) {
125
            return $property->getTable()->getName() == $this->table->getName();
126
        });
127
128
        return $exposedProperties;
129
    }
130
131
    /**
132
     * Returns the list of properties for this table (including parent tables).
133
     *
134
     * @param Table $table
135
     *
136
     * @return AbstractBeanPropertyDescriptor[]
137
     */
138
    private function getProperties(Table $table)
139
    {
140
        $parentRelationship = $this->schemaAnalyzer->getParentRelationship($table->getName());
141
        if ($parentRelationship) {
142
            $parentTable = $this->schema->getTable($parentRelationship->getForeignTableName());
143
            $properties = $this->getProperties($parentTable);
144
            // we merge properties by overriding property names.
145
            $localProperties = $this->getPropertiesForTable($table);
146
            foreach ($localProperties as $name => $property) {
147
                // We do not override properties if this is a primary key!
148
                if ($property->isPrimaryKey()) {
149
                    continue;
150
                }
151
                $properties[$name] = $property;
152
            }
153
        } else {
154
            $properties = $this->getPropertiesForTable($table);
155
        }
156
157
        return $properties;
158
    }
159
160
    /**
161
     * Returns the list of properties for this table (ignoring parent tables).
162
     *
163
     * @param Table $table
164
     *
165
     * @return AbstractBeanPropertyDescriptor[]
166
     */
167
    private function getPropertiesForTable(Table $table)
168
    {
169
        $parentRelationship = $this->schemaAnalyzer->getParentRelationship($table->getName());
170
        if ($parentRelationship) {
171
            $ignoreColumns = $parentRelationship->getLocalColumns();
172
        } else {
173
            $ignoreColumns = [];
174
        }
175
176
        $beanPropertyDescriptors = [];
177
178
        foreach ($table->getColumns() as $column) {
179
            if (array_search($column->getName(), $ignoreColumns) !== false) {
180
                continue;
181
            }
182
183
            $fk = $this->isPartOfForeignKey($table, $column);
184
            if ($fk !== null) {
185
                // Check that previously added descriptors are not added on same FK (can happen with multi key FK).
186
                foreach ($beanPropertyDescriptors as $beanDescriptor) {
187
                    if ($beanDescriptor instanceof ObjectBeanPropertyDescriptor && $beanDescriptor->getForeignKey() === $fk) {
188
                        continue 2;
189
                    }
190
                }
191
                // Check that this property is not an inheritance relationship
192
                $parentRelationship = $this->schemaAnalyzer->getParentRelationship($table->getName());
193
                if ($parentRelationship === $fk) {
194
                    continue;
195
                }
196
197
                $beanPropertyDescriptors[] = new ObjectBeanPropertyDescriptor($table, $fk, $this->schemaAnalyzer);
198
            } else {
199
                $beanPropertyDescriptors[] = new ScalarBeanPropertyDescriptor($table, $column);
200
            }
201
        }
202
203
        // Now, let's get the name of all properties and let's check there is no duplicate.
204
        /** @var $names AbstractBeanPropertyDescriptor[] */
205
        $names = [];
206
        foreach ($beanPropertyDescriptors as $beanDescriptor) {
207
            $name = $beanDescriptor->getUpperCamelCaseName();
208
            if (isset($names[$name])) {
209
                $names[$name]->useAlternativeName();
210
                $beanDescriptor->useAlternativeName();
211
            } else {
212
                $names[$name] = $beanDescriptor;
213
            }
214
        }
215
216
        // Final check (throw exceptions if problem arises)
217
        $names = [];
218
        foreach ($beanPropertyDescriptors as $beanDescriptor) {
219
            $name = $beanDescriptor->getUpperCamelCaseName();
220
            if (isset($names[$name])) {
221
                throw new TDBMException('Unsolvable name conflict while generating method name');
222
            } else {
223
                $names[$name] = $beanDescriptor;
224
            }
225
        }
226
227
        // Last step, let's rebuild the list with a map:
228
        $beanPropertyDescriptorsMap = [];
229
        foreach ($beanPropertyDescriptors as $beanDescriptor) {
230
            $beanPropertyDescriptorsMap[$beanDescriptor->getLowerCamelCaseName()] = $beanDescriptor;
231
        }
232
233
        return $beanPropertyDescriptorsMap;
234
    }
235
236
    public function generateBeanConstructor()
237
    {
238
        $constructorProperties = $this->getConstructorProperties();
239
240
        $constructorCode = '    /**
241
     * The constructor takes all compulsory arguments.
242
     *
243
%s
244
     */
245
    public function __construct(%s)
246
    {
247
%s%s    }
248
    ';
249
250
        $paramAnnotations = [];
251
        $arguments = [];
252
        $assigns = [];
253
        $parentConstructorArguments = [];
254
255
        foreach ($constructorProperties as $property) {
256
            $className = $property->getClassName();
257
            if ($className) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $className 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...
258
                $arguments[] = $className.' '.$property->getVariableName();
259
            } else {
260
                $arguments[] = $property->getVariableName();
261
            }
262
            $paramAnnotations[] = $property->getParamAnnotation();
263
            if ($property->getTable()->getName() === $this->table->getName()) {
264
                $assigns[] = $property->getConstructorAssignCode()."\n";
265
            } else {
266
                $parentConstructorArguments[] = $property->getVariableName();
267
            }
268
        }
269
270
        $parentConstructorCode = sprintf("        parent::__construct(%s);\n", implode(', ', $parentConstructorArguments));
271
272
        foreach ($this->getPropertiesWithDefault() as $property) {
273
            $assigns[] = $property->assignToDefaultCode()."\n";
274
        }
275
276
        return sprintf($constructorCode, implode("\n", $paramAnnotations), implode(', ', $arguments), $parentConstructorCode, implode('', $assigns));
277
    }
278
279
    public function getDirectForeignKeysDescriptors()
280
    {
281
        $fks = $this->tdbmSchemaAnalyzer->getIncomingForeignKeys($this->table->getName());
282
283
        $descriptors = [];
284
285
        foreach ($fks as $fk) {
286
            $descriptors[] = new DirectForeignKeyMethodDescriptor($fk, $this->table);
287
        }
288
289
        return $descriptors;
290
    }
291
292
    private function getPivotTableDescriptors()
293
    {
294
        $descs = [];
295
        foreach ($this->schemaAnalyzer->detectJunctionTables(true) as $table) {
296
            // There are exactly 2 FKs since this is a pivot table.
297
            $fks = array_values($table->getForeignKeys());
298
299
            if ($fks[0]->getForeignTableName() === $this->table->getName()) {
300
                list($localFk, $remoteFk) = $fks;
301
            } elseif ($fks[1]->getForeignTableName() === $this->table->getName()) {
302
                list($remoteFk, $localFk) = $fks;
303
            } else {
304
                continue;
305
            }
306
307
            $descs[] = new PivotTableMethodsDescriptor($table, $localFk, $remoteFk);
308
        }
309
310
        return $descs;
311
    }
312
313
    /**
314
     * Returns the list of method descriptors (and applies the alternative name if needed).
315
     *
316
     * @return MethodDescriptorInterface[]
317
     */
318
    private function getMethodDescriptors()
319
    {
320
        $directForeignKeyDescriptors = $this->getDirectForeignKeysDescriptors();
321
        $pivotTableDescriptors = $this->getPivotTableDescriptors();
322
323
        $descriptors = array_merge($directForeignKeyDescriptors, $pivotTableDescriptors);
324
325
        // Descriptors by method names
326
        $descriptorsByMethodName = [];
327
328
        foreach ($descriptors as $descriptor) {
329
            $descriptorsByMethodName[$descriptor->getName()][] = $descriptor;
330
        }
331
332
        foreach ($descriptorsByMethodName as $descriptorsForMethodName) {
333
            if (count($descriptorsForMethodName) > 1) {
334
                foreach ($descriptorsForMethodName as $descriptor) {
335
                    $descriptor->useAlternativeName();
336
                }
337
            }
338
        }
339
340
        return $descriptors;
341
    }
342
343
    public function generateJsonSerialize()
344
    {
345
        $tableName = $this->table->getName();
346
        $parentFk = $this->schemaAnalyzer->getParentRelationship($tableName);
347
        if ($parentFk !== null) {
348
            $initializer = '$array = parent::jsonSerialize($stopRecursion);';
349
        } else {
350
            $initializer = '$array = [];';
351
        }
352
353
        $str = '
354
    /**
355
     * Serializes the object for JSON encoding.
356
     *
357
     * @param bool $stopRecursion Parameter used internally by TDBM to stop embedded objects from embedding other objects.
358
     * @return array
359
     */
360
    public function jsonSerialize($stopRecursion = false)
361
    {
362
        %s
363
%s
364
%s
365
        return $array;
366
    }
367
';
368
369
        $propertiesCode = '';
370
        foreach ($this->beanPropertyDescriptors as $beanPropertyDescriptor) {
371
            $propertiesCode .= $beanPropertyDescriptor->getJsonSerializeCode();
372
        }
373
374
        // Many2many relationships
375
        $methodsCode = '';
376
        foreach ($this->getMethodDescriptors() as $methodDescriptor) {
377
            $methodsCode .= $methodDescriptor->getJsonSerializeCode();
378
        }
379
380
        return sprintf($str, $initializer, $propertiesCode, $methodsCode);
381
    }
382
383
    /**
384
     * Returns as an array the class we need to extend from and the list of use statements.
385
     *
386
     * @return array
387
     */
388
    private function generateExtendsAndUseStatements(ForeignKeyConstraint $parentFk = null)
389
    {
390
        $classes = [];
391
        if ($parentFk !== null) {
392
            $extends = TDBMDaoGenerator::getBeanNameFromTableName($parentFk->getForeignTableName());
393
            $classes[] = $extends;
394
        }
395
396
        foreach ($this->getBeanPropertyDescriptors() as $beanPropertyDescriptor) {
397
            $className = $beanPropertyDescriptor->getClassName();
398
            if (null !== $className) {
399
                $classes[] = $beanPropertyDescriptor->getClassName();
400
            }
401
        }
402
403
        foreach ($this->getMethodDescriptors() as $descriptor) {
404
            $classes = array_merge($classes, $descriptor->getUsedClasses());
405
        }
406
407
        $classes = array_unique($classes);
408
409
        return $classes;
410
    }
411
412
    /**
413
     * Writes the PHP bean file with all getters and setters from the table passed in parameter.
414
     *
415
     * @param string $beannamespace The namespace of the bean
416
     */
417
    public function generatePhpCode($beannamespace)
418
    {
419
        $tableName = $this->table->getName();
420
        $baseClassName = TDBMDaoGenerator::getBaseBeanNameFromTableName($tableName);
421
        $className = TDBMDaoGenerator::getBeanNameFromTableName($tableName);
422
        $parentFk = $this->schemaAnalyzer->getParentRelationship($tableName);
423
424
        $classes = $this->generateExtendsAndUseStatements($parentFk);
425
426
        $uses = array_map(function ($className) use ($beannamespace) {
427
            return 'use '.$beannamespace.'\\'.$className.";\n";
428
        }, $classes);
429
        $use = implode('', $uses);
430
431
        if ($parentFk !== null) {
432
            $extends = TDBMDaoGenerator::getBeanNameFromTableName($parentFk->getForeignTableName());
433
        } else {
434
            $extends = 'AbstractTDBMObject';
435
            $use .= "use Mouf\\Database\\TDBM\\AbstractTDBMObject;\n";
436
        }
437
438
        $str = "<?php
439
namespace {$beannamespace}\\Generated;
440
441
use Mouf\\Database\\TDBM\\ResultIterator;
442
use Mouf\\Database\\TDBM\\ResultArray;
443
use Mouf\\Database\\TDBM\\AlterableResultIterator;
444
$use
445
/*
446
 * This file has been automatically generated by TDBM.
447
 * DO NOT edit this file, as it might be overwritten.
448
 * If you need to perform changes, edit the $className class instead!
449
 */
450
451
/**
452
 * The $baseClassName class maps the '$tableName' table in database.
453
 */
454
class $baseClassName extends $extends implements \\JsonSerializable
455
{
456
";
457
458
        $str .= $this->generateBeanConstructor();
459
460
        foreach ($this->getExposedProperties() as $property) {
461
            $str .= $property->getGetterSetterCode();
462
        }
463
464
        foreach ($this->getMethodDescriptors() as $methodDescriptor) {
465
            $str .= $methodDescriptor->getCode();
466
        }
467
        $str .= $this->generateJsonSerialize();
468
469
        $str .= $this->generateGetUsedTablesCode();
470
471
        $str .= $this->generateOnDeleteCode();
472
473
        $str .= '}
474
';
475
476
        return $str;
477
    }
478
479
    /**
480
     * @param string $beanNamespace
481
     * @param string $beanClassName
482
     *
483
     * @return array first element: list of used beans, second item: PHP code as a string
484
     */
485
    public function generateFindByDaoCode($beanNamespace, $beanClassName)
486
    {
487
        $code = '';
488
        $usedBeans = [];
489
        foreach ($this->table->getIndexes() as $index) {
490
            if (!$index->isPrimary()) {
491
                list($usedBeansForIndex, $codeForIndex) = $this->generateFindByDaoCodeForIndex($index, $beanNamespace, $beanClassName);
492
                $code .= $codeForIndex;
493
                $usedBeans = array_merge($usedBeans, $usedBeansForIndex);
494
            }
495
        }
496
497
        return [$usedBeans, $code];
498
    }
499
500
    /**
501
     * @param Index  $index
502
     * @param string $beanNamespace
503
     * @param string $beanClassName
504
     *
505
     * @return array first element: list of used beans, second item: PHP code as a string
506
     */
507
    private function generateFindByDaoCodeForIndex(Index $index, $beanNamespace, $beanClassName)
508
    {
509
        $columns = $index->getColumns();
510
        $usedBeans = [];
511
512
        /*
513
         * The list of elements building this index (expressed as columns or foreign keys)
514
         * @var AbstractBeanPropertyDescriptor[]
515
         */
516
        $elements = [];
517
518
        foreach ($columns as $column) {
519
            $fk = $this->isPartOfForeignKey($this->table, $this->table->getColumn($column));
520
            if ($fk !== null) {
521
                if (!in_array($fk, $elements)) {
522
                    $elements[] = new ObjectBeanPropertyDescriptor($this->table, $fk, $this->schemaAnalyzer);
523
                }
524
            } else {
525
                $elements[] = new ScalarBeanPropertyDescriptor($this->table, $this->table->getColumn($column));
526
            }
527
        }
528
529
        // If the index is actually only a foreign key, let's bypass it entirely.
530
        if (count($elements) === 1 && $elements[0] instanceof ObjectBeanPropertyDescriptor) {
531
            return [[], ''];
532
        }
533
534
        $methodNameComponent = [];
535
        $functionParameters = [];
536
        $first = true;
537
        foreach ($elements as $element) {
538
            $methodNameComponent[] = $element->getUpperCamelCaseName();
539
            $functionParameter = $element->getClassName();
540
            if ($functionParameter) {
541
                $usedBeans[] = $beanNamespace.'\\'.$functionParameter;
542
                $functionParameter .= ' ';
543
            }
544
            $functionParameter .= $element->getVariableName();
545
            if ($first) {
546
                $first = false;
547
            } else {
548
                $functionParameter .= ' = null';
549
            }
550
            $functionParameters[] = $functionParameter;
551
        }
552
        if ($index->isUnique()) {
553
            $methodName = 'findOneBy'.implode('And', $methodNameComponent);
554
            $calledMethod = 'findOne';
555
            $returnType = "{$beanClassName}";
556
        } else {
557
            $methodName = 'findBy'.implode('And', $methodNameComponent);
558
            $returnType = "{$beanClassName}[]|ResultIterator|ResultArray";
559
            $calledMethod = 'find';
560
        }
561
        $functionParametersString = implode(', ', $functionParameters);
562
563
        $count = 0;
564
565
        $params = [];
566
        $filterArrayCode = '';
567
        $commentArguments = [];
568
        foreach ($elements as $element) {
569
            $params[] = $element->getParamAnnotation();
570
            if ($element instanceof ScalarBeanPropertyDescriptor) {
571
                $filterArrayCode .= '            '.var_export($element->getColumnName(), true).' => '.$element->getVariableName().",\n";
572
            } else {
573
                ++$count;
574
                $filterArrayCode .= '            '.$count.' => '.$element->getVariableName().",\n";
575
            }
576
            $commentArguments[] = substr($element->getVariableName(), 1);
577
        }
578
        $paramsString = implode("\n", $params);
579
580
        $code = "
581
    /**
582
     * Get a list of $beanClassName filtered by ".implode(', ', $commentArguments).".
583
     *
584
$paramsString
585
     * @param mixed \$orderBy The order string
586
     * @param array \$additionalTablesFetch A list of additional tables to fetch (for performance improvement)
587
     * @param string \$mode Either TDBMService::MODE_ARRAY or TDBMService::MODE_CURSOR (for large datasets). Defaults to TDBMService::MODE_ARRAY.
588
     * @return $returnType
589
     */
590
    public function $methodName($functionParametersString, \$orderBy = null, array \$additionalTablesFetch = array(), \$mode = null)
591
    {
592
        \$filter = [
593
".$filterArrayCode."        ];
594
        return \$this->$calledMethod(\$filter, [], \$orderBy, \$additionalTablesFetch, \$mode);
595
    }
596
";
597
598
        return [$usedBeans, $code];
599
    }
600
601
    /**
602
     * Generates the code for the getUsedTable protected method.
603
     *
604
     * @return string
605
     */
606
    private function generateGetUsedTablesCode()
607
    {
608
        $hasParentRelationship = $this->schemaAnalyzer->getParentRelationship($this->table->getName()) !== null;
609
        if ($hasParentRelationship) {
610
            $code = sprintf('        $tables = parent::getUsedTables();
611
        $tables[] = %s;
612
613
        return $tables;', var_export($this->table->getName(), true));
614
        } else {
615
            $code = sprintf('        return [ %s ];', var_export($this->table->getName(), true));
616
        }
617
618
        return sprintf('
619
    /**
620
     * Returns an array of used tables by this bean (from parent to child relationship).
621
     *
622
     * @return string[]
623
     */
624
    protected function getUsedTables()
625
    {
626
%s
627
    }
628
', $code);
629
    }
630
631
    private function generateOnDeleteCode()
632
    {
633
        $code = '';
634
        $relationships = $this->getPropertiesForTable($this->table);
635
        foreach ($relationships as $relationship) {
636
            if ($relationship instanceof ObjectBeanPropertyDescriptor) {
637
                $code .= sprintf('        $this->setRef('.var_export($relationship->getForeignKey()->getName(), true).', null, '.var_export($this->table->getName(), true).");\n");
638
            }
639
        }
640
641
        if ($code) {
642
            return sprintf('
643
    /**
644
     * Method called when the bean is removed from database.
645
     *
646
     */
647
    protected function onDelete()
648
    {
649
        parent::onDelete();
650
%s    }
651
', $code);
652
        }
653
654
        return '';
655
    }
656
}
657