Completed
Pull Request — master (#1410)
by Ilya
10:40
created

EntityGenerator   D

Complexity

Total Complexity 292

Size/Duplication

Total Lines 1816
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 94.29%

Importance

Changes 4
Bugs 2 Features 2
Metric Value
wmc 292
c 4
b 2
f 2
lcom 1
cbo 3
dl 0
loc 1816
ccs 594
cts 630
cp 0.9429
rs 4.4102

58 Methods

Rating   Name   Duplication   Size   Complexity  
A generateEntityClass() 0 22 1
A setExtension() 0 4 1
A setClassToExtend() 0 4 1
A setGenerateAnnotations() 0 4 1
A setEmbeddablesImmutable() 0 4 1
A setAnnotationPrefix() 0 4 1
A setUpdateEntityIfExists() 0 4 1
A setRegenerateEntityIfExists() 0 4 1
A setGenerateStubMethods() 0 4 1
A setBackupExisting() 0 4 1
A hasNamespace() 0 4 2
A extendsClass() 0 4 2
A getClassToExtend() 0 4 1
A getNamespace() 0 4 1
A generateEntityAnnotation() 0 14 4
A __construct() 0 6 2
A generate() 0 6 2
A generateUpdatedEntityClass() 0 10 2
A setNumSpaces() 0 5 1
A setFieldVisibility() 0 8 3
A getType() 0 8 2
A generateEntityNamespace() 0 6 2
A generateEntityUse() 0 8 2
A generateEntityClassName() 0 5 2
C generateEntityBody() 0 34 7
C generateEntityConstructor() 0 24 7
D parseTokensInEntityFile() 0 46 19
C hasProperty() 0 22 9
C hasMethod() 0 23 9
B getTraits() 0 20 5
A getClassToExtendName() 0 6 1
A getClassName() 0 5 2
B generateEntityDocBlock() 0 32 6
D generateTableAnnotation() 0 32 10
A generateTableConstraints() 0 13 3
A generateInheritanceAnnotation() 0 6 2
A generateDiscriminatorColumnAnnotation() 0 11 2
A generateDiscriminatorMapAnnotation() 0 12 3
F generateEntityStubMethods() 0 66 26
B isAssociationIsNullable() 0 21 7
C writeEntityClass() 0 33 11
D generateEmbeddableConstructor() 0 88 11
A generateEntityLifecycleCallbackMethods() 0 14 3
A generateEntityAssociationMappingProperties() 0 16 4
C generateEntityFieldMappingProperties() 0 22 7
A generateEntityEmbeddedProperties() 0 15 4
C generateEntityStubMethod() 0 45 7
B generateLifecycleCallbacks() 0 30 2
D generateJoinColumnAnnotation() 0 30 10
F generateAssociationMappingPropertyDocBlock() 0 145 36
F generateFieldMappingPropertyDocBlock() 0 89 22
A generateEmbeddedPropertyDocBlock() 0 23 3
A prefixCodeWithSpaces() 0 12 3
A getInheritanceTypeString() 0 8 2
A getChangeTrackingPolicyString() 0 8 2
A getIdGeneratorTypeString() 0 8 2
A exportTableOptions() 0 14 3
A getLifecycleCallbackMethods() 0 16 4

How to fix   Complexity   

Complex Class

Complex classes like EntityGenerator 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 EntityGenerator, and based on these observations, apply Extract Interface, too.

1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\ORM\Tools;
21
22
use Doctrine\ORM\Mapping\ClassMetadataInfo;
23
use Doctrine\Common\Util\Inflector;
24
use Doctrine\DBAL\Types\Type;
25
26
/**
27
 * Generic class used to generate PHP5 entity classes from ClassMetadataInfo instances.
28
 *
29
 *     [php]
30
 *     $classes = $em->getClassMetadataFactory()->getAllMetadata();
31
 *
32
 *     $generator = new \Doctrine\ORM\Tools\EntityGenerator();
33
 *     $generator->setGenerateAnnotations(true);
34
 *     $generator->setGenerateStubMethods(true);
35
 *     $generator->setRegenerateEntityIfExists(false);
36
 *     $generator->setUpdateEntityIfExists(true);
37
 *     $generator->generate($classes, '/path/to/generate/entities');
38
 *
39
 *
40
 * @link    www.doctrine-project.org
41
 * @since   2.0
42
 * @author  Benjamin Eberlei <[email protected]>
43
 * @author  Guilherme Blanco <[email protected]>
44
 * @author  Jonathan Wage <[email protected]>
45
 * @author  Roman Borschel <[email protected]>
46
 */
47
class EntityGenerator
48
{
49
    /**
50
     * Specifies class fields should be protected.
51
     */
52
    const FIELD_VISIBLE_PROTECTED = 'protected';
53
54
    /**
55
     * Specifies class fields should be private.
56
     */
57
    const FIELD_VISIBLE_PRIVATE = 'private';
58
59
    /**
60
     * @var bool
61
     */
62
    protected $backupExisting = true;
63
64
    /**
65
     * The extension to use for written php files.
66
     *
67
     * @var string
68
     */
69
    protected $extension = '.php';
70
71
    /**
72
     * Whether or not the current ClassMetadataInfo instance is new or old.
73
     *
74
     * @var boolean
75
     */
76
    protected $isNew = true;
77
78
    /**
79
     * @var array
80
     */
81
    protected $staticReflection = array();
82
83
    /**
84
     * Number of spaces to use for indention in generated code.
85
     */
86
    protected $numSpaces = 4;
87
88
    /**
89
     * The actual spaces to use for indention.
90
     *
91
     * @var string
92
     */
93
    protected $spaces = '    ';
94
95
    /**
96
     * The class all generated entities should extend.
97
     *
98
     * @var string
99
     */
100
    protected $classToExtend;
101
102
    /**
103
     * Whether or not to generation annotations.
104
     *
105
     * @var boolean
106
     */
107
    protected $generateAnnotations = false;
108
109
    /**
110
     * @var string
111
     */
112
    protected $annotationsPrefix = '';
113
114
    /**
115
     * Whether or not to generate sub methods.
116
     *
117
     * @var boolean
118
     */
119
    protected $generateEntityStubMethods = false;
120
121
    /**
122
     * Whether or not to update the entity class if it exists already.
123
     *
124
     * @var boolean
125
     */
126
    protected $updateEntityIfExists = false;
127
128
    /**
129
     * Whether or not to re-generate entity class if it exists already.
130
     *
131
     * @var boolean
132
     */
133
    protected $regenerateEntityIfExists = false;
134
135
    /**
136
     * Visibility of the field
137
     *
138
     * @var string
139
     */
140
    protected $fieldVisibility = 'private';
141
142
    /**
143
     * Whether or not to make generated embeddables immutable.
144
     *
145
     * @var boolean.
146
     */
147
    protected $embeddablesImmutable = false;
148
149
    /**
150
     * Hash-map for handle types.
151
     *
152
     * @var array
153
     */
154
    protected $typeAlias = array(
155
        Type::DATETIMETZ    => '\DateTime',
156
        Type::DATETIME      => '\DateTime',
157
        Type::DATE          => '\DateTime',
158
        Type::TIME          => '\DateTime',
159
        Type::OBJECT        => '\stdClass',
160
        Type::INTEGER       => 'int',
161
        Type::BIGINT        => 'int',
162
        Type::SMALLINT      => 'int',
163
        Type::TEXT          => 'string',
164
        Type::BLOB          => 'string',
165
        Type::DECIMAL       => 'string',
166
        Type::JSON_ARRAY    => 'array',
167
        Type::SIMPLE_ARRAY  => 'array',
168
        Type::BOOLEAN       => 'bool',
169
    );
170
171
    /**
172
     * Hash-map to handle generator types string.
173
     *
174
     * @var array
175
     */
176
    protected static $generatorStrategyMap = array(
177
        ClassMetadataInfo::GENERATOR_TYPE_AUTO      => 'AUTO',
178
        ClassMetadataInfo::GENERATOR_TYPE_SEQUENCE  => 'SEQUENCE',
179
        ClassMetadataInfo::GENERATOR_TYPE_TABLE     => 'TABLE',
180
        ClassMetadataInfo::GENERATOR_TYPE_IDENTITY  => 'IDENTITY',
181
        ClassMetadataInfo::GENERATOR_TYPE_NONE      => 'NONE',
182
        ClassMetadataInfo::GENERATOR_TYPE_UUID      => 'UUID',
183
        ClassMetadataInfo::GENERATOR_TYPE_CUSTOM    => 'CUSTOM'
184
    );
185
186
    /**
187
     * Hash-map to handle the change tracking policy string.
188
     *
189
     * @var array
190
     */
191
    protected static $changeTrackingPolicyMap = array(
192
        ClassMetadataInfo::CHANGETRACKING_DEFERRED_IMPLICIT  => 'DEFERRED_IMPLICIT',
193
        ClassMetadataInfo::CHANGETRACKING_DEFERRED_EXPLICIT  => 'DEFERRED_EXPLICIT',
194
        ClassMetadataInfo::CHANGETRACKING_NOTIFY             => 'NOTIFY',
195
    );
196
197
    /**
198
     * Hash-map to handle the inheritance type string.
199
     *
200
     * @var array
201
     */
202
    protected static $inheritanceTypeMap = array(
203
        ClassMetadataInfo::INHERITANCE_TYPE_NONE            => 'NONE',
204
        ClassMetadataInfo::INHERITANCE_TYPE_JOINED          => 'JOINED',
205
        ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_TABLE    => 'SINGLE_TABLE',
206
        ClassMetadataInfo::INHERITANCE_TYPE_TABLE_PER_CLASS => 'TABLE_PER_CLASS',
207
    );
208
209
    /**
210
     * @var string
211
     */
212
    protected static $classTemplate =
213
'<?php
214
215
<namespace>
216
<useStatement>
217
<entityAnnotation>
218
<entityClassName>
219
{
220
<entityBody>
221
}
222
';
223
224
    /**
225
     * @var string
226
     */
227
    protected static $getMethodTemplate =
228
'/**
229
 * <description>
230
 *
231
 * @return <variableType>
232
 */
233
public function <methodName>()
234
{
235
<spaces>return $this-><fieldName>;
236
}';
237
238
    /**
239
     * @var string
240
     */
241
    protected static $setMethodTemplate =
242
'/**
243
 * <description>
244
 *
245
 * @param <variableType> $<variableName>
246
 *
247
 * @return <entity>
248
 */
249
public function <methodName>(<methodTypeHint>$<variableName><variableDefault>)
250
{
251
<spaces>$this-><fieldName> = $<variableName>;
252
253
<spaces>return $this;
254
}';
255
256
    /**
257
     * @var string
258
     */
259
    protected static $addMethodTemplate =
260
'/**
261
 * <description>
262
 *
263
 * @param <variableType> $<variableName>
264
 *
265
 * @return <entity>
266
 */
267
public function <methodName>(<methodTypeHint>$<variableName>)
268
{
269
<spaces>$this-><fieldName>[] = $<variableName>;
270
271
<spaces>return $this;
272
}';
273
274
    /**
275
     * @var string
276
     */
277
    protected static $removeMethodTemplate =
278
'/**
279
 * <description>
280
 *
281
 * @param <variableType> $<variableName>
282
 *
283
 * @return boolean TRUE if this collection contained the specified element, FALSE otherwise.
284
 */
285
public function <methodName>(<methodTypeHint>$<variableName>)
286
{
287
<spaces>return $this-><fieldName>->removeElement($<variableName>);
288
}';
289
290
    /**
291
     * @var string
292
     */
293
    protected static $lifecycleCallbackMethodTemplate =
294
'/**
295
 * <lifecycleNames>
296
 */
297
public function <methodName>()
298
{
299
<spaces>// Add your code here
300
}';
301
302
    /**
303
     * @var string
304
     */
305
    protected static $constructorMethodTemplate =
306
'/**
307
 * Constructor
308
 */
309
public function __construct()
310
{
311
<spaces><collections>
312
}
313
';
314
315
    /**
316
     * @var string
317
     */
318
    protected static $embeddableConstructorMethodTemplate =
319
'/**
320
 * Constructor
321
 *
322
 * <paramTags>
323
 */
324
public function __construct(<params>)
325
{
326
<spaces><fields>
327
}
328
';
329
330
    /**
331
     * Constructor.
332
     */
333 41
    public function __construct()
334
    {
335 41
        if (version_compare(\Doctrine\Common\Version::VERSION, '2.2.0-DEV', '>=')) {
336 41
            $this->annotationsPrefix = 'ORM\\';
337
        }
338 41
    }
339
340
    /**
341
     * Generates and writes entity classes for the given array of ClassMetadataInfo instances.
342
     *
343
     * @param array  $metadatas
344
     * @param string $outputDirectory
345
     *
346
     * @return void
347
     */
348
    public function generate(array $metadatas, $outputDirectory)
349
    {
350
        foreach ($metadatas as $metadata) {
351
            $this->writeEntityClass($metadata, $outputDirectory);
352
        }
353
    }
354
355
    /**
356
     * Generates and writes entity class to disk for the given ClassMetadataInfo instance.
357
     *
358
     * @param ClassMetadataInfo $metadata
359
     * @param string            $outputDirectory
360
     *
361
     * @return void
362
     *
363
     * @throws \RuntimeException
364
     */
365 31
    public function writeEntityClass(ClassMetadataInfo $metadata, $outputDirectory)
366
    {
367 31
        $path = $outputDirectory . '/' . str_replace('\\', DIRECTORY_SEPARATOR, $metadata->name) . $this->extension;
368 31
        $dir = dirname($path);
369
370 31
        if ( ! is_dir($dir)) {
371 2
            mkdir($dir, 0775, true);
372
        }
373
374 31
        $this->isNew = !file_exists($path) || (file_exists($path) && $this->regenerateEntityIfExists);
375
376 31
        if ( ! $this->isNew) {
377 3
            $this->parseTokensInEntityFile(file_get_contents($path));
378
        } else {
379 30
            $this->staticReflection[$metadata->name] = array('properties' => array(), 'methods' => array());
380
        }
381
382 31
        if ($this->backupExisting && file_exists($path)) {
383 3
            $backupPath = dirname($path) . DIRECTORY_SEPARATOR . basename($path) . "~";
384 3
            if (!copy($path, $backupPath)) {
385
                throw new \RuntimeException("Attempt to backup overwritten entity file but copy operation failed.");
386
            }
387
        }
388
389
        // If entity doesn't exist or we're re-generating the entities entirely
390 31
        if ($this->isNew) {
391 30
            file_put_contents($path, $this->generateEntityClass($metadata));
392
        // If entity exists and we're allowed to update the entity class
393 3
        } elseif ( ! $this->isNew && $this->updateEntityIfExists) {
394 3
            file_put_contents($path, $this->generateUpdatedEntityClass($metadata, $path));
395
        }
396 31
        chmod($path, 0664);
397 31
    }
398
399
    /**
400
     * Generates a PHP5 Doctrine 2 entity class from the given ClassMetadataInfo instance.
401
     *
402
     * @param ClassMetadataInfo $metadata
403
     *
404
     * @return string
405
     */
406 31
    public function generateEntityClass(ClassMetadataInfo $metadata)
407
    {
408
        $placeHolders = array(
409 31
            '<namespace>',
410
            '<useStatement>',
411
            '<entityAnnotation>',
412
            '<entityClassName>',
413
            '<entityBody>'
414
        );
415
416
        $replacements = array(
417 31
            $this->generateEntityNamespace($metadata),
418 31
            $this->generateEntityUse(),
419 31
            $this->generateEntityDocBlock($metadata),
420 31
            $this->generateEntityClassName($metadata),
421 31
            $this->generateEntityBody($metadata)
422
        );
423
424 31
        $code = str_replace($placeHolders, $replacements, static::$classTemplate) . "\n";
425
426 31
        return str_replace('<spaces>', $this->spaces, $code);
427
    }
428
429
    /**
430
     * Generates the updated code for the given ClassMetadataInfo and entity at path.
431
     *
432
     * @param ClassMetadataInfo $metadata
433
     * @param string            $path
434
     *
435
     * @return string
436
     */
437 3
    public function generateUpdatedEntityClass(ClassMetadataInfo $metadata, $path)
438
    {
439 3
        $currentCode = file_get_contents($path);
440
441 3
        $body = $this->generateEntityBody($metadata);
442 3
        $body = str_replace('<spaces>', $this->spaces, $body);
443 3
        $last = strrpos($currentCode, '}');
444
445 3
        return substr($currentCode, 0, $last) . $body . (strlen($body) > 0 ? "\n" : '') . "}\n";
446
    }
447
448
    /**
449
     * Sets the number of spaces the exported class should have.
450
     *
451
     * @param integer $numSpaces
452
     *
453
     * @return void
454
     */
455
    public function setNumSpaces($numSpaces)
456
    {
457
        $this->spaces = str_repeat(' ', $numSpaces);
458
        $this->numSpaces = $numSpaces;
459
    }
460
461
    /**
462
     * Sets the extension to use when writing php files to disk.
463
     *
464
     * @param string $extension
465
     *
466
     * @return void
467
     */
468
    public function setExtension($extension)
469
    {
470
        $this->extension = $extension;
471
    }
472
473
    /**
474
     * Sets the name of the class the generated classes should extend from.
475
     *
476
     * @param string $classToExtend
477
     *
478
     * @return void
479
     */
480 1
    public function setClassToExtend($classToExtend)
481
    {
482 1
        $this->classToExtend = $classToExtend;
483 1
    }
484
485
    /**
486
     * Sets whether or not to generate annotations for the entity.
487
     *
488
     * @param bool $bool
489
     *
490
     * @return void
491
     */
492 40
    public function setGenerateAnnotations($bool)
493
    {
494 40
        $this->generateAnnotations = $bool;
495 40
    }
496
497
    /**
498
     * Sets the class fields visibility for the entity (can either be private or protected).
499
     *
500
     * @param bool $visibility
501
     *
502
     * @return void
503
     *
504
     * @throws \InvalidArgumentException
505
     */
506 39
    public function setFieldVisibility($visibility)
507
    {
508 39
        if ($visibility !== static::FIELD_VISIBLE_PRIVATE && $visibility !== static::FIELD_VISIBLE_PROTECTED) {
509
            throw new \InvalidArgumentException('Invalid provided visibility (only private and protected are allowed): ' . $visibility);
510
        }
511
512 39
        $this->fieldVisibility = $visibility;
513 39
    }
514
515
    /**
516
     * Sets whether or not to generate immutable embeddables.
517
     *
518
     * @param boolean $embeddablesImmutable
519
     */
520 1
    public function setEmbeddablesImmutable($embeddablesImmutable)
521
    {
522 1
        $this->embeddablesImmutable = (boolean) $embeddablesImmutable;
523 1
    }
524
525
    /**
526
     * Sets an annotation prefix.
527
     *
528
     * @param string $prefix
529
     *
530
     * @return void
531
     */
532 40
    public function setAnnotationPrefix($prefix)
533
    {
534 40
        $this->annotationsPrefix = $prefix;
535 40
    }
536
537
    /**
538
     * Sets whether or not to try and update the entity if it already exists.
539
     *
540
     * @param bool $bool
541
     *
542
     * @return void
543
     */
544 40
    public function setUpdateEntityIfExists($bool)
545
    {
546 40
        $this->updateEntityIfExists = $bool;
547 40
    }
548
549
    /**
550
     * Sets whether or not to regenerate the entity if it exists.
551
     *
552
     * @param bool $bool
553
     *
554
     * @return void
555
     */
556 40
    public function setRegenerateEntityIfExists($bool)
557
    {
558 40
        $this->regenerateEntityIfExists = $bool;
559 40
    }
560
561
    /**
562
     * Sets whether or not to generate stub methods for the entity.
563
     *
564
     * @param bool $bool
565
     *
566
     * @return void
567
     */
568 40
    public function setGenerateStubMethods($bool)
569
    {
570 40
        $this->generateEntityStubMethods = $bool;
571 40
    }
572
573
    /**
574
     * Should an existing entity be backed up if it already exists?
575
     *
576
     * @param bool $bool
577
     *
578
     * @return void
579
     */
580 1
    public function setBackupExisting($bool)
581
    {
582 1
        $this->backupExisting = $bool;
583 1
    }
584
585
    /**
586
     * @param string $type
587
     *
588
     * @return string
589
     */
590 31
    protected function getType($type)
591
    {
592 31
        if (isset($this->typeAlias[$type])) {
593 30
            return $this->typeAlias[$type];
594
        }
595
596 18
        return $type;
597
    }
598
599
    /**
600
     * @param ClassMetadataInfo $metadata
601
     *
602
     * @return string
603
     */
604 31
    protected function generateEntityNamespace(ClassMetadataInfo $metadata)
605
    {
606 31
        if ($this->hasNamespace($metadata)) {
607 31
            return 'namespace ' . $this->getNamespace($metadata) .';';
608
        }
609 2
    }
610
611 31
    protected function generateEntityUse()
612
    {
613 31
        if ($this->generateAnnotations) {
614 31
            return "\n".'use Doctrine\ORM\Mapping as ORM;'."\n";
615
        } else {
616
            return "";
617
        }
618
    }
619
620
    /**
621
     * @param ClassMetadataInfo $metadata
622
     *
623
     * @return string
624
     */
625 31
    protected function generateEntityClassName(ClassMetadataInfo $metadata)
626
    {
627 31
        return 'class ' . $this->getClassName($metadata) .
628 31
            ($this->extendsClass() ? ' extends ' . $this->getClassToExtendName() : null);
629
    }
630
631
    /**
632
     * @param ClassMetadataInfo $metadata
633
     *
634
     * @return string
635
     */
636 32
    protected function generateEntityBody(ClassMetadataInfo $metadata)
637
    {
638 32
        $fieldMappingProperties = $this->generateEntityFieldMappingProperties($metadata);
639 32
        $embeddedProperties = $this->generateEntityEmbeddedProperties($metadata);
640 32
        $associationMappingProperties = $this->generateEntityAssociationMappingProperties($metadata);
641 32
        $stubMethods = $this->generateEntityStubMethods ? $this->generateEntityStubMethods($metadata) : null;
642 32
        $lifecycleCallbackMethods = $this->generateEntityLifecycleCallbackMethods($metadata);
643
644 32
        $code = array();
645
646 32
        if ($fieldMappingProperties) {
647 29
            $code[] = $fieldMappingProperties;
648
        }
649
650 32
        if ($embeddedProperties) {
651 8
            $code[] = $embeddedProperties;
652
        }
653
654 32
        if ($associationMappingProperties) {
655 11
            $code[] = $associationMappingProperties;
656
        }
657
658 32
        $code[] = $this->generateEntityConstructor($metadata);
659
660 32
        if ($stubMethods) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $stubMethods of type string|null 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...
661 30
            $code[] = $stubMethods;
662
        }
663
664 32
        if ($lifecycleCallbackMethods) {
665 12
            $code[] = $lifecycleCallbackMethods;
666
        }
667
668 32
        return implode("\n", $code);
669
    }
670
671
    /**
672
     * @param ClassMetadataInfo $metadata
673
     *
674
     * @return string
675
     */
676 32
    protected function generateEntityConstructor(ClassMetadataInfo $metadata)
677
    {
678 32
        if ($this->hasMethod('__construct', $metadata)) {
679 2
            return '';
680
        }
681
682 32
        if ($metadata->isEmbeddedClass && $this->embeddablesImmutable) {
683 1
            return $this->generateEmbeddableConstructor($metadata);
684
        }
685
686 31
        $collections = array();
687
688 31
        foreach ($metadata->associationMappings as $mapping) {
689 13
            if ($mapping['type'] & ClassMetadataInfo::TO_MANY) {
690 13
                $collections[] = '$this->'.$mapping['fieldName'].' = new \Doctrine\Common\Collections\ArrayCollection();';
691
            }
692
        }
693
694 31
        if ($collections) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $collections of type array 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...
695 11
            return $this->prefixCodeWithSpaces(str_replace("<collections>", implode("\n".$this->spaces, $collections), static::$constructorMethodTemplate));
696
        }
697
698 27
        return '';
699
    }
700
701
    /**
702
     * @param ClassMetadataInfo $metadata
703
     *
704
     * @return string
705
     */
706 1
    private function generateEmbeddableConstructor(ClassMetadataInfo $metadata)
707
    {
708 1
        $paramTypes = array();
709 1
        $paramVariables = array();
710 1
        $params = array();
711 1
        $fields = array();
712
713
        // Resort fields to put optional fields at the end of the method signature.
714 1
        $requiredFields = array();
715 1
        $optionalFields = array();
716
717 1
        foreach ($metadata->fieldMappings as $fieldMapping) {
718 1
            if (empty($fieldMapping['nullable'])) {
719 1
                $requiredFields[] = $fieldMapping;
720
721 1
                continue;
722
            }
723
724 1
            $optionalFields[] = $fieldMapping;
725
        }
726
727 1
        $fieldMappings = array_merge($requiredFields, $optionalFields);
728
729 1
        foreach ($metadata->embeddedClasses as $fieldName => $embeddedClass) {
730 1
            $paramType = '\\' . ltrim($embeddedClass['class'], '\\');
731 1
            $paramVariable = '$' . $fieldName;
732
733 1
            $paramTypes[] = $paramType;
734 1
            $paramVariables[] = $paramVariable;
735 1
            $params[] = $paramType . ' ' . $paramVariable;
736 1
            $fields[] = '$this->' . $fieldName . ' = ' . $paramVariable . ';';
737
        }
738
739 1
        foreach ($fieldMappings as $fieldMapping) {
740 1
            if (isset($fieldMapping['declaredField']) &&
741 1
                isset($metadata->embeddedClasses[$fieldMapping['declaredField']])
742
            ) {
743
                continue;
744
            }
745
746 1
            $paramTypes[] = $this->getType($fieldMapping['type']) . (!empty($fieldMapping['nullable']) ? '|null' : '');
747 1
            $param = '$' . $fieldMapping['fieldName'];
748 1
            $paramVariables[] = $param;
749
750 1
            if ($fieldMapping['type'] === 'datetime') {
751 1
                $param = $this->getType($fieldMapping['type']) . ' ' . $param;
752
            }
753
754 1
            if (!empty($fieldMapping['nullable'])) {
755 1
                $param .= ' = null';
756
            }
757
758 1
            $params[] = $param;
759
760 1
            $fields[] = '$this->' . $fieldMapping['fieldName'] . ' = $' . $fieldMapping['fieldName'] . ';';
761
        }
762
763 1
        $maxParamTypeLength = max(array_map('strlen', $paramTypes));
764 1
        $paramTags = array_map(
765
            function ($type, $variable) use ($maxParamTypeLength) {
766 1
                return '@param ' . $type . str_repeat(' ', $maxParamTypeLength - strlen($type) + 1) . $variable;
767 1
            },
768
            $paramTypes,
769
            $paramVariables
770
        );
771
772
        // Generate multi line constructor if the signature exceeds 120 characters.
773 1
        if (array_sum(array_map('strlen', $params)) + count($params) * 2 + 29 > 120) {
774 1
            $delimiter = "\n" . $this->spaces;
775 1
            $params = $delimiter . implode(',' . $delimiter, $params) . "\n";
776
        } else {
777 1
            $params = implode(', ', $params);
778
        }
779
780
        $replacements = array(
781 1
            '<paramTags>' => implode("\n * ", $paramTags),
782 1
            '<params>'    => $params,
783 1
            '<fields>'    => implode("\n" . $this->spaces, $fields),
784
        );
785
786 1
        $constructor = str_replace(
787
            array_keys($replacements),
788
            array_values($replacements),
789 1
            static::$embeddableConstructorMethodTemplate
790
        );
791
792 1
        return $this->prefixCodeWithSpaces($constructor);
793
    }
794
795
    /**
796
     * @todo this won't work if there is a namespace in brackets and a class outside of it.
797
     *
798
     * @param string $src
799
     *
800
     * @return void
801
     */
802 8
    protected function parseTokensInEntityFile($src)
803
    {
804 8
        $tokens = token_get_all($src);
805 8
        $lastSeenNamespace = "";
806 8
        $lastSeenClass = false;
807
808 8
        $inNamespace = false;
809 8
        $inClass = false;
810
811 8
        for ($i = 0; $i < count($tokens); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
812 8
            $token = $tokens[$i];
813 8
            if (in_array($token[0], array(T_WHITESPACE, T_COMMENT, T_DOC_COMMENT))) {
814 8
                continue;
815
            }
816
817 8
            if ($inNamespace) {
818 8
                if ($token[0] == T_NS_SEPARATOR || $token[0] == T_STRING) {
819 8
                    $lastSeenNamespace .= $token[1];
820 8
                } elseif (is_string($token) && in_array($token, array(';', '{'))) {
821 8
                    $inNamespace = false;
822
                }
823
            }
824
825 8
            if ($inClass) {
826 8
                $inClass = false;
827 8
                $lastSeenClass = $lastSeenNamespace . ($lastSeenNamespace ? '\\' : '') . $token[1];
828 8
                $this->staticReflection[$lastSeenClass]['properties'] = array();
829 8
                $this->staticReflection[$lastSeenClass]['methods'] = array();
830
            }
831
832 8
            if ($token[0] == T_NAMESPACE) {
833 8
                $lastSeenNamespace = "";
834 8
                $inNamespace = true;
835 8
            } elseif ($token[0] == T_CLASS && $tokens[$i-1][0] != T_DOUBLE_COLON) {
836 8
                $inClass = true;
837 8
            } elseif ($token[0] == T_FUNCTION) {
838 3
                if ($tokens[$i+2][0] == T_STRING) {
839 3
                    $this->staticReflection[$lastSeenClass]['methods'][] = strtolower($tokens[$i+2][1]);
840
                } elseif ($tokens[$i+2] == "&" && $tokens[$i+3][0] == T_STRING) {
841 3
                    $this->staticReflection[$lastSeenClass]['methods'][] = strtolower($tokens[$i+3][1]);
842
                }
843 8
            } elseif (in_array($token[0], array(T_VAR, T_PUBLIC, T_PRIVATE, T_PROTECTED)) && $tokens[$i+2][0] != T_FUNCTION) {
844 4
                $this->staticReflection[$lastSeenClass]['properties'][] = substr($tokens[$i+2][1], 1);
845
            }
846
        }
847 8
    }
848
849
    /**
850
     * @param string            $property
851
     * @param ClassMetadataInfo $metadata
852
     *
853
     * @return bool
854
     */
855 31
    protected function hasProperty($property, ClassMetadataInfo $metadata)
856
    {
857 31
        if ($this->extendsClass() || (!$this->isNew && class_exists($metadata->name))) {
858
            // don't generate property if its already on the base class.
859 2
            $reflClass = new \ReflectionClass($this->getClassToExtend() ?: $metadata->name);
860 2
            if ($reflClass->hasProperty($property)) {
861 1
                return true;
862
            }
863
        }
864
865
        // check traits for existing property
866 30
        foreach ($this->getTraits($metadata) as $trait) {
867 2
            if ($trait->hasProperty($property)) {
868 2
                return true;
869
            }
870
        }
871
872
        return (
873 30
            isset($this->staticReflection[$metadata->name]) &&
874 30
            in_array($property, $this->staticReflection[$metadata->name]['properties'])
875
        );
876
    }
877
878
    /**
879
     * @param string            $method
880
     * @param ClassMetadataInfo $metadata
881
     *
882
     * @return bool
883
     */
884 32
    protected function hasMethod($method, ClassMetadataInfo $metadata)
885
    {
886 32
        if ($this->extendsClass() || (!$this->isNew && class_exists($metadata->name))) {
887
            // don't generate method if its already on the base class.
888 2
            $reflClass = new \ReflectionClass($this->getClassToExtend() ?: $metadata->name);
889
890 2
            if ($reflClass->hasMethod($method)) {
891 1
                return true;
892
            }
893
        }
894
895
        // check traits for existing method
896 32
        foreach ($this->getTraits($metadata) as $trait) {
897 2
            if ($trait->hasMethod($method)) {
898 2
                return true;
899
            }
900
        }
901
902
        return (
903 32
            isset($this->staticReflection[$metadata->name]) &&
904 32
            in_array(strtolower($method), $this->staticReflection[$metadata->name]['methods'])
905
        );
906
    }
907
908
    /**
909
     * @param ClassMetadataInfo $metadata
910
     *
911
     * @return array
912
     */
913 32
    protected function getTraits(ClassMetadataInfo $metadata)
914
    {
915 32
        if (! ($metadata->reflClass !== null || class_exists($metadata->name))) {
916 26
            return [];
917
        }
918
919 7
        $reflClass = $metadata->reflClass === null
920 1
            ? new \ReflectionClass($metadata->name)
921 7
            : $metadata->reflClass;
922
923 7
        $traits = array();
924
925 7
        while ($reflClass !== false) {
926 7
            $traits = array_merge($traits, $reflClass->getTraits());
927
928 7
            $reflClass = $reflClass->getParentClass();
929
        }
930
931 7
        return $traits;
932
    }
933
934
    /**
935
     * @param ClassMetadataInfo $metadata
936
     *
937
     * @return bool
938
     */
939 31
    protected function hasNamespace(ClassMetadataInfo $metadata)
940
    {
941 31
        return strpos($metadata->name, '\\') ? true : false;
942
    }
943
944
    /**
945
     * @return bool
946
     */
947 32
    protected function extendsClass()
948
    {
949 32
        return $this->classToExtend ? true : false;
950
    }
951
952
    /**
953
     * @return string
954
     */
955 2
    protected function getClassToExtend()
956
    {
957 2
        return $this->classToExtend;
958
    }
959
960
    /**
961
     * @return string
962
     */
963 1
    protected function getClassToExtendName()
964
    {
965 1
        $refl = new \ReflectionClass($this->getClassToExtend());
966
967 1
        return '\\' . $refl->getName();
968
    }
969
970
    /**
971
     * @param ClassMetadataInfo $metadata
972
     *
973
     * @return string
974
     */
975 32
    protected function getClassName(ClassMetadataInfo $metadata)
976
    {
977 32
        return ($pos = strrpos($metadata->name, '\\'))
978 32
            ? substr($metadata->name, $pos + 1, strlen($metadata->name)) : $metadata->name;
979
    }
980
981
    /**
982
     * @param ClassMetadataInfo $metadata
983
     *
984
     * @return string
985
     */
986 31
    protected function getNamespace(ClassMetadataInfo $metadata)
987
    {
988 31
        return substr($metadata->name, 0, strrpos($metadata->name, '\\'));
989
    }
990
991
    /**
992
     * @param ClassMetadataInfo $metadata
993
     *
994
     * @return string
995
     */
996 31
    protected function generateEntityDocBlock(ClassMetadataInfo $metadata)
997
    {
998 31
        $lines = array();
999 31
        $lines[] = '/**';
1000 31
        $lines[] = ' * ' . $this->getClassName($metadata);
1001
1002 31
        if ($this->generateAnnotations) {
1003 31
            $lines[] = ' *';
1004
1005
            $methods = array(
1006 31
                'generateTableAnnotation',
1007
                'generateInheritanceAnnotation',
1008
                'generateDiscriminatorColumnAnnotation',
1009
                'generateDiscriminatorMapAnnotation',
1010
                'generateEntityAnnotation',
1011
            );
1012
1013 31
            foreach ($methods as $method) {
1014 31
                if ($code = $this->$method($metadata)) {
1015 31
                    $lines[] = ' * ' . $code;
1016
                }
1017
            }
1018
1019 31
            if (isset($metadata->lifecycleCallbacks) && $metadata->lifecycleCallbacks) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $metadata->lifecycleCallbacks of type array 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...
1020 12
                $lines[] = ' * @' . $this->annotationsPrefix . 'HasLifecycleCallbacks';
1021
            }
1022
        }
1023
1024 31
        $lines[] = ' */';
1025
1026 31
        return implode("\n", $lines);
1027
    }
1028
1029
    /**
1030
     * @param ClassMetadataInfo $metadata
1031
     *
1032
     * @return string
1033
     */
1034 31
    protected function generateEntityAnnotation(ClassMetadataInfo $metadata)
1035
    {
1036 31
        $prefix = '@' . $this->annotationsPrefix;
1037
1038 31
        if ($metadata->isEmbeddedClass) {
1039 9
            return $prefix . 'Embeddable';
1040
        }
1041
1042 29
        $customRepository = $metadata->customRepositoryClassName
1043 11
            ? '(repositoryClass="' . $metadata->customRepositoryClassName . '")'
1044 29
            : '';
1045
1046 29
        return $prefix . ($metadata->isMappedSuperclass ? 'MappedSuperclass' : 'Entity') . $customRepository;
1047
    }
1048
1049
    /**
1050
     * @param ClassMetadataInfo $metadata
1051
     *
1052
     * @return string
1053
     */
1054 31
    protected function generateTableAnnotation($metadata)
1055
    {
1056 31
        if ($metadata->isEmbeddedClass) {
1057 9
            return '';
1058
        }
1059
1060 29
        $table = array();
1061
1062 29
        if (isset($metadata->table['schema'])) {
1063
            $table[] = 'schema="' . $metadata->table['schema'] . '"';
1064
        }
1065
1066 29
        if (isset($metadata->table['name'])) {
1067 26
            $table[] = 'name="' . $metadata->table['name'] . '"';
1068
        }
1069
1070 29
        if (isset($metadata->table['options']) && $metadata->table['options']) {
1071 1
            $table[] = 'options={' . $this->exportTableOptions((array) $metadata->table['options']) . '}';
1072
        }
1073
1074 29
        if (isset($metadata->table['uniqueConstraints']) && $metadata->table['uniqueConstraints']) {
1075 9
            $constraints = $this->generateTableConstraints('UniqueConstraint', $metadata->table['uniqueConstraints']);
1076 9
            $table[] = 'uniqueConstraints={' . $constraints . '}';
1077
        }
1078
1079 29
        if (isset($metadata->table['indexes']) && $metadata->table['indexes']) {
1080 9
            $constraints = $this->generateTableConstraints('Index', $metadata->table['indexes']);
1081 9
            $table[] = 'indexes={' . $constraints . '}';
1082
        }
1083
1084 29
        return '@' . $this->annotationsPrefix . 'Table(' . implode(', ', $table) . ')';
1085
    }
1086
1087
    /**
1088
     * @param string $constraintName
1089
     * @param array  $constraints
1090
     *
1091
     * @return string
1092
     */
1093 9
    protected function generateTableConstraints($constraintName, $constraints)
1094
    {
1095 9
        $annotations = array();
1096 9
        foreach ($constraints as $name => $constraint) {
1097 9
            $columns = array();
1098 9
            foreach ($constraint['columns'] as $column) {
1099 9
                $columns[] = '"' . $column . '"';
1100
            }
1101 9
            $annotations[] = '@' . $this->annotationsPrefix . $constraintName . '(name="' . $name . '", columns={' . implode(', ', $columns) . '})';
1102
        }
1103
1104 9
        return implode(', ', $annotations);
1105
    }
1106
1107
    /**
1108
     * @param ClassMetadataInfo $metadata
1109
     *
1110
     * @return string
1111
     */
1112 31
    protected function generateInheritanceAnnotation($metadata)
1113
    {
1114 31
        if ($metadata->inheritanceType != ClassMetadataInfo::INHERITANCE_TYPE_NONE) {
1115
            return '@' . $this->annotationsPrefix . 'InheritanceType("'.$this->getInheritanceTypeString($metadata->inheritanceType).'")';
1116
        }
1117 31
    }
1118
1119
    /**
1120
     * @param ClassMetadataInfo $metadata
1121
     *
1122
     * @return string
1123
     */
1124 31
    protected function generateDiscriminatorColumnAnnotation($metadata)
1125
    {
1126 31
        if ($metadata->inheritanceType != ClassMetadataInfo::INHERITANCE_TYPE_NONE) {
1127
            $discrColumn = $metadata->discriminatorColumn;
1128
            $columnDefinition = 'name="' . $discrColumn['name']
1129
                . '", type="' . $discrColumn['type']
1130
                . '", length=' . $discrColumn['length'];
1131
1132
            return '@' . $this->annotationsPrefix . 'DiscriminatorColumn(' . $columnDefinition . ')';
1133
        }
1134 31
    }
1135
1136
    /**
1137
     * @param ClassMetadataInfo $metadata
1138
     *
1139
     * @return string
1140
     */
1141 31
    protected function generateDiscriminatorMapAnnotation($metadata)
1142
    {
1143 31
        if ($metadata->inheritanceType != ClassMetadataInfo::INHERITANCE_TYPE_NONE) {
1144
            $inheritanceClassMap = array();
1145
1146
            foreach ($metadata->discriminatorMap as $type => $class) {
1147
                $inheritanceClassMap[] .= '"' . $type . '" = "' . $class . '"';
1148
            }
1149
1150
            return '@' . $this->annotationsPrefix . 'DiscriminatorMap({' . implode(', ', $inheritanceClassMap) . '})';
1151
        }
1152 31
    }
1153
1154
    /**
1155
     * @param ClassMetadataInfo $metadata
1156
     *
1157
     * @return string
1158
     */
1159 31
    protected function generateEntityStubMethods(ClassMetadataInfo $metadata)
1160
    {
1161 31
        $methods = array();
1162
1163 31
        foreach ($metadata->fieldMappings as $fieldMapping) {
1164 30
            if (isset($fieldMapping['declaredField']) &&
1165 30
                isset($metadata->embeddedClasses[$fieldMapping['declaredField']])
1166
            ) {
1167
                continue;
1168
            }
1169
1170 30
            if (( ! isset($fieldMapping['id']) ||
1171 28
                    ! $fieldMapping['id'] ||
1172 30
                    $metadata->generatorType == ClassMetadataInfo::GENERATOR_TYPE_NONE
1173 30
                ) && (! $metadata->isEmbeddedClass || ! $this->embeddablesImmutable)
1174
            ) {
1175 25
                if ($code = $this->generateEntityStubMethod($metadata, 'set', $fieldMapping['fieldName'], $fieldMapping['type'])) {
1176 25
                    $methods[] = $code;
1177
                }
1178
            }
1179
1180 30
            if ($code = $this->generateEntityStubMethod($metadata, 'get', $fieldMapping['fieldName'], $fieldMapping['type'])) {
1181 30
                $methods[] = $code;
1182
            }
1183
        }
1184
1185 31
        foreach ($metadata->embeddedClasses as $fieldName => $embeddedClass) {
1186 8
            if (isset($embeddedClass['declaredField'])) {
1187 1
                continue;
1188
            }
1189
1190 8
            if ( ! $metadata->isEmbeddedClass || ! $this->embeddablesImmutable) {
1191 7
                if ($code = $this->generateEntityStubMethod($metadata, 'set', $fieldName, $embeddedClass['class'])) {
1192 7
                    $methods[] = $code;
1193
                }
1194
            }
1195
1196 8
            if ($code = $this->generateEntityStubMethod($metadata, 'get', $fieldName, $embeddedClass['class'])) {
1197 8
                $methods[] = $code;
1198
            }
1199
        }
1200
1201 31
        foreach ($metadata->associationMappings as $associationMapping) {
1202 12
            if ($associationMapping['type'] & ClassMetadataInfo::TO_ONE) {
1203 11
                $nullable = $this->isAssociationIsNullable($associationMapping) ? 'null' : null;
1204 11
                if ($code = $this->generateEntityStubMethod($metadata, 'set', $associationMapping['fieldName'], $associationMapping['targetEntity'], $nullable)) {
1205 9
                    $methods[] = $code;
1206
                }
1207 11
                if ($code = $this->generateEntityStubMethod($metadata, 'get', $associationMapping['fieldName'], $associationMapping['targetEntity'])) {
1208 11
                    $methods[] = $code;
1209
                }
1210 10
            } elseif ($associationMapping['type'] & ClassMetadataInfo::TO_MANY) {
1211 10
                if ($code = $this->generateEntityStubMethod($metadata, 'add', $associationMapping['fieldName'], $associationMapping['targetEntity'])) {
1212 10
                    $methods[] = $code;
1213
                }
1214 10
                if ($code = $this->generateEntityStubMethod($metadata, 'remove', $associationMapping['fieldName'], $associationMapping['targetEntity'])) {
1215 10
                    $methods[] = $code;
1216
                }
1217 10
                if ($code = $this->generateEntityStubMethod($metadata, 'get', $associationMapping['fieldName'], 'Doctrine\Common\Collections\Collection')) {
1218 12
                    $methods[] = $code;
1219
                }
1220
            }
1221
        }
1222
1223 31
        return implode("\n\n", $methods);
1224
    }
1225
1226
    /**
1227
     * @param array $associationMapping
1228
     *
1229
     * @return bool
1230
     */
1231 11
    protected function isAssociationIsNullable($associationMapping)
1232
    {
1233 11
        if (isset($associationMapping['id']) && $associationMapping['id']) {
1234
            return false;
1235
        }
1236
1237 11
        if (isset($associationMapping['joinColumns'])) {
1238 2
            $joinColumns = $associationMapping['joinColumns'];
1239
        } else {
1240
            //@todo there is no way to retrieve targetEntity metadata
1241 9
            $joinColumns = array();
1242
        }
1243
1244 11
        foreach ($joinColumns as $joinColumn) {
1245 2
            if (isset($joinColumn['nullable']) && !$joinColumn['nullable']) {
1246 2
                return false;
1247
            }
1248
        }
1249
1250 11
        return true;
1251
    }
1252
1253
    /**
1254
     * @param ClassMetadataInfo $metadata
1255
     *
1256
     * @return string
1257
     */
1258 32
    protected function generateEntityLifecycleCallbackMethods(ClassMetadataInfo $metadata)
1259
    {
1260 32
        $methods = $this->getLifecycleCallbackMethods($metadata);
1261
1262 32
        $methodsCode = array();
1263
1264 32
        foreach ($methods as $methodName => $lifecycleNames) {
1265 12
            if ($code = $this->generateLifecycleCallbacks($lifecycleNames, $methodName, $metadata)) {
1266 12
                $methodsCode[] = $code;
1267
            }
1268
        }
1269
1270 32
        return implode("\n\n", $methodsCode);
1271
    }
1272
1273
    /**
1274
     * @param ClassMetadataInfo $metadata
1275
     *
1276
     * @return string
1277
     */
1278 32
    protected function generateEntityAssociationMappingProperties(ClassMetadataInfo $metadata)
1279
    {
1280 32
        $lines = array();
1281
1282 32
        foreach ($metadata->associationMappings as $associationMapping) {
1283 13
            if ($this->hasProperty($associationMapping['fieldName'], $metadata)) {
1284 4
                continue;
1285
            }
1286
1287 11
            $lines[] = $this->generateAssociationMappingPropertyDocBlock($associationMapping, $metadata);
1288 11
            $lines[] = $this->spaces . $this->fieldVisibility . ' $' . $associationMapping['fieldName']
1289 11
                     . ($associationMapping['type'] == 'manyToMany' ? ' = array()' : null) . ";\n";
1290
        }
1291
1292 32
        return implode("\n", $lines);
1293
    }
1294
1295
    /**
1296
     * @param ClassMetadataInfo $metadata
1297
     *
1298
     * @return string
1299
     */
1300 32
    protected function generateEntityFieldMappingProperties(ClassMetadataInfo $metadata)
1301
    {
1302 32
        $lines = array();
1303
1304 32
        foreach ($metadata->fieldMappings as $fieldMapping) {
1305 31
            if ($this->hasProperty($fieldMapping['fieldName'], $metadata) ||
1306 30
                $metadata->isInheritedField($fieldMapping['fieldName']) ||
1307
                (
1308 29
                    isset($fieldMapping['declaredField']) &&
1309 31
                    isset($metadata->embeddedClasses[$fieldMapping['declaredField']])
1310
                )
1311
            ) {
1312 4
                continue;
1313
            }
1314
1315 29
            $lines[] = $this->generateFieldMappingPropertyDocBlock($fieldMapping, $metadata);
1316 29
            $lines[] = $this->spaces . $this->fieldVisibility . ' $' . $fieldMapping['fieldName']
1317 29
                     . (isset($fieldMapping['options']['default']) ? ' = ' . var_export($fieldMapping['options']['default'], true) : null) . ";\n";
1318
        }
1319
1320 32
        return implode("\n", $lines);
1321
    }
1322
1323
    /**
1324
     * @param ClassMetadataInfo $metadata
1325
     *
1326
     * @return string
1327
     */
1328 32
    protected function generateEntityEmbeddedProperties(ClassMetadataInfo $metadata)
1329
    {
1330 32
        $lines = array();
1331
1332 32
        foreach ($metadata->embeddedClasses as $fieldName => $embeddedClass) {
1333 8
            if (isset($embeddedClass['declaredField']) || $this->hasProperty($fieldName, $metadata)) {
1334 2
                continue;
1335
            }
1336
1337 8
            $lines[] = $this->generateEmbeddedPropertyDocBlock($embeddedClass);
1338 8
            $lines[] = $this->spaces . $this->fieldVisibility . ' $' . $fieldName . ";\n";
1339
        }
1340
1341 32
        return implode("\n", $lines);
1342
    }
1343
1344
    /**
1345
     * @param ClassMetadataInfo $metadata
1346
     * @param string            $type
1347
     * @param string            $fieldName
1348
     * @param string|null       $typeHint
1349
     * @param string|null       $defaultValue
1350
     *
1351
     * @return string
1352
     */
1353 30
    protected function generateEntityStubMethod(ClassMetadataInfo $metadata, $type, $fieldName, $typeHint = null,  $defaultValue = null)
1354
    {
1355 30
        $methodName = $type . Inflector::classify($fieldName);
1356 30
        $variableName = Inflector::camelize($fieldName);
1357 30
        if (in_array($type, array("add", "remove"))) {
1358 10
            $methodName = Inflector::singularize($methodName);
1359 10
            $variableName = Inflector::singularize($variableName);
1360
        }
1361
1362 30
        if ($this->hasMethod($methodName, $metadata)) {
1363 5
            return '';
1364
        }
1365 30
        $this->staticReflection[$metadata->name]['methods'][] = strtolower($methodName);
1366
1367 30
        $var = sprintf('%sMethodTemplate', $type);
1368 30
        $template = static::$$var;
1369
1370 30
        $methodTypeHint = null;
1371 30
        $types          = Type::getTypesMap();
1372 30
        $variableType   = $typeHint ? $this->getType($typeHint) : null;
1373
1374 30
        if ($typeHint && ! isset($types[$typeHint])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $typeHint of type string|null 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...
1375 12
            $variableType   =  '\\' . ltrim($variableType, '\\');
1376 12
            $methodTypeHint =  '\\' . $typeHint . ' ';
1377
        }
1378
1379
        $replacements = array(
1380 30
          '<description>'       => ucfirst($type) . ' ' . $variableName,
1381 30
          '<methodTypeHint>'    => $methodTypeHint,
1382 30
          '<variableType>'      => $variableType,
1383 30
          '<variableName>'      => $variableName,
1384 30
          '<methodName>'        => $methodName,
1385 30
          '<fieldName>'         => $fieldName,
1386 30
          '<variableDefault>'   => ($defaultValue !== null ) ? (' = '.$defaultValue) : '',
1387 30
          '<entity>'            => $this->getClassName($metadata)
1388
        );
1389
1390 30
        $method = str_replace(
1391
            array_keys($replacements),
1392
            array_values($replacements),
1393
            $template
1394
        );
1395
1396 30
        return $this->prefixCodeWithSpaces($method);
1397
    }
1398
1399
    /**
1400
     * @param string[]          $lifecycleNames
1401
     * @param string            $methodName
1402
     * @param ClassMetadataInfo $metadata
1403
     *
1404
     * @return string
1405
     */
1406 12
    protected function generateLifecycleCallbacks($lifecycleNames, $methodName, $metadata)
1407
    {
1408 12
        if ($this->hasMethod($methodName, $metadata)) {
1409 2
            return '';
1410
        }
1411
1412 12
        $this->staticReflection[$metadata->name]['methods'][] = strtolower($methodName);
1413
1414 12
        $lifecycles = implode("\n * ",
1415
            array_map(
1416 12
                function ($name) {
1417 12
                    return '@' . $this->annotationsPrefix . ucfirst($name);
1418 12
                },
1419
                $lifecycleNames
1420
            )
1421
        );
1422
1423
        $replacements = array(
1424 12
            '<lifecycleNames>' => $lifecycles,
1425 12
            '<methodName>'     => $methodName,
1426
        );
1427
1428 12
        $method = str_replace(
1429
            array_keys($replacements),
1430
            array_values($replacements),
1431 12
            static::$lifecycleCallbackMethodTemplate
1432
        );
1433
1434 12
        return $this->prefixCodeWithSpaces($method);
1435
    }
1436
1437
    /**
1438
     * @param array $joinColumn
1439
     *
1440
     * @return string
1441
     */
1442 11
    protected function generateJoinColumnAnnotation(array $joinColumn)
1443
    {
1444 11
        $joinColumnAnnot = array();
1445
1446 11
        if (isset($joinColumn['name'])) {
1447 11
            $joinColumnAnnot[] = 'name="' . $joinColumn['name'] . '"';
1448
        }
1449
1450 11
        if (isset($joinColumn['referencedColumnName'])) {
1451 11
            $joinColumnAnnot[] = 'referencedColumnName="' . $joinColumn['referencedColumnName'] . '"';
1452
        }
1453
1454 11
        if (isset($joinColumn['unique']) && $joinColumn['unique']) {
1455 1
            $joinColumnAnnot[] = 'unique=' . ($joinColumn['unique'] ? 'true' : 'false');
1456
        }
1457
1458 11
        if (isset($joinColumn['nullable'])) {
1459 1
            $joinColumnAnnot[] = 'nullable=' . ($joinColumn['nullable'] ? 'true' : 'false');
1460
        }
1461
1462 11
        if (isset($joinColumn['onDelete'])) {
1463 1
            $joinColumnAnnot[] = 'onDelete="' . ($joinColumn['onDelete'] . '"');
1464
        }
1465
1466 11
        if (isset($joinColumn['columnDefinition'])) {
1467 1
            $joinColumnAnnot[] = 'columnDefinition="' . $joinColumn['columnDefinition'] . '"';
1468
        }
1469
1470 11
        return '@' . $this->annotationsPrefix . 'JoinColumn(' . implode(', ', $joinColumnAnnot) . ')';
1471
    }
1472
1473
    /**
1474
     * @param array             $associationMapping
1475
     * @param ClassMetadataInfo $metadata
1476
     *
1477
     * @return string
1478
     */
1479 11
    protected function generateAssociationMappingPropertyDocBlock(array $associationMapping, ClassMetadataInfo $metadata)
1480
    {
1481 11
        $lines = array();
1482 11
        $lines[] = $this->spaces . '/**';
1483
1484 11
        if ($associationMapping['type'] & ClassMetadataInfo::TO_MANY) {
1485 11
            $lines[] = $this->spaces . ' * @var \Doctrine\Common\Collections\Collection';
1486
        } else {
1487 10
            $lines[] = $this->spaces . ' * @var \\' . ltrim($associationMapping['targetEntity'], '\\');
1488
        }
1489
1490 11
        if ($this->generateAnnotations) {
1491 11
            $lines[] = $this->spaces . ' *';
1492
1493 11
            if (isset($associationMapping['id']) && $associationMapping['id']) {
1494
                $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'Id';
1495
1496
                if ($generatorType = $this->getIdGeneratorTypeString($metadata->generatorType)) {
1497
                    $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'GeneratedValue(strategy="' . $generatorType . '")';
1498
                }
1499
            }
1500
1501 11
            $type = null;
1502 11
            switch ($associationMapping['type']) {
1503 11
                case ClassMetadataInfo::ONE_TO_ONE:
1504 10
                    $type = 'OneToOne';
1505 10
                    break;
1506 11
                case ClassMetadataInfo::MANY_TO_ONE:
1507 1
                    $type = 'ManyToOne';
1508 1
                    break;
1509 11
                case ClassMetadataInfo::ONE_TO_MANY:
1510 1
                    $type = 'OneToMany';
1511 1
                    break;
1512 11
                case ClassMetadataInfo::MANY_TO_MANY:
1513 11
                    $type = 'ManyToMany';
1514 11
                    break;
1515
            }
1516 11
            $typeOptions = array();
1517
1518 11
            if (isset($associationMapping['targetEntity'])) {
1519 11
                $typeOptions[] = 'targetEntity="' . $associationMapping['targetEntity'] . '"';
1520
            }
1521
1522 11
            if (isset($associationMapping['inversedBy'])) {
1523 1
                $typeOptions[] = 'inversedBy="' . $associationMapping['inversedBy'] . '"';
1524
            }
1525
1526 11
            if (isset($associationMapping['mappedBy'])) {
1527 10
                $typeOptions[] = 'mappedBy="' . $associationMapping['mappedBy'] . '"';
1528
            }
1529
1530 11
            if ($associationMapping['cascade']) {
1531 1
                $cascades = array();
1532
1533 1
                if ($associationMapping['isCascadePersist']) $cascades[] = '"persist"';
1534 1
                if ($associationMapping['isCascadeRemove']) $cascades[] = '"remove"';
1535 1
                if ($associationMapping['isCascadeDetach']) $cascades[] = '"detach"';
1536 1
                if ($associationMapping['isCascadeMerge']) $cascades[] = '"merge"';
1537 1
                if ($associationMapping['isCascadeRefresh']) $cascades[] = '"refresh"';
1538
1539 1
                if (count($cascades) === 5) {
1540 1
                    $cascades = array('"all"');
1541
                }
1542
1543 1
                $typeOptions[] = 'cascade={' . implode(',', $cascades) . '}';
1544
            }
1545
1546 11
            if (isset($associationMapping['orphanRemoval']) && $associationMapping['orphanRemoval']) {
1547 1
                $typeOptions[] = 'orphanRemoval=' . ($associationMapping['orphanRemoval'] ? 'true' : 'false');
1548
            }
1549
1550 11
            if (isset($associationMapping['fetch']) && $associationMapping['fetch'] !== ClassMetadataInfo::FETCH_LAZY) {
1551
                $fetchMap = array(
1552 10
                    ClassMetadataInfo::FETCH_EXTRA_LAZY => 'EXTRA_LAZY',
1553 10
                    ClassMetadataInfo::FETCH_EAGER      => 'EAGER',
1554
                );
1555
1556 10
                $typeOptions[] = 'fetch="' . $fetchMap[$associationMapping['fetch']] . '"';
1557
            }
1558
1559 11
            $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . '' . $type . '(' . implode(', ', $typeOptions) . ')';
1560
1561 11
            if (isset($associationMapping['joinColumns']) && $associationMapping['joinColumns']) {
1562 1
                $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'JoinColumns({';
1563
1564 1
                $joinColumnsLines = array();
1565
1566 1
                foreach ($associationMapping['joinColumns'] as $joinColumn) {
1567 1
                    if ($joinColumnAnnot = $this->generateJoinColumnAnnotation($joinColumn)) {
1568 1
                        $joinColumnsLines[] = $this->spaces . ' *   ' . $joinColumnAnnot;
1569
                    }
1570
                }
1571
1572 1
                $lines[] = implode(",\n", $joinColumnsLines);
1573 1
                $lines[] = $this->spaces . ' * })';
1574
            }
1575
1576 11
            if (isset($associationMapping['joinTable']) && $associationMapping['joinTable']) {
1577 11
                $joinTable = array();
1578 11
                $joinTable[] = 'name="' . $associationMapping['joinTable']['name'] . '"';
1579
1580 11
                if (isset($associationMapping['joinTable']['schema'])) {
1581
                    $joinTable[] = 'schema="' . $associationMapping['joinTable']['schema'] . '"';
1582
                }
1583
1584 11
                $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'JoinTable(' . implode(', ', $joinTable) . ',';
1585 11
                $lines[] = $this->spaces . ' *   joinColumns={';
1586
1587 11
                $joinColumnsLines = array();
1588
1589 11
                foreach ($associationMapping['joinTable']['joinColumns'] as $joinColumn) {
1590 11
                    $joinColumnsLines[] = $this->spaces . ' *     ' . $this->generateJoinColumnAnnotation($joinColumn);
1591
                }
1592
1593 11
                $lines[] = implode(",". PHP_EOL, $joinColumnsLines);
1594 11
                $lines[] = $this->spaces . ' *   },';
1595 11
                $lines[] = $this->spaces . ' *   inverseJoinColumns={';
1596
1597 11
                $inverseJoinColumnsLines = array();
1598
1599 11
                foreach ($associationMapping['joinTable']['inverseJoinColumns'] as $joinColumn) {
1600 11
                    $inverseJoinColumnsLines[] = $this->spaces . ' *     ' . $this->generateJoinColumnAnnotation($joinColumn);
1601
                }
1602
1603 11
                $lines[] = implode(",". PHP_EOL, $inverseJoinColumnsLines);
1604 11
                $lines[] = $this->spaces . ' *   }';
1605 11
                $lines[] = $this->spaces . ' * )';
1606
            }
1607
1608 11
            if (isset($associationMapping['orderBy'])) {
1609 1
                $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'OrderBy({';
1610
1611 1
                foreach ($associationMapping['orderBy'] as $name => $direction) {
1612 1
                    $lines[] = $this->spaces . ' *     "' . $name . '"="' . $direction . '",';
1613
                }
1614
1615 1
                $lines[count($lines) - 1] = substr($lines[count($lines) - 1], 0, strlen($lines[count($lines) - 1]) - 1);
1616 1
                $lines[] = $this->spaces . ' * })';
1617
            }
1618
        }
1619
1620 11
        $lines[] = $this->spaces . ' */';
1621
1622 11
        return implode("\n", $lines);
1623
    }
1624
1625
    /**
1626
     * @param array             $fieldMapping
1627
     * @param ClassMetadataInfo $metadata
1628
     *
1629
     * @return string
1630
     */
1631 29
    protected function generateFieldMappingPropertyDocBlock(array $fieldMapping, ClassMetadataInfo $metadata)
1632
    {
1633 29
        $lines = array();
1634 29
        $lines[] = $this->spaces . '/**';
1635 29
        $lines[] = $this->spaces . ' * @var ' . $this->getType($fieldMapping['type']);
1636
1637 29
        if ($this->generateAnnotations) {
1638 29
            $lines[] = $this->spaces . ' *';
1639
1640 29
            $column = array();
1641 29
            if (isset($fieldMapping['columnName'])) {
1642 29
                $column[] = 'name="' . $fieldMapping['columnName'] . '"';
1643
            }
1644
1645 29
            if (isset($fieldMapping['type'])) {
1646 29
                $column[] = 'type="' . $fieldMapping['type'] . '"';
1647
            }
1648
1649 29
            if (isset($fieldMapping['length'])) {
1650 4
                $column[] = 'length=' . $fieldMapping['length'];
1651
            }
1652
1653 29
            if (isset($fieldMapping['precision'])) {
1654 4
                $column[] = 'precision=' .  $fieldMapping['precision'];
1655
            }
1656
1657 29
            if (isset($fieldMapping['scale'])) {
1658 4
                $column[] = 'scale=' . $fieldMapping['scale'];
1659
            }
1660
1661 29
            if (isset($fieldMapping['nullable'])) {
1662 8
                $column[] = 'nullable=' .  var_export($fieldMapping['nullable'], true);
1663
            }
1664
1665 29
            $options = [];
1666
1667 29
            if (isset($fieldMapping['options']['unsigned']) && $fieldMapping['options']['unsigned']) {
1668 1
                $options[] = '"unsigned"=true';
1669
            }
1670
1671 29
            if ($options) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $options of type array 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...
1672 1
                $column[] = 'options={'.implode(',', $options).'}';
1673
            }
1674
1675 29
            if (isset($fieldMapping['columnDefinition'])) {
1676 1
                $column[] = 'columnDefinition="' . $fieldMapping['columnDefinition'] . '"';
1677
            }
1678
1679 29
            if (isset($fieldMapping['unique'])) {
1680 4
                $column[] = 'unique=' . var_export($fieldMapping['unique'], true);
1681
            }
1682
1683 29
            $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'Column(' . implode(', ', $column) . ')';
1684
1685 29
            if (isset($fieldMapping['id']) && $fieldMapping['id']) {
1686 27
                $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'Id';
1687
1688 27
                if ($generatorType = $this->getIdGeneratorTypeString($metadata->generatorType)) {
1689 27
                    $lines[] = $this->spaces.' * @' . $this->annotationsPrefix . 'GeneratedValue(strategy="' . $generatorType . '")';
1690
                }
1691
1692 27
                if ($metadata->sequenceGeneratorDefinition) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $metadata->sequenceGeneratorDefinition of type array 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...
1693 1
                    $sequenceGenerator = array();
1694
1695 1
                    if (isset($metadata->sequenceGeneratorDefinition['sequenceName'])) {
1696 1
                        $sequenceGenerator[] = 'sequenceName="' . $metadata->sequenceGeneratorDefinition['sequenceName'] . '"';
1697
                    }
1698
1699 1
                    if (isset($metadata->sequenceGeneratorDefinition['allocationSize'])) {
1700 1
                        $sequenceGenerator[] = 'allocationSize=' . $metadata->sequenceGeneratorDefinition['allocationSize'];
1701
                    }
1702
1703 1
                    if (isset($metadata->sequenceGeneratorDefinition['initialValue'])) {
1704 1
                        $sequenceGenerator[] = 'initialValue=' . $metadata->sequenceGeneratorDefinition['initialValue'];
1705
                    }
1706
1707 1
                    $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'SequenceGenerator(' . implode(', ', $sequenceGenerator) . ')';
1708
                }
1709
            }
1710
1711 29
            if (isset($fieldMapping['version']) && $fieldMapping['version']) {
1712
                $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'Version';
1713
            }
1714
        }
1715
1716 29
        $lines[] = $this->spaces . ' */';
1717
1718 29
        return implode("\n", $lines);
1719
    }
1720
1721
    /**
1722
     * @param array $embeddedClass
1723
     *
1724
     * @return string
1725
     */
1726 8
    protected function generateEmbeddedPropertyDocBlock(array $embeddedClass)
1727
    {
1728 8
        $lines = array();
1729 8
        $lines[] = $this->spaces . '/**';
1730 8
        $lines[] = $this->spaces . ' * @var \\' . ltrim($embeddedClass['class'], '\\');
1731
1732 8
        if ($this->generateAnnotations) {
1733 8
            $lines[] = $this->spaces . ' *';
1734
1735 8
            $embedded = array('class="' . $embeddedClass['class'] . '"');
1736
1737 8
            if (isset($fieldMapping['columnPrefix'])) {
0 ignored issues
show
Bug introduced by
The variable $fieldMapping seems to never exist, and therefore isset should always return false. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
1738
                $embedded[] = 'columnPrefix=' . var_export($embeddedClass['columnPrefix'], true);
1739
            }
1740
1741 8
            $lines[] = $this->spaces . ' * @' .
1742 8
                $this->annotationsPrefix . 'Embedded(' . implode(', ', $embedded) . ')';
1743
        }
1744
1745 8
        $lines[] = $this->spaces . ' */';
1746
1747 8
        return implode("\n", $lines);
1748
    }
1749
1750
    /**
1751
     * @param string $code
1752
     * @param int    $num
1753
     *
1754
     * @return string
1755
     */
1756 31
    protected function prefixCodeWithSpaces($code, $num = 1)
1757
    {
1758 31
        $lines = explode("\n", $code);
1759
1760 31
        foreach ($lines as $key => $value) {
1761 31
            if ( ! empty($value)) {
1762 31
                $lines[$key] = str_repeat($this->spaces, $num) . $lines[$key];
1763
            }
1764
        }
1765
1766 31
        return implode("\n", $lines);
1767
    }
1768
1769
    /**
1770
     * @param integer $type The inheritance type used by the class and its subclasses.
1771
     *
1772
     * @return string The literal string for the inheritance type.
1773
     *
1774
     * @throws \InvalidArgumentException When the inheritance type does not exist.
1775
     */
1776 1
    protected function getInheritanceTypeString($type)
1777
    {
1778 1
        if ( ! isset(static::$inheritanceTypeMap[$type])) {
1779 1
            throw new \InvalidArgumentException(sprintf('Invalid provided InheritanceType: %s', $type));
1780
        }
1781
1782 1
        return static::$inheritanceTypeMap[$type];
1783
    }
1784
1785
    /**
1786
     * @param integer $type The policy used for change-tracking for the mapped class.
1787
     *
1788
     * @return string The literal string for the change-tracking type.
1789
     *
1790
     * @throws \InvalidArgumentException When the change-tracking type does not exist.
1791
     */
1792 1
    protected function getChangeTrackingPolicyString($type)
1793
    {
1794 1
        if ( ! isset(static::$changeTrackingPolicyMap[$type])) {
1795 1
            throw new \InvalidArgumentException(sprintf('Invalid provided ChangeTrackingPolicy: %s', $type));
1796
        }
1797
1798 1
        return static::$changeTrackingPolicyMap[$type];
1799
    }
1800
1801
    /**
1802
     * @param integer $type The generator to use for the mapped class.
1803
     *
1804
     * @return string The literal string for the generator type.
1805
     *
1806
     * @throws \InvalidArgumentException    When the generator type does not exist.
1807
     */
1808 28
    protected function getIdGeneratorTypeString($type)
1809
    {
1810 28
        if ( ! isset(static::$generatorStrategyMap[$type])) {
1811 1
            throw new \InvalidArgumentException(sprintf('Invalid provided IdGeneratorType: %s', $type));
1812
        }
1813
1814 28
        return static::$generatorStrategyMap[$type];
1815
    }
1816
1817
    /**
1818
     * Exports (nested) option elements.
1819
     *
1820
     * @param array $options
1821
     *
1822
     * @return string
1823
     */
1824 1
    private function exportTableOptions(array $options)
1825
    {
1826 1
        $optionsStr = array();
1827
1828 1
        foreach ($options as $name => $option) {
1829 1
            if (is_array($option)) {
1830 1
                $optionsStr[] = '"' . $name . '"={' . $this->exportTableOptions($option) . '}';
1831
            } else {
1832 1
                $optionsStr[] = '"' . $name . '"="' . (string) $option . '"';
1833
            }
1834
        }
1835
1836 1
        return implode(',', $optionsStr);
1837
    }
1838
1839
    /**
1840
     * Get lifecycle callback methods grouped by method name
1841
     *
1842
     * @param ClassMetadataInfo $metadata
1843
     *
1844
     * @return array
1845
     */
1846 32
    private function getLifecycleCallbackMethods(ClassMetadataInfo $metadata)
1847
    {
1848 32
        if (!isset($metadata->lifecycleCallbacks)) {
1849
            return array();
1850
        }
1851
1852 32
        $methods = array();
1853
1854 32
        foreach ($metadata->lifecycleCallbacks as $lifecycleName => $methodNames) {
1855 12
            foreach ($methodNames as $methodName) {
1856 12
                $methods[$methodName][] = $lifecycleName;
1857
            }
1858
        }
1859
1860 32
        return $methods;
1861
    }
1862
}
1863