Completed
Push — master ( c14805...89a008 )
by Marco
10:07
created

EntityGenerator   D

Complexity

Total Complexity 291

Size/Duplication

Total Lines 1804
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 94.44%

Importance

Changes 0
Metric Value
wmc 291
lcom 1
cbo 3
dl 0
loc 1804
ccs 594
cts 629
cp 0.9444
rs 4.4102
c 0
b 0
f 0

58 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 2
A generate() 0 6 2
A generateEntityClass() 0 22 1
A generateUpdatedEntityClass() 0 10 2
A setNumSpaces() 0 5 1
A setExtension() 0 4 1
A setClassToExtend() 0 4 1
A setGenerateAnnotations() 0 4 1
A setFieldVisibility() 0 8 3
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 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 generateEmbeddableConstructor() 0 88 11
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 generateEntityAnnotation() 0 14 4
D generateTableAnnotation() 0 32 10
A generateInheritanceAnnotation() 0 6 2
A generateDiscriminatorColumnAnnotation() 0 11 2
A generateDiscriminatorMapAnnotation() 0 12 3
C hasProperty() 0 22 9
C hasMethod() 0 23 9
B getTraits() 0 20 5
A hasNamespace() 0 4 1
A extendsClass() 0 4 1
A getClassToExtend() 0 4 1
A getClassToExtendName() 0 6 1
A getClassName() 0 5 2
A getNamespace() 0 4 1
B generateEntityDocBlock() 0 32 6
D writeEntityClass() 0 33 9
D parseTokensInEntityFile() 0 47 18
A generateTableConstraints() 0 13 3
F generateEntityStubMethods() 0 67 26
B isAssociationIsNullable() 0 21 7
B generateEntityLifecycleCallbackMethods() 0 18 6
A generateEntityAssociationMappingProperties() 0 16 4
C generateEntityFieldMappingProperties() 0 22 7
A generateEntityEmbeddedProperties() 0 15 4
C generateEntityStubMethod() 0 45 8
A generateLifecycleCallbackMethod() 0 20 2
D generateJoinColumnAnnotation() 0 30 10
F generateAssociationMappingPropertyDocBlock() 0 145 36
F generateFieldMappingPropertyDocBlock() 0 91 23
A nullableFieldExpression() 0 8 3
A exportTableOptions() 0 14 3

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
 * @<name>
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 38
    public function __construct()
334
    {
335 38
        if (version_compare(\Doctrine\Common\Version::VERSION, '2.2.0-DEV', '>=')) {
336 38
            $this->annotationsPrefix = 'ORM\\';
337
        }
338 38
    }
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 29
    public function writeEntityClass(ClassMetadataInfo $metadata, $outputDirectory)
366
    {
367 29
        $path = $outputDirectory . '/' . str_replace('\\', DIRECTORY_SEPARATOR, $metadata->name) . $this->extension;
368 29
        $dir = dirname($path);
369
370 29
        if ( ! is_dir($dir)) {
371 2
            mkdir($dir, 0775, true);
372
        }
373
374 29
        $this->isNew = ! file_exists($path) || $this->regenerateEntityIfExists;
375
376 29
        if ( ! $this->isNew) {
377 3
            $this->parseTokensInEntityFile(file_get_contents($path));
378
        } else {
379 28
            $this->staticReflection[$metadata->name] = array('properties' => array(), 'methods' => array());
380
        }
381
382 29
        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 29
        if ($this->isNew) {
391 28
            file_put_contents($path, $this->generateEntityClass($metadata));
392
        // If entity exists and we're allowed to update the entity class
393 3
        } elseif ($this->updateEntityIfExists) {
394 3
            file_put_contents($path, $this->generateUpdatedEntityClass($metadata, $path));
395
        }
396 29
        chmod($path, 0664);
397 29
    }
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 29
    public function generateEntityClass(ClassMetadataInfo $metadata)
407
    {
408
        $placeHolders = array(
409 29
            '<namespace>',
410
            '<useStatement>',
411
            '<entityAnnotation>',
412
            '<entityClassName>',
413
            '<entityBody>'
414
        );
415
416
        $replacements = array(
417 29
            $this->generateEntityNamespace($metadata),
418 29
            $this->generateEntityUse(),
419 29
            $this->generateEntityDocBlock($metadata),
420 29
            $this->generateEntityClassName($metadata),
421 29
            $this->generateEntityBody($metadata)
422
        );
423
424 29
        $code = str_replace($placeHolders, $replacements, static::$classTemplate) . "\n";
425
426 29
        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 . ($body ? "\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 38
    public function setGenerateAnnotations($bool)
493
    {
494 38
        $this->generateAnnotations = $bool;
495 38
    }
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 37
    public function setFieldVisibility($visibility)
507
    {
508 37
        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 37
        $this->fieldVisibility = $visibility;
513 37
    }
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 38
    public function setAnnotationPrefix($prefix)
533
    {
534 38
        $this->annotationsPrefix = $prefix;
535 38
    }
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 38
    public function setUpdateEntityIfExists($bool)
545
    {
546 38
        $this->updateEntityIfExists = $bool;
547 38
    }
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 38
    public function setRegenerateEntityIfExists($bool)
557
    {
558 38
        $this->regenerateEntityIfExists = $bool;
559 38
    }
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 38
    public function setGenerateStubMethods($bool)
569
    {
570 38
        $this->generateEntityStubMethods = $bool;
571 38
    }
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 29
    protected function getType($type)
591
    {
592 29
        if (isset($this->typeAlias[$type])) {
593 28
            return $this->typeAlias[$type];
594
        }
595
596 18
        return $type;
597
    }
598
599
    /**
600
     * @param ClassMetadataInfo $metadata
601
     *
602
     * @return string
603
     */
604 29
    protected function generateEntityNamespace(ClassMetadataInfo $metadata)
605
    {
606 29
        if ($this->hasNamespace($metadata)) {
607 29
            return 'namespace ' . $this->getNamespace($metadata) .';';
608
        }
609 2
    }
610
611 29
    protected function generateEntityUse()
612
    {
613 29
        if ($this->generateAnnotations) {
614 29
            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 29
    protected function generateEntityClassName(ClassMetadataInfo $metadata)
626
    {
627 29
        return 'class ' . $this->getClassName($metadata) .
628 29
            ($this->extendsClass() ? ' extends ' . $this->getClassToExtendName() : null);
629
    }
630
631
    /**
632
     * @param ClassMetadataInfo $metadata
633
     *
634
     * @return string
635
     */
636 30
    protected function generateEntityBody(ClassMetadataInfo $metadata)
637
    {
638 30
        $fieldMappingProperties = $this->generateEntityFieldMappingProperties($metadata);
639 30
        $embeddedProperties = $this->generateEntityEmbeddedProperties($metadata);
640 30
        $associationMappingProperties = $this->generateEntityAssociationMappingProperties($metadata);
641 30
        $stubMethods = $this->generateEntityStubMethods ? $this->generateEntityStubMethods($metadata) : null;
642 30
        $lifecycleCallbackMethods = $this->generateEntityLifecycleCallbackMethods($metadata);
643
644 30
        $code = array();
645
646 30
        if ($fieldMappingProperties) {
647 27
            $code[] = $fieldMappingProperties;
648
        }
649
650 30
        if ($embeddedProperties) {
651 8
            $code[] = $embeddedProperties;
652
        }
653
654 30
        if ($associationMappingProperties) {
655 11
            $code[] = $associationMappingProperties;
656
        }
657
658 30
        $code[] = $this->generateEntityConstructor($metadata);
659
660 30
        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 28
            $code[] = $stubMethods;
662
        }
663
664 30
        if ($lifecycleCallbackMethods) {
665 10
            $code[] = $lifecycleCallbackMethods;
666
        }
667
668 30
        return implode("\n", $code);
669
    }
670
671
    /**
672
     * @param ClassMetadataInfo $metadata
673
     *
674
     * @return string
675
     */
676 30
    protected function generateEntityConstructor(ClassMetadataInfo $metadata)
677
    {
678 30
        if ($this->hasMethod('__construct', $metadata)) {
679 2
            return '';
680
        }
681
682 30
        if ($metadata->isEmbeddedClass && $this->embeddablesImmutable) {
683 1
            return $this->generateEmbeddableConstructor($metadata);
684
        }
685
686 29
        $collections = array();
687
688 29
        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 29
        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 25
        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 1
            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
        $tokensCount = count($tokens);
806 8
        $lastSeenNamespace = '';
807 8
        $lastSeenClass = false;
808
809 8
        $inNamespace = false;
810 8
        $inClass = false;
811
812 8
        for ($i = 0; $i < $tokensCount; $i++) {
813 8
            $token = $tokens[$i];
814 8
            if (in_array($token[0], array(T_WHITESPACE, T_COMMENT, T_DOC_COMMENT), true)) {
815 8
                continue;
816
            }
817
818 8
            if ($inNamespace) {
819 8
                if (in_array($token[0], array(T_NS_SEPARATOR, T_STRING), true)) {
820 8
                    $lastSeenNamespace .= $token[1];
821 8
                } elseif (is_string($token) && in_array($token, array(';', '{'), true)) {
822 8
                    $inNamespace = false;
823
                }
824
            }
825
826 8
            if ($inClass) {
827 8
                $inClass = false;
828 8
                $lastSeenClass = $lastSeenNamespace . ($lastSeenNamespace ? '\\' : '') . $token[1];
829 8
                $this->staticReflection[$lastSeenClass]['properties'] = array();
830 8
                $this->staticReflection[$lastSeenClass]['methods'] = array();
831
            }
832
833 8
            if (T_NAMESPACE === $token[0]) {
834 8
                $lastSeenNamespace = '';
835 8
                $inNamespace = true;
836 8
            } elseif (T_CLASS === $token[0] && T_DOUBLE_COLON !== $tokens[$i-1][0]) {
837 8
                $inClass = true;
838 8
            } elseif (T_FUNCTION === $token[0]) {
839 3
                if (T_STRING === $tokens[$i+2][0]) {
840 3
                    $this->staticReflection[$lastSeenClass]['methods'][] = strtolower($tokens[$i+2][1]);
841
                } elseif ($tokens[$i+2] == '&' && T_STRING === $tokens[$i+3][0]) {
842 3
                    $this->staticReflection[$lastSeenClass]['methods'][] = strtolower($tokens[$i+3][1]);
843
                }
844 8
            } elseif (in_array($token[0], array(T_VAR, T_PUBLIC, T_PRIVATE, T_PROTECTED), true) && T_FUNCTION !== $tokens[$i+2][0]) {
845 4
                $this->staticReflection[$lastSeenClass]['properties'][] = substr($tokens[$i+2][1], 1);
846
            }
847
        }
848 8
    }
849
850
    /**
851
     * @param string            $property
852
     * @param ClassMetadataInfo $metadata
853
     *
854
     * @return bool
855
     */
856 29
    protected function hasProperty($property, ClassMetadataInfo $metadata)
857
    {
858 29
        if ($this->extendsClass() || (!$this->isNew && class_exists($metadata->name))) {
859
            // don't generate property if its already on the base class.
860 2
            $reflClass = new \ReflectionClass($this->getClassToExtend() ?: $metadata->name);
861 2
            if ($reflClass->hasProperty($property)) {
862 1
                return true;
863
            }
864
        }
865
866
        // check traits for existing property
867 28
        foreach ($this->getTraits($metadata) as $trait) {
868 2
            if ($trait->hasProperty($property)) {
869 2
                return true;
870
            }
871
        }
872
873
        return (
874 28
            isset($this->staticReflection[$metadata->name]) &&
875 28
            in_array($property, $this->staticReflection[$metadata->name]['properties'], true)
876
        );
877
    }
878
879
    /**
880
     * @param string            $method
881
     * @param ClassMetadataInfo $metadata
882
     *
883
     * @return bool
884
     */
885 30
    protected function hasMethod($method, ClassMetadataInfo $metadata)
886
    {
887 30
        if ($this->extendsClass() || (!$this->isNew && class_exists($metadata->name))) {
888
            // don't generate method if its already on the base class.
889 2
            $reflClass = new \ReflectionClass($this->getClassToExtend() ?: $metadata->name);
890
891 2
            if ($reflClass->hasMethod($method)) {
892 1
                return true;
893
            }
894
        }
895
896
        // check traits for existing method
897 30
        foreach ($this->getTraits($metadata) as $trait) {
898 2
            if ($trait->hasMethod($method)) {
899 2
                return true;
900
            }
901
        }
902
903
        return (
904 30
            isset($this->staticReflection[$metadata->name]) &&
905 30
            in_array(strtolower($method), $this->staticReflection[$metadata->name]['methods'], true)
906
        );
907
    }
908
909
    /**
910
     * @param ClassMetadataInfo $metadata
911
     *
912
     * @return array
913
     */
914 30
    protected function getTraits(ClassMetadataInfo $metadata)
915
    {
916 30
        if (! ($metadata->reflClass !== null || class_exists($metadata->name))) {
917 24
            return [];
918
        }
919
920 7
        $reflClass = $metadata->reflClass === null
921 1
            ? new \ReflectionClass($metadata->name)
922 7
            : $metadata->reflClass;
923
924 7
        $traits = array();
925
926 7
        while ($reflClass !== false) {
927 7
            $traits = array_merge($traits, $reflClass->getTraits());
928
929 7
            $reflClass = $reflClass->getParentClass();
930
        }
931
932 7
        return $traits;
933
    }
934
935
    /**
936
     * @param ClassMetadataInfo $metadata
937
     *
938
     * @return bool
939
     */
940 29
    protected function hasNamespace(ClassMetadataInfo $metadata)
941
    {
942 29
        return (bool) strpos($metadata->name, '\\');
943
    }
944
945
    /**
946
     * @return bool
947
     */
948 30
    protected function extendsClass()
949
    {
950 30
        return (bool) $this->classToExtend;
951
    }
952
953
    /**
954
     * @return string
955
     */
956 2
    protected function getClassToExtend()
957
    {
958 2
        return $this->classToExtend;
959
    }
960
961
    /**
962
     * @return string
963
     */
964 1
    protected function getClassToExtendName()
965
    {
966 1
        $refl = new \ReflectionClass($this->getClassToExtend());
967
968 1
        return '\\' . $refl->getName();
0 ignored issues
show
Bug introduced by
Consider using $refl->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
969
    }
970
971
    /**
972
     * @param ClassMetadataInfo $metadata
973
     *
974
     * @return string
975
     */
976 30
    protected function getClassName(ClassMetadataInfo $metadata)
977
    {
978 30
        return ($pos = strrpos($metadata->name, '\\'))
979 30
            ? substr($metadata->name, $pos + 1, strlen($metadata->name)) : $metadata->name;
980
    }
981
982
    /**
983
     * @param ClassMetadataInfo $metadata
984
     *
985
     * @return string
986
     */
987 29
    protected function getNamespace(ClassMetadataInfo $metadata)
988
    {
989 29
        return substr($metadata->name, 0, strrpos($metadata->name, '\\'));
990
    }
991
992
    /**
993
     * @param ClassMetadataInfo $metadata
994
     *
995
     * @return string
996
     */
997 29
    protected function generateEntityDocBlock(ClassMetadataInfo $metadata)
998
    {
999 29
        $lines = array();
1000 29
        $lines[] = '/**';
1001 29
        $lines[] = ' * ' . $this->getClassName($metadata);
1002
1003 29
        if ($this->generateAnnotations) {
1004 29
            $lines[] = ' *';
1005
1006
            $methods = array(
1007 29
                'generateTableAnnotation',
1008
                'generateInheritanceAnnotation',
1009
                'generateDiscriminatorColumnAnnotation',
1010
                'generateDiscriminatorMapAnnotation',
1011
                'generateEntityAnnotation',
1012
            );
1013
1014 29
            foreach ($methods as $method) {
1015 29
                if ($code = $this->$method($metadata)) {
1016 29
                    $lines[] = ' * ' . $code;
1017
                }
1018
            }
1019
1020 29
            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...
1021 10
                $lines[] = ' * @' . $this->annotationsPrefix . 'HasLifecycleCallbacks';
1022
            }
1023
        }
1024
1025 29
        $lines[] = ' */';
1026
1027 29
        return implode("\n", $lines);
1028
    }
1029
1030
    /**
1031
     * @param ClassMetadataInfo $metadata
1032
     *
1033
     * @return string
1034
     */
1035 29
    protected function generateEntityAnnotation(ClassMetadataInfo $metadata)
1036
    {
1037 29
        $prefix = '@' . $this->annotationsPrefix;
1038
1039 29
        if ($metadata->isEmbeddedClass) {
1040 9
            return $prefix . 'Embeddable';
1041
        }
1042
1043 27
        $customRepository = $metadata->customRepositoryClassName
1044 11
            ? '(repositoryClass="' . $metadata->customRepositoryClassName . '")'
1045 27
            : '';
1046
1047 27
        return $prefix . ($metadata->isMappedSuperclass ? 'MappedSuperclass' : 'Entity') . $customRepository;
1048
    }
1049
1050
    /**
1051
     * @param ClassMetadataInfo $metadata
1052
     *
1053
     * @return string
1054
     */
1055 29
    protected function generateTableAnnotation(ClassMetadataInfo $metadata)
1056
    {
1057 29
        if ($metadata->isEmbeddedClass) {
1058 9
            return '';
1059
        }
1060
1061 27
        $table = array();
1062
1063 27
        if (isset($metadata->table['schema'])) {
1064
            $table[] = 'schema="' . $metadata->table['schema'] . '"';
1065
        }
1066
1067 27
        if (isset($metadata->table['name'])) {
1068 24
            $table[] = 'name="' . $metadata->table['name'] . '"';
1069
        }
1070
1071 27
        if (isset($metadata->table['options']) && $metadata->table['options']) {
1072 1
            $table[] = 'options={' . $this->exportTableOptions((array) $metadata->table['options']) . '}';
1073
        }
1074
1075 27
        if (isset($metadata->table['uniqueConstraints']) && $metadata->table['uniqueConstraints']) {
1076 9
            $constraints = $this->generateTableConstraints('UniqueConstraint', $metadata->table['uniqueConstraints']);
1077 9
            $table[] = 'uniqueConstraints={' . $constraints . '}';
1078
        }
1079
1080 27
        if (isset($metadata->table['indexes']) && $metadata->table['indexes']) {
1081 9
            $constraints = $this->generateTableConstraints('Index', $metadata->table['indexes']);
1082 9
            $table[] = 'indexes={' . $constraints . '}';
1083
        }
1084
1085 27
        return '@' . $this->annotationsPrefix . 'Table(' . implode(', ', $table) . ')';
1086
    }
1087
1088
    /**
1089
     * @param string $constraintName
1090
     * @param array  $constraints
1091
     *
1092
     * @return string
1093
     */
1094 9
    protected function generateTableConstraints($constraintName, array $constraints)
1095
    {
1096 9
        $annotations = array();
1097 9
        foreach ($constraints as $name => $constraint) {
1098 9
            $columns = array();
1099 9
            foreach ($constraint['columns'] as $column) {
1100 9
                $columns[] = '"' . $column . '"';
1101
            }
1102 9
            $annotations[] = '@' . $this->annotationsPrefix . $constraintName . '(name="' . $name . '", columns={' . implode(', ', $columns) . '})';
1103
        }
1104
1105 9
        return implode(', ', $annotations);
1106
    }
1107
1108
    /**
1109
     * @param ClassMetadataInfo $metadata
1110
     *
1111
     * @return string
1112
     */
1113 29
    protected function generateInheritanceAnnotation(ClassMetadataInfo $metadata)
1114
    {
1115 29
        if ($metadata->inheritanceType != ClassMetadataInfo::INHERITANCE_TYPE_NONE) {
1116
            return '@' . $this->annotationsPrefix . 'InheritanceType("'.$this->getInheritanceTypeString($metadata->inheritanceType).'")';
1117
        }
1118 29
    }
1119
1120
    /**
1121
     * @param ClassMetadataInfo $metadata
1122
     *
1123
     * @return string
1124
     */
1125 29
    protected function generateDiscriminatorColumnAnnotation(ClassMetadataInfo $metadata)
1126
    {
1127 29
        if ($metadata->inheritanceType != ClassMetadataInfo::INHERITANCE_TYPE_NONE) {
1128
            $discrColumn = $metadata->discriminatorColumn;
1129
            $columnDefinition = 'name="' . $discrColumn['name']
1130
                . '", type="' . $discrColumn['type']
1131
                . '", length=' . $discrColumn['length'];
1132
1133
            return '@' . $this->annotationsPrefix . 'DiscriminatorColumn(' . $columnDefinition . ')';
1134
        }
1135 29
    }
1136
1137
    /**
1138
     * @param ClassMetadataInfo $metadata
1139
     *
1140
     * @return string
1141
     */
1142 29
    protected function generateDiscriminatorMapAnnotation(ClassMetadataInfo $metadata)
1143
    {
1144 29
        if ($metadata->inheritanceType != ClassMetadataInfo::INHERITANCE_TYPE_NONE) {
1145
            $inheritanceClassMap = array();
1146
1147
            foreach ($metadata->discriminatorMap as $type => $class) {
1148
                $inheritanceClassMap[] .= '"' . $type . '" = "' . $class . '"';
1149
            }
1150
1151
            return '@' . $this->annotationsPrefix . 'DiscriminatorMap({' . implode(', ', $inheritanceClassMap) . '})';
1152
        }
1153 29
    }
1154
1155
    /**
1156
     * @param ClassMetadataInfo $metadata
1157
     *
1158
     * @return string
1159
     */
1160 29
    protected function generateEntityStubMethods(ClassMetadataInfo $metadata)
1161
    {
1162 29
        $methods = array();
1163
1164 29
        foreach ($metadata->fieldMappings as $fieldMapping) {
1165 28
            if (isset($fieldMapping['declaredField']) &&
1166 28
                isset($metadata->embeddedClasses[$fieldMapping['declaredField']])
1167
            ) {
1168
                continue;
1169
            }
1170
1171 28
            $nullableField = $this->nullableFieldExpression($fieldMapping);
1172
1173 28
            if (( ! isset($fieldMapping['id']) ||
1174 26
                    ! $fieldMapping['id'] ||
1175 28
                    $metadata->generatorType == ClassMetadataInfo::GENERATOR_TYPE_NONE
1176 28
                ) && (! $metadata->isEmbeddedClass || ! $this->embeddablesImmutable)
1177 28
                && $code = $this->generateEntityStubMethod($metadata, 'set', $fieldMapping['fieldName'], $fieldMapping['type'], $nullableField)
1178
            ) {
1179 25
                $methods[] = $code;
1180
            }
1181
1182 28
            if ($code = $this->generateEntityStubMethod($metadata, 'get', $fieldMapping['fieldName'], $fieldMapping['type'], $nullableField)) {
1183 28
                $methods[] = $code;
1184
            }
1185
        }
1186
1187 29
        foreach ($metadata->embeddedClasses as $fieldName => $embeddedClass) {
1188 8
            if (isset($embeddedClass['declaredField'])) {
1189 1
                continue;
1190
            }
1191
1192 8
            if ( ! $metadata->isEmbeddedClass || ! $this->embeddablesImmutable) {
1193 7
                if ($code = $this->generateEntityStubMethod($metadata, 'set', $fieldName, $embeddedClass['class'])) {
1194 7
                    $methods[] = $code;
1195
                }
1196
            }
1197
1198 8
            if ($code = $this->generateEntityStubMethod($metadata, 'get', $fieldName, $embeddedClass['class'])) {
1199 8
                $methods[] = $code;
1200
            }
1201
        }
1202
1203 29
        foreach ($metadata->associationMappings as $associationMapping) {
1204 12
            if ($associationMapping['type'] & ClassMetadataInfo::TO_ONE) {
1205 11
                $nullable = $this->isAssociationIsNullable($associationMapping) ? 'null' : null;
1206 11
                if ($code = $this->generateEntityStubMethod($metadata, 'set', $associationMapping['fieldName'], $associationMapping['targetEntity'], $nullable)) {
1207 9
                    $methods[] = $code;
1208
                }
1209 11
                if ($code = $this->generateEntityStubMethod($metadata, 'get', $associationMapping['fieldName'], $associationMapping['targetEntity'], $nullable)) {
1210 11
                    $methods[] = $code;
1211
                }
1212 10
            } elseif ($associationMapping['type'] & ClassMetadataInfo::TO_MANY) {
1213 10
                if ($code = $this->generateEntityStubMethod($metadata, 'add', $associationMapping['fieldName'], $associationMapping['targetEntity'])) {
1214 10
                    $methods[] = $code;
1215
                }
1216 10
                if ($code = $this->generateEntityStubMethod($metadata, 'remove', $associationMapping['fieldName'], $associationMapping['targetEntity'])) {
1217 10
                    $methods[] = $code;
1218
                }
1219 10
                if ($code = $this->generateEntityStubMethod($metadata, 'get', $associationMapping['fieldName'], 'Doctrine\Common\Collections\Collection')) {
1220 12
                    $methods[] = $code;
1221
                }
1222
            }
1223
        }
1224
1225 29
        return implode("\n\n", $methods);
1226
    }
1227
1228
    /**
1229
     * @param array $associationMapping
1230
     *
1231
     * @return bool
1232
     */
1233 11
    protected function isAssociationIsNullable(array $associationMapping)
1234
    {
1235 11
        if (isset($associationMapping['id']) && $associationMapping['id']) {
1236
            return false;
1237
        }
1238
1239 11
        if (isset($associationMapping['joinColumns'])) {
1240 2
            $joinColumns = $associationMapping['joinColumns'];
1241
        } else {
1242
            //@todo there is no way to retrieve targetEntity metadata
1243 9
            $joinColumns = array();
1244
        }
1245
1246 11
        foreach ($joinColumns as $joinColumn) {
1247 2
            if (isset($joinColumn['nullable']) && !$joinColumn['nullable']) {
1248 2
                return false;
1249
            }
1250
        }
1251
1252 11
        return true;
1253
    }
1254
1255
    /**
1256
     * @param ClassMetadataInfo $metadata
1257
     *
1258
     * @return string
1259
     */
1260 30
    protected function generateEntityLifecycleCallbackMethods(ClassMetadataInfo $metadata)
1261
    {
1262 30
        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...
1263 10
            $methods = array();
1264
1265 10
            foreach ($metadata->lifecycleCallbacks as $name => $callbacks) {
1266 10
                foreach ($callbacks as $callback) {
1267 10
                    if ($code = $this->generateLifecycleCallbackMethod($name, $callback, $metadata)) {
1268 10
                        $methods[] = $code;
1269
                    }
1270
                }
1271
            }
1272
1273 10
            return implode("\n\n", $methods);
1274
        }
1275
1276 27
        return "";
1277
    }
1278
1279
    /**
1280
     * @param ClassMetadataInfo $metadata
1281
     *
1282
     * @return string
1283
     */
1284 30
    protected function generateEntityAssociationMappingProperties(ClassMetadataInfo $metadata)
1285
    {
1286 30
        $lines = array();
1287
1288 30
        foreach ($metadata->associationMappings as $associationMapping) {
1289 13
            if ($this->hasProperty($associationMapping['fieldName'], $metadata)) {
1290 4
                continue;
1291
            }
1292
1293 11
            $lines[] = $this->generateAssociationMappingPropertyDocBlock($associationMapping, $metadata);
1294 11
            $lines[] = $this->spaces . $this->fieldVisibility . ' $' . $associationMapping['fieldName']
1295 11
                     . ($associationMapping['type'] == 'manyToMany' ? ' = array()' : null) . ";\n";
1296
        }
1297
1298 30
        return implode("\n", $lines);
1299
    }
1300
1301
    /**
1302
     * @param ClassMetadataInfo $metadata
1303
     *
1304
     * @return string
1305
     */
1306 30
    protected function generateEntityFieldMappingProperties(ClassMetadataInfo $metadata)
1307
    {
1308 30
        $lines = array();
1309
1310 30
        foreach ($metadata->fieldMappings as $fieldMapping) {
1311 29
            if ($this->hasProperty($fieldMapping['fieldName'], $metadata) ||
1312 28
                $metadata->isInheritedField($fieldMapping['fieldName']) ||
1313
                (
1314 27
                    isset($fieldMapping['declaredField']) &&
1315 29
                    isset($metadata->embeddedClasses[$fieldMapping['declaredField']])
1316
                )
1317
            ) {
1318 4
                continue;
1319
            }
1320
1321 27
            $lines[] = $this->generateFieldMappingPropertyDocBlock($fieldMapping, $metadata);
1322 27
            $lines[] = $this->spaces . $this->fieldVisibility . ' $' . $fieldMapping['fieldName']
1323 27
                     . (isset($fieldMapping['options']['default']) ? ' = ' . var_export($fieldMapping['options']['default'], true) : null) . ";\n";
1324
        }
1325
1326 30
        return implode("\n", $lines);
1327
    }
1328
1329
    /**
1330
     * @param ClassMetadataInfo $metadata
1331
     *
1332
     * @return string
1333
     */
1334 30
    protected function generateEntityEmbeddedProperties(ClassMetadataInfo $metadata)
1335
    {
1336 30
        $lines = array();
1337
1338 30
        foreach ($metadata->embeddedClasses as $fieldName => $embeddedClass) {
1339 8
            if (isset($embeddedClass['declaredField']) || $this->hasProperty($fieldName, $metadata)) {
1340 2
                continue;
1341
            }
1342
1343 8
            $lines[] = $this->generateEmbeddedPropertyDocBlock($embeddedClass);
1344 8
            $lines[] = $this->spaces . $this->fieldVisibility . ' $' . $fieldName . ";\n";
1345
        }
1346
1347 30
        return implode("\n", $lines);
1348
    }
1349
1350
    /**
1351
     * @param ClassMetadataInfo $metadata
1352
     * @param string            $type
1353
     * @param string            $fieldName
1354
     * @param string|null       $typeHint
1355
     * @param string|null       $defaultValue
1356
     *
1357
     * @return string
1358
     */
1359 28
    protected function generateEntityStubMethod(ClassMetadataInfo $metadata, $type, $fieldName, $typeHint = null, $defaultValue = null)
1360
    {
1361 28
        $methodName = $type . Inflector::classify($fieldName);
1362 28
        $variableName = Inflector::camelize($fieldName);
1363 28
        if (in_array($type, array("add", "remove"))) {
1364 10
            $methodName = Inflector::singularize($methodName);
1365 10
            $variableName = Inflector::singularize($variableName);
1366
        }
1367
1368 28
        if ($this->hasMethod($methodName, $metadata)) {
1369 5
            return '';
1370
        }
1371 28
        $this->staticReflection[$metadata->name]['methods'][] = strtolower($methodName);
1372
1373 28
        $var = sprintf('%sMethodTemplate', $type);
1374 28
        $template = static::$$var;
1375
1376 28
        $methodTypeHint = null;
1377 28
        $types          = Type::getTypesMap();
1378 28
        $variableType   = $typeHint ? $this->getType($typeHint) : null;
1379
1380 28
        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...
1381 12
            $variableType   =  '\\' . ltrim($variableType, '\\');
1382 12
            $methodTypeHint =  '\\' . $typeHint . ' ';
1383
        }
1384
1385
        $replacements = array(
1386 28
          '<description>'       => ucfirst($type) . ' ' . $variableName . '.',
1387 28
          '<methodTypeHint>'    => $methodTypeHint,
1388 28
          '<variableType>'      => $variableType . (null !== $defaultValue ? ('|' . $defaultValue) : ''),
1389 28
          '<variableName>'      => $variableName,
1390 28
          '<methodName>'        => $methodName,
1391 28
          '<fieldName>'         => $fieldName,
1392 28
          '<variableDefault>'   => ($defaultValue !== null ) ? (' = ' . $defaultValue) : '',
1393 28
          '<entity>'            => $this->getClassName($metadata)
1394
        );
1395
1396 28
        $method = str_replace(
1397
            array_keys($replacements),
1398
            array_values($replacements),
1399
            $template
1400
        );
1401
1402 28
        return $this->prefixCodeWithSpaces($method);
1403
    }
1404
1405
    /**
1406
     * @param string            $name
1407
     * @param string            $methodName
1408
     * @param ClassMetadataInfo $metadata
1409
     *
1410
     * @return string
1411
     */
1412 10
    protected function generateLifecycleCallbackMethod($name, $methodName, ClassMetadataInfo $metadata)
1413
    {
1414 10
        if ($this->hasMethod($methodName, $metadata)) {
1415 2
            return '';
1416
        }
1417 10
        $this->staticReflection[$metadata->name]['methods'][] = $methodName;
1418
1419
        $replacements = array(
1420 10
            '<name>'        => $this->annotationsPrefix . ucfirst($name),
1421 10
            '<methodName>'  => $methodName,
1422
        );
1423
1424 10
        $method = str_replace(
1425
            array_keys($replacements),
1426
            array_values($replacements),
1427 10
            static::$lifecycleCallbackMethodTemplate
1428
        );
1429
1430 10
        return $this->prefixCodeWithSpaces($method);
1431
    }
1432
1433
    /**
1434
     * @param array $joinColumn
1435
     *
1436
     * @return string
1437
     */
1438 11
    protected function generateJoinColumnAnnotation(array $joinColumn)
1439
    {
1440 11
        $joinColumnAnnot = array();
1441
1442 11
        if (isset($joinColumn['name'])) {
1443 11
            $joinColumnAnnot[] = 'name="' . $joinColumn['name'] . '"';
1444
        }
1445
1446 11
        if (isset($joinColumn['referencedColumnName'])) {
1447 11
            $joinColumnAnnot[] = 'referencedColumnName="' . $joinColumn['referencedColumnName'] . '"';
1448
        }
1449
1450 11
        if (isset($joinColumn['unique']) && $joinColumn['unique']) {
1451 1
            $joinColumnAnnot[] = 'unique=' . ($joinColumn['unique'] ? 'true' : 'false');
1452
        }
1453
1454 11
        if (isset($joinColumn['nullable'])) {
1455 1
            $joinColumnAnnot[] = 'nullable=' . ($joinColumn['nullable'] ? 'true' : 'false');
1456
        }
1457
1458 11
        if (isset($joinColumn['onDelete'])) {
1459 1
            $joinColumnAnnot[] = 'onDelete="' . ($joinColumn['onDelete'] . '"');
1460
        }
1461
1462 11
        if (isset($joinColumn['columnDefinition'])) {
1463 1
            $joinColumnAnnot[] = 'columnDefinition="' . $joinColumn['columnDefinition'] . '"';
1464
        }
1465
1466 11
        return '@' . $this->annotationsPrefix . 'JoinColumn(' . implode(', ', $joinColumnAnnot) . ')';
1467
    }
1468
1469
    /**
1470
     * @param array             $associationMapping
1471
     * @param ClassMetadataInfo $metadata
1472
     *
1473
     * @return string
1474
     */
1475 11
    protected function generateAssociationMappingPropertyDocBlock(array $associationMapping, ClassMetadataInfo $metadata)
1476
    {
1477 11
        $lines = array();
1478 11
        $lines[] = $this->spaces . '/**';
1479
1480 11
        if ($associationMapping['type'] & ClassMetadataInfo::TO_MANY) {
1481 11
            $lines[] = $this->spaces . ' * @var \Doctrine\Common\Collections\Collection';
1482
        } else {
1483 10
            $lines[] = $this->spaces . ' * @var \\' . ltrim($associationMapping['targetEntity'], '\\');
1484
        }
1485
1486 11
        if ($this->generateAnnotations) {
1487 11
            $lines[] = $this->spaces . ' *';
1488
1489 11
            if (isset($associationMapping['id']) && $associationMapping['id']) {
1490
                $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'Id';
1491
1492
                if ($generatorType = $this->getIdGeneratorTypeString($metadata->generatorType)) {
1493
                    $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'GeneratedValue(strategy="' . $generatorType . '")';
1494
                }
1495
            }
1496
1497 11
            $type = null;
1498 11
            switch ($associationMapping['type']) {
1499 11
                case ClassMetadataInfo::ONE_TO_ONE:
1500 10
                    $type = 'OneToOne';
1501 10
                    break;
1502 11
                case ClassMetadataInfo::MANY_TO_ONE:
1503 1
                    $type = 'ManyToOne';
1504 1
                    break;
1505 11
                case ClassMetadataInfo::ONE_TO_MANY:
1506 1
                    $type = 'OneToMany';
1507 1
                    break;
1508 11
                case ClassMetadataInfo::MANY_TO_MANY:
1509 11
                    $type = 'ManyToMany';
1510 11
                    break;
1511
            }
1512 11
            $typeOptions = array();
1513
1514 11
            if (isset($associationMapping['targetEntity'])) {
1515 11
                $typeOptions[] = 'targetEntity="' . $associationMapping['targetEntity'] . '"';
1516
            }
1517
1518 11
            if (isset($associationMapping['inversedBy'])) {
1519 1
                $typeOptions[] = 'inversedBy="' . $associationMapping['inversedBy'] . '"';
1520
            }
1521
1522 11
            if (isset($associationMapping['mappedBy'])) {
1523 10
                $typeOptions[] = 'mappedBy="' . $associationMapping['mappedBy'] . '"';
1524
            }
1525
1526 11
            if ($associationMapping['cascade']) {
1527 1
                $cascades = array();
1528
1529 1
                if ($associationMapping['isCascadePersist']) $cascades[] = '"persist"';
1530 1
                if ($associationMapping['isCascadeRemove']) $cascades[] = '"remove"';
1531 1
                if ($associationMapping['isCascadeDetach']) $cascades[] = '"detach"';
1532 1
                if ($associationMapping['isCascadeMerge']) $cascades[] = '"merge"';
1533 1
                if ($associationMapping['isCascadeRefresh']) $cascades[] = '"refresh"';
1534
1535 1
                if (count($cascades) === 5) {
1536 1
                    $cascades = array('"all"');
1537
                }
1538
1539 1
                $typeOptions[] = 'cascade={' . implode(',', $cascades) . '}';
1540
            }
1541
1542 11
            if (isset($associationMapping['orphanRemoval']) && $associationMapping['orphanRemoval']) {
1543 1
                $typeOptions[] = 'orphanRemoval=' . ($associationMapping['orphanRemoval'] ? 'true' : 'false');
1544
            }
1545
1546 11
            if (isset($associationMapping['fetch']) && $associationMapping['fetch'] !== ClassMetadataInfo::FETCH_LAZY) {
1547
                $fetchMap = array(
1548 10
                    ClassMetadataInfo::FETCH_EXTRA_LAZY => 'EXTRA_LAZY',
1549 10
                    ClassMetadataInfo::FETCH_EAGER      => 'EAGER',
1550
                );
1551
1552 10
                $typeOptions[] = 'fetch="' . $fetchMap[$associationMapping['fetch']] . '"';
1553
            }
1554
1555 11
            $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . '' . $type . '(' . implode(', ', $typeOptions) . ')';
1556
1557 11
            if (isset($associationMapping['joinColumns']) && $associationMapping['joinColumns']) {
1558 1
                $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'JoinColumns({';
1559
1560 1
                $joinColumnsLines = array();
1561
1562 1
                foreach ($associationMapping['joinColumns'] as $joinColumn) {
1563 1
                    if ($joinColumnAnnot = $this->generateJoinColumnAnnotation($joinColumn)) {
1564 1
                        $joinColumnsLines[] = $this->spaces . ' *   ' . $joinColumnAnnot;
1565
                    }
1566
                }
1567
1568 1
                $lines[] = implode(",\n", $joinColumnsLines);
1569 1
                $lines[] = $this->spaces . ' * })';
1570
            }
1571
1572 11
            if (isset($associationMapping['joinTable']) && $associationMapping['joinTable']) {
1573 11
                $joinTable = array();
1574 11
                $joinTable[] = 'name="' . $associationMapping['joinTable']['name'] . '"';
1575
1576 11
                if (isset($associationMapping['joinTable']['schema'])) {
1577
                    $joinTable[] = 'schema="' . $associationMapping['joinTable']['schema'] . '"';
1578
                }
1579
1580 11
                $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'JoinTable(' . implode(', ', $joinTable) . ',';
1581 11
                $lines[] = $this->spaces . ' *   joinColumns={';
1582
1583 11
                $joinColumnsLines = array();
1584
1585 11
                foreach ($associationMapping['joinTable']['joinColumns'] as $joinColumn) {
1586 11
                    $joinColumnsLines[] = $this->spaces . ' *     ' . $this->generateJoinColumnAnnotation($joinColumn);
1587
                }
1588
1589 11
                $lines[] = implode(",". PHP_EOL, $joinColumnsLines);
1590 11
                $lines[] = $this->spaces . ' *   },';
1591 11
                $lines[] = $this->spaces . ' *   inverseJoinColumns={';
1592
1593 11
                $inverseJoinColumnsLines = array();
1594
1595 11
                foreach ($associationMapping['joinTable']['inverseJoinColumns'] as $joinColumn) {
1596 11
                    $inverseJoinColumnsLines[] = $this->spaces . ' *     ' . $this->generateJoinColumnAnnotation($joinColumn);
1597
                }
1598
1599 11
                $lines[] = implode(",". PHP_EOL, $inverseJoinColumnsLines);
1600 11
                $lines[] = $this->spaces . ' *   }';
1601 11
                $lines[] = $this->spaces . ' * )';
1602
            }
1603
1604 11
            if (isset($associationMapping['orderBy'])) {
1605 1
                $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'OrderBy({';
1606
1607 1
                foreach ($associationMapping['orderBy'] as $name => $direction) {
1608 1
                    $lines[] = $this->spaces . ' *     "' . $name . '"="' . $direction . '",';
1609
                }
1610
1611 1
                $lines[count($lines) - 1] = substr($lines[count($lines) - 1], 0, strlen($lines[count($lines) - 1]) - 1);
1612 1
                $lines[] = $this->spaces . ' * })';
1613
            }
1614
        }
1615
1616 11
        $lines[] = $this->spaces . ' */';
1617
1618 11
        return implode("\n", $lines);
1619
    }
1620
1621
    /**
1622
     * @param array             $fieldMapping
1623
     * @param ClassMetadataInfo $metadata
1624
     *
1625
     * @return string
1626
     */
1627 27
    protected function generateFieldMappingPropertyDocBlock(array $fieldMapping, ClassMetadataInfo $metadata)
1628
    {
1629 27
        $lines = array();
1630 27
        $lines[] = $this->spaces . '/**';
1631 27
        $lines[] = $this->spaces . ' * @var '
1632 27
            . $this->getType($fieldMapping['type'])
1633 27
            . ($this->nullableFieldExpression($fieldMapping) ? '|null' : '');
1634
1635 27
        if ($this->generateAnnotations) {
1636 27
            $lines[] = $this->spaces . ' *';
1637
1638 27
            $column = array();
1639 27
            if (isset($fieldMapping['columnName'])) {
1640 27
                $column[] = 'name="' . $fieldMapping['columnName'] . '"';
1641
            }
1642
1643 27
            if (isset($fieldMapping['type'])) {
1644 27
                $column[] = 'type="' . $fieldMapping['type'] . '"';
1645
            }
1646
1647 27
            if (isset($fieldMapping['length'])) {
1648 4
                $column[] = 'length=' . $fieldMapping['length'];
1649
            }
1650
1651 27
            if (isset($fieldMapping['precision'])) {
1652 4
                $column[] = 'precision=' .  $fieldMapping['precision'];
1653
            }
1654
1655 27
            if (isset($fieldMapping['scale'])) {
1656 4
                $column[] = 'scale=' . $fieldMapping['scale'];
1657
            }
1658
1659 27
            if (isset($fieldMapping['nullable'])) {
1660 8
                $column[] = 'nullable=' .  var_export($fieldMapping['nullable'], true);
1661
            }
1662
1663 27
            $options = [];
1664
1665 27
            if (isset($fieldMapping['options']['unsigned']) && $fieldMapping['options']['unsigned']) {
1666 1
                $options[] = '"unsigned"=true';
1667
            }
1668
1669 27
            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...
1670 1
                $column[] = 'options={'.implode(',', $options).'}';
1671
            }
1672
1673 27
            if (isset($fieldMapping['columnDefinition'])) {
1674 1
                $column[] = 'columnDefinition="' . $fieldMapping['columnDefinition'] . '"';
1675
            }
1676
1677 27
            if (isset($fieldMapping['unique'])) {
1678 4
                $column[] = 'unique=' . var_export($fieldMapping['unique'], true);
1679
            }
1680
1681 27
            $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'Column(' . implode(', ', $column) . ')';
1682
1683 27
            if (isset($fieldMapping['id']) && $fieldMapping['id']) {
1684 25
                $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'Id';
1685
1686 25
                if ($generatorType = $this->getIdGeneratorTypeString($metadata->generatorType)) {
1687 25
                    $lines[] = $this->spaces.' * @' . $this->annotationsPrefix . 'GeneratedValue(strategy="' . $generatorType . '")';
1688
                }
1689
1690 25
                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...
1691 1
                    $sequenceGenerator = array();
1692
1693 1
                    if (isset($metadata->sequenceGeneratorDefinition['sequenceName'])) {
1694 1
                        $sequenceGenerator[] = 'sequenceName="' . $metadata->sequenceGeneratorDefinition['sequenceName'] . '"';
1695
                    }
1696
1697 1
                    if (isset($metadata->sequenceGeneratorDefinition['allocationSize'])) {
1698 1
                        $sequenceGenerator[] = 'allocationSize=' . $metadata->sequenceGeneratorDefinition['allocationSize'];
1699
                    }
1700
1701 1
                    if (isset($metadata->sequenceGeneratorDefinition['initialValue'])) {
1702 1
                        $sequenceGenerator[] = 'initialValue=' . $metadata->sequenceGeneratorDefinition['initialValue'];
1703
                    }
1704
1705 1
                    $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'SequenceGenerator(' . implode(', ', $sequenceGenerator) . ')';
1706
                }
1707
            }
1708
1709 27
            if (isset($fieldMapping['version']) && $fieldMapping['version']) {
1710
                $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'Version';
1711
            }
1712
        }
1713
1714 27
        $lines[] = $this->spaces . ' */';
1715
1716 27
        return implode("\n", $lines);
1717
    }
1718
1719
    /**
1720
     * @param array $embeddedClass
1721
     *
1722
     * @return string
1723
     */
1724 8
    protected function generateEmbeddedPropertyDocBlock(array $embeddedClass)
1725
    {
1726 8
        $lines = array();
1727 8
        $lines[] = $this->spaces . '/**';
1728 8
        $lines[] = $this->spaces . ' * @var \\' . ltrim($embeddedClass['class'], '\\');
1729
1730 8
        if ($this->generateAnnotations) {
1731 8
            $lines[] = $this->spaces . ' *';
1732
1733 8
            $embedded = array('class="' . $embeddedClass['class'] . '"');
1734
1735 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...
1736
                $embedded[] = 'columnPrefix=' . var_export($embeddedClass['columnPrefix'], true);
1737
            }
1738
1739 8
            $lines[] = $this->spaces . ' * @' .
1740 8
                $this->annotationsPrefix . 'Embedded(' . implode(', ', $embedded) . ')';
1741
        }
1742
1743 8
        $lines[] = $this->spaces . ' */';
1744
1745 8
        return implode("\n", $lines);
1746
    }
1747
1748
    /**
1749
     * @param string $code
1750
     * @param int    $num
1751
     *
1752
     * @return string
1753
     */
1754 29
    protected function prefixCodeWithSpaces($code, $num = 1)
1755
    {
1756 29
        $lines = explode("\n", $code);
1757
1758 29
        foreach ($lines as $key => $value) {
1759 29
            if ( ! empty($value)) {
1760 29
                $lines[$key] = str_repeat($this->spaces, $num) . $lines[$key];
1761
            }
1762
        }
1763
1764 29
        return implode("\n", $lines);
1765
    }
1766
1767
    /**
1768
     * @param integer $type The inheritance type used by the class and its subclasses.
1769
     *
1770
     * @return string The literal string for the inheritance type.
1771
     *
1772
     * @throws \InvalidArgumentException When the inheritance type does not exist.
1773
     */
1774 1
    protected function getInheritanceTypeString($type)
1775
    {
1776 1
        if ( ! isset(static::$inheritanceTypeMap[$type])) {
1777 1
            throw new \InvalidArgumentException(sprintf('Invalid provided InheritanceType: %s', $type));
1778
        }
1779
1780 1
        return static::$inheritanceTypeMap[$type];
1781
    }
1782
1783
    /**
1784
     * @param integer $type The policy used for change-tracking for the mapped class.
1785
     *
1786
     * @return string The literal string for the change-tracking type.
1787
     *
1788
     * @throws \InvalidArgumentException When the change-tracking type does not exist.
1789
     */
1790 1
    protected function getChangeTrackingPolicyString($type)
1791
    {
1792 1
        if ( ! isset(static::$changeTrackingPolicyMap[$type])) {
1793 1
            throw new \InvalidArgumentException(sprintf('Invalid provided ChangeTrackingPolicy: %s', $type));
1794
        }
1795
1796 1
        return static::$changeTrackingPolicyMap[$type];
1797
    }
1798
1799
    /**
1800
     * @param integer $type The generator to use for the mapped class.
1801
     *
1802
     * @return string The literal string for the generator type.
1803
     *
1804
     * @throws \InvalidArgumentException    When the generator type does not exist.
1805
     */
1806 26
    protected function getIdGeneratorTypeString($type)
1807
    {
1808 26
        if ( ! isset(static::$generatorStrategyMap[$type])) {
1809 1
            throw new \InvalidArgumentException(sprintf('Invalid provided IdGeneratorType: %s', $type));
1810
        }
1811
1812 26
        return static::$generatorStrategyMap[$type];
1813
    }
1814
1815
    /**
1816
     * @param array $fieldMapping
1817
     *
1818
     * @return string|null
1819
     */
1820 29
    private function nullableFieldExpression(array $fieldMapping)
1821
    {
1822 29
        if (isset($fieldMapping['nullable']) && true === $fieldMapping['nullable']) {
1823 5
            return 'null';
1824
        }
1825
1826 29
        return null;
1827
    }
1828
1829
    /**
1830
     * Exports (nested) option elements.
1831
     *
1832
     * @param array $options
1833
     *
1834
     * @return string
1835
     */
1836 1
    private function exportTableOptions(array $options)
1837
    {
1838 1
        $optionsStr = array();
1839
1840 1
        foreach ($options as $name => $option) {
1841 1
            if (is_array($option)) {
1842 1
                $optionsStr[] = '"' . $name . '"={' . $this->exportTableOptions($option) . '}';
1843
            } else {
1844 1
                $optionsStr[] = '"' . $name . '"="' . (string) $option . '"';
1845
            }
1846
        }
1847
1848 1
        return implode(',', $optionsStr);
1849
    }
1850
}
1851