vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php line 39

Open in your IDE?
  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. namespace Doctrine\ORM\Mapping\Driver;
  20. use Doctrine\Common\Annotations\AnnotationReader;
  21. use Doctrine\Common\Persistence\Mapping\ClassMetadata;
  22. use Doctrine\Common\Persistence\Mapping\Driver\AnnotationDriver as AbstractAnnotationDriver;
  23. use Doctrine\ORM\Events;
  24. use Doctrine\ORM\Mapping;
  25. use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
  26. use Doctrine\ORM\Mapping\MappingException;
  27. /**
  28.  * The AnnotationDriver reads the mapping metadata from docblock annotations.
  29.  *
  30.  * @since 2.0
  31.  * @author Benjamin Eberlei <kontakt@beberlei.de>
  32.  * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
  33.  * @author Jonathan H. Wage <jonwage@gmail.com>
  34.  * @author Roman Borschel <roman@code-factory.org>
  35.  */
  36. class AnnotationDriver extends AbstractAnnotationDriver
  37. {
  38.     /**
  39.      * {@inheritDoc}
  40.      */
  41.     protected $entityAnnotationClasses = [
  42.         Mapping\Entity::class => 1,
  43.         Mapping\MappedSuperclass::class => 2,
  44.     ];
  45.     /**
  46.      * {@inheritDoc}
  47.      */
  48.     public function loadMetadataForClass($classNameClassMetadata $metadata)
  49.     {
  50.         /* @var $metadata \Doctrine\ORM\Mapping\ClassMetadataInfo */
  51.         $class $metadata->getReflectionClass();
  52.         if ( ! $class) {
  53.             // this happens when running annotation driver in combination with
  54.             // static reflection services. This is not the nicest fix
  55.             $class = new \ReflectionClass($metadata->name);
  56.         }
  57.         $classAnnotations $this->reader->getClassAnnotations($class);
  58.         if ($classAnnotations) {
  59.             foreach ($classAnnotations as $key => $annot) {
  60.                 if ( ! is_numeric($key)) {
  61.                     continue;
  62.                 }
  63.                 $classAnnotations[get_class($annot)] = $annot;
  64.             }
  65.         }
  66.         // Evaluate Entity annotation
  67.         if (isset($classAnnotations[Mapping\Entity::class])) {
  68.             $entityAnnot $classAnnotations[Mapping\Entity::class];
  69.             if ($entityAnnot->repositoryClass !== null) {
  70.                 $metadata->setCustomRepositoryClass($entityAnnot->repositoryClass);
  71.             }
  72.             if ($entityAnnot->readOnly) {
  73.                 $metadata->markReadOnly();
  74.             }
  75.         } else if (isset($classAnnotations[Mapping\MappedSuperclass::class])) {
  76.             $mappedSuperclassAnnot $classAnnotations[Mapping\MappedSuperclass::class];
  77.             $metadata->setCustomRepositoryClass($mappedSuperclassAnnot->repositoryClass);
  78.             $metadata->isMappedSuperclass true;
  79.         } else if (isset($classAnnotations[Mapping\Embeddable::class])) {
  80.             $metadata->isEmbeddedClass true;
  81.         } else {
  82.             throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
  83.         }
  84.         // Evaluate Table annotation
  85.         if (isset($classAnnotations[Mapping\Table::class])) {
  86.             $tableAnnot   $classAnnotations[Mapping\Table::class];
  87.             $primaryTable = [
  88.                 'name'   => $tableAnnot->name,
  89.                 'schema' => $tableAnnot->schema
  90.             ];
  91.             if ($tableAnnot->indexes !== null) {
  92.                 foreach ($tableAnnot->indexes as $indexAnnot) {
  93.                     $index = ['columns' => $indexAnnot->columns];
  94.                     if ( ! empty($indexAnnot->flags)) {
  95.                         $index['flags'] = $indexAnnot->flags;
  96.                     }
  97.                     if ( ! empty($indexAnnot->options)) {
  98.                         $index['options'] = $indexAnnot->options;
  99.                     }
  100.                     if ( ! empty($indexAnnot->name)) {
  101.                         $primaryTable['indexes'][$indexAnnot->name] = $index;
  102.                     } else {
  103.                         $primaryTable['indexes'][] = $index;
  104.                     }
  105.                 }
  106.             }
  107.             if ($tableAnnot->uniqueConstraints !== null) {
  108.                 foreach ($tableAnnot->uniqueConstraints as $uniqueConstraintAnnot) {
  109.                     $uniqueConstraint = ['columns' => $uniqueConstraintAnnot->columns];
  110.                     if ( ! empty($uniqueConstraintAnnot->options)) {
  111.                         $uniqueConstraint['options'] = $uniqueConstraintAnnot->options;
  112.                     }
  113.                     if ( ! empty($uniqueConstraintAnnot->name)) {
  114.                         $primaryTable['uniqueConstraints'][$uniqueConstraintAnnot->name] = $uniqueConstraint;
  115.                     } else {
  116.                         $primaryTable['uniqueConstraints'][] = $uniqueConstraint;
  117.                     }
  118.                 }
  119.             }
  120.             if ($tableAnnot->options) {
  121.                 $primaryTable['options'] = $tableAnnot->options;
  122.             }
  123.             $metadata->setPrimaryTable($primaryTable);
  124.         }
  125.         // Evaluate @Cache annotation
  126.         if (isset($classAnnotations[Mapping\Cache::class])) {
  127.             $cacheAnnot $classAnnotations[Mapping\Cache::class];
  128.             $cacheMap   = [
  129.                 'region' => $cacheAnnot->region,
  130.                 'usage'  => constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' $cacheAnnot->usage),
  131.             ];
  132.             $metadata->enableCache($cacheMap);
  133.         }
  134.         // Evaluate NamedNativeQueries annotation
  135.         if (isset($classAnnotations[Mapping\NamedNativeQueries::class])) {
  136.             $namedNativeQueriesAnnot $classAnnotations[Mapping\NamedNativeQueries::class];
  137.             foreach ($namedNativeQueriesAnnot->value as $namedNativeQuery) {
  138.                 $metadata->addNamedNativeQuery(
  139.                     [
  140.                         'name'              => $namedNativeQuery->name,
  141.                         'query'             => $namedNativeQuery->query,
  142.                         'resultClass'       => $namedNativeQuery->resultClass,
  143.                         'resultSetMapping'  => $namedNativeQuery->resultSetMapping,
  144.                     ]
  145.                 );
  146.             }
  147.         }
  148.         // Evaluate SqlResultSetMappings annotation
  149.         if (isset($classAnnotations[Mapping\SqlResultSetMappings::class])) {
  150.             $sqlResultSetMappingsAnnot $classAnnotations[Mapping\SqlResultSetMappings::class];
  151.             foreach ($sqlResultSetMappingsAnnot->value as $resultSetMapping) {
  152.                 $entities = [];
  153.                 $columns  = [];
  154.                 foreach ($resultSetMapping->entities as $entityResultAnnot) {
  155.                     $entityResult = [
  156.                         'fields'                => [],
  157.                         'entityClass'           => $entityResultAnnot->entityClass,
  158.                         'discriminatorColumn'   => $entityResultAnnot->discriminatorColumn,
  159.                     ];
  160.                     foreach ($entityResultAnnot->fields as $fieldResultAnnot) {
  161.                         $entityResult['fields'][] = [
  162.                             'name'      => $fieldResultAnnot->name,
  163.                             'column'    => $fieldResultAnnot->column
  164.                         ];
  165.                     }
  166.                     $entities[] = $entityResult;
  167.                 }
  168.                 foreach ($resultSetMapping->columns as $columnResultAnnot) {
  169.                     $columns[] = [
  170.                         'name' => $columnResultAnnot->name,
  171.                     ];
  172.                 }
  173.                 $metadata->addSqlResultSetMapping(
  174.                     [
  175.                         'name'          => $resultSetMapping->name,
  176.                         'entities'      => $entities,
  177.                         'columns'       => $columns
  178.                     ]
  179.                 );
  180.             }
  181.         }
  182.         // Evaluate NamedQueries annotation
  183.         if (isset($classAnnotations[Mapping\NamedQueries::class])) {
  184.             $namedQueriesAnnot $classAnnotations[Mapping\NamedQueries::class];
  185.             if ( ! is_array($namedQueriesAnnot->value)) {
  186.                 throw new \UnexpectedValueException("@NamedQueries should contain an array of @NamedQuery annotations.");
  187.             }
  188.             foreach ($namedQueriesAnnot->value as $namedQuery) {
  189.                 if ( ! ($namedQuery instanceof Mapping\NamedQuery)) {
  190.                     throw new \UnexpectedValueException("@NamedQueries should contain an array of @NamedQuery annotations.");
  191.                 }
  192.                 $metadata->addNamedQuery(
  193.                     [
  194.                         'name'  => $namedQuery->name,
  195.                         'query' => $namedQuery->query
  196.                     ]
  197.                 );
  198.             }
  199.         }
  200.         // Evaluate InheritanceType annotation
  201.         if (isset($classAnnotations[Mapping\InheritanceType::class])) {
  202.             $inheritanceTypeAnnot $classAnnotations[Mapping\InheritanceType::class];
  203.             $metadata->setInheritanceType(
  204.                 constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' $inheritanceTypeAnnot->value)
  205.             );
  206.             if ($metadata->inheritanceType != Mapping\ClassMetadata::INHERITANCE_TYPE_NONE) {
  207.                 // Evaluate DiscriminatorColumn annotation
  208.                 if (isset($classAnnotations[Mapping\DiscriminatorColumn::class])) {
  209.                     $discrColumnAnnot $classAnnotations[Mapping\DiscriminatorColumn::class];
  210.                     $metadata->setDiscriminatorColumn(
  211.                         [
  212.                             'name'             => $discrColumnAnnot->name,
  213.                             'type'             => $discrColumnAnnot->type ?: 'string',
  214.                             'length'           => $discrColumnAnnot->length ?: 255,
  215.                             'columnDefinition' => $discrColumnAnnot->columnDefinition,
  216.                         ]
  217.                     );
  218.                 } else {
  219.                     $metadata->setDiscriminatorColumn(['name' => 'dtype''type' => 'string''length' => 255]);
  220.                 }
  221.                 // Evaluate DiscriminatorMap annotation
  222.                 if (isset($classAnnotations[Mapping\DiscriminatorMap::class])) {
  223.                     $discrMapAnnot $classAnnotations[Mapping\DiscriminatorMap::class];
  224.                     $metadata->setDiscriminatorMap($discrMapAnnot->value);
  225.                 }
  226.             }
  227.         }
  228.         // Evaluate DoctrineChangeTrackingPolicy annotation
  229.         if (isset($classAnnotations[Mapping\ChangeTrackingPolicy::class])) {
  230.             $changeTrackingAnnot $classAnnotations[Mapping\ChangeTrackingPolicy::class];
  231.             $metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_' $changeTrackingAnnot->value));
  232.         }
  233.         // Evaluate annotations on properties/fields
  234.         /* @var $property \ReflectionProperty */
  235.         foreach ($class->getProperties() as $property) {
  236.             if ($metadata->isMappedSuperclass && ! $property->isPrivate()
  237.                 ||
  238.                 $metadata->isInheritedField($property->name)
  239.                 ||
  240.                 $metadata->isInheritedAssociation($property->name)
  241.                 ||
  242.                 $metadata->isInheritedEmbeddedClass($property->name)) {
  243.                 continue;
  244.             }
  245.             $mapping = [];
  246.             $mapping['fieldName'] = $property->getName();
  247.             // Evaluate @Cache annotation
  248.             if (($cacheAnnot $this->reader->getPropertyAnnotation($propertyMapping\Cache::class)) !== null) {
  249.                 $mapping['cache'] = $metadata->getAssociationCacheDefaults(
  250.                     $mapping['fieldName'],
  251.                     [
  252.                         'usage'  => constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' $cacheAnnot->usage),
  253.                         'region' => $cacheAnnot->region,
  254.                     ]
  255.                 );
  256.             }
  257.             // Check for JoinColumn/JoinColumns annotations
  258.             $joinColumns = [];
  259.             if ($joinColumnAnnot $this->reader->getPropertyAnnotation($propertyMapping\JoinColumn::class)) {
  260.                 $joinColumns[] = $this->joinColumnToArray($joinColumnAnnot);
  261.             } else if ($joinColumnsAnnot $this->reader->getPropertyAnnotation($propertyMapping\JoinColumns::class)) {
  262.                 foreach ($joinColumnsAnnot->value as $joinColumn) {
  263.                     $joinColumns[] = $this->joinColumnToArray($joinColumn);
  264.                 }
  265.             }
  266.             // Field can only be annotated with one of:
  267.             // @Column, @OneToOne, @OneToMany, @ManyToOne, @ManyToMany
  268.             if ($columnAnnot $this->reader->getPropertyAnnotation($propertyMapping\Column::class)) {
  269.                 if ($columnAnnot->type == null) {
  270.                     throw MappingException::propertyTypeIsRequired($className$property->getName());
  271.                 }
  272.                 $mapping $this->columnToArray($property->getName(), $columnAnnot);
  273.                 if ($idAnnot $this->reader->getPropertyAnnotation($propertyMapping\Id::class)) {
  274.                     $mapping['id'] = true;
  275.                 }
  276.                 if ($generatedValueAnnot $this->reader->getPropertyAnnotation($propertyMapping\GeneratedValue::class)) {
  277.                     $metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' $generatedValueAnnot->strategy));
  278.                 }
  279.                 if ($this->reader->getPropertyAnnotation($propertyMapping\Version::class)) {
  280.                     $metadata->setVersionMapping($mapping);
  281.                 }
  282.                 $metadata->mapField($mapping);
  283.                 // Check for SequenceGenerator/TableGenerator definition
  284.                 if ($seqGeneratorAnnot $this->reader->getPropertyAnnotation($propertyMapping\SequenceGenerator::class)) {
  285.                     $metadata->setSequenceGeneratorDefinition(
  286.                         [
  287.                             'sequenceName' => $seqGeneratorAnnot->sequenceName,
  288.                             'allocationSize' => $seqGeneratorAnnot->allocationSize,
  289.                             'initialValue' => $seqGeneratorAnnot->initialValue
  290.                         ]
  291.                     );
  292.                 } else if ($this->reader->getPropertyAnnotation($property'Doctrine\ORM\Mapping\TableGenerator')) {
  293.                     throw MappingException::tableIdGeneratorNotImplemented($className);
  294.                 } else if ($customGeneratorAnnot $this->reader->getPropertyAnnotation($propertyMapping\CustomIdGenerator::class)) {
  295.                     $metadata->setCustomGeneratorDefinition(
  296.                         [
  297.                             'class' => $customGeneratorAnnot->class
  298.                         ]
  299.                     );
  300.                 }
  301.             } else if ($oneToOneAnnot $this->reader->getPropertyAnnotation($propertyMapping\OneToOne::class)) {
  302.                 if ($idAnnot $this->reader->getPropertyAnnotation($propertyMapping\Id::class)) {
  303.                     $mapping['id'] = true;
  304.                 }
  305.                 $mapping['targetEntity'] = $oneToOneAnnot->targetEntity;
  306.                 $mapping['joinColumns'] = $joinColumns;
  307.                 $mapping['mappedBy'] = $oneToOneAnnot->mappedBy;
  308.                 $mapping['inversedBy'] = $oneToOneAnnot->inversedBy;
  309.                 $mapping['cascade'] = $oneToOneAnnot->cascade;
  310.                 $mapping['orphanRemoval'] = $oneToOneAnnot->orphanRemoval;
  311.                 $mapping['fetch'] = $this->getFetchMode($className$oneToOneAnnot->fetch);
  312.                 $metadata->mapOneToOne($mapping);
  313.             } else if ($oneToManyAnnot $this->reader->getPropertyAnnotation($propertyMapping\OneToMany::class)) {
  314.                 $mapping['mappedBy'] = $oneToManyAnnot->mappedBy;
  315.                 $mapping['targetEntity'] = $oneToManyAnnot->targetEntity;
  316.                 $mapping['cascade'] = $oneToManyAnnot->cascade;
  317.                 $mapping['indexBy'] = $oneToManyAnnot->indexBy;
  318.                 $mapping['orphanRemoval'] = $oneToManyAnnot->orphanRemoval;
  319.                 $mapping['fetch'] = $this->getFetchMode($className$oneToManyAnnot->fetch);
  320.                 if ($orderByAnnot $this->reader->getPropertyAnnotation($propertyMapping\OrderBy::class)) {
  321.                     $mapping['orderBy'] = $orderByAnnot->value;
  322.                 }
  323.                 $metadata->mapOneToMany($mapping);
  324.             } else if ($manyToOneAnnot $this->reader->getPropertyAnnotation($propertyMapping\ManyToOne::class)) {
  325.                 if ($idAnnot $this->reader->getPropertyAnnotation($propertyMapping\Id::class)) {
  326.                     $mapping['id'] = true;
  327.                 }
  328.                 $mapping['joinColumns'] = $joinColumns;
  329.                 $mapping['cascade'] = $manyToOneAnnot->cascade;
  330.                 $mapping['inversedBy'] = $manyToOneAnnot->inversedBy;
  331.                 $mapping['targetEntity'] = $manyToOneAnnot->targetEntity;
  332.                 $mapping['fetch'] = $this->getFetchMode($className$manyToOneAnnot->fetch);
  333.                 $metadata->mapManyToOne($mapping);
  334.             } else if ($manyToManyAnnot $this->reader->getPropertyAnnotation($propertyMapping\ManyToMany::class)) {
  335.                 $joinTable = [];
  336.                 if ($joinTableAnnot $this->reader->getPropertyAnnotation($propertyMapping\JoinTable::class)) {
  337.                     $joinTable = [
  338.                         'name' => $joinTableAnnot->name,
  339.                         'schema' => $joinTableAnnot->schema
  340.                     ];
  341.                     foreach ($joinTableAnnot->joinColumns as $joinColumn) {
  342.                         $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumn);
  343.                     }
  344.                     foreach ($joinTableAnnot->inverseJoinColumns as $joinColumn) {
  345.                         $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumn);
  346.                     }
  347.                 }
  348.                 $mapping['joinTable'] = $joinTable;
  349.                 $mapping['targetEntity'] = $manyToManyAnnot->targetEntity;
  350.                 $mapping['mappedBy'] = $manyToManyAnnot->mappedBy;
  351.                 $mapping['inversedBy'] = $manyToManyAnnot->inversedBy;
  352.                 $mapping['cascade'] = $manyToManyAnnot->cascade;
  353.                 $mapping['indexBy'] = $manyToManyAnnot->indexBy;
  354.                 $mapping['orphanRemoval'] = $manyToManyAnnot->orphanRemoval;
  355.                 $mapping['fetch'] = $this->getFetchMode($className$manyToManyAnnot->fetch);
  356.                 if ($orderByAnnot $this->reader->getPropertyAnnotation($propertyMapping\OrderBy::class)) {
  357.                     $mapping['orderBy'] = $orderByAnnot->value;
  358.                 }
  359.                 $metadata->mapManyToMany($mapping);
  360.             } else if ($embeddedAnnot $this->reader->getPropertyAnnotation($propertyMapping\Embedded::class)) {
  361.                 $mapping['class'] = $embeddedAnnot->class;
  362.                 $mapping['columnPrefix'] = $embeddedAnnot->columnPrefix;
  363.                 $metadata->mapEmbedded($mapping);
  364.             }
  365.         }
  366.         // Evaluate AssociationOverrides annotation
  367.         if (isset($classAnnotations[Mapping\AssociationOverrides::class])) {
  368.             $associationOverridesAnnot $classAnnotations[Mapping\AssociationOverrides::class];
  369.             foreach ($associationOverridesAnnot->value as $associationOverride) {
  370.                 $override   = [];
  371.                 $fieldName  $associationOverride->name;
  372.                 // Check for JoinColumn/JoinColumns annotations
  373.                 if ($associationOverride->joinColumns) {
  374.                     $joinColumns = [];
  375.                     foreach ($associationOverride->joinColumns as $joinColumn) {
  376.                         $joinColumns[] = $this->joinColumnToArray($joinColumn);
  377.                     }
  378.                     $override['joinColumns'] = $joinColumns;
  379.                 }
  380.                 // Check for JoinTable annotations
  381.                 if ($associationOverride->joinTable) {
  382.                     $joinTableAnnot $associationOverride->joinTable;
  383.                     $joinTable      = [
  384.                         'name'      => $joinTableAnnot->name,
  385.                         'schema'    => $joinTableAnnot->schema
  386.                     ];
  387.                     foreach ($joinTableAnnot->joinColumns as $joinColumn) {
  388.                         $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumn);
  389.                     }
  390.                     foreach ($joinTableAnnot->inverseJoinColumns as $joinColumn) {
  391.                         $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumn);
  392.                     }
  393.                     $override['joinTable'] = $joinTable;
  394.                 }
  395.                 // Check for inversedBy
  396.                 if ($associationOverride->inversedBy) {
  397.                     $override['inversedBy'] = $associationOverride->inversedBy;
  398.                 }
  399.                 // Check for `fetch`
  400.                 if ($associationOverride->fetch) {
  401.                     $override['fetch'] = constant(Mapping\ClassMetadata::class . '::FETCH_' $associationOverride->fetch);
  402.                 }
  403.                 $metadata->setAssociationOverride($fieldName$override);
  404.             }
  405.         }
  406.         // Evaluate AttributeOverrides annotation
  407.         if (isset($classAnnotations[Mapping\AttributeOverrides::class])) {
  408.             $attributeOverridesAnnot $classAnnotations[Mapping\AttributeOverrides::class];
  409.             foreach ($attributeOverridesAnnot->value as $attributeOverrideAnnot) {
  410.                 $attributeOverride $this->columnToArray($attributeOverrideAnnot->name$attributeOverrideAnnot->column);
  411.                 $metadata->setAttributeOverride($attributeOverrideAnnot->name$attributeOverride);
  412.             }
  413.         }
  414.         // Evaluate EntityListeners annotation
  415.         if (isset($classAnnotations[Mapping\EntityListeners::class])) {
  416.             $entityListenersAnnot $classAnnotations[Mapping\EntityListeners::class];
  417.             foreach ($entityListenersAnnot->value as $item) {
  418.                 $listenerClassName $metadata->fullyQualifiedClassName($item);
  419.                 if ( ! class_exists($listenerClassName)) {
  420.                     throw MappingException::entityListenerClassNotFound($listenerClassName$className);
  421.                 }
  422.                 $hasMapping     false;
  423.                 $listenerClass  = new \ReflectionClass($listenerClassName);
  424.                 /* @var $method \ReflectionMethod */
  425.                 foreach ($listenerClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
  426.                     // find method callbacks.
  427.                     $callbacks  $this->getMethodCallbacks($method);
  428.                     $hasMapping $hasMapping ?: ( ! empty($callbacks));
  429.                     foreach ($callbacks as $value) {
  430.                         $metadata->addEntityListener($value[1], $listenerClassName$value[0]);
  431.                     }
  432.                 }
  433.                 // Evaluate the listener using naming convention.
  434.                 if ( ! $hasMapping ) {
  435.                     EntityListenerBuilder::bindEntityListener($metadata$listenerClassName);
  436.                 }
  437.             }
  438.         }
  439.         // Evaluate @HasLifecycleCallbacks annotation
  440.         if (isset($classAnnotations[Mapping\HasLifecycleCallbacks::class])) {
  441.             /* @var $method \ReflectionMethod */
  442.             foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
  443.                 foreach ($this->getMethodCallbacks($method) as $value) {
  444.                     $metadata->addLifecycleCallback($value[0], $value[1]);
  445.                 }
  446.             }
  447.         }
  448.     }
  449.     /**
  450.      * Attempts to resolve the fetch mode.
  451.      *
  452.      * @param string $className The class name.
  453.      * @param string $fetchMode The fetch mode.
  454.      *
  455.      * @return integer The fetch mode as defined in ClassMetadata.
  456.      *
  457.      * @throws MappingException If the fetch mode is not valid.
  458.      */
  459.     private function getFetchMode($className$fetchMode)
  460.     {
  461.         if ( ! defined('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' $fetchMode)) {
  462.             throw MappingException::invalidFetchMode($className$fetchMode);
  463.         }
  464.         return constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' $fetchMode);
  465.     }
  466.     /**
  467.      * Parses the given method.
  468.      *
  469.      * @param \ReflectionMethod $method
  470.      *
  471.      * @return array
  472.      */
  473.     private function getMethodCallbacks(\ReflectionMethod $method)
  474.     {
  475.         $callbacks   = [];
  476.         $annotations $this->reader->getMethodAnnotations($method);
  477.         foreach ($annotations as $annot) {
  478.             if ($annot instanceof Mapping\PrePersist) {
  479.                 $callbacks[] = [$method->nameEvents::prePersist];
  480.             }
  481.             if ($annot instanceof Mapping\PostPersist) {
  482.                 $callbacks[] = [$method->nameEvents::postPersist];
  483.             }
  484.             if ($annot instanceof Mapping\PreUpdate) {
  485.                 $callbacks[] = [$method->nameEvents::preUpdate];
  486.             }
  487.             if ($annot instanceof Mapping\PostUpdate) {
  488.                 $callbacks[] = [$method->nameEvents::postUpdate];
  489.             }
  490.             if ($annot instanceof Mapping\PreRemove) {
  491.                 $callbacks[] = [$method->nameEvents::preRemove];
  492.             }
  493.             if ($annot instanceof Mapping\PostRemove) {
  494.                 $callbacks[] = [$method->nameEvents::postRemove];
  495.             }
  496.             if ($annot instanceof Mapping\PostLoad) {
  497.                 $callbacks[] = [$method->nameEvents::postLoad];
  498.             }
  499.             if ($annot instanceof Mapping\PreFlush) {
  500.                 $callbacks[] = [$method->nameEvents::preFlush];
  501.             }
  502.         }
  503.         return $callbacks;
  504.     }
  505.     /**
  506.      * Parse the given JoinColumn as array
  507.      *
  508.      * @param Mapping\JoinColumn $joinColumn
  509.      * @return array
  510.      */
  511.     private function joinColumnToArray(Mapping\JoinColumn $joinColumn)
  512.     {
  513.         return [
  514.             'name' => $joinColumn->name,
  515.             'unique' => $joinColumn->unique,
  516.             'nullable' => $joinColumn->nullable,
  517.             'onDelete' => $joinColumn->onDelete,
  518.             'columnDefinition' => $joinColumn->columnDefinition,
  519.             'referencedColumnName' => $joinColumn->referencedColumnName,
  520.         ];
  521.     }
  522.     /**
  523.      * Parse the given Column as array
  524.      *
  525.      * @param string $fieldName
  526.      * @param Mapping\Column $column
  527.      *
  528.      * @return array
  529.      */
  530.     private function columnToArray($fieldNameMapping\Column $column)
  531.     {
  532.         $mapping = [
  533.             'fieldName' => $fieldName,
  534.             'type'      => $column->type,
  535.             'scale'     => $column->scale,
  536.             'length'    => $column->length,
  537.             'unique'    => $column->unique,
  538.             'nullable'  => $column->nullable,
  539.             'precision' => $column->precision
  540.         ];
  541.         if ($column->options) {
  542.             $mapping['options'] = $column->options;
  543.         }
  544.         if (isset($column->name)) {
  545.             $mapping['columnName'] = $column->name;
  546.         }
  547.         if (isset($column->columnDefinition)) {
  548.             $mapping['columnDefinition'] = $column->columnDefinition;
  549.         }
  550.         return $mapping;
  551.     }
  552.     /**
  553.      * Factory method for the Annotation Driver.
  554.      *
  555.      * @param array|string          $paths
  556.      * @param AnnotationReader|null $reader
  557.      *
  558.      * @return AnnotationDriver
  559.      */
  560.     static public function create($paths = [], AnnotationReader $reader null)
  561.     {
  562.         if ($reader == null) {
  563.             $reader = new AnnotationReader();
  564.         }
  565.         return new self($reader$paths);
  566.     }
  567. }