EntityGenerator.php 32 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
<?php
/*
 *  $Id$
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * This software consists of voluntary contributions made by many individuals
 * and is licensed under the LGPL. For more information, see
 * <http://www.doctrine-project.org>.
 */

namespace Doctrine\ORM\Tools;

use Doctrine\ORM\Mapping\ClassMetadataInfo,
25 26
    Doctrine\ORM\Mapping\AssociationMapping,
    Doctrine\Common\Util\Inflector;
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55

/**
 * Generic class used to generate PHP5 entity classes from ClassMetadataInfo instances
 *
 *     [php]
 *     $classes = $em->getClassMetadataFactory()->getAllMetadata();
 *
 *     $generator = new \Doctrine\ORM\Tools\EntityGenerator();
 *     $generator->setGenerateAnnotations(true);
 *     $generator->setGenerateStubMethods(true);
 *     $generator->setRegenerateEntityIfExists(false);
 *     $generator->setUpdateEntityIfExists(true);
 *     $generator->generate($classes, '/path/to/generate/entities');
 *
 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
 * @link    www.doctrine-project.org
 * @since   2.0
 * @version $Revision$
 * @author  Benjamin Eberlei <kontakt@beberlei.de>
 * @author  Guilherme Blanco <guilhermeblanco@hotmail.com>
 * @author  Jonathan Wage <jonwage@gmail.com>
 * @author  Roman Borschel <roman@code-factory.org>
 */
class EntityGenerator
{
    /** The extension to use for written php files */
    private $_extension = '.php';

    /** Whether or not the current ClassMetadataInfo instance is new or old */
56
    private $_isNew = true;
57

58 59
    /** If isNew is false then this variable contains instance of ReflectionClass for current entity */
    private $_reflection;
60 61 62 63 64 65 66 67 68 69 70 71 72 73

    /** Number of spaces to use for indention in generated code */
    private $_numSpaces = 4;

    /** The actual spaces to use for indention */
    private $_spaces = '    ';

    /** The class all generated entities should extend */
    private $_classToExtend;

    /** Whether or not to generation annotations */
    private $_generateAnnotations = false;

    /** Whether or not to generated sub methods */
74
    private $_generateEntityStubMethods = false;
75 76 77 78 79 80 81

    /** Whether or not to update the entity class if it exists already */
    private $_updateEntityIfExists = false;

    /** Whether or not to re-generate entity class if it exists already */
    private $_regenerateEntityIfExists = false;

82
    private static $_classTemplate =
83 84 85
'<?php

<namespace><use>
86

87 88 89 90 91 92
<entityAnnotation>
<entityClassName>
{
<entityBody>
}';

93 94
    private static $_getMethodTemplate =
'/**
95 96 97 98
 * <description>
 *
 * @return <variableType>$<variableName>
 */
99 100 101 102 103 104 105
public function <methodName>()
{
    return $this-><fieldName>;
}';

    private static $_setMethodTemplate =
'/**
106 107 108 109
 * <description>
 *
 * @param <variableType>$<variableName>
 */
110 111 112 113 114 115 116
public function <methodName>(<methodTypeHint>$<variableName>)
{
    $this-><fieldName> = $<variableName>;
}';

    private static $_addMethodTemplate =
'/**
117 118 119 120
 * <description>
 *
 * @param <variableType>$<variableName>
 */
121 122 123 124 125 126 127
public function <methodName>(<methodTypeHint>$<variableName>)
{
    $this-><fieldName>[] = $<variableName>;
}';

    private static $_lifecycleCallbackMethodTemplate =
'/**
128 129
 * @<name>
 */
130 131 132 133 134
public function <methodName>()
{
    // Add your code here
}';

135 136 137 138
    /**
     * Generate and write entity classes for the given array of ClassMetadataInfo instances
     *
     * @param array $metadatas
139
     * @param string $outputDirectory 
140 141 142 143 144 145 146 147 148 149 150 151 152
     * @return void
     */
    public function generate(array $metadatas, $outputDirectory)
    {
        foreach ($metadatas as $metadata) {
            $this->writeEntityClass($metadata, $outputDirectory);
        }
    }

    /**
     * Generated and write entity class to disk for the given ClassMetadataInfo instance
     *
     * @param ClassMetadataInfo $metadata
153
     * @param string $outputDirectory 
154 155 156 157 158 159
     * @return void
     */
    public function writeEntityClass(ClassMetadataInfo $metadata, $outputDirectory)
    {
        $path = $outputDirectory . '/' . str_replace('\\', DIRECTORY_SEPARATOR, $metadata->name) . $this->_extension;
        $dir = dirname($path);
160

161 162 163 164 165 166
        if ( ! is_dir($dir)) {
            mkdir($dir, 0777, true);
        }

        $this->_isNew = ! file_exists($path);

167 168
        if ( ! $this->_isNew) {
            require_once $path;
169

170 171 172
            $this->_reflection = new \ReflectionClass($metadata->name);
        }

173 174 175 176 177 178 179 180 181 182 183 184
        // If entity doesn't exist or we're re-generating the entities entirely
        if ($this->_isNew || ( ! $this->_isNew && $this->_regenerateEntityIfExists)) {
            file_put_contents($path, $this->generateEntityClass($metadata));
        // If entity exists and we're allowed to update the entity class
        } else if ( ! $this->_isNew && $this->_updateEntityIfExists) {
            file_put_contents($path, $this->generateUpdatedEntityClass($metadata, $path));
        }
    }

    /**
     * Generate a PHP5 Doctrine 2 entity class from the given ClassMetadataInfo instance
     *
185
     * @param ClassMetadataInfo $metadata 
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
     * @return string $code
     */
    public function generateEntityClass(ClassMetadataInfo $metadata)
    {
        $placeHolders = array(
            '<namespace>',
            '<use>',
            '<entityAnnotation>',
            '<entityClassName>',
            '<entityBody>'
        );

        $replacements = array(
            $this->_generateEntityNamespace($metadata),
            $this->_generateEntityUse($metadata),
201
            $this->_generateEntityDocBlock($metadata),
202 203 204 205
            $this->_generateEntityClassName($metadata),
            $this->_generateEntityBody($metadata)
        );

206
        return str_replace($placeHolders, $replacements, self::$_classTemplate);
207 208 209 210 211
    }

    /**
     * Generate the updated code for the given ClassMetadataInfo and entity at path
     *
212 213
     * @param ClassMetadataInfo $metadata 
     * @param string $path 
214 215 216 217
     * @return string $code;
     */
    public function generateUpdatedEntityClass(ClassMetadataInfo $metadata, $path)
    {
218
        $currentCode = file_get_contents($path);
219 220

        $body = $this->_generateEntityBody($metadata);
221
        $last = strrpos($currentCode, '}');
222 223

        return substr($currentCode, 0, $last) . $body . '}';
224 225 226 227 228
    }

    /**
     * Set the number of spaces the exported class should have
     *
229
     * @param integer $numSpaces 
230 231 232 233 234 235 236 237 238 239 240
     * @return void
     */
    public function setNumSpaces($numSpaces)
    {
        $this->_spaces = str_repeat(' ', $numSpaces);
        $this->_numSpaces = $numSpaces;
    }

    /**
     * Set the extension to use when writing php files to disk
     *
241
     * @param string $extension 
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
     * @return void
     */
    public function setExtension($extension)
    {
        $this->_extension = $extension;
    }

    /**
     * Set the name of the class the generated classes should extend from
     *
     * @return void
     */
    public function setClassToExtend($classToExtend)
    {
        $this->_classToExtend = $classToExtend;
    }

    /**
     * Set whether or not to generate annotations for the entity
     *
262
     * @param bool $bool 
263 264 265 266 267 268 269 270 271 272
     * @return void
     */
    public function setGenerateAnnotations($bool)
    {
        $this->_generateAnnotations = $bool;
    }

    /**
     * Set whether or not to try and update the entity if it already exists
     *
273
     * @param bool $bool 
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
     * @return void
     */
    public function setUpdateEntityIfExists($bool)
    {
        $this->_updateEntityIfExists = $bool;
    }

    /**
     * Set whether or not to regenerate the entity if it exists
     *
     * @param bool $bool
     * @return void
     */
    public function setRegenerateEntityIfExists($bool)
    {
        $this->_regenerateEntityIfExists = $bool;
    }

    /**
     * Set whether or not to generate stub methods for the entity
     *
     * @param bool $bool
     * @return void
     */
    public function setGenerateStubMethods($bool)
    {
300
        $this->_generateEntityStubMethods = $bool;
301 302 303 304 305 306 307 308 309 310 311 312
    }

    private function _generateEntityNamespace(ClassMetadataInfo $metadata)
    {
        if ($this->_hasNamespace($metadata)) {
            return 'namespace ' . $this->_getNamespace($metadata) .';';
        }
    }

    private function _generateEntityUse(ClassMetadataInfo $metadata)
    {
        if ($this->_extendsClass()) {
313
            return "\n\nuse " . $this->_getClassToExtendNamespace() . ";\n";
314 315 316 317 318 319
        }
    }

    private function _generateEntityClassName(ClassMetadataInfo $metadata)
    {
        return 'class ' . $this->_getClassName($metadata) .
320
            ($this->_extendsClass() ? ' extends ' . $this->_getClassToExtendName() : null);
321 322 323 324 325 326
    }

    private function _generateEntityBody(ClassMetadataInfo $metadata)
    {
        $fieldMappingProperties  = $this->_generateEntityFieldMappingProperties($metadata);
        $associationMappingProperties = $this->_generateEntityAssociationMappingProperties($metadata);
327
        $stubMethods = $this->_generateEntityStubMethods ? $this->_generateEntityStubMethods($metadata) : null;
328 329
        $lifecycleCallbackMethods = $this->_generateEntityLifecycleCallbackMethods($metadata);

330 331
        $code = array();

332
        if ($fieldMappingProperties) {
333
            $code[] = $fieldMappingProperties;
334
        }
335

336
        if ($associationMappingProperties) {
337
            $code[] = $associationMappingProperties;
338
        }
339

340
        if ($stubMethods) {
341
            $code[] = $stubMethods;
342
        }
343

344
        if ($lifecycleCallbackMethods) {
345
            $code[] = $lifecycleCallbackMethods;
346
        }
347 348

        return implode("\n", $code);
349 350
    }

351
    private function _hasProperty($property, ClassMetadataInfo $metadata)
352
    {
353
        return ($this->_isNew) ? false : $this->_reflection->hasProperty($property);
354 355
    }

356
    private function _hasMethod($method, ClassMetadataInfo $metadata)
357
    {
358
        return ($this->_isNew) ? false : $this->_reflection->hasMethod($method);
359 360
    }

361
    private function _hasNamespace(ClassMetadataInfo $metadata)
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
    {
        return strpos($metadata->name, '\\') ? true : false;
    }

    private function _extendsClass()
    {
        return $this->_classToExtend ? true : false;
    }

    private function _getClassToExtend()
    {
        return $this->_classToExtend;
    }

    private function _getClassToExtendName()
    {
        $refl = new \ReflectionClass($this->_getClassToExtend());
379

380 381 382 383 384 385
        return $refl->getShortName();
    }

    private function _getClassToExtendNamespace()
    {
        $refl = new \ReflectionClass($this->_getClassToExtend());
386 387

        return $refl->getNamespaceName() ? $refl->getNamespaceName():$refl->getShortName();        
388 389
    }

390
    private function _getClassName(ClassMetadataInfo $metadata)
391
    {
392 393
        return ($pos = strrpos($metadata->name, '\\'))
            ? substr($metadata->name, $pos + 1, strlen($metadata->name)) : $metadata->name;
394 395
    }

396
    private function _getNamespace(ClassMetadataInfo $metadata)
397 398 399 400
    {
        return substr($metadata->name, 0, strrpos($metadata->name, '\\'));
    }

401
    private function _generateEntityDocBlock(ClassMetadataInfo $metadata)
402 403 404
    {
        $lines = array();
        $lines[] = '/**';
405
        $lines[] = ' * '.$metadata->name;
406

407 408 409 410 411 412 413 414 415
        if ($this->_generateAnnotations) {
            $lines[] = ' *';

            $methods = array(
                '_generateTableAnnotation',
                '_generateInheritanceAnnotation',
                '_generateDiscriminatorColumnAnnotation',
                '_generateDiscriminatorMapAnnotation'
            );
416

417 418 419 420
            foreach ($methods as $method) {
                if ($code = $this->$method($metadata)) {
                    $lines[] = ' * ' . $code;
                }
421 422
            }

423 424 425 426 427
            if ($metadata->isMappedSuperclass) {
                $lines[] = ' * @MappedSupperClass';
            } else {
                $lines[] = ' * @Entity';
            }
428

429 430 431
            if ($metadata->customRepositoryClassName) {
                $lines[count($lines) - 1] .= '(repositoryClass="' . $metadata->customRepositoryClassName . '")';
            }
432

433 434 435
            if (isset($metadata->lifecycleCallbacks) && $metadata->lifecycleCallbacks) {
                $lines[] = ' * @HasLifecycleCallbacks';
            }
436 437 438 439 440 441 442 443 444 445
        }

        $lines[] = ' */';

        return implode("\n", $lines);
    }

    private function _generateTableAnnotation($metadata)
    {
        $table = array();
446 447
        if ($metadata->table['name']) {
            $table[] = 'name="' . $metadata->table['name'] . '"';
448
        }
449

450 451
        if (isset($metadata->table['schema'])) {
            $table[] = 'schema="' . $metadata->table['schema'] . '"';
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
        }

        return '@Table(' . implode(', ', $table) . ')';
    }

    private function _generateInheritanceAnnotation($metadata)
    {
        if ($metadata->inheritanceType != ClassMetadataInfo::INHERITANCE_TYPE_NONE) {
            return '@InheritanceType("'.$this->_getInheritanceTypeString($metadata->inheritanceType).'")';
        }
    }

    private function _generateDiscriminatorColumnAnnotation($metadata)
    {
        if ($metadata->inheritanceType != ClassMetadataInfo::INHERITANCE_TYPE_NONE) {
            $discrColumn = $metadata->discriminatorValue;
            $columnDefinition = 'name="' . $discrColumn['name']
                . '", type="' . $discrColumn['type']
                . '", length=' . $discrColumn['length'];

            return '@DiscriminatorColumn(' . $columnDefinition . ')';
        }
    }

    private function _generateDiscriminatorMapAnnotation($metadata)
    {
        if ($metadata->inheritanceType != ClassMetadataInfo::INHERITANCE_TYPE_NONE) {
            $inheritanceClassMap = array();

            foreach ($metadata->discriminatorMap as $type => $class) {
                $inheritanceClassMap[] .= '"' . $type . '" = "' . $class . '"';
            }

            return '@DiscriminatorMap({' . implode(', ', $inheritanceClassMap) . '})';
        }
    }

    private function _generateEntityStubMethods(ClassMetadataInfo $metadata)
    {
        $methods = array();

        foreach ($metadata->fieldMappings as $fieldMapping) {
            if ( ! isset($fieldMapping['id']) || ! $fieldMapping['id']) {
495
                if ($code = $this->_generateEntityStubMethod($metadata, 'set', $fieldMapping['fieldName'], $fieldMapping['type'])) {
496 497 498 499
                    $methods[] = $code;
                }
            }

500
            if ($code = $this->_generateEntityStubMethod($metadata, 'get', $fieldMapping['fieldName'], $fieldMapping['type'])) {
501 502 503 504 505 506
                $methods[] = $code;
            }
        }

        foreach ($metadata->associationMappings as $associationMapping) {
            if ($associationMapping instanceof \Doctrine\ORM\Mapping\OneToOneMapping) {
507
                if ($code = $this->_generateEntityStubMethod($metadata, 'set', $associationMapping->sourceFieldName, $associationMapping->targetEntityName)) {
508 509
                    $methods[] = $code;
                }
510
                if ($code = $this->_generateEntityStubMethod($metadata, 'get', $associationMapping->sourceFieldName, $associationMapping->targetEntityName)) {
511 512 513 514
                    $methods[] = $code;
                }
            } else if ($associationMapping instanceof \Doctrine\ORM\Mapping\OneToManyMapping) {
                if ($associationMapping->isOwningSide) {
515
                    if ($code = $this->_generateEntityStubMethod($metadata, 'set', $associationMapping->sourceFieldName, $associationMapping->targetEntityName)) {
516 517
                        $methods[] = $code;
                    }
518
                    if ($code = $this->_generateEntityStubMethod($metadata, 'get', $associationMapping->sourceFieldName, $associationMapping->targetEntityName)) {
519 520 521
                        $methods[] = $code;
                    }
                } else {
522
                    if ($code = $this->_generateEntityStubMethod($metadata, 'add', $associationMapping->sourceFieldName, $associationMapping->targetEntityName)) {
523 524
                        $methods[] = $code;
                    }
525
                    if ($code = $this->_generateEntityStubMethod($metadata, 'get', $associationMapping->sourceFieldName, 'Doctrine\Common\Collections\Collection')) {
526
                        $methods[] = $code;
527 528 529
                    }
                }
            } else if ($associationMapping instanceof \Doctrine\ORM\Mapping\ManyToManyMapping) {
530
                if ($code = $this->_generateEntityStubMethod($metadata, 'add', $associationMapping->sourceFieldName, $associationMapping->targetEntityName)) {
531 532
                    $methods[] = $code;
                }
533
                if ($code = $this->_generateEntityStubMethod($metadata, 'get', $associationMapping->sourceFieldName, 'Doctrine\Common\Collections\Collection')) {
534 535 536 537 538
                    $methods[] = $code;
                }
            }
        }

539
        return implode("\n\n", $methods);
540 541 542 543 544 545
    }

    private function _generateEntityLifecycleCallbackMethods(ClassMetadataInfo $metadata)
    {
        if (isset($metadata->lifecycleCallbacks) && $metadata->lifecycleCallbacks) {
            $methods = array();
546

547 548 549 550 551 552 553
            foreach ($metadata->lifecycleCallbacks as $name => $callbacks) {
                foreach ($callbacks as $callback) {
                    if ($code = $this->_generateLifecycleCallbackMethod($name, $callback, $metadata)) {
                        $methods[] = $code;
                    }
                }
            }
554

555 556 557 558 559 560 561
            return implode('', $methods);
        }
    }

    private function _generateEntityAssociationMappingProperties(ClassMetadataInfo $metadata)
    {
        $lines = array();
562

563 564 565 566
        foreach ($metadata->associationMappings as $associationMapping) {
            if ($this->_hasProperty($associationMapping->sourceFieldName, $metadata)) {
                continue;
            }
567

568
            $lines[] = $this->_generateAssociationMappingPropertyDocBlock($associationMapping, $metadata);
569 570
            $lines[] = $this->_spaces . 'private $' . $associationMapping->sourceFieldName
                     . ($associationMapping->isManyToMany() ? ' = array()' : null) . ";\n";
571
        }
572

573
        return implode("\n", $lines);
574 575 576 577 578
    }

    private function _generateEntityFieldMappingProperties(ClassMetadataInfo $metadata)
    {
        $lines = array();
579

580 581 582 583
        foreach ($metadata->fieldMappings as $fieldMapping) {
            if ($this->_hasProperty($fieldMapping['fieldName'], $metadata)) {
                continue;
            }
584

585
            $lines[] = $this->_generateFieldMappingPropertyDocBlock($fieldMapping, $metadata);
586 587
            $lines[] = $this->_spaces . 'private $' . $fieldMapping['fieldName']
                     . (isset($fieldMapping['default']) ? ' = ' . var_export($fieldMapping['default'], true) : null) . ";\n";
588
        }
589 590

        return implode("\n", $lines);
591 592
    }

593
    private function _generateEntityStubMethod(ClassMetadataInfo $metadata, $type, $fieldName, $typeHint = null)
594
    {
595
        $methodName = $type . Inflector::classify($fieldName);
596

597 598 599 600
        if ($this->_hasMethod($methodName, $metadata)) {
            return;
        }

601 602
        $var = sprintf('_%sMethodTemplate', $type);
        $template = self::$$var;
603

604
        $variableType = $typeHint ? $typeHint . ' ' : null;
605

606
        $types = \Doctrine\DBAL\Types\Type::getTypesMap();
607
        $methodTypeHint = $typeHint && ! isset($types[$typeHint]) ? '\\' . $typeHint . ' ' : null;
608

609 610 611 612 613 614 615 616
        $replacements = array(
          '<description>'       => ucfirst($type) . ' ' . $fieldName,
          '<methodTypeHint>'    => $methodTypeHint,
          '<variableType>'      => $variableType,
          '<variableName>'      => Inflector::camelize($fieldName),
          '<methodName>'        => $methodName,
          '<fieldName>'         => $fieldName
        );
617

618 619 620 621 622 623 624
        $method = str_replace(
            array_keys($replacements),
            array_values($replacements),
            $template
        );

        return $this->_prefixCodeWithSpaces($method);
625 626 627 628 629 630 631 632
    }

    private function _generateLifecycleCallbackMethod($name, $methodName, $metadata)
    {
        if ($this->_hasMethod($methodName, $metadata)) {
            return;
        }

633 634 635 636
        $replacements = array(
            '<name>'        => $name,
            '<methodName>'  => $methodName,
        );
637

638 639 640 641 642
        $method = str_replace(
            array_keys($replacements),
            array_values($replacements),
            self::$_lifecycleCallbackMethodTemplate
        );
643

644
        return $this->_prefixCodeWithSpaces($method);
645 646 647 648 649
    }

    private function _generateJoinColumnAnnotation(array $joinColumn)
    {
        $joinColumnAnnot = array();
650

651 652 653
        if (isset($joinColumn['name'])) {
            $joinColumnAnnot[] = 'name="' . $joinColumn['name'] . '"';
        }
654

655 656 657
        if (isset($joinColumn['referencedColumnName'])) {
            $joinColumnAnnot[] = 'referencedColumnName="' . $joinColumn['referencedColumnName'] . '"';
        }
658

659 660 661
        if (isset($joinColumn['unique']) && $joinColumn['unique']) {
            $joinColumnAnnot[] = 'unique=' . ($joinColumn['unique'] ? 'true' : 'false');
        }
662

663 664 665
        if (isset($joinColumn['nullable'])) {
            $joinColumnAnnot[] = 'nullable=' . ($joinColumn['nullable'] ? 'true' : 'false');
        }
666

667 668 669
        if (isset($joinColumn['onDelete'])) {
            $joinColumnAnnot[] = 'onDelete=' . ($joinColumn['onDelete'] ? 'true' : 'false');
        }
670

671 672 673
        if (isset($joinColumn['onUpdate'])) {
            $joinColumnAnnot[] = 'onUpdate=' . ($joinColumn['onUpdate'] ? 'true' : 'false');
        }
674

675 676 677
        if (isset($joinColumn['columnDefinition'])) {
            $joinColumnAnnot[] = 'columnDefinition="' . $joinColumn['columnDefinition'] . '"';
        }
678

679 680 681
        return '@JoinColumn(' . implode(', ', $joinColumnAnnot) . ')';
    }

682
    private function _generateAssociationMappingPropertyDocBlock(AssociationMapping $associationMapping, ClassMetadataInfo $metadata)
683 684 685
    {
        $lines = array();
        $lines[] = $this->_spaces . '/**';
686
        $lines[] = $this->_spaces . ' * @var ' . $associationMapping->targetEntityName;
687

688 689
        if ($this->_generateAnnotations) {
            $lines[] = $this->_spaces . ' *';
690

691 692 693
            $e = explode('\\', get_class($associationMapping));
            $type = str_replace('Mapping', '', end($e));
            $typeOptions = array();
694

695 696
            if (isset($associationMapping->targetEntityName)) {
                $typeOptions[] = 'targetEntity="' . $associationMapping->targetEntityName . '"';
697
            }
698

699 700 701
            if (isset($associationMapping->mappedBy)) {
                $typeOptions[] = 'mappedBy="' . $associationMapping->mappedBy . '"';
            }
702

703 704
            if ($associationMapping->hasCascades()) {
                $cascades = array();
705

706 707 708 709 710
                if ($associationMapping->isCascadePersist) $cascades[] = '"persist"';
                if ($associationMapping->isCascadeRemove) $cascades[] = '"remove"';
                if ($associationMapping->isCascadeDetach) $cascades[] = '"detach"';
                if ($associationMapping->isCascadeMerge) $cascades[] = '"merge"';
                if ($associationMapping->isCascadeRefresh) $cascades[] = '"refresh"';
711 712

                $typeOptions[] = 'cascade={' . implode(',', $cascades) . '}';            
713
            }
714

715 716
            if (isset($associationMapping->orphanRemoval) && $associationMapping->orphanRemoval) {
                $typeOptions[] = 'orphanRemoval=' . ($associationMapping->orphanRemoval ? 'true' : 'false');
717 718
            }

719
            $lines[] = $this->_spaces . ' * @' . $type . '(' . implode(', ', $typeOptions) . ')';
720

721 722
            if (isset($associationMapping->joinColumns) && $associationMapping->joinColumns) {
                $lines[] = $this->_spaces . ' * @JoinColumns({';
723

724
                $joinColumnsLines = array();
725

726 727 728 729 730
                foreach ($associationMapping->joinColumns as $joinColumn) {
                    if ($joinColumnAnnot = $this->_generateJoinColumnAnnotation($joinColumn)) {
                        $joinColumnsLines[] = $this->_spaces . ' *   ' . $joinColumnAnnot;
                    }
                }
731

732 733
                $lines[] = implode(",\n", $joinColumnsLines);
                $lines[] = $this->_spaces . ' * })';
734 735
            }

736 737 738
            if (isset($associationMapping->joinTable) && $associationMapping->joinTable) {
                $joinTable = array();
                $joinTable[] = 'name="' . $associationMapping->joinTable['name'] . '"';
739

740 741 742 743 744 745
                if (isset($associationMapping->joinTable['schema'])) {
                    $joinTable[] = 'schema="' . $associationMapping->joinTable['schema'] . '"';
                }

                $lines[] = $this->_spaces . ' * @JoinTable(' . implode(', ', $joinTable) . ',';
                $lines[] = $this->_spaces . ' *   joinColumns={';
746

747 748 749 750
                foreach ($associationMapping->joinTable['joinColumns'] as $joinColumn) {
                    $lines[] = $this->_spaces . ' *     ' . $this->_generateJoinColumnAnnotation($joinColumn);
                }

751
                $lines[] = $this->_spaces . ' *   },';
752
                $lines[] = $this->_spaces . ' *   inverseJoinColumns={';
753

754 755 756 757
                foreach ($associationMapping->joinTable['inverseJoinColumns'] as $joinColumn) {
                    $lines[] = $this->_spaces . ' *     ' . $this->_generateJoinColumnAnnotation($joinColumn);
                }

758
                $lines[] = $this->_spaces . ' *   }';
759 760
                $lines[] = $this->_spaces . ' * )';
            }
761

762 763
            if (isset($associationMapping->orderBy)) {
                $lines[] = $this->_spaces . ' * @OrderBy({';
764

765
                foreach ($associationMapping->orderBy as $name => $direction) {
766
                    $lines[] = $this->_spaces . ' *     "' . $name . '"="' . $direction . '",'; 
767
                }
768

769 770
                $lines[count($lines) - 1] = substr($lines[count($lines) - 1], 0, strlen($lines[count($lines) - 1]) - 1);
                $lines[] = $this->_spaces . ' * })';
771 772 773 774 775 776 777 778
            }
        }

        $lines[] = $this->_spaces . ' */';

        return implode("\n", $lines);
    }

779
    private function _generateFieldMappingPropertyDocBlock(array $fieldMapping, ClassMetadataInfo $metadata)
780 781 782
    {
        $lines = array();
        $lines[] = $this->_spaces . '/**';
783
        $lines[] = $this->_spaces . ' * @var ' . $fieldMapping['type'] . ' $' . $fieldMapping['fieldName'];
784

785 786 787 788 789 790
        if ($this->_generateAnnotations) {
            $lines[] = $this->_spaces . ' *';

            $column = array();
            if (isset($fieldMapping['columnName'])) {
                $column[] = 'name="' . $fieldMapping['columnName'] . '"';
791
            }
792

793 794
            if (isset($fieldMapping['type'])) {
                $column[] = 'type="' . $fieldMapping['type'] . '"';
795
            }
796

797 798 799
            if (isset($fieldMapping['length'])) {
                $column[] = 'length=' . $fieldMapping['length'];
            }
800

801 802 803
            if (isset($fieldMapping['precision'])) {
                $column[] = 'precision=' .  $fieldMapping['precision'];
            }
804

805 806 807
            if (isset($fieldMapping['scale'])) {
                $column[] = 'scale=' . $fieldMapping['scale'];
            }
808

809 810
            if (isset($fieldMapping['nullable'])) {
                $column[] = 'nullable=' .  var_export($fieldMapping['nullable'], true);
811
            }
812

813 814 815
            if (isset($fieldMapping['columnDefinition'])) {
                $column[] = 'columnDefinition="' . $fieldMapping['columnDefinition'] . '"';
            }
816

817 818
            if (isset($fieldMapping['options'])) {
                $options = array();
819

820 821 822 823
                foreach ($fieldMapping['options'] as $key => $value) {
                    $value = var_export($value, true);
                    $value = str_replace("'", '"', $value);
                    $options[] = ! is_numeric($key) ? $key . '=' . $value:$value;
824
                }
825

826 827
                if ($options) {
                    $column[] = 'options={' . implode(', ', $options) . '}';
828
                }
829
            }
830

831 832 833
            if (isset($fieldMapping['unique'])) {
                $column[] = 'unique=' . var_export($fieldMapping['unique'], true);
            }
834

835
            $lines[] = $this->_spaces . ' * @Column(' . implode(', ', $column) . ')';
836

837 838
            if (isset($fieldMapping['id']) && $fieldMapping['id']) {
                $lines[] = $this->_spaces . ' * @Id';
839

840 841 842
                if ($generatorType = $this->_getIdGeneratorTypeString($metadata->generatorType)) {
                    $lines[] = $this->_spaces.' * @GeneratedValue(strategy="' . $generatorType . '")';
                }
843

844 845
                if ($metadata->sequenceGeneratorDefinition) {
                    $sequenceGenerator = array();
846

847 848 849
                    if (isset($metadata->sequenceGeneratorDefinition['sequenceName'])) {
                        $sequenceGenerator[] = 'sequenceName="' . $metadata->sequenceGeneratorDefinition['sequenceName'] . '"';
                    }
850

851 852 853
                    if (isset($metadata->sequenceGeneratorDefinition['allocationSize'])) {
                        $sequenceGenerator[] = 'allocationSize="' . $metadata->sequenceGeneratorDefinition['allocationSize'] . '"';
                    }
854

855 856 857
                    if (isset($metadata->sequenceGeneratorDefinition['initialValue'])) {
                        $sequenceGenerator[] = 'initialValue="' . $metadata->sequenceGeneratorDefinition['initialValue'] . '"';
                    }
858

859
                    $lines[] = $this->_spaces . ' * @SequenceGenerator(' . implode(', ', $sequenceGenerator) . ')';
860
                }
861
            }
862

863 864
            if (isset($fieldMapping['version']) && $fieldMapping['version']) {
                $lines[] = $this->_spaces . ' * @Version';
865 866
            }
        }
867

868 869 870 871 872
        $lines[] = $this->_spaces . ' */';

        return implode("\n", $lines);
    }

873 874 875
    private function _prefixCodeWithSpaces($code, $num = 1)
    {
        $lines = explode("\n", $code);
876

877
        foreach ($lines as $key => $value) {
878
            $lines[$key] = str_repeat($this->_spaces, $num) . $lines[$key];
879
        }
880

881 882 883
        return implode("\n", $lines);
    }

884 885
    private function _getInheritanceTypeString($type)
    {
886
        switch ($type) {
887 888 889 890 891
            case ClassMetadataInfo::INHERITANCE_TYPE_NONE:
                return 'NONE';

            case ClassMetadataInfo::INHERITANCE_TYPE_JOINED:
                return 'JOINED';
892

893 894
            case ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_TABLE:
                return 'SINGLE_TABLE';
895

896 897
            case ClassMetadataInfo::INHERITANCE_TYPE_TABLE_PER_CLASS:
                return 'PER_CLASS';
898 899 900

            default:
                throw new \InvalidArgumentException('Invalid provided InheritanceType: ' . $type);
901 902 903 904 905
        }
    }

    private function _getChangeTrackingPolicyString($policy)
    {
906
        switch ($policy) {
907 908
            case ClassMetadataInfo::CHANGETRACKING_DEFERRED_IMPLICIT:
                return 'DEFERRED_IMPLICIT';
909

910 911
            case ClassMetadataInfo::CHANGETRACKING_DEFERRED_EXPLICIT:
                return 'DEFERRED_EXPLICIT';
912

913 914
            case ClassMetadataInfo::CHANGETRACKING_NOTIFY:
                return 'NOTIFY';
915 916 917

            default:
                throw new \InvalidArgumentException('Invalid provided ChangeTrackingPolicy: ' . $policy);
918 919 920 921 922
        }
    }

    private function _getIdGeneratorTypeString($type)
    {
923
        switch ($type) {
924 925
            case ClassMetadataInfo::GENERATOR_TYPE_AUTO:
                return 'AUTO';
926

927 928
            case ClassMetadataInfo::GENERATOR_TYPE_SEQUENCE:
                return 'SEQUENCE';
929

930 931
            case ClassMetadataInfo::GENERATOR_TYPE_TABLE:
                return 'TABLE';
932

933 934
            case ClassMetadataInfo::GENERATOR_TYPE_IDENTITY:
                return 'IDENTITY';
935

936 937 938
            case ClassMetadataInfo::GENERATOR_TYPE_NONE:
                return 'NONE';

939 940
            default:
                throw new \InvalidArgumentException('Invalid provided IdGeneratorType: ' . $type);
941 942 943
        }
    }
}