vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php line 53

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Doctrine\ORM\Mapping\Driver;
  4. use Doctrine\Deprecations\Deprecation;
  5. use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
  6. use Doctrine\ORM\Mapping\ClassMetadata;
  7. use Doctrine\ORM\Mapping\MappingException;
  8. use Doctrine\Persistence\Mapping\ClassMetadata as PersistenceClassMetadata;
  9. use Doctrine\Persistence\Mapping\Driver\FileDriver;
  10. use InvalidArgumentException;
  11. use LogicException;
  12. use Symfony\Component\Yaml\Yaml;
  13. use function array_map;
  14. use function class_exists;
  15. use function constant;
  16. use function defined;
  17. use function explode;
  18. use function file_get_contents;
  19. use function is_array;
  20. use function is_string;
  21. use function sprintf;
  22. use function strlen;
  23. use function strtoupper;
  24. use function substr;
  25. /**
  26.  * The YamlDriver reads the mapping metadata from yaml schema files.
  27.  *
  28.  * @deprecated 2.7 This class is being removed from the ORM and won't have any replacement
  29.  */
  30. class YamlDriver extends FileDriver
  31. {
  32.     public const DEFAULT_FILE_EXTENSION = '.dcm.yml';
  33.     /**
  34.      * {@inheritDoc}
  35.      */
  36.     public function __construct($locator, $fileExtension = self::DEFAULT_FILE_EXTENSION)
  37.     {
  38.         Deprecation::trigger(
  39.             'doctrine/orm',
  40.             'https://github.com/doctrine/orm/issues/8465',
  41.             'YAML mapping driver is deprecated and will be removed in Doctrine ORM 3.0, please migrate to attribute or XML driver.'
  42.         );
  43.         if (! class_exists(Yaml::class)) {
  44.             throw new LogicException(sprintf(
  45.                 'The YAML metadata driver cannot be enabled because the "symfony/yaml" library'
  46.                 . ' is not installed. Please run "composer require symfony/yaml" or choose a different'
  47.                 . ' metadata driver.'
  48.             ));
  49.         }
  50.         parent::__construct($locator, $fileExtension);
  51.     }
  52.     /**
  53.      * {@inheritDoc}
  54.      *
  55.      * @psalm-param class-string<T> $className
  56.      * @psalm-param ClassMetadata<T> $metadata
  57.      *
  58.      * @template T of object
  59.      */
  60.     public function loadMetadataForClass($className, PersistenceClassMetadata $metadata)
  61.     {
  62.         $element = $this->getElement($className);
  63.         if ($element['type'] === 'entity') {
  64.             if (isset($element['repositoryClass'])) {
  65.                 $metadata->setCustomRepositoryClass($element['repositoryClass']);
  66.             }
  67.             if (isset($element['readOnly']) && $element['readOnly'] === true) {
  68.                 $metadata->markReadOnly();
  69.             }
  70.         } elseif ($element['type'] === 'mappedSuperclass') {
  71.             $metadata->setCustomRepositoryClass(
  72.                 $element['repositoryClass'] ?? null
  73.             );
  74.             $metadata->isMappedSuperclass = true;
  75.         } elseif ($element['type'] === 'embeddable') {
  76.             $metadata->isEmbeddedClass = true;
  77.         } else {
  78.             throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
  79.         }
  80.         // Evaluate root level properties
  81.         $primaryTable = [];
  82.         if (isset($element['table'])) {
  83.             $primaryTable['name'] = $element['table'];
  84.         }
  85.         if (isset($element['schema'])) {
  86.             $primaryTable['schema'] = $element['schema'];
  87.         }
  88.         // Evaluate second level cache
  89.         if (isset($element['cache'])) {
  90.             $metadata->enableCache($this->cacheToArray($element['cache']));
  91.         }
  92.         $metadata->setPrimaryTable($primaryTable);
  93.         // Evaluate named queries
  94.         if (isset($element['namedQueries'])) {
  95.             foreach ($element['namedQueries'] as $name => $queryMapping) {
  96.                 if (is_string($queryMapping)) {
  97.                     $queryMapping = ['query' => $queryMapping];
  98.                 }
  99.                 if (! isset($queryMapping['name'])) {
  100.                     $queryMapping['name'] = $name;
  101.                 }
  102.                 $metadata->addNamedQuery($queryMapping);
  103.             }
  104.         }
  105.         // Evaluate named native queries
  106.         if (isset($element['namedNativeQueries'])) {
  107.             foreach ($element['namedNativeQueries'] as $name => $mappingElement) {
  108.                 if (! isset($mappingElement['name'])) {
  109.                     $mappingElement['name'] = $name;
  110.                 }
  111.                 $metadata->addNamedNativeQuery(
  112.                     [
  113.                         'name'              => $mappingElement['name'],
  114.                         'query'             => $mappingElement['query'] ?? null,
  115.                         'resultClass'       => $mappingElement['resultClass'] ?? null,
  116.                         'resultSetMapping'  => $mappingElement['resultSetMapping'] ?? null,
  117.                     ]
  118.                 );
  119.             }
  120.         }
  121.         // Evaluate sql result set mappings
  122.         if (isset($element['sqlResultSetMappings'])) {
  123.             foreach ($element['sqlResultSetMappings'] as $name => $resultSetMapping) {
  124.                 if (! isset($resultSetMapping['name'])) {
  125.                     $resultSetMapping['name'] = $name;
  126.                 }
  127.                 $entities = [];
  128.                 $columns  = [];
  129.                 if (isset($resultSetMapping['entityResult'])) {
  130.                     foreach ($resultSetMapping['entityResult'] as $entityResultElement) {
  131.                         $entityResult = [
  132.                             'fields'                => [],
  133.                             'entityClass'           => $entityResultElement['entityClass'] ?? null,
  134.                             'discriminatorColumn'   => $entityResultElement['discriminatorColumn'] ?? null,
  135.                         ];
  136.                         if (isset($entityResultElement['fieldResult'])) {
  137.                             foreach ($entityResultElement['fieldResult'] as $fieldResultElement) {
  138.                                 $entityResult['fields'][] = [
  139.                                     'name'      => $fieldResultElement['name'] ?? null,
  140.                                     'column'    => $fieldResultElement['column'] ?? null,
  141.                                 ];
  142.                             }
  143.                         }
  144.                         $entities[] = $entityResult;
  145.                     }
  146.                 }
  147.                 if (isset($resultSetMapping['columnResult'])) {
  148.                     foreach ($resultSetMapping['columnResult'] as $columnResultAnnot) {
  149.                         $columns[] = [
  150.                             'name' => $columnResultAnnot['name'] ?? null,
  151.                         ];
  152.                     }
  153.                 }
  154.                 $metadata->addSqlResultSetMapping(
  155.                     [
  156.                         'name'          => $resultSetMapping['name'],
  157.                         'entities'      => $entities,
  158.                         'columns'       => $columns,
  159.                     ]
  160.                 );
  161.             }
  162.         }
  163.         if (isset($element['inheritanceType'])) {
  164.             $metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . strtoupper($element['inheritanceType'])));
  165.             if ($metadata->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) {
  166.                 // Evaluate discriminatorColumn
  167.                 if (isset($element['discriminatorColumn'])) {
  168.                     $discrColumn = $element['discriminatorColumn'];
  169.                     $metadata->setDiscriminatorColumn(
  170.                         [
  171.                             'name' => isset($discrColumn['name']) ? (string) $discrColumn['name'] : null,
  172.                             'type' => isset($discrColumn['type']) ? (string) $discrColumn['type'] : 'string',
  173.                             'length' => isset($discrColumn['length']) ? (int) $discrColumn['length'] : 255,
  174.                             'columnDefinition' => isset($discrColumn['columnDefinition']) ? (string) $discrColumn['columnDefinition'] : null,
  175.                             'enumType' => isset($discrColumn['enumType']) ? (string) $discrColumn['enumType'] : null,
  176.                         ]
  177.                     );
  178.                 } else {
  179.                     $metadata->setDiscriminatorColumn(['name' => 'dtype', 'type' => 'string', 'length' => 255]);
  180.                 }
  181.                 // Evaluate discriminatorMap
  182.                 if (isset($element['discriminatorMap'])) {
  183.                     $metadata->setDiscriminatorMap($element['discriminatorMap']);
  184.                 }
  185.             }
  186.         }
  187.         // Evaluate changeTrackingPolicy
  188.         if (isset($element['changeTrackingPolicy'])) {
  189.             $metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_'
  190.                 . strtoupper($element['changeTrackingPolicy'])));
  191.         }
  192.         // Evaluate indexes
  193.         if (isset($element['indexes'])) {
  194.             foreach ($element['indexes'] as $name => $indexYml) {
  195.                 if (! isset($indexYml['name'])) {
  196.                     $indexYml['name'] = $name;
  197.                 }
  198.                 $index = [];
  199.                 if (isset($indexYml['columns'])) {
  200.                     if (is_string($indexYml['columns'])) {
  201.                         $index['columns'] = array_map('trim', explode(',', $indexYml['columns']));
  202.                     } else {
  203.                         $index['columns'] = $indexYml['columns'];
  204.                     }
  205.                 }
  206.                 if (isset($indexYml['fields'])) {
  207.                     if (is_string($indexYml['fields'])) {
  208.                         $index['fields'] = array_map('trim', explode(',', $indexYml['fields']));
  209.                     } else {
  210.                         $index['fields'] = $indexYml['fields'];
  211.                     }
  212.                 }
  213.                 if (
  214.                     isset($index['columns'], $index['fields'])
  215.                     || (
  216.                         ! isset($index['columns'])
  217.                         && ! isset($index['fields'])
  218.                     )
  219.                 ) {
  220.                     throw MappingException::invalidIndexConfiguration(
  221.                         $className,
  222.                         $indexYml['name']
  223.                     );
  224.                 }
  225.                 if (isset($indexYml['flags'])) {
  226.                     if (is_string($indexYml['flags'])) {
  227.                         $index['flags'] = array_map('trim', explode(',', $indexYml['flags']));
  228.                     } else {
  229.                         $index['flags'] = $indexYml['flags'];
  230.                     }
  231.                 }
  232.                 if (isset($indexYml['options'])) {
  233.                     $index['options'] = $indexYml['options'];
  234.                 }
  235.                 $metadata->table['indexes'][$indexYml['name']] = $index;
  236.             }
  237.         }
  238.         // Evaluate uniqueConstraints
  239.         if (isset($element['uniqueConstraints'])) {
  240.             foreach ($element['uniqueConstraints'] as $name => $uniqueYml) {
  241.                 if (! isset($uniqueYml['name'])) {
  242.                     $uniqueYml['name'] = $name;
  243.                 }
  244.                 $unique = [];
  245.                 if (isset($uniqueYml['columns'])) {
  246.                     if (is_string($uniqueYml['columns'])) {
  247.                         $unique['columns'] = array_map('trim', explode(',', $uniqueYml['columns']));
  248.                     } else {
  249.                         $unique['columns'] = $uniqueYml['columns'];
  250.                     }
  251.                 }
  252.                 if (isset($uniqueYml['fields'])) {
  253.                     if (is_string($uniqueYml['fields'])) {
  254.                         $unique['fields'] = array_map('trim', explode(',', $uniqueYml['fields']));
  255.                     } else {
  256.                         $unique['fields'] = $uniqueYml['fields'];
  257.                     }
  258.                 }
  259.                 if (
  260.                     isset($unique['columns'], $unique['fields'])
  261.                     || (
  262.                         ! isset($unique['columns'])
  263.                         && ! isset($unique['fields'])
  264.                     )
  265.                 ) {
  266.                     throw MappingException::invalidUniqueConstraintConfiguration(
  267.                         $className,
  268.                         $uniqueYml['name']
  269.                     );
  270.                 }
  271.                 if (isset($uniqueYml['options'])) {
  272.                     $unique['options'] = $uniqueYml['options'];
  273.                 }
  274.                 $metadata->table['uniqueConstraints'][$uniqueYml['name']] = $unique;
  275.             }
  276.         }
  277.         if (isset($element['options'])) {
  278.             $metadata->table['options'] = $element['options'];
  279.         }
  280.         $associationIds = [];
  281.         if (isset($element['id'])) {
  282.             // Evaluate identifier settings
  283.             foreach ($element['id'] as $name => $idElement) {
  284.                 if (isset($idElement['associationKey']) && $idElement['associationKey'] === true) {
  285.                     $associationIds[$name] = true;
  286.                     continue;
  287.                 }
  288.                 $mapping = [
  289.                     'id' => true,
  290.                     'fieldName' => $name,
  291.                 ];
  292.                 if (isset($idElement['type'])) {
  293.                     $mapping['type'] = $idElement['type'];
  294.                 }
  295.                 if (isset($idElement['column'])) {
  296.                     $mapping['columnName'] = $idElement['column'];
  297.                 }
  298.                 if (isset($idElement['length'])) {
  299.                     $mapping['length'] = $idElement['length'];
  300.                 }
  301.                 if (isset($idElement['columnDefinition'])) {
  302.                     $mapping['columnDefinition'] = $idElement['columnDefinition'];
  303.                 }
  304.                 if (isset($idElement['options'])) {
  305.                     $mapping['options'] = $idElement['options'];
  306.                 }
  307.                 $metadata->mapField($mapping);
  308.                 if (isset($idElement['generator'])) {
  309.                     $metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_'
  310.                         . strtoupper($idElement['generator']['strategy'])));
  311.                 }
  312.                 // Check for SequenceGenerator definition
  313.                 if (isset($idElement['sequenceGenerator'])) {
  314.                     $metadata->setSequenceGeneratorDefinition($idElement['sequenceGenerator']);
  315.                 } elseif (isset($idElement['customIdGenerator'])) {
  316.                     $customGenerator = $idElement['customIdGenerator'];
  317.                     $metadata->setCustomGeneratorDefinition(
  318.                         [
  319.                             'class' => (string) $customGenerator['class'],
  320.                         ]
  321.                     );
  322.                 }
  323.             }
  324.         }
  325.         // Evaluate fields
  326.         if (isset($element['fields'])) {
  327.             foreach ($element['fields'] as $name => $fieldMapping) {
  328.                 $mapping = $this->columnToArray($name, $fieldMapping);
  329.                 if (isset($fieldMapping['id'])) {
  330.                     $mapping['id'] = true;
  331.                     if (isset($fieldMapping['generator']['strategy'])) {
  332.                         $metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_'
  333.                             . strtoupper($fieldMapping['generator']['strategy'])));
  334.                     }
  335.                 }
  336.                 if (isset($mapping['version'])) {
  337.                     $metadata->setVersionMapping($mapping);
  338.                     unset($mapping['version']);
  339.                 }
  340.                 $metadata->mapField($mapping);
  341.             }
  342.         }
  343.         if (isset($element['embedded'])) {
  344.             foreach ($element['embedded'] as $name => $embeddedMapping) {
  345.                 $mapping = [
  346.                     'fieldName' => $name,
  347.                     'class' => $embeddedMapping['class'] ?? null,
  348.                     'columnPrefix' => $embeddedMapping['columnPrefix'] ?? null,
  349.                 ];
  350.                 $metadata->mapEmbedded($mapping);
  351.             }
  352.         }
  353.         // Evaluate oneToOne relationships
  354.         if (isset($element['oneToOne'])) {
  355.             foreach ($element['oneToOne'] as $name => $oneToOneElement) {
  356.                 $mapping = [
  357.                     'fieldName' => $name,
  358.                     'targetEntity' => $oneToOneElement['targetEntity'] ?? null,
  359.                 ];
  360.                 if (isset($associationIds[$mapping['fieldName']])) {
  361.                     $mapping['id'] = true;
  362.                 }
  363.                 if (isset($oneToOneElement['fetch'])) {
  364.                     $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToOneElement['fetch']);
  365.                 }
  366.                 if (isset($oneToOneElement['mappedBy'])) {
  367.                     $mapping['mappedBy'] = $oneToOneElement['mappedBy'];
  368.                 } else {
  369.                     if (isset($oneToOneElement['inversedBy'])) {
  370.                         $mapping['inversedBy'] = $oneToOneElement['inversedBy'];
  371.                     }
  372.                     $joinColumns = [];
  373.                     if (isset($oneToOneElement['joinColumn'])) {
  374.                         $joinColumns[] = $this->joinColumnToArray($oneToOneElement['joinColumn']);
  375.                     } elseif (isset($oneToOneElement['joinColumns'])) {
  376.                         foreach ($oneToOneElement['joinColumns'] as $joinColumnName => $joinColumnElement) {
  377.                             if (! isset($joinColumnElement['name'])) {
  378.                                 $joinColumnElement['name'] = $joinColumnName;
  379.                             }
  380.                             $joinColumns[] = $this->joinColumnToArray($joinColumnElement);
  381.                         }
  382.                     }
  383.                     $mapping['joinColumns'] = $joinColumns;
  384.                 }
  385.                 if (isset($oneToOneElement['cascade'])) {
  386.                     $mapping['cascade'] = $oneToOneElement['cascade'];
  387.                 }
  388.                 if (isset($oneToOneElement['orphanRemoval'])) {
  389.                     $mapping['orphanRemoval'] = (bool) $oneToOneElement['orphanRemoval'];
  390.                 }
  391.                 // Evaluate second level cache
  392.                 if (isset($oneToOneElement['cache'])) {
  393.                     $mapping['cache'] = $metadata->getAssociationCacheDefaults($mapping['fieldName'], $this->cacheToArray($oneToOneElement['cache']));
  394.                 }
  395.                 $metadata->mapOneToOne($mapping);
  396.             }
  397.         }
  398.         // Evaluate oneToMany relationships
  399.         if (isset($element['oneToMany'])) {
  400.             foreach ($element['oneToMany'] as $name => $oneToManyElement) {
  401.                 $mapping = [
  402.                     'fieldName' => $name,
  403.                     'targetEntity' => $oneToManyElement['targetEntity'],
  404.                     'mappedBy' => $oneToManyElement['mappedBy'],
  405.                 ];
  406.                 if (isset($oneToManyElement['fetch'])) {
  407.                     $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToManyElement['fetch']);
  408.                 }
  409.                 if (isset($oneToManyElement['cascade'])) {
  410.                     $mapping['cascade'] = $oneToManyElement['cascade'];
  411.                 }
  412.                 if (isset($oneToManyElement['orphanRemoval'])) {
  413.                     $mapping['orphanRemoval'] = (bool) $oneToManyElement['orphanRemoval'];
  414.                 }
  415.                 if (isset($oneToManyElement['orderBy'])) {
  416.                     $mapping['orderBy'] = $oneToManyElement['orderBy'];
  417.                 }
  418.                 if (isset($oneToManyElement['indexBy'])) {
  419.                     $mapping['indexBy'] = $oneToManyElement['indexBy'];
  420.                 }
  421.                 // Evaluate second level cache
  422.                 if (isset($oneToManyElement['cache'])) {
  423.                     $mapping['cache'] = $metadata->getAssociationCacheDefaults($mapping['fieldName'], $this->cacheToArray($oneToManyElement['cache']));
  424.                 }
  425.                 $metadata->mapOneToMany($mapping);
  426.             }
  427.         }
  428.         // Evaluate manyToOne relationships
  429.         if (isset($element['manyToOne'])) {
  430.             foreach ($element['manyToOne'] as $name => $manyToOneElement) {
  431.                 $mapping = [
  432.                     'fieldName' => $name,
  433.                     'targetEntity' => $manyToOneElement['targetEntity'] ?? null,
  434.                 ];
  435.                 if (isset($associationIds[$mapping['fieldName']])) {
  436.                     $mapping['id'] = true;
  437.                 }
  438.                 if (isset($manyToOneElement['fetch'])) {
  439.                     $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToOneElement['fetch']);
  440.                 }
  441.                 if (isset($manyToOneElement['inversedBy'])) {
  442.                     $mapping['inversedBy'] = $manyToOneElement['inversedBy'];
  443.                 }
  444.                 $joinColumns = [];
  445.                 if (isset($manyToOneElement['joinColumn'])) {
  446.                     $joinColumns[] = $this->joinColumnToArray($manyToOneElement['joinColumn']);
  447.                 } elseif (isset($manyToOneElement['joinColumns'])) {
  448.                     foreach ($manyToOneElement['joinColumns'] as $joinColumnName => $joinColumnElement) {
  449.                         if (! isset($joinColumnElement['name'])) {
  450.                             $joinColumnElement['name'] = $joinColumnName;
  451.                         }
  452.                         $joinColumns[] = $this->joinColumnToArray($joinColumnElement);
  453.                     }
  454.                 }
  455.                 $mapping['joinColumns'] = $joinColumns;
  456.                 if (isset($manyToOneElement['cascade'])) {
  457.                     $mapping['cascade'] = $manyToOneElement['cascade'];
  458.                 }
  459.                 // Evaluate second level cache
  460.                 if (isset($manyToOneElement['cache'])) {
  461.                     $mapping['cache'] = $metadata->getAssociationCacheDefaults($mapping['fieldName'], $this->cacheToArray($manyToOneElement['cache']));
  462.                 }
  463.                 $metadata->mapManyToOne($mapping);
  464.             }
  465.         }
  466.         // Evaluate manyToMany relationships
  467.         if (isset($element['manyToMany'])) {
  468.             foreach ($element['manyToMany'] as $name => $manyToManyElement) {
  469.                 $mapping = [
  470.                     'fieldName' => $name,
  471.                     'targetEntity' => $manyToManyElement['targetEntity'],
  472.                 ];
  473.                 if (isset($manyToManyElement['fetch'])) {
  474.                     $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToManyElement['fetch']);
  475.                 }
  476.                 if (isset($manyToManyElement['mappedBy'])) {
  477.                     $mapping['mappedBy'] = $manyToManyElement['mappedBy'];
  478.                 } elseif (isset($manyToManyElement['joinTable'])) {
  479.                     $joinTableElement = $manyToManyElement['joinTable'];
  480.                     $joinTable        = [
  481.                         'name' => $joinTableElement['name'],
  482.                     ];
  483.                     if (isset($joinTableElement['schema'])) {
  484.                         $joinTable['schema'] = $joinTableElement['schema'];
  485.                     }
  486.                     if (isset($joinTableElement['joinColumns'])) {
  487.                         foreach ($joinTableElement['joinColumns'] as $joinColumnName => $joinColumnElement) {
  488.                             if (! isset($joinColumnElement['name'])) {
  489.                                 $joinColumnElement['name'] = $joinColumnName;
  490.                             }
  491.                             $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement);
  492.                         }
  493.                     }
  494.                     if (isset($joinTableElement['inverseJoinColumns'])) {
  495.                         foreach ($joinTableElement['inverseJoinColumns'] as $joinColumnName => $joinColumnElement) {
  496.                             if (! isset($joinColumnElement['name'])) {
  497.                                 $joinColumnElement['name'] = $joinColumnName;
  498.                             }
  499.                             $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumnElement);
  500.                         }
  501.                     }
  502.                     $mapping['joinTable'] = $joinTable;
  503.                 }
  504.                 if (isset($manyToManyElement['inversedBy'])) {
  505.                     $mapping['inversedBy'] = $manyToManyElement['inversedBy'];
  506.                 }
  507.                 if (isset($manyToManyElement['cascade'])) {
  508.                     $mapping['cascade'] = $manyToManyElement['cascade'];
  509.                 }
  510.                 if (isset($manyToManyElement['orderBy'])) {
  511.                     $mapping['orderBy'] = $manyToManyElement['orderBy'];
  512.                 }
  513.                 if (isset($manyToManyElement['indexBy'])) {
  514.                     $mapping['indexBy'] = $manyToManyElement['indexBy'];
  515.                 }
  516.                 if (isset($manyToManyElement['orphanRemoval'])) {
  517.                     $mapping['orphanRemoval'] = (bool) $manyToManyElement['orphanRemoval'];
  518.                 }
  519.                 // Evaluate second level cache
  520.                 if (isset($manyToManyElement['cache'])) {
  521.                     $mapping['cache'] = $metadata->getAssociationCacheDefaults($mapping['fieldName'], $this->cacheToArray($manyToManyElement['cache']));
  522.                 }
  523.                 $metadata->mapManyToMany($mapping);
  524.             }
  525.         }
  526.         // Evaluate associationOverride
  527.         if (isset($element['associationOverride']) && is_array($element['associationOverride'])) {
  528.             foreach ($element['associationOverride'] as $fieldName => $associationOverrideElement) {
  529.                 $override = [];
  530.                 // Check for joinColumn
  531.                 if (isset($associationOverrideElement['joinColumn'])) {
  532.                     $joinColumns = [];
  533.                     foreach ($associationOverrideElement['joinColumn'] as $name => $joinColumnElement) {
  534.                         if (! isset($joinColumnElement['name'])) {
  535.                             $joinColumnElement['name'] = $name;
  536.                         }
  537.                         $joinColumns[] = $this->joinColumnToArray($joinColumnElement);
  538.                     }
  539.                     $override['joinColumns'] = $joinColumns;
  540.                 }
  541.                 // Check for joinTable
  542.                 if (isset($associationOverrideElement['joinTable'])) {
  543.                     $joinTableElement = $associationOverrideElement['joinTable'];
  544.                     $joinTable        =  [
  545.                         'name' => $joinTableElement['name'],
  546.                     ];
  547.                     if (isset($joinTableElement['schema'])) {
  548.                         $joinTable['schema'] = $joinTableElement['schema'];
  549.                     }
  550.                     foreach ($joinTableElement['joinColumns'] as $name => $joinColumnElement) {
  551.                         if (! isset($joinColumnElement['name'])) {
  552.                             $joinColumnElement['name'] = $name;
  553.                         }
  554.                         $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement);
  555.                     }
  556.                     foreach ($joinTableElement['inverseJoinColumns'] as $name => $joinColumnElement) {
  557.                         if (! isset($joinColumnElement['name'])) {
  558.                             $joinColumnElement['name'] = $name;
  559.                         }
  560.                         $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumnElement);
  561.                     }
  562.                     $override['joinTable'] = $joinTable;
  563.                 }
  564.                 // Check for inversedBy
  565.                 if (isset($associationOverrideElement['inversedBy'])) {
  566.                     $override['inversedBy'] = (string) $associationOverrideElement['inversedBy'];
  567.                 }
  568.                 // Check for `fetch`
  569.                 if (isset($associationOverrideElement['fetch'])) {
  570.                     $override['fetch'] = constant(ClassMetadata::class . '::FETCH_' . $associationOverrideElement['fetch']);
  571.                 }
  572.                 $metadata->setAssociationOverride($fieldName, $override);
  573.             }
  574.         }
  575.         // Evaluate associationOverride
  576.         if (isset($element['attributeOverride']) && is_array($element['attributeOverride'])) {
  577.             foreach ($element['attributeOverride'] as $fieldName => $attributeOverrideElement) {
  578.                 $mapping = $this->columnToArray($fieldName, $attributeOverrideElement);
  579.                 $metadata->setAttributeOverride($fieldName, $mapping);
  580.             }
  581.         }
  582.         // Evaluate lifeCycleCallbacks
  583.         if (isset($element['lifecycleCallbacks'])) {
  584.             foreach ($element['lifecycleCallbacks'] as $type => $methods) {
  585.                 foreach ($methods as $method) {
  586.                     $metadata->addLifecycleCallback($method, constant('Doctrine\ORM\Events::' . $type));
  587.                 }
  588.             }
  589.         }
  590.         // Evaluate entityListeners
  591.         if (isset($element['entityListeners'])) {
  592.             foreach ($element['entityListeners'] as $className => $entityListener) {
  593.                 // Evaluate the listener using naming convention.
  594.                 if (empty($entityListener)) {
  595.                     EntityListenerBuilder::bindEntityListener($metadata, $className);
  596.                     continue;
  597.                 }
  598.                 foreach ($entityListener as $eventName => $callbackElement) {
  599.                     foreach ($callbackElement as $methodName) {
  600.                         $metadata->addEntityListener($eventName, $className, $methodName);
  601.                     }
  602.                 }
  603.             }
  604.         }
  605.     }
  606.     /**
  607.      * Constructs a joinColumn mapping array based on the information
  608.      * found in the given join column element.
  609.      *
  610.      * @psalm-param array{
  611.      *                   referencedColumnName?: mixed,
  612.      *                   name?: mixed,
  613.      *                   fieldName?: mixed,
  614.      *                   unique?: mixed,
  615.      *                   nullable?: mixed,
  616.      *                   onDelete?: mixed,
  617.      *                   columnDefinition?: mixed
  618.      *              } $joinColumnElement The array join column element.
  619.      *
  620.      * @return mixed[] The mapping array.
  621.      * @psalm-return array{
  622.      *                   referencedColumnName?: string,
  623.      *                   name?: string,
  624.      *                   fieldName?: string,
  625.      *                   unique?: bool,
  626.      *                   nullable?: bool,
  627.      *                   onDelete?: mixed,
  628.      *                   columnDefinition?: mixed
  629.      *               }
  630.      */
  631.     private function joinColumnToArray(array $joinColumnElement): array
  632.     {
  633.         $joinColumn = [];
  634.         if (isset($joinColumnElement['referencedColumnName'])) {
  635.             $joinColumn['referencedColumnName'] = (string) $joinColumnElement['referencedColumnName'];
  636.         }
  637.         if (isset($joinColumnElement['name'])) {
  638.             $joinColumn['name'] = (string) $joinColumnElement['name'];
  639.         }
  640.         if (isset($joinColumnElement['fieldName'])) {
  641.             $joinColumn['fieldName'] = (string) $joinColumnElement['fieldName'];
  642.         }
  643.         if (isset($joinColumnElement['unique'])) {
  644.             $joinColumn['unique'] = (bool) $joinColumnElement['unique'];
  645.         }
  646.         if (isset($joinColumnElement['nullable'])) {
  647.             $joinColumn['nullable'] = (bool) $joinColumnElement['nullable'];
  648.         }
  649.         if (isset($joinColumnElement['onDelete'])) {
  650.             $joinColumn['onDelete'] = $joinColumnElement['onDelete'];
  651.         }
  652.         if (isset($joinColumnElement['columnDefinition'])) {
  653.             $joinColumn['columnDefinition'] = $joinColumnElement['columnDefinition'];
  654.         }
  655.         return $joinColumn;
  656.     }
  657.     /**
  658.      * Parses the given column as array.
  659.      *
  660.      * @psalm-param array{
  661.      *                   type?: string,
  662.      *                   column?: string,
  663.      *                   precision?: mixed,
  664.      *                   scale?: mixed,
  665.      *                   unique?: mixed,
  666.      *                   options?: mixed,
  667.      *                   nullable?: mixed,
  668.      *                   insertable?: mixed,
  669.      *                   updatable?: mixed,
  670.      *                   generated?: mixed,
  671.      *                   enumType?: class-string,
  672.      *                   version?: mixed,
  673.      *                   columnDefinition?: mixed
  674.      *              }|null $column
  675.      *
  676.      * @return mixed[]
  677.      * @psalm-return array{
  678.      *                   fieldName: string,
  679.      *                   type?: string,
  680.      *                   columnName?: string,
  681.      *                   length?: int,
  682.      *                   precision?: mixed,
  683.      *                   scale?: mixed,
  684.      *                   unique?: bool,
  685.      *                   options?: mixed,
  686.      *                   nullable?: mixed,
  687.      *                   notInsertable?: mixed,
  688.      *                   notUpdatable?: mixed,
  689.      *                   generated?: mixed,
  690.      *                   enumType?: class-string,
  691.      *                   version?: mixed,
  692.      *                   columnDefinition?: mixed
  693.      *               }
  694.      */
  695.     private function columnToArray(string $fieldName, ?array $column): array
  696.     {
  697.         $mapping = ['fieldName' => $fieldName];
  698.         if (isset($column['type'])) {
  699.             $params = explode('(', $column['type']);
  700.             $column['type']  = $params[0];
  701.             $mapping['type'] = $column['type'];
  702.             if (isset($params[1])) {
  703.                 $column['length'] = (int) substr($params[1], 0, strlen($params[1]) - 1);
  704.             }
  705.         }
  706.         if (isset($column['column'])) {
  707.             $mapping['columnName'] = $column['column'];
  708.         }
  709.         if (isset($column['length'])) {
  710.             $mapping['length'] = $column['length'];
  711.         }
  712.         if (isset($column['precision'])) {
  713.             $mapping['precision'] = $column['precision'];
  714.         }
  715.         if (isset($column['scale'])) {
  716.             $mapping['scale'] = $column['scale'];
  717.         }
  718.         if (isset($column['unique'])) {
  719.             $mapping['unique'] = (bool) $column['unique'];
  720.         }
  721.         if (isset($column['options'])) {
  722.             $mapping['options'] = $column['options'];
  723.         }
  724.         if (isset($column['nullable'])) {
  725.             $mapping['nullable'] = $column['nullable'];
  726.         }
  727.         if (isset($column['insertable']) && ! (bool) $column['insertable']) {
  728.             $mapping['notInsertable'] = true;
  729.         }
  730.         if (isset($column['updatable']) && ! (bool) $column['updatable']) {
  731.             $mapping['notUpdatable'] = true;
  732.         }
  733.         if (isset($column['generated'])) {
  734.             $mapping['generated'] = constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATED_' . $column['generated']);
  735.         }
  736.         if (isset($column['version']) && $column['version']) {
  737.             $mapping['version'] = $column['version'];
  738.         }
  739.         if (isset($column['columnDefinition'])) {
  740.             $mapping['columnDefinition'] = $column['columnDefinition'];
  741.         }
  742.         if (isset($column['enumType'])) {
  743.             $mapping['enumType'] = $column['enumType'];
  744.         }
  745.         return $mapping;
  746.     }
  747.     /**
  748.      * Parse / Normalize the cache configuration
  749.      *
  750.      * @param mixed[] $cacheMapping
  751.      * @psalm-param array{usage: string|null, region?: mixed} $cacheMapping
  752.      *
  753.      * @return mixed[]
  754.      * @psalm-return array{usage: int|null, region: string|null}
  755.      */
  756.     private function cacheToArray(array $cacheMapping): array
  757.     {
  758.         $region = isset($cacheMapping['region']) ? (string) $cacheMapping['region'] : null;
  759.         $usage  = isset($cacheMapping['usage']) ? strtoupper($cacheMapping['usage']) : null;
  760.         if ($usage && ! defined('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $usage)) {
  761.             throw new InvalidArgumentException(sprintf('Invalid cache usage "%s"', $usage));
  762.         }
  763.         if ($usage) {
  764.             $usage = (int) constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $usage);
  765.         }
  766.         return [
  767.             'usage'  => $usage,
  768.             'region' => $region,
  769.         ];
  770.     }
  771.     /**
  772.      * {@inheritDoc}
  773.      */
  774.     protected function loadMappingFile($file)
  775.     {
  776.         return Yaml::parse(file_get_contents($file));
  777.     }
  778. }