Completed
Pull Request — master (#5569)
by Jérémy
67:47 queued 04:57
created

EntityGenerator::generateEntityClass()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 24
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1.0156

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 24
ccs 6
cts 8
cp 0.75
rs 8.9713
cc 1
eloc 17
nc 1
nop 1
crap 1.0156
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
     * Whether or not to add PHP strict types.
151
     *
152
     * @var boolean
153
     */
154
    protected $strictTypes = false;
155
156
    /**
157
     * Whether or not to force type hinting for method result and scalar parameters.
158
     *
159
     * @var boolean
160
     */
161
    protected $generateMethodsTypeHinting = false;
162
163
    /**
164
     * Hash-map for handle types.
165
     *
166
     * @var array
167
     */
168
    protected $typeAlias = array(
169
        Type::DATETIMETZ    => '\DateTime',
170
        Type::DATETIME      => '\DateTime',
171
        Type::DATE          => '\DateTime',
172
        Type::TIME          => '\DateTime',
173
        Type::OBJECT        => '\stdClass',
174
        Type::INTEGER       => 'int',
175
        Type::BIGINT        => 'int',
176
        Type::SMALLINT      => 'int',
177
        Type::TEXT          => 'string',
178
        Type::BLOB          => 'string',
179
        Type::DECIMAL       => 'string',
180
        Type::JSON_ARRAY    => 'array',
181
        Type::SIMPLE_ARRAY  => 'array',
182
        Type::BOOLEAN       => 'bool',
183
    );
184
185
    /**
186
     * Hash-map for handle strict types
187
     *
188
     * @var array
189
     */
190
    protected $typeHintingAlias = array(
191
        Type::TARRAY        => 'array',
192
        Type::SIMPLE_ARRAY  => 'array',
193
        Type::JSON_ARRAY    => 'array',
194
        Type::STRING        => 'string',
195
        Type::FLOAT         => 'float',
196
        Type::GUID          => 'string',
197
    );
198
199
    /**
200
     * Hash-map to handle generator types string.
201
     *
202
     * @var array
203
     */
204
    protected static $generatorStrategyMap = array(
205
        ClassMetadataInfo::GENERATOR_TYPE_AUTO      => 'AUTO',
206
        ClassMetadataInfo::GENERATOR_TYPE_SEQUENCE  => 'SEQUENCE',
207
        ClassMetadataInfo::GENERATOR_TYPE_TABLE     => 'TABLE',
208
        ClassMetadataInfo::GENERATOR_TYPE_IDENTITY  => 'IDENTITY',
209
        ClassMetadataInfo::GENERATOR_TYPE_NONE      => 'NONE',
210
        ClassMetadataInfo::GENERATOR_TYPE_UUID      => 'UUID',
211
        ClassMetadataInfo::GENERATOR_TYPE_CUSTOM    => 'CUSTOM'
212
    );
213
214
    /**
215
     * Hash-map to handle the change tracking policy string.
216
     *
217
     * @var array
218
     */
219
    protected static $changeTrackingPolicyMap = array(
220
        ClassMetadataInfo::CHANGETRACKING_DEFERRED_IMPLICIT  => 'DEFERRED_IMPLICIT',
221
        ClassMetadataInfo::CHANGETRACKING_DEFERRED_EXPLICIT  => 'DEFERRED_EXPLICIT',
222
        ClassMetadataInfo::CHANGETRACKING_NOTIFY             => 'NOTIFY',
223
    );
224
225
    /**
226
     * Hash-map to handle the inheritance type string.
227
     *
228
     * @var array
229
     */
230
    protected static $inheritanceTypeMap = array(
231
        ClassMetadataInfo::INHERITANCE_TYPE_NONE            => 'NONE',
232
        ClassMetadataInfo::INHERITANCE_TYPE_JOINED          => 'JOINED',
233
        ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_TABLE    => 'SINGLE_TABLE',
234
        ClassMetadataInfo::INHERITANCE_TYPE_TABLE_PER_CLASS => 'TABLE_PER_CLASS',
235
    );
236
237
    /**
238
     * @var string
239
     */
240
    protected static $classTemplate =
241
'<?php
242
<strictTypes>
243
<namespace>
244
<useStatement>
245
<entityAnnotation>
246
<entityClassName>
247
{
248
<entityBody>
249
}
250
';
251
252
    /**
253
     * @var string
254
     */
255
    protected static $getMethodTemplate =
256
'/**
257
 * <description>
258
 *
259
 * @return <variableType>
260
 */
261
public function <methodName>() <methodTypeReturn>
262
{
263
<spaces>return $this-><fieldName>;
264
}';
265
266
    /**
267
     * @var string
268
     */
269
    protected static $setMethodTemplate =
270
'/**
271
 * <description>
272
 *
273
 * @param <variableType> $<variableName>
274
 *
275
 * @return <entity>
276
 */
277
public function <methodName>(<methodTypeHint>$<variableName><variableDefault>) <methodTypeReturn>
278
{
279
<spaces>$this-><fieldName> = $<variableName>;
280
281
<spaces>return $this;
282
}';
283
284
    /**
285
     * @var string
286
     */
287
    protected static $addMethodTemplate =
288
'/**
289
 * <description>
290
 *
291
 * @param <variableType> $<variableName>
292
 *
293
 * @return <entity>
294
 */
295
public function <methodName>(<methodTypeHint>$<variableName>) <methodTypeReturn>
296
{
297
<spaces>$this-><fieldName>[] = $<variableName>;
298
299
<spaces>return $this;
300
}';
301
302
    /**
303
     * @var string
304
     */
305
    protected static $removeMethodTemplate =
306
'/**
307
 * <description>
308
 *
309
 * @param <variableType> $<variableName>
310
 *
311
 * @return boolean TRUE if this collection contained the specified element, FALSE otherwise.
312
 */
313
public function <methodName>(<methodTypeHint>$<variableName>) <methodTypeReturn>
314
{
315
<spaces>return $this-><fieldName>->removeElement($<variableName>);
316
}';
317
318
    /**
319
     * @var string
320
     */
321
    protected static $lifecycleCallbackMethodTemplate =
322
'/**
323
 * @<name>
324
 */
325
public function <methodName>()
326
{
327
<spaces>// Add your code here
328
}';
329
330
    /**
331
     * @var string
332
     */
333 39
    protected static $constructorMethodTemplate =
334
'/**
335 39
 * Constructor
336 39
 */
337
public function __construct()
338 39
{
339
<spaces><collections>
340
}
341
';
342
343
    /**
344
     * @var string
345
     */
346
    protected static $embeddableConstructorMethodTemplate =
347
'/**
348
 * Constructor
349
 *
350
 * <paramTags>
351
 */
352
public function __construct(<params>)
353
{
354
<spaces><fields>
355
}
356
';
357
358
    /**
359
     * Constructor.
360
     */
361
    public function __construct()
362
    {
363
        if (version_compare(\Doctrine\Common\Version::VERSION, '2.2.0-DEV', '>=')) {
364
            $this->annotationsPrefix = 'ORM\\';
365 29
        }
366
    }
367 29
368 29
    /**
369
     * Generates and writes entity classes for the given array of ClassMetadataInfo instances.
370 29
     *
371 2
     * @param array  $metadatas
372
     * @param string $outputDirectory
373
     *
374 29
     * @return void
375
     */
376 29
    public function generate(array $metadatas, $outputDirectory)
377 3
    {
378
        foreach ($metadatas as $metadata) {
379 28
            $this->writeEntityClass($metadata, $outputDirectory);
380
        }
381
    }
382 29
383 3
    /**
384 3
     * Generates and writes entity class to disk for the given ClassMetadataInfo instance.
385
     *
386
     * @param ClassMetadataInfo $metadata
387
     * @param string            $outputDirectory
388
     *
389
     * @return void
390 29
     *
391 28
     * @throws \RuntimeException
392
     */
393 3
    public function writeEntityClass(ClassMetadataInfo $metadata, $outputDirectory)
394 3
    {
395
        $path = $outputDirectory . '/' . str_replace('\\', DIRECTORY_SEPARATOR, $metadata->name) . $this->extension;
396 29
        $dir = dirname($path);
397 29
398
        if ( ! is_dir($dir)) {
399
            mkdir($dir, 0775, true);
400
        }
401
402
        $this->isNew = !file_exists($path) || (file_exists($path) && $this->regenerateEntityIfExists);
403
404
        if ( ! $this->isNew) {
405
            $this->parseTokensInEntityFile(file_get_contents($path));
406 29
        } else {
407
            $this->staticReflection[$metadata->name] = array('properties' => array(), 'methods' => array());
408
        }
409 29
410
        if ($this->backupExisting && file_exists($path)) {
411
            $backupPath = dirname($path) . DIRECTORY_SEPARATOR . basename($path) . "~";
412
            if (!copy($path, $backupPath)) {
413
                throw new \RuntimeException("Attempt to backup overwritten entity file but copy operation failed.");
414
            }
415
        }
416
417 29
        // If entity doesn't exist or we're re-generating the entities entirely
418 29
        if ($this->isNew) {
419 29
            file_put_contents($path, $this->generateEntityClass($metadata));
420 29
        // If entity exists and we're allowed to update the entity class
421 29
        } elseif ( ! $this->isNew && $this->updateEntityIfExists) {
422
            file_put_contents($path, $this->generateUpdatedEntityClass($metadata, $path));
423
        }
424 29
        chmod($path, 0664);
425
    }
426 29
427
    /**
428
     * Generates a PHP5 Doctrine 2 entity class from the given ClassMetadataInfo instance.
429
     *
430
     * @param ClassMetadataInfo $metadata
431
     *
432
     * @return string
433
     */
434
    public function generateEntityClass(ClassMetadataInfo $metadata)
435
    {
436
        $placeHolders = array(
437 3
            '<strictTypes>',
438
            '<namespace>',
439 3
            '<useStatement>',
440
            '<entityAnnotation>',
441 3
            '<entityClassName>',
442 3
            '<entityBody>'
443 3
        );
444
445 3
        $replacements = array(
446
            $this->generateEntityStrictTypes(),
447
            $this->generateEntityNamespace($metadata),
448
            $this->generateEntityUse(),
449
            $this->generateEntityDocBlock($metadata),
450
            $this->generateEntityClassName($metadata),
451
            $this->generateEntityBody($metadata)
452
        );
453
454
        $code = str_replace($placeHolders, $replacements, static::$classTemplate) . "\n";
455
456
        return str_replace('<spaces>', $this->spaces, $code);
457
    }
458
459
    /**
460
     * Generates the updated code for the given ClassMetadataInfo and entity at path.
461
     *
462
     * @param ClassMetadataInfo $metadata
463
     * @param string            $path
464
     *
465
     * @return string
466
     */
467
    public function generateUpdatedEntityClass(ClassMetadataInfo $metadata, $path)
468
    {
469
        $currentCode = file_get_contents($path);
470
471
        $body = $this->generateEntityBody($metadata);
472
        $body = str_replace('<spaces>', $this->spaces, $body);
473
        $last = strrpos($currentCode, '}');
474
475
        return substr($currentCode, 0, $last) . $body . (strlen($body) > 0 ? "\n" : '') . "}\n";
476
    }
477
478
    /**
479
     * Sets the number of spaces the exported class should have.
480 1
     *
481
     * @param integer $numSpaces
482 1
     *
483 1
     * @return void
484
     */
485
    public function setNumSpaces($numSpaces)
486
    {
487
        $this->spaces = str_repeat(' ', $numSpaces);
488
        $this->numSpaces = $numSpaces;
489
    }
490
491
    /**
492 38
     * Sets the extension to use when writing php files to disk.
493
     *
494 38
     * @param string $extension
495 38
     *
496
     * @return void
497
     */
498
    public function setExtension($extension)
499
    {
500
        $this->extension = $extension;
501
    }
502
503
    /**
504
     * Sets the name of the class the generated classes should extend from.
505
     *
506 37
     * @param string $classToExtend
507
     *
508 37
     * @return void
509
     */
510
    public function setClassToExtend($classToExtend)
511
    {
512 37
        $this->classToExtend = $classToExtend;
513 37
    }
514
515
    /**
516
     * Sets whether or not to generate annotations for the entity.
517
     *
518
     * @param bool $bool
519
     *
520 1
     * @return void
521
     */
522 1
    public function setGenerateAnnotations($bool)
523 1
    {
524
        $this->generateAnnotations = $bool;
525
    }
526
527
    /**
528
     * Sets the class fields visibility for the entity (can either be private or protected).
529
     *
530
     * @param bool $visibility
531
     *
532 38
     * @return void
533
     *
534 38
     * @throws \InvalidArgumentException
535 38
     */
536
    public function setFieldVisibility($visibility)
537
    {
538
        if ($visibility !== static::FIELD_VISIBLE_PRIVATE && $visibility !== static::FIELD_VISIBLE_PROTECTED) {
539
            throw new \InvalidArgumentException('Invalid provided visibility (only private and protected are allowed): ' . $visibility);
540
        }
541
542
        $this->fieldVisibility = $visibility;
543
    }
544 38
545
    /**
546 38
     * Sets whether or not to generate immutable embeddables.
547 38
     *
548
     * @param boolean $embeddablesImmutable
549
     */
550
    public function setEmbeddablesImmutable($embeddablesImmutable)
551
    {
552
        $this->embeddablesImmutable = (boolean) $embeddablesImmutable;
553
    }
554
555
    /**
556 38
     * Sets an annotation prefix.
557
     *
558 38
     * @param string $prefix
559 38
     *
560
     * @return void
561
     */
562
    public function setAnnotationPrefix($prefix)
563
    {
564
        $this->annotationsPrefix = $prefix;
565
    }
566
567
    /**
568 38
     * Sets whether or not to try and update the entity if it already exists.
569
     *
570 38
     * @param bool $bool
571 38
     *
572
     * @return void
573
     */
574
    public function setUpdateEntityIfExists($bool)
575
    {
576
        $this->updateEntityIfExists = $bool;
577
    }
578
579
    /**
580 1
     * Sets whether or not to regenerate the entity if it exists.
581
     *
582 1
     * @param bool $bool
583 1
     *
584
     * @return void
585
     */
586
    public function setRegenerateEntityIfExists($bool)
587
    {
588
        $this->regenerateEntityIfExists = $bool;
589
    }
590 29
591
    /**
592 29
     * Sets whether or not to generate stub methods for the entity.
593 28
     *
594
     * @param bool $bool
595
     *
596 18
     * @return void
597
     */
598
    public function setGenerateStubMethods($bool)
599
    {
600
        $this->generateEntityStubMethods = $bool;
601
    }
602
603
    /**
604 29
     * Should an existing entity be backed up if it already exists?
605
     *
606 29
     * @param bool $bool
607 29
     *
608
     * @return void
609 2
     */
610
    public function setBackupExisting($bool)
611 29
    {
612
        $this->backupExisting = $bool;
613 29
    }
614 29
615
    /**
616
     * Set whether or not to add PHP strict types.
617
     *
618
     * @param bool $bool
619
     *
620
     * @return void
621
     */
622
    public function setStrictTypes($bool)
623
    {
624
        $this->strictTypes = $bool;
625 29
    }
626
627 29
    /**
628 29
     * Set whether or not to force type hinting for method result and scalar parameters.
629
     *
630
     * @param bool $bool
631
     *
632
     * @param void
633
     */
634
    public function setGenerateMethodsTypeHinting($bool)
635
    {
636 30
        $this->generateMethodsTypeHinting = $bool;
637
    }
638 30
639 30
    /**
640 30
     * @param string $type
641 30
     *
642 30
     * @return string
643
     */
644 30
    protected function getType($type)
645
    {
646 30
        if (isset($this->typeAlias[$type])) {
647 27
            return $this->typeAlias[$type];
648
        }
649
650 30
        return $type;
651 8
    }
652
653
    /**
654 30
     * @return string
655 11
     */
656
    protected function generateEntityStrictTypes()
657
    {
658 30
        if ($this->strictTypes) {
659
            return "\n".'declare(strict_types=1);'."\n";
660 30
        }
661 28
662
        return '';
663
    }
664 30
665 10
    /**
666
     * @param ClassMetadataInfo $metadata
667
     *
668 30
     * @return string
669
     */
670
    protected function generateEntityNamespace(ClassMetadataInfo $metadata)
671
    {
672
        if ($this->hasNamespace($metadata)) {
673
            return 'namespace ' . $this->getNamespace($metadata) .';';
674
        }
675
    }
676 30
677
    protected function generateEntityUse()
678 30
    {
679 2
        if ($this->generateAnnotations) {
680
            return "\n".'use Doctrine\ORM\Mapping as ORM;'."\n";
681
        } else {
682 30
            return "";
683 1
        }
684
    }
685
686 29
    /**
687
     * @param ClassMetadataInfo $metadata
688 29
     *
689 13
     * @return string
690 13
     */
691
    protected function generateEntityClassName(ClassMetadataInfo $metadata)
692
    {
693
        return 'class ' . $this->getClassName($metadata) .
694 29
            ($this->extendsClass() ? ' extends ' . $this->getClassToExtendName() : null);
695 11
    }
696
697
    /**
698 25
     * @param ClassMetadataInfo $metadata
699
     *
700
     * @return string
701
     */
702
    protected function generateEntityBody(ClassMetadataInfo $metadata)
703
    {
704
        $fieldMappingProperties = $this->generateEntityFieldMappingProperties($metadata);
705
        $embeddedProperties = $this->generateEntityEmbeddedProperties($metadata);
706 1
        $associationMappingProperties = $this->generateEntityAssociationMappingProperties($metadata);
707
        $stubMethods = $this->generateEntityStubMethods ? $this->generateEntityStubMethods($metadata) : null;
708 1
        $lifecycleCallbackMethods = $this->generateEntityLifecycleCallbackMethods($metadata);
709 1
710 1
        $code = array();
711 1
712
        if ($fieldMappingProperties) {
713
            $code[] = $fieldMappingProperties;
714 1
        }
715 1
716
        if ($embeddedProperties) {
717 1
            $code[] = $embeddedProperties;
718 1
        }
719 1
720
        if ($associationMappingProperties) {
721 1
            $code[] = $associationMappingProperties;
722
        }
723
724 1
        $code[] = $this->generateEntityConstructor($metadata);
725
726
        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...
727 1
            $code[] = $stubMethods;
728
        }
729 1
730 1
        if ($lifecycleCallbackMethods) {
731 1
            $code[] = $lifecycleCallbackMethods;
732
        }
733 1
734 1
        return implode("\n", $code);
735 1
    }
736 1
737
    /**
738
     * @param ClassMetadataInfo $metadata
739 1
     *
740 1
     * @return string
741 1
     */
742
    protected function generateEntityConstructor(ClassMetadataInfo $metadata)
743
    {
744
        if ($this->hasMethod('__construct', $metadata)) {
745
            return '';
746 1
        }
747 1
748 1
        if ($metadata->isEmbeddedClass && $this->embeddablesImmutable) {
749
            return $this->generateEmbeddableConstructor($metadata);
750 1
        }
751 1
752
        $collections = array();
753
754 1
        foreach ($metadata->associationMappings as $mapping) {
755 1
            if ($mapping['type'] & ClassMetadataInfo::TO_MANY) {
756
                $collections[] = '$this->'.$mapping['fieldName'].' = new \Doctrine\Common\Collections\ArrayCollection();';
757
            }
758 1
        }
759
760 1
        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...
761
            return $this->prefixCodeWithSpaces(str_replace("<collections>", implode("\n".$this->spaces, $collections), static::$constructorMethodTemplate));
762
        }
763 1
764 1
        return '';
765 1
    }
766 1
767 1
    /**
768
     * @param ClassMetadataInfo $metadata
769
     *
770
     * @return string
771
     */
772
    private function generateEmbeddableConstructor(ClassMetadataInfo $metadata)
773 1
    {
774 1
        $paramTypes = array();
775 1
        $paramVariables = array();
776
        $params = array();
777 1
        $fields = array();
778
779
        // Resort fields to put optional fields at the end of the method signature.
780
        $requiredFields = array();
781 1
        $optionalFields = array();
782 1
783 1
        foreach ($metadata->fieldMappings as $fieldMapping) {
784
            if (empty($fieldMapping['nullable'])) {
785
                $requiredFields[] = $fieldMapping;
786 1
787
                continue;
788
            }
789 1
790
            $optionalFields[] = $fieldMapping;
791
        }
792 1
793
        $fieldMappings = array_merge($requiredFields, $optionalFields);
794
795
        foreach ($metadata->embeddedClasses as $fieldName => $embeddedClass) {
796
            $paramType = '\\' . ltrim($embeddedClass['class'], '\\');
797
            $paramVariable = '$' . $fieldName;
798
799
            $paramTypes[] = $paramType;
800
            $paramVariables[] = $paramVariable;
801
            $params[] = $paramType . ' ' . $paramVariable;
802 8
            $fields[] = '$this->' . $fieldName . ' = ' . $paramVariable . ';';
803
        }
804 8
805 8
        foreach ($fieldMappings as $fieldMapping) {
806 8
            if (isset($fieldMapping['declaredField']) &&
807
                isset($metadata->embeddedClasses[$fieldMapping['declaredField']])
808 8
            ) {
809 8
                continue;
810
            }
811 8
812 8
            $paramTypes[] = $this->getType($fieldMapping['type']) . (!empty($fieldMapping['nullable']) ? '|null' : '');
813 8
            $param = '$' . $fieldMapping['fieldName'];
814 8
            $paramVariables[] = $param;
815
816
            if ($fieldMapping['type'] === 'datetime') {
817 8
                $param = $this->getType($fieldMapping['type']) . ' ' . $param;
818 8
            }
819 8
820 8
            if (!empty($fieldMapping['nullable'])) {
821 8
                $param .= ' = null';
822
            }
823
824
            $params[] = $param;
825 8
826 8
            $fields[] = '$this->' . $fieldMapping['fieldName'] . ' = $' . $fieldMapping['fieldName'] . ';';
827 8
        }
828 8
829 8
        $maxParamTypeLength = max(array_map('strlen', $paramTypes));
830
        $paramTags = array_map(
831
            function ($type, $variable) use ($maxParamTypeLength) {
832 8
                return '@param ' . $type . str_repeat(' ', $maxParamTypeLength - strlen($type) + 1) . $variable;
833 8
            },
834 8
            $paramTypes,
835 8
            $paramVariables
836 8
        );
837 8
838 3
        // Generate multi line constructor if the signature exceeds 120 characters.
839 3
        if (array_sum(array_map('strlen', $params)) + count($params) * 2 + 29 > 120) {
840
            $delimiter = "\n" . $this->spaces;
841 3
            $params = $delimiter . implode(',' . $delimiter, $params) . "\n";
842
        } else {
843 8
            $params = implode(', ', $params);
844 4
        }
845
846
        $replacements = array(
847 8
            '<paramTags>' => implode("\n * ", $paramTags),
848
            '<params>'    => $params,
849
            '<fields>'    => implode("\n" . $this->spaces, $fields),
850
        );
851
852
        $constructor = str_replace(
853
            array_keys($replacements),
854
            array_values($replacements),
855 29
            static::$embeddableConstructorMethodTemplate
856
        );
857 29
858
        return $this->prefixCodeWithSpaces($constructor);
859 2
    }
860 2
861 1
    /**
862
     * @todo this won't work if there is a namespace in brackets and a class outside of it.
863
     *
864
     * @param string $src
865
     *
866 28
     * @return void
867 2
     */
868 2
    protected function parseTokensInEntityFile($src)
869
    {
870
        $tokens = token_get_all($src);
871
        $lastSeenNamespace = "";
872
        $lastSeenClass = false;
873 28
874 28
        $inNamespace = false;
875
        $inClass = false;
876
877
        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...
878
            $token = $tokens[$i];
879
            if (in_array($token[0], array(T_WHITESPACE, T_COMMENT, T_DOC_COMMENT))) {
880
                continue;
881
            }
882
883
            if ($inNamespace) {
884 30
                if ($token[0] == T_NS_SEPARATOR || $token[0] == T_STRING) {
885
                    $lastSeenNamespace .= $token[1];
886 30
                } elseif (is_string($token) && in_array($token, array(';', '{'))) {
887
                    $inNamespace = false;
888 2
                }
889
            }
890 2
891 1
            if ($inClass) {
892
                $inClass = false;
893
                $lastSeenClass = $lastSeenNamespace . ($lastSeenNamespace ? '\\' : '') . $token[1];
894
                $this->staticReflection[$lastSeenClass]['properties'] = array();
895
                $this->staticReflection[$lastSeenClass]['methods'] = array();
896 30
            }
897 2
898 2
            if ($token[0] == T_NAMESPACE) {
899
                $lastSeenNamespace = "";
900
                $inNamespace = true;
901
            } elseif ($token[0] == T_CLASS && $tokens[$i-1][0] != T_DOUBLE_COLON) {
902
                $inClass = true;
903 30
            } elseif ($token[0] == T_FUNCTION) {
904 30
                if ($tokens[$i+2][0] == T_STRING) {
905
                    $this->staticReflection[$lastSeenClass]['methods'][] = strtolower($tokens[$i+2][1]);
906
                } elseif ($tokens[$i+2] == "&" && $tokens[$i+3][0] == T_STRING) {
907
                    $this->staticReflection[$lastSeenClass]['methods'][] = strtolower($tokens[$i+3][1]);
908
                }
909
            } elseif (in_array($token[0], array(T_VAR, T_PUBLIC, T_PRIVATE, T_PROTECTED)) && $tokens[$i+2][0] != T_FUNCTION) {
910
                $this->staticReflection[$lastSeenClass]['properties'][] = substr($tokens[$i+2][1], 1);
911
            }
912
        }
913 30
    }
914
915 30
    /**
916 24
     * @param string            $property
917
     * @param ClassMetadataInfo $metadata
918
     *
919 7
     * @return bool
920 1
     */
921 7
    protected function hasProperty($property, ClassMetadataInfo $metadata)
922
    {
923 7
        if ($this->extendsClass() || (!$this->isNew && class_exists($metadata->name))) {
924
            // don't generate property if its already on the base class.
925 7
            $reflClass = new \ReflectionClass($this->getClassToExtend() ?: $metadata->name);
926 7
            if ($reflClass->hasProperty($property)) {
927
                return true;
928 7
            }
929
        }
930
931 7
        // check traits for existing property
932
        foreach ($this->getTraits($metadata) as $trait) {
933
            if ($trait->hasProperty($property)) {
934
                return true;
935
            }
936
        }
937
938
        return (
939 29
            isset($this->staticReflection[$metadata->name]) &&
940
            in_array($property, $this->staticReflection[$metadata->name]['properties'])
941 29
        );
942
    }
943
944
    /**
945
     * @param string            $method
946
     * @param ClassMetadataInfo $metadata
947 30
     *
948
     * @return bool
949 30
     */
950
    protected function hasMethod($method, ClassMetadataInfo $metadata)
951
    {
952
        if ($this->extendsClass() || (!$this->isNew && class_exists($metadata->name))) {
953
            // don't generate method if its already on the base class.
954
            $reflClass = new \ReflectionClass($this->getClassToExtend() ?: $metadata->name);
955 2
956
            if ($reflClass->hasMethod($method)) {
957 2
                return true;
958
            }
959
        }
960
961
        // check traits for existing method
962
        foreach ($this->getTraits($metadata) as $trait) {
963 1
            if ($trait->hasMethod($method)) {
964
                return true;
965 1
            }
966
        }
967 1
968
        return (
969
            isset($this->staticReflection[$metadata->name]) &&
970
            in_array(strtolower($method), $this->staticReflection[$metadata->name]['methods'])
971
        );
972
    }
973
974
    /**
975 30
     * @param ClassMetadataInfo $metadata
976
     *
977 30
     * @return array
978 30
     */
979
    protected function getTraits(ClassMetadataInfo $metadata)
980
    {
981
        if (! ($metadata->reflClass !== null || class_exists($metadata->name))) {
982
            return [];
983
        }
984
985
        $reflClass = $metadata->reflClass === null
986 29
            ? new \ReflectionClass($metadata->name)
987
            : $metadata->reflClass;
988 29
989
        $traits = array();
990
991
        while ($reflClass !== false) {
992
            $traits = array_merge($traits, $reflClass->getTraits());
993
994
            $reflClass = $reflClass->getParentClass();
995
        }
996 29
997
        return $traits;
998 29
    }
999 29
1000 29
    /**
1001
     * @param ClassMetadataInfo $metadata
1002 29
     *
1003 29
     * @return bool
1004
     */
1005
    protected function hasNamespace(ClassMetadataInfo $metadata)
1006 29
    {
1007
        return strpos($metadata->name, '\\') ? true : false;
1008
    }
1009
1010
    /**
1011
     * @return bool
1012
     */
1013 29
    protected function extendsClass()
1014 29
    {
1015 29
        return $this->classToExtend ? true : false;
1016
    }
1017
1018
    /**
1019 29
     * @return string
1020 10
     */
1021
    protected function getClassToExtend()
1022
    {
1023
        return $this->classToExtend;
1024 29
    }
1025
1026 29
    /**
1027
     * @return string
1028
     */
1029
    protected function getClassToExtendName()
1030
    {
1031
        $refl = new \ReflectionClass($this->getClassToExtend());
1032
1033
        return '\\' . $refl->getName();
1034 29
    }
1035
1036 29
    /**
1037
     * @param ClassMetadataInfo $metadata
1038 29
     *
1039 9
     * @return string
1040
     */
1041
    protected function getClassName(ClassMetadataInfo $metadata)
1042 27
    {
1043 11
        return ($pos = strrpos($metadata->name, '\\'))
1044 27
            ? substr($metadata->name, $pos + 1, strlen($metadata->name)) : $metadata->name;
1045
    }
1046 27
1047
    /**
1048
     * @param ClassMetadataInfo $metadata
1049
     *
1050
     * @return string
1051
     */
1052
    protected function getNamespace(ClassMetadataInfo $metadata)
1053
    {
1054 29
        return substr($metadata->name, 0, strrpos($metadata->name, '\\'));
1055
    }
1056 29
1057 9
    /**
1058
     * @param ClassMetadataInfo $metadata
1059
     *
1060 27
     * @return string
1061
     */
1062 27
    protected function generateEntityDocBlock(ClassMetadataInfo $metadata)
1063
    {
1064
        $lines = array();
1065
        $lines[] = '/**';
1066 27
        $lines[] = ' * ' . $this->getClassName($metadata);
1067 24
1068
        if ($this->generateAnnotations) {
1069
            $lines[] = ' *';
1070 27
1071 1
            $methods = array(
1072
                'generateTableAnnotation',
1073
                'generateInheritanceAnnotation',
1074 27
                'generateDiscriminatorColumnAnnotation',
1075 9
                'generateDiscriminatorMapAnnotation',
1076 9
                'generateEntityAnnotation',
1077
            );
1078
1079 27
            foreach ($methods as $method) {
1080 9
                if ($code = $this->$method($metadata)) {
1081 9
                    $lines[] = ' * ' . $code;
1082
                }
1083
            }
1084 27
1085
            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...
1086
                $lines[] = ' * @' . $this->annotationsPrefix . 'HasLifecycleCallbacks';
1087
            }
1088
        }
1089
1090
        $lines[] = ' */';
1091
1092
        return implode("\n", $lines);
1093 9
    }
1094
1095 9
    /**
1096 9
     * @param ClassMetadataInfo $metadata
1097 9
     *
1098 9
     * @return string
1099 9
     */
1100
    protected function generateEntityAnnotation(ClassMetadataInfo $metadata)
1101 9
    {
1102
        $prefix = '@' . $this->annotationsPrefix;
1103
1104 9
        if ($metadata->isEmbeddedClass) {
1105
            return $prefix . 'Embeddable';
1106
        }
1107
1108
        $customRepository = $metadata->customRepositoryClassName
1109
            ? '(repositoryClass="' . $metadata->customRepositoryClassName . '")'
1110
            : '';
1111
1112 29
        return $prefix . ($metadata->isMappedSuperclass ? 'MappedSuperclass' : 'Entity') . $customRepository;
1113
    }
1114 29
1115
    /**
1116
     * @param ClassMetadataInfo $metadata
1117 29
     *
1118
     * @return string
1119
     */
1120
    protected function generateTableAnnotation($metadata)
1121
    {
1122
        if ($metadata->isEmbeddedClass) {
1123
            return '';
1124 29
        }
1125
1126 29
        $table = array();
1127
1128
        if (isset($metadata->table['schema'])) {
1129
            $table[] = 'schema="' . $metadata->table['schema'] . '"';
1130
        }
1131
1132
        if (isset($metadata->table['name'])) {
1133
            $table[] = 'name="' . $metadata->table['name'] . '"';
1134 29
        }
1135
1136
        if (isset($metadata->table['options']) && $metadata->table['options']) {
1137
            $table[] = 'options={' . $this->exportTableOptions((array) $metadata->table['options']) . '}';
1138
        }
1139
1140
        if (isset($metadata->table['uniqueConstraints']) && $metadata->table['uniqueConstraints']) {
1141 29
            $constraints = $this->generateTableConstraints('UniqueConstraint', $metadata->table['uniqueConstraints']);
1142
            $table[] = 'uniqueConstraints={' . $constraints . '}';
1143 29
        }
1144
1145
        if (isset($metadata->table['indexes']) && $metadata->table['indexes']) {
1146
            $constraints = $this->generateTableConstraints('Index', $metadata->table['indexes']);
1147
            $table[] = 'indexes={' . $constraints . '}';
1148
        }
1149
1150
        return '@' . $this->annotationsPrefix . 'Table(' . implode(', ', $table) . ')';
1151
    }
1152 29
1153
    /**
1154
     * @param string $constraintName
1155
     * @param array  $constraints
1156
     *
1157
     * @return string
1158
     */
1159 29
    protected function generateTableConstraints($constraintName, $constraints)
1160
    {
1161 29
        $annotations = array();
1162
        foreach ($constraints as $name => $constraint) {
1163 29
            $columns = array();
1164 28
            foreach ($constraint['columns'] as $column) {
1165 28
                $columns[] = '"' . $column . '"';
1166
            }
1167
            $annotations[] = '@' . $this->annotationsPrefix . $constraintName . '(name="' . $name . '", columns={' . implode(', ', $columns) . '})';
1168
        }
1169
1170 28
        return implode(', ', $annotations);
1171 26
    }
1172 28
1173 28
    /**
1174
     * @param ClassMetadataInfo $metadata
1175 25
     *
1176 25
     * @return string
1177
     */
1178
    protected function generateInheritanceAnnotation($metadata)
1179
    {
1180 28
        if ($metadata->inheritanceType != ClassMetadataInfo::INHERITANCE_TYPE_NONE) {
1181 28
            return '@' . $this->annotationsPrefix . 'InheritanceType("'.$this->getInheritanceTypeString($metadata->inheritanceType).'")';
1182
        }
1183
    }
1184
1185 29
    /**
1186 8
     * @param ClassMetadataInfo $metadata
1187 1
     *
1188
     * @return string
1189
     */
1190 8
    protected function generateDiscriminatorColumnAnnotation($metadata)
1191 7
    {
1192 7
        if ($metadata->inheritanceType != ClassMetadataInfo::INHERITANCE_TYPE_NONE) {
1193
            $discrColumn = $metadata->discriminatorColumn;
1194
            $columnDefinition = 'name="' . $discrColumn['name']
1195
                . '", type="' . $discrColumn['type']
1196 8
                . '", length=' . $discrColumn['length'];
1197 8
1198
            return '@' . $this->annotationsPrefix . 'DiscriminatorColumn(' . $columnDefinition . ')';
1199
        }
1200
    }
1201 29
1202 12
    /**
1203 11
     * @param ClassMetadataInfo $metadata
1204 11
     *
1205 9
     * @return string
1206
     */
1207 11
    protected function generateDiscriminatorMapAnnotation($metadata)
1208 11
    {
1209
        if ($metadata->inheritanceType != ClassMetadataInfo::INHERITANCE_TYPE_NONE) {
1210 10
            $inheritanceClassMap = array();
1211 10
1212 10
            foreach ($metadata->discriminatorMap as $type => $class) {
1213
                $inheritanceClassMap[] .= '"' . $type . '" = "' . $class . '"';
1214 10
            }
1215 10
1216
            return '@' . $this->annotationsPrefix . 'DiscriminatorMap({' . implode(', ', $inheritanceClassMap) . '})';
1217 10
        }
1218 12
    }
1219
1220
    /**
1221
     * @param ClassMetadataInfo $metadata
1222
     *
1223 29
     * @return string
1224
     */
1225
    protected function generateEntityStubMethods(ClassMetadataInfo $metadata)
1226
    {
1227
        $methods = array();
1228
1229
        foreach ($metadata->fieldMappings as $fieldMapping) {
1230
            if (isset($fieldMapping['declaredField']) &&
1231 11
                isset($metadata->embeddedClasses[$fieldMapping['declaredField']])
1232
            ) {
1233 11
                continue;
1234
            }
1235
1236
            if (( ! isset($fieldMapping['id']) ||
1237 11
                    ! $fieldMapping['id'] ||
1238 2
                    $metadata->generatorType == ClassMetadataInfo::GENERATOR_TYPE_NONE
1239
                ) && (! $metadata->isEmbeddedClass || ! $this->embeddablesImmutable)
1240
            ) {
1241 9
                if ($code = $this->generateEntityStubMethod($metadata, 'set', $fieldMapping['fieldName'], $fieldMapping['type'])) {
1242
                    $methods[] = $code;
1243
                }
1244 11
            }
1245 2
1246 2
            if ($code = $this->generateEntityStubMethod($metadata, 'get', $fieldMapping['fieldName'], $fieldMapping['type'])) {
1247
                $methods[] = $code;
1248
            }
1249
        }
1250 11
1251
        foreach ($metadata->embeddedClasses as $fieldName => $embeddedClass) {
1252
            if (isset($embeddedClass['declaredField'])) {
1253
                continue;
1254
            }
1255
1256
            if ( ! $metadata->isEmbeddedClass || ! $this->embeddablesImmutable) {
1257
                if ($code = $this->generateEntityStubMethod($metadata, 'set', $fieldName, $embeddedClass['class'])) {
1258 30
                    $methods[] = $code;
1259
                }
1260 30
            }
1261 10
1262
            if ($code = $this->generateEntityStubMethod($metadata, 'get', $fieldName, $embeddedClass['class'])) {
1263 10
                $methods[] = $code;
1264 10
            }
1265 10
        }
1266 10
1267
        foreach ($metadata->associationMappings as $associationMapping) {
1268
            if ($associationMapping['type'] & ClassMetadataInfo::TO_ONE) {
1269
                $nullable = $this->isAssociationIsNullable($associationMapping) ? 'null' : null;
1270
                if ($code = $this->generateEntityStubMethod($metadata, 'set', $associationMapping['fieldName'], $associationMapping['targetEntity'], $nullable)) {
1271 10
                    $methods[] = $code;
1272
                }
1273
                if ($code = $this->generateEntityStubMethod($metadata, 'get', $associationMapping['fieldName'], $associationMapping['targetEntity'])) {
1274 27
                    $methods[] = $code;
1275
                }
1276
            } elseif ($associationMapping['type'] & ClassMetadataInfo::TO_MANY) {
1277
                if ($code = $this->generateEntityStubMethod($metadata, 'add', $associationMapping['fieldName'], $associationMapping['targetEntity'])) {
1278
                    $methods[] = $code;
1279
                }
1280
                if ($code = $this->generateEntityStubMethod($metadata, 'remove', $associationMapping['fieldName'], $associationMapping['targetEntity'])) {
1281
                    $methods[] = $code;
1282 30
                }
1283
                if ($code = $this->generateEntityStubMethod($metadata, 'get', $associationMapping['fieldName'], 'Doctrine\Common\Collections\Collection')) {
1284 30
                    $methods[] = $code;
1285
                }
1286 30
            }
1287 13
        }
1288 4
1289
        return implode("\n\n", $methods);
1290
    }
1291 11
1292 11
    /**
1293 11
     * @param array $associationMapping
1294
     *
1295
     * @return bool
1296 30
     */
1297
    protected function isAssociationIsNullable($associationMapping)
1298
    {
1299
        if (isset($associationMapping['id']) && $associationMapping['id']) {
1300
            return false;
1301
        }
1302
1303
        if (isset($associationMapping['joinColumns'])) {
1304 30
            $joinColumns = $associationMapping['joinColumns'];
1305
        } else {
1306 30
            //@todo there is no way to retrieve targetEntity metadata
1307
            $joinColumns = array();
1308 30
        }
1309 29
1310 28
        foreach ($joinColumns as $joinColumn) {
1311
            if (isset($joinColumn['nullable']) && !$joinColumn['nullable']) {
1312 27
                return false;
1313 29
            }
1314
        }
1315
1316 4
        return true;
1317
    }
1318
1319 27
    /**
1320 27
     * @param ClassMetadataInfo $metadata
1321 27
     *
1322
     * @return string
1323
     */
1324 30
    protected function generateEntityLifecycleCallbackMethods(ClassMetadataInfo $metadata)
1325
    {
1326
        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...
1327
            $methods = array();
1328
1329
            foreach ($metadata->lifecycleCallbacks as $name => $callbacks) {
1330
                foreach ($callbacks as $callback) {
1331
                    if ($code = $this->generateLifecycleCallbackMethod($name, $callback, $metadata)) {
1332 30
                        $methods[] = $code;
1333
                    }
1334 30
                }
1335
            }
1336 30
1337 8
            return implode("\n\n", $methods);
1338 2
        }
1339
1340
        return "";
1341 8
    }
1342 8
1343
    /**
1344
     * @param ClassMetadataInfo $metadata
1345 30
     *
1346
     * @return string
1347
     */
1348
    protected function generateEntityAssociationMappingProperties(ClassMetadataInfo $metadata)
1349
    {
1350
        $lines = array();
1351
1352
        foreach ($metadata->associationMappings as $associationMapping) {
1353
            if ($this->hasProperty($associationMapping['fieldName'], $metadata)) {
1354
                continue;
1355
            }
1356
1357 28
            $lines[] = $this->generateAssociationMappingPropertyDocBlock($associationMapping, $metadata);
1358
            $lines[] = $this->spaces . $this->fieldVisibility . ' $' . $associationMapping['fieldName']
1359 28
                     . ($associationMapping['type'] == 'manyToMany' ? ' = array()' : null) . ";\n";
1360 28
        }
1361 28
1362 10
        return implode("\n", $lines);
1363 10
    }
1364
1365
    /**
1366 28
     * @param ClassMetadataInfo $metadata
1367 5
     *
1368
     * @return string
1369 28
     */
1370
    protected function generateEntityFieldMappingProperties(ClassMetadataInfo $metadata)
1371 28
    {
1372 28
        $lines = array();
1373
1374 28
        foreach ($metadata->fieldMappings as $fieldMapping) {
1375 28
            if ($this->hasProperty($fieldMapping['fieldName'], $metadata) ||
1376 28
                $metadata->isInheritedField($fieldMapping['fieldName']) ||
1377
                (
1378 28
                    isset($fieldMapping['declaredField']) &&
1379 12
                    isset($metadata->embeddedClasses[$fieldMapping['declaredField']])
1380 12
                )
1381
            ) {
1382
                continue;
1383
            }
1384 28
1385 28
            $lines[] = $this->generateFieldMappingPropertyDocBlock($fieldMapping, $metadata);
1386 28
            $lines[] = $this->spaces . $this->fieldVisibility . ' $' . $fieldMapping['fieldName']
1387 28
                     . (isset($fieldMapping['options']['default']) ? ' = ' . var_export($fieldMapping['options']['default'], true) : null) . ";\n";
1388 28
        }
1389 28
1390 28
        return implode("\n", $lines);
1391 28
    }
1392
1393
    /**
1394 28
     * @param ClassMetadataInfo $metadata
1395
     *
1396
     * @return string
1397
     */
1398
    protected function generateEntityEmbeddedProperties(ClassMetadataInfo $metadata)
1399
    {
1400 28
        $lines = array();
1401
1402
        foreach ($metadata->embeddedClasses as $fieldName => $embeddedClass) {
1403
            if (isset($embeddedClass['declaredField']) || $this->hasProperty($fieldName, $metadata)) {
1404
                continue;
1405
            }
1406
1407
            $lines[] = $this->generateEmbeddedPropertyDocBlock($embeddedClass);
1408
            $lines[] = $this->spaces . $this->fieldVisibility . ' $' . $fieldName . ";\n";
1409
        }
1410 10
1411
        return implode("\n", $lines);
1412 10
    }
1413 2
1414
    /**
1415 10
     * @param ClassMetadataInfo $metadata
1416
     * @param string            $type
1417
     * @param string            $fieldName
1418 10
     * @param string|null       $typeHint
1419 10
     * @param string|null       $defaultValue
1420
     *
1421
     * @return string
1422 10
     */
1423
    protected function generateEntityStubMethod(ClassMetadataInfo $metadata, $type, $fieldName, $typeHint = null,  $defaultValue = null)
1424
    {
1425 10
        $methodName = $type . Inflector::classify($fieldName);
1426
        $variableName = Inflector::camelize($fieldName);
1427
        if (in_array($type, array("add", "remove"))) {
1428 10
            $methodName = Inflector::singularize($methodName);
1429
            $variableName = Inflector::singularize($variableName);
1430
        }
1431
1432
        if ($this->hasMethod($methodName, $metadata)) {
1433
            return '';
1434
        }
1435
        $this->staticReflection[$metadata->name]['methods'][] = strtolower($methodName);
1436 11
1437
        $var = sprintf('%sMethodTemplate', $type);
1438 11
        $template = static::$$var;
1439
1440 11
        $methodTypeHint = null;
1441 11
        $types          = Type::getTypesMap();
1442
        $variableType   = $typeHint ? $this->getType($typeHint) : null;
1443
1444 11
        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...
1445 11
            $variableType   =  '\\' . ltrim($variableType, '\\');
1446
            $methodTypeHint =  '\\' . $typeHint . ' ';
1447
        }
1448 11
1449 1
        $methodReturnType = null;
1450
        if ($this->generateMethodsTypeHinting) {
1451
            $methodReturnType = $this->getMethodReturnType($metadata, $type, $fieldName, $variableType);
1452 11
1453 1
            if (null === $methodTypeHint) {
1454
                $type = isset($this->typeHintingAlias[$variableType]) ? $this->typeHintingAlias[$variableType] : $variableType;
1455
                $methodTypeHint = $type.' ';
1456 11
            }
1457 1
        }
1458
1459
        $replacements = array(
1460 11
          '<description>'       => ucfirst($type) . ' ' . $variableName,
1461 1
          '<methodTypeHint>'    => $methodTypeHint,
1462
          '<variableType>'      => $variableType,
1463
          '<variableName>'      => $variableName,
1464 11
          '<methodName>'        => $methodName,
1465
          '<fieldName>'         => $fieldName,
1466
          '<variableDefault>'   => ($defaultValue !== null ) ? (' = '.$defaultValue) : '',
1467
          '<entity>'            => $this->getClassName($metadata),
1468
          '<methodTypeReturn>'  => $methodReturnType,
1469
        );
1470
1471
        $method = str_replace(
1472
            array_keys($replacements),
1473 11
            array_values($replacements),
1474
            $template
1475 11
        );
1476 11
1477
        return $this->prefixCodeWithSpaces($method);
1478 11
    }
1479 11
1480
    /**
1481 10
     * @param string            $name
1482
     * @param string            $methodName
1483
     * @param ClassMetadataInfo $metadata
1484 11
     *
1485 11
     * @return string
1486
     */
1487 11
    protected function generateLifecycleCallbackMethod($name, $methodName, $metadata)
1488
    {
1489
        if ($this->hasMethod($methodName, $metadata)) {
1490
            return '';
1491
        }
1492
        $this->staticReflection[$metadata->name]['methods'][] = $methodName;
1493
1494
        $replacements = array(
1495 11
            '<name>'        => $this->annotationsPrefix . ucfirst($name),
1496 11
            '<methodName>'  => $methodName,
1497 11
        );
1498 10
1499 10
        $method = str_replace(
1500 11
            array_keys($replacements),
1501 1
            array_values($replacements),
1502 1
            static::$lifecycleCallbackMethodTemplate
1503 11
        );
1504 1
1505 1
        return $this->prefixCodeWithSpaces($method);
1506 11
    }
1507 11
1508 11
    /**
1509
     * @param array $joinColumn
1510 11
     *
1511
     * @return string
1512 11
     */
1513 11
    protected function generateJoinColumnAnnotation(array $joinColumn)
1514
    {
1515
        $joinColumnAnnot = array();
1516 11
1517 1
        if (isset($joinColumn['name'])) {
1518
            $joinColumnAnnot[] = 'name="' . $joinColumn['name'] . '"';
1519
        }
1520 11
1521 10
        if (isset($joinColumn['referencedColumnName'])) {
1522
            $joinColumnAnnot[] = 'referencedColumnName="' . $joinColumn['referencedColumnName'] . '"';
1523
        }
1524 11
1525 1
        if (isset($joinColumn['unique']) && $joinColumn['unique']) {
1526
            $joinColumnAnnot[] = 'unique=' . ($joinColumn['unique'] ? 'true' : 'false');
1527 1
        }
1528 1
1529 1
        if (isset($joinColumn['nullable'])) {
1530 1
            $joinColumnAnnot[] = 'nullable=' . ($joinColumn['nullable'] ? 'true' : 'false');
1531 1
        }
1532
1533 1
        if (isset($joinColumn['onDelete'])) {
1534 1
            $joinColumnAnnot[] = 'onDelete="' . ($joinColumn['onDelete'] . '"');
1535
        }
1536
1537 1
        if (isset($joinColumn['columnDefinition'])) {
1538
            $joinColumnAnnot[] = 'columnDefinition="' . $joinColumn['columnDefinition'] . '"';
1539
        }
1540 11
1541 1
        return '@' . $this->annotationsPrefix . 'JoinColumn(' . implode(', ', $joinColumnAnnot) . ')';
1542
    }
1543
1544 11
    /**
1545
     * @param array             $associationMapping
1546 10
     * @param ClassMetadataInfo $metadata
1547 10
     *
1548
     * @return string
1549
     */
1550 10
    protected function generateAssociationMappingPropertyDocBlock(array $associationMapping, ClassMetadataInfo $metadata)
1551
    {
1552
        $lines = array();
1553 11
        $lines[] = $this->spaces . '/**';
1554
1555 11
        if ($associationMapping['type'] & ClassMetadataInfo::TO_MANY) {
1556 1
            $lines[] = $this->spaces . ' * @var \Doctrine\Common\Collections\Collection';
1557
        } else {
1558 1
            $lines[] = $this->spaces . ' * @var \\' . ltrim($associationMapping['targetEntity'], '\\');
1559
        }
1560 1
1561 1
        if ($this->generateAnnotations) {
1562 1
            $lines[] = $this->spaces . ' *';
1563
1564
            if (isset($associationMapping['id']) && $associationMapping['id']) {
1565
                $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'Id';
1566 1
1567 1
                if ($generatorType = $this->getIdGeneratorTypeString($metadata->generatorType)) {
1568
                    $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'GeneratedValue(strategy="' . $generatorType . '")';
1569
                }
1570 11
            }
1571 11
1572 11
            $type = null;
1573
            switch ($associationMapping['type']) {
1574 11
                case ClassMetadataInfo::ONE_TO_ONE:
1575
                    $type = 'OneToOne';
1576
                    break;
1577
                case ClassMetadataInfo::MANY_TO_ONE:
1578 11
                    $type = 'ManyToOne';
1579 11
                    break;
1580
                case ClassMetadataInfo::ONE_TO_MANY:
1581 11
                    $type = 'OneToMany';
1582
                    break;
1583 11
                case ClassMetadataInfo::MANY_TO_MANY:
1584 11
                    $type = 'ManyToMany';
1585
                    break;
1586
            }
1587 11
            $typeOptions = array();
1588 11
1589 11
            if (isset($associationMapping['targetEntity'])) {
1590
                $typeOptions[] = 'targetEntity="' . $associationMapping['targetEntity'] . '"';
1591 11
            }
1592
1593 11
            if (isset($associationMapping['inversedBy'])) {
1594 11
                $typeOptions[] = 'inversedBy="' . $associationMapping['inversedBy'] . '"';
1595
            }
1596
1597 11
            if (isset($associationMapping['mappedBy'])) {
1598 11
                $typeOptions[] = 'mappedBy="' . $associationMapping['mappedBy'] . '"';
1599 11
            }
1600
1601
            if ($associationMapping['cascade']) {
1602 11
                $cascades = array();
1603 1
1604
                if ($associationMapping['isCascadePersist']) $cascades[] = '"persist"';
1605 1
                if ($associationMapping['isCascadeRemove']) $cascades[] = '"remove"';
1606 1
                if ($associationMapping['isCascadeDetach']) $cascades[] = '"detach"';
1607
                if ($associationMapping['isCascadeMerge']) $cascades[] = '"merge"';
1608
                if ($associationMapping['isCascadeRefresh']) $cascades[] = '"refresh"';
1609 1
1610 1
                if (count($cascades) === 5) {
1611
                    $cascades = array('"all"');
1612
                }
1613
1614 11
                $typeOptions[] = 'cascade={' . implode(',', $cascades) . '}';
1615
            }
1616 11
1617
            if (isset($associationMapping['orphanRemoval']) && $associationMapping['orphanRemoval']) {
1618
                $typeOptions[] = 'orphanRemoval=' . ($associationMapping['orphanRemoval'] ? 'true' : 'false');
1619
            }
1620
1621
            if (isset($associationMapping['fetch']) && $associationMapping['fetch'] !== ClassMetadataInfo::FETCH_LAZY) {
1622
                $fetchMap = array(
1623
                    ClassMetadataInfo::FETCH_EXTRA_LAZY => 'EXTRA_LAZY',
1624
                    ClassMetadataInfo::FETCH_EAGER      => 'EAGER',
1625 27
                );
1626
1627 27
                $typeOptions[] = 'fetch="' . $fetchMap[$associationMapping['fetch']] . '"';
1628 27
            }
1629 27
1630
            $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . '' . $type . '(' . implode(', ', $typeOptions) . ')';
1631 27
1632 27
            if (isset($associationMapping['joinColumns']) && $associationMapping['joinColumns']) {
1633
                $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'JoinColumns({';
1634 27
1635 27
                $joinColumnsLines = array();
1636 27
1637
                foreach ($associationMapping['joinColumns'] as $joinColumn) {
1638
                    if ($joinColumnAnnot = $this->generateJoinColumnAnnotation($joinColumn)) {
1639 27
                        $joinColumnsLines[] = $this->spaces . ' *   ' . $joinColumnAnnot;
1640 27
                    }
1641
                }
1642
1643 27
                $lines[] = implode(",\n", $joinColumnsLines);
1644 4
                $lines[] = $this->spaces . ' * })';
1645
            }
1646
1647 27
            if (isset($associationMapping['joinTable']) && $associationMapping['joinTable']) {
1648 4
                $joinTable = array();
1649
                $joinTable[] = 'name="' . $associationMapping['joinTable']['name'] . '"';
1650
1651 27
                if (isset($associationMapping['joinTable']['schema'])) {
1652 4
                    $joinTable[] = 'schema="' . $associationMapping['joinTable']['schema'] . '"';
1653
                }
1654
1655 27
                $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'JoinTable(' . implode(', ', $joinTable) . ',';
1656 8
                $lines[] = $this->spaces . ' *   joinColumns={';
1657
1658
                $joinColumnsLines = array();
1659 27
1660
                foreach ($associationMapping['joinTable']['joinColumns'] as $joinColumn) {
1661 27
                    $joinColumnsLines[] = $this->spaces . ' *     ' . $this->generateJoinColumnAnnotation($joinColumn);
1662 1
                }
1663
1664
                $lines[] = implode(",". PHP_EOL, $joinColumnsLines);
1665 27
                $lines[] = $this->spaces . ' *   },';
1666 1
                $lines[] = $this->spaces . ' *   inverseJoinColumns={';
1667
1668
                $inverseJoinColumnsLines = array();
1669 27
1670 1
                foreach ($associationMapping['joinTable']['inverseJoinColumns'] as $joinColumn) {
1671
                    $inverseJoinColumnsLines[] = $this->spaces . ' *     ' . $this->generateJoinColumnAnnotation($joinColumn);
1672
                }
1673 27
1674 4
                $lines[] = implode(",". PHP_EOL, $inverseJoinColumnsLines);
1675
                $lines[] = $this->spaces . ' *   }';
1676
                $lines[] = $this->spaces . ' * )';
1677 27
            }
1678
1679 27
            if (isset($associationMapping['orderBy'])) {
1680 25
                $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'OrderBy({';
1681
1682 25
                foreach ($associationMapping['orderBy'] as $name => $direction) {
1683 25
                    $lines[] = $this->spaces . ' *     "' . $name . '"="' . $direction . '",';
1684
                }
1685
1686 25
                $lines[count($lines) - 1] = substr($lines[count($lines) - 1], 0, strlen($lines[count($lines) - 1]) - 1);
1687 1
                $lines[] = $this->spaces . ' * })';
1688
            }
1689 1
        }
1690 1
1691
        $lines[] = $this->spaces . ' */';
1692
1693 1
        return implode("\n", $lines);
1694 1
    }
1695
1696
    /**
1697 1
     * @param array             $fieldMapping
1698 1
     * @param ClassMetadataInfo $metadata
1699
     *
1700
     * @return string
1701 1
     */
1702
    protected function generateFieldMappingPropertyDocBlock(array $fieldMapping, ClassMetadataInfo $metadata)
1703
    {
1704
        $lines = array();
1705 27
        $lines[] = $this->spaces . '/**';
1706
        $lines[] = $this->spaces . ' * @var ' . $this->getType($fieldMapping['type']);
1707
1708
        if ($this->generateAnnotations) {
1709
            $lines[] = $this->spaces . ' *';
1710 27
1711
            $column = array();
1712 27
            if (isset($fieldMapping['columnName'])) {
1713
                $column[] = 'name="' . $fieldMapping['columnName'] . '"';
1714
            }
1715
1716
            if (isset($fieldMapping['type'])) {
1717
                $column[] = 'type="' . $fieldMapping['type'] . '"';
1718
            }
1719
1720 8
            if (isset($fieldMapping['length'])) {
1721
                $column[] = 'length=' . $fieldMapping['length'];
1722 8
            }
1723 8
1724 8
            if (isset($fieldMapping['precision'])) {
1725
                $column[] = 'precision=' .  $fieldMapping['precision'];
1726 8
            }
1727 8
1728
            if (isset($fieldMapping['scale'])) {
1729 8
                $column[] = 'scale=' . $fieldMapping['scale'];
1730
            }
1731 8
1732
            if (isset($fieldMapping['nullable'])) {
1733
                $column[] = 'nullable=' .  var_export($fieldMapping['nullable'], true);
1734
            }
1735 8
1736 8
            $options = [];
1737
1738
            if (isset($fieldMapping['options']['unsigned']) && $fieldMapping['options']['unsigned']) {
1739 8
                $options[] = '"unsigned"=true';
1740
            }
1741 8
1742
            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...
1743
                $column[] = 'options={'.implode(',', $options).'}';
1744
            }
1745
1746
            if (isset($fieldMapping['columnDefinition'])) {
1747
                $column[] = 'columnDefinition="' . $fieldMapping['columnDefinition'] . '"';
1748
            }
1749
1750 29
            if (isset($fieldMapping['unique'])) {
1751
                $column[] = 'unique=' . var_export($fieldMapping['unique'], true);
1752 29
            }
1753
1754 29
            $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'Column(' . implode(', ', $column) . ')';
1755 29
1756 29
            if (isset($fieldMapping['id']) && $fieldMapping['id']) {
1757
                $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'Id';
1758
1759
                if ($generatorType = $this->getIdGeneratorTypeString($metadata->generatorType)) {
1760 29
                    $lines[] = $this->spaces.' * @' . $this->annotationsPrefix . 'GeneratedValue(strategy="' . $generatorType . '")';
1761
                }
1762
1763
                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...
1764
                    $sequenceGenerator = array();
1765
1766
                    if (isset($metadata->sequenceGeneratorDefinition['sequenceName'])) {
1767
                        $sequenceGenerator[] = 'sequenceName="' . $metadata->sequenceGeneratorDefinition['sequenceName'] . '"';
1768
                    }
1769
1770 1
                    if (isset($metadata->sequenceGeneratorDefinition['allocationSize'])) {
1771
                        $sequenceGenerator[] = 'allocationSize=' . $metadata->sequenceGeneratorDefinition['allocationSize'];
1772 1
                    }
1773 1
1774
                    if (isset($metadata->sequenceGeneratorDefinition['initialValue'])) {
1775
                        $sequenceGenerator[] = 'initialValue=' . $metadata->sequenceGeneratorDefinition['initialValue'];
1776 1
                    }
1777
1778
                    $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'SequenceGenerator(' . implode(', ', $sequenceGenerator) . ')';
1779
                }
1780
            }
1781
1782
            if (isset($fieldMapping['version']) && $fieldMapping['version']) {
1783
                $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'Version';
1784
            }
1785
        }
1786 1
1787
        $lines[] = $this->spaces . ' */';
1788 1
1789 1
        return implode("\n", $lines);
1790
    }
1791
1792 1
    /**
1793
     * @param array $embeddedClass
1794
     *
1795
     * @return string
1796
     */
1797
    protected function generateEmbeddedPropertyDocBlock(array $embeddedClass)
1798
    {
1799
        $lines = array();
1800
        $lines[] = $this->spaces . '/**';
1801
        $lines[] = $this->spaces . ' * @var \\' . ltrim($embeddedClass['class'], '\\');
1802 26
1803
        if ($this->generateAnnotations) {
1804 26
            $lines[] = $this->spaces . ' *';
1805 1
1806
            $embedded = array('class="' . $embeddedClass['class'] . '"');
1807
1808 26
            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...
1809
                $embedded[] = 'columnPrefix=' . var_export($embeddedClass['columnPrefix'], true);
1810
            }
1811
1812
            $lines[] = $this->spaces . ' * @' .
1813
                $this->annotationsPrefix . 'Embedded(' . implode(', ', $embedded) . ')';
1814
        }
1815
1816
        $lines[] = $this->spaces . ' */';
1817
1818 1
        return implode("\n", $lines);
1819
    }
1820 1
1821
    /**
1822 1
     * @param string $code
1823 1
     * @param int    $num
1824 1
     *
1825
     * @return string
1826 1
     */
1827
    protected function prefixCodeWithSpaces($code, $num = 1)
1828
    {
1829
        $lines = explode("\n", $code);
1830 1
1831
        foreach ($lines as $key => $value) {
1832
            if ( ! empty($value)) {
1833
                $lines[$key] = str_repeat($this->spaces, $num) . $lines[$key];
1834
            }
1835
        }
1836
1837
        return implode("\n", $lines);
1838
    }
1839
1840
    /**
1841
     * @param integer $type The inheritance type used by the class and its subclasses.
1842
     *
1843
     * @return string The literal string for the inheritance type.
1844
     *
1845
     * @throws \InvalidArgumentException When the inheritance type does not exist.
1846
     */
1847
    protected function getInheritanceTypeString($type)
1848
    {
1849
        if ( ! isset(static::$inheritanceTypeMap[$type])) {
1850
            throw new \InvalidArgumentException(sprintf('Invalid provided InheritanceType: %s', $type));
1851
        }
1852
1853
        return static::$inheritanceTypeMap[$type];
1854
    }
1855
1856
    /**
1857
     * @param integer $type The policy used for change-tracking for the mapped class.
1858
     *
1859
     * @return string The literal string for the change-tracking type.
1860
     *
1861
     * @throws \InvalidArgumentException When the change-tracking type does not exist.
1862
     */
1863
    protected function getChangeTrackingPolicyString($type)
1864
    {
1865
        if ( ! isset(static::$changeTrackingPolicyMap[$type])) {
1866
            throw new \InvalidArgumentException(sprintf('Invalid provided ChangeTrackingPolicy: %s', $type));
1867
        }
1868
1869
        return static::$changeTrackingPolicyMap[$type];
1870
    }
1871
1872
    /**
1873
     * @param integer $type The generator to use for the mapped class.
1874
     *
1875
     * @return string The literal string for the generator type.
1876
     *
1877
     * @throws \InvalidArgumentException    When the generator type does not exist.
1878
     */
1879
    protected function getIdGeneratorTypeString($type)
1880
    {
1881
        if ( ! isset(static::$generatorStrategyMap[$type])) {
1882
            throw new \InvalidArgumentException(sprintf('Invalid provided IdGeneratorType: %s', $type));
1883
        }
1884
1885
        return static::$generatorStrategyMap[$type];
1886
    }
1887
1888
    /**
1889
     * Exports (nested) option elements.
1890
     *
1891
     * @param array $options
1892
     *
1893
     * @return string
1894
     */
1895
    private function exportTableOptions(array $options)
1896
    {
1897
        $optionsStr = array();
1898
1899
        foreach ($options as $name => $option) {
1900
            if (is_array($option)) {
1901
                $optionsStr[] = '"' . $name . '"={' . $this->exportTableOptions($option) . '}';
1902
            } else {
1903
                $optionsStr[] = '"' . $name . '"="' . (string) $option . '"';
1904
            }
1905
        }
1906
1907
        return implode(',', $optionsStr);
1908
    }
1909
1910
    /**
1911
     * @param ClassMetadataInfo $metadata
1912
     * @param string            $type
1913
     * @param string            $fieldName
1914
     * @param string            $variableType
1915
     * @return string
1916
     */
1917
    private function getMethodReturnType(ClassMetadataInfo $metadata, $type, $fieldName, $variableType)
1918
    {
1919
        if (in_array($type, array('set', 'add'))) {
1920
            return sprintf(': self', $this->getClassName($metadata));
1921
        }
1922
1923
        if ('get' === $type) {
1924
            if (
1925
                $metadata->isSingleValuedAssociation($fieldName) ||
1926
                (!$metadata->hasAssociation($fieldName) && $metadata->isNullable($fieldName))
1927
            ) {
1928
                return null;
1929
            }
1930
1931
            $type = isset($this->typeHintingAlias[$variableType]) ? $this->typeHintingAlias[$variableType] : $variableType;
1932
            return sprintf(': %s', $type);
1933
        }
1934
1935
        if ('remove' === $type) {
1936
            return ': bool';
1937
        }
1938
1939
        return null;
1940
    }
1941
}
1942