@param EntityManagerInterface $em
@param ClassMetadata[]        $classes

@return ClassMetadata[]
484834
private function getCommitOrder(EntityManagerInterface $em, array $classes)
    {
        $sorter = new TopologicalSorter();

        foreach ($classes as $class) {
            if ( ! $sorter->hasNode($class->name)) {
                $sorter->addNode($class->name, $class);
            }

            // $class before its parents
            foreach ($class->parentClasses as $parentClass) {
                $parentClass     = $em->getClassMetadata($parentClass);
                $parentClassName = $parentClass->getName();

                if ( ! $sorter->hasNode($parentClassName)) {
                    $sorter->addNode($parentClassName, $parentClass);
                }

                $sorter->addDependency($class->name, $parentClassName);
            }

            foreach ($class->associationMappings as $assoc) {
                if ($assoc['isOwningSide']) {
                    /* @var $targetClass ClassMetadata */
                    $targetClass     = $em->getClassMetadata($assoc['targetEntity']);
                    $targetClassName = $targetClass->getName();

                    if ( ! $sorter->hasNode($targetClassName)) {
                        $sorter->addNode($targetClassName, $targetClass);
                    }

                    // add dependency ($targetClass before $class)
                    $sorter->addDependency($targetClassName, $class->name);

                    // parents of $targetClass before $class, too
                    foreach ($targetClass->parentClasses as $parentClass) {
                        $parentClass     = $em->getClassMetadata($parentClass);
                        $parentClassName = $parentClass->getName();

                        if ( ! $sorter->hasNode($parentClassName)) {
                            $sorter->addNode($parentClassName, $parentClass);
                        }

                        $sorter->addDependency($parentClassName, $class->name);
                    }
                }
            }
        }

        return array_reverse($sorter->sort());
    }
195714
public static function getScheduledAClassContentNotForDeletions(EntityManager $em, $with_revision = false)
    {
        return array_merge(self::getScheduledAClassContentInsertions($em, $with_revision), self::getScheduledAClassContentUpdates($em, $with_revision));
    }
595199
public function registerEntityClassesMetadataDriver(Array $classes = array(), $namespace = 'Psc', \Doctrine\Common\Annotations\Reader $reader = NULL) {
    if (!isset($this->entityClassesMetadataDriver)) {
      if (!isset($reader)) {
        $reader = $this->createAnnotationReader();
      }
      $this->entityClassesMetadataDriver = new \Psc\Doctrine\MetadataDriver($reader, NULL, $classes);
      $this->registerMetadataDriver($this->entityClassesMetadataDriver, $namespace);
    }
    
    return $this;
  }
741969
protected function registerManaged(ClassMetadata $class, $entity, array $data)
    {
        if ($class->isIdentifierComposite) {
            $id = array();

            foreach ($class->identifier as $fieldName) {
                $id[$fieldName] = isset($class->associationMappings[$fieldName])
                    ? $data[$class->associationMappings[$fieldName]['joinColumns'][0]['name']]
                    : $data[$fieldName];
            }
        } else {
            $fieldName = $class->identifier[0];
            $id        = array(
                $fieldName => isset($class->associationMappings[$fieldName])
                    ? $data[$class->associationMappings[$fieldName]['joinColumns'][0]['name']]
                    : $data[$fieldName]
            );
        }

        $this->_em->getUnitOfWork()->registerManaged($entity, $id, $data);
    }
720584
public function getAllowedModules(array $entityClassNames = [])
    {
        $moduleOptionsManager = $this->getModuleOptionsPluginManager();
        $allowedModules = [];
        foreach ($entityClassNames as $entityClassName) {
            if ($moduleOptionsManager->hasModuleNameByClassName($entityClassName)) {
                $moduleName = $moduleOptionsManager->getModuleNameByClassName($entityClassName);
                $allowedModules[$moduleName] = $moduleName;
            }
        }

        return  $allowedModules;
    }
532812
public function configure(EntityManagerInterface $em)
    {
        $platform = $em->getConnection()->getDatabasePlatform();

        foreach ($this->typeClasses as $fqcn) {
            $name = constant("${fqcn}::NAME");

            if (Type::hasType($name)) {
                continue;
            }

            Type::addType($name, $fqcn);

            // Register with platform
            $platform->registerDoctrineTypeMapping(sprintf('db_%s', $name), $name);
        }
    }
494929
public static function getTypeOfColumn($columnName, ClassMetadata $class, EntityManagerInterface $em)
    {
        if (isset($class->fieldNames[$columnName])) {
            $fieldName = $class->fieldNames[$columnName];
            $property  = $class->getProperty($fieldName);

            switch (true) {
                case $property instanceof FieldMetadata:
                    return $property->getType();

                // Optimization: Do not loop through all properties later since we can recognize to-one owning scenario
                case $property instanceof ToOneAssociationMetadata:
                    // We know this is the owning side of a to-one because we found columns in the class (join columns)
                    foreach ($property->getJoinColumns() as $joinColumn) {
                        if ($joinColumn->getColumnName() !== $columnName) {
                            continue;
                        }

                        $targetClass = $em->getClassMetadata($property->getTargetEntity());

                        return self::getTypeOfColumn($joinColumn->getReferencedColumnName(), $targetClass, $em);
                    }

                    break;
            }
        }

        // iterate over association mappings
        foreach ($class->getDeclaredPropertiesIterator() as $association) {
            if (! ($association instanceof AssociationMetadata)) {
                continue;
            }

            // resolve join columns over to-one or to-many
            $targetClass = $em->getClassMetadata($association->getTargetEntity());

            if (! $association->isOwningSide()) {
                $association = $targetClass->getProperty($association->getMappedBy());
                $targetClass = $em->getClassMetadata($association->getTargetEntity());
            }

            $joinColumns = $association instanceof ManyToManyAssociationMetadata
                ? $association->getJoinTable()->getInverseJoinColumns()
                : $association->getJoinColumns();

            foreach ($joinColumns as $joinColumn) {
                if ($joinColumn->getColumnName() !== $columnName) {
                    continue;
                }

                return self::getTypeOfColumn($joinColumn->getReferencedColumnName(), $targetClass, $em);
            }
        }

        throw new RuntimeException(sprintf(
            'Could not resolve type of column "%s" of class "%s"',
            $columnName,
            $class->getClassName()
        ));
    }
450121
public function getSchemaFromMetadata(array $classes)
    {
        // Reminder for processed classes, used for hierarchies
        $processedClasses     = [];
        $eventManager         = $this->em->getEventManager();
        $schemaManager        = $this->em->getConnection()->getSchemaManager();
        $metadataSchemaConfig = $schemaManager->createSchemaConfig();

        $metadataSchemaConfig->setExplicitForeignKeyIndexes(false);
        $schema = new Schema([], [], $metadataSchemaConfig);

        $addedFks       = [];
        $blacklistedFks = [];

        foreach ($classes as $class) {
            /** @var ClassMetadata $class */
            if ($this->processingNotRequired($class, $processedClasses)) {
                continue;
            }

            $table = $schema->createTable($class->table->getQuotedQualifiedName($this->platform));

            switch ($class->inheritanceType) {
                case InheritanceType::SINGLE_TABLE:
                    $this->gatherColumns($class, $table);
                    $this->gatherRelationsSql($class, $table, $schema, $addedFks, $blacklistedFks);

                    // Add the discriminator column
                    $this->addDiscriminatorColumnDefinition($class, $table);

                    // Aggregate all the information from all classes in the hierarchy
                    $parentClass = $class;

                    while (($parentClass = $parentClass->getParent()) !== null) {
                        // Parent class information is already contained in this class
                        $processedClasses[$parentClass->getClassName()] = true;
                    }

                    foreach ($class->getSubClasses() as $subClassName) {
                        $subClass = $this->em->getClassMetadata($subClassName);

                        $this->gatherColumns($subClass, $table);
                        $this->gatherRelationsSql($subClass, $table, $schema, $addedFks, $blacklistedFks);

                        $processedClasses[$subClassName] = true;
                    }

                    break;

                case InheritanceType::JOINED:
                    // Add all non-inherited fields as columns
                    $pkColumns = [];

                    foreach ($class->getDeclaredPropertiesIterator() as $fieldName => $property) {
                        if (! ($property instanceof FieldMetadata)) {
                            continue;
                        }

                        if (! $class->isInheritedProperty($fieldName)) {
                            $columnName = $this->platform->quoteIdentifier($property->getColumnName());

                            $this->gatherColumn($class, $property, $table);

                            if ($class->isIdentifier($fieldName)) {
                                $pkColumns[] = $columnName;
                            }
                        }
                    }

                    $this->gatherRelationsSql($class, $table, $schema, $addedFks, $blacklistedFks);

                    // Add the discriminator column only to the root table
                    if ($class->isRootEntity()) {
                        $this->addDiscriminatorColumnDefinition($class, $table);
                    } else {
                        // Add an ID FK column to child tables
                        $inheritedKeyColumns = [];

                        foreach ($class->identifier as $identifierField) {
                            $idProperty = $class->getProperty($identifierField);

                            if ($class->isInheritedProperty($identifierField)) {
                                $column     = $this->gatherColumn($class, $idProperty, $table);
                                $columnName = $column->getQuotedName($this->platform);

                                // TODO: This seems rather hackish, can we optimize it?
                                $column->setAutoincrement(false);

                                $pkColumns[]           = $columnName;
                                $inheritedKeyColumns[] = $columnName;
                            }
                        }

                        if (! empty($inheritedKeyColumns)) {
                            // Add a FK constraint on the ID column
                            $rootClass = $this->em->getClassMetadata($class->getRootClassName());

                            $table->addForeignKeyConstraint(
                                $rootClass->table->getQuotedQualifiedName($this->platform),
                                $inheritedKeyColumns,
                                $inheritedKeyColumns,
                                ['onDelete' => 'CASCADE']
                            );
                        }
                    }

                    $table->setPrimaryKey($pkColumns);

                    break;

                case InheritanceType::TABLE_PER_CLASS:
                    throw NotSupported::create();

                default:
                    $this->gatherColumns($class, $table);
                    $this->gatherRelationsSql($class, $table, $schema, $addedFks, $blacklistedFks);

                    break;
            }

            $pkColumns = [];

            foreach ($class->identifier as $identifierField) {
                $property = $class->getProperty($identifierField);

                if ($property instanceof FieldMetadata) {
                    $pkColumns[] = $this->platform->quoteIdentifier($property->getColumnName());

                    continue;
                }

                if ($property instanceof ToOneAssociationMetadata) {
                    foreach ($property->getJoinColumns() as $joinColumn) {
                        $pkColumns[] = $this->platform->quoteIdentifier($joinColumn->getColumnName());
                    }
                }
            }

            if (! $table->hasIndex('primary')) {
                $table->setPrimaryKey($pkColumns);
            }

            // there can be unique indexes automatically created for join column
            // if join column is also primary key we should keep only primary key on this column
            // so, remove indexes overruled by primary key
            $primaryKey = $table->getIndex('primary');

            foreach ($table->getIndexes() as $idxKey => $existingIndex) {
                if ($primaryKey->overrules($existingIndex)) {
                    $table->dropIndex($idxKey);
                }
            }

            if ($class->table->getIndexes()) {
                foreach ($class->table->getIndexes() as $indexName => $indexData) {
                    $indexName = is_numeric($indexName) ? null : $indexName;
                    $index     = new Index($indexName, $indexData['columns'], $indexData['unique'], $indexData['flags'], $indexData['options']);

                    foreach ($table->getIndexes() as $tableIndexName => $tableIndex) {
                        if ($tableIndex->isFullfilledBy($index)) {
                            $table->dropIndex($tableIndexName);
                            break;
                        }
                    }

                    if ($indexData['unique']) {
                        $table->addUniqueIndex($indexData['columns'], $indexName, $indexData['options']);
                    } else {
                        $table->addIndex($indexData['columns'], $indexName, $indexData['flags'], $indexData['options']);
                    }
                }
            }

            if ($class->table->getUniqueConstraints()) {
                foreach ($class->table->getUniqueConstraints() as $indexName => $indexData) {
                    $indexName = is_numeric($indexName) ? null : $indexName;
                    $uniqIndex = new Index($indexName, $indexData['columns'], true, false, $indexData['flags'], $indexData['options']);

                    foreach ($table->getIndexes() as $tableIndexName => $tableIndex) {
                        if ($tableIndex->isFullfilledBy($uniqIndex)) {
                            $table->dropIndex($tableIndexName);
                            break;
                        }
                    }

                    $table->addUniqueConstraint($indexData['columns'], $indexName, $indexData['flags'], $indexData['options']);
                }
            }

            if ($class->table->getOptions()) {
                foreach ($class->table->getOptions() as $key => $val) {
                    $table->addOption($key, $val);
                }
            }

            $processedClasses[$class->getClassName()] = true;

            foreach ($class->getDeclaredPropertiesIterator() as $property) {
                if (! $property instanceof FieldMetadata
                    || ! $property->hasValueGenerator()
                    || $property->getValueGenerator()->getType() !== GeneratorType::SEQUENCE
                    || $class->getClassName() !== $class->getRootClassName()) {
                    continue;
                }

                $quotedName = $this->platform->quoteIdentifier($property->getValueGenerator()->getDefinition()['sequenceName']);

                if (! $schema->hasSequence($quotedName)) {
                    $schema->createSequence($quotedName, $property->getValueGenerator()->getDefinition()['allocationSize']);
                }
            }

            if ($eventManager->hasListeners(ToolEvents::postGenerateSchemaTable)) {
                $eventManager->dispatchEvent(
                    ToolEvents::postGenerateSchemaTable,
                    new GenerateSchemaTableEventArgs($class, $schema, $table)
                );
            }
        }

        if (! $this->platform->supportsSchemas() && ! $this->platform->canEmulateSchemas()) {
            $schema->visit(new RemoveNamespacedAssets());
        }

        if ($eventManager->hasListeners(ToolEvents::postGenerateSchema)) {
            $eventManager->dispatchEvent(
                ToolEvents::postGenerateSchema,
                new GenerateSchemaEventArgs($this->em, $schema)
            );
        }

        return $schema;
    }
29525
protected function processMetadata(MetadatableInterface $entity, EntityManager $entityManager)
    {
        if (null === $entity->getMetadatas()) {
            return;
        }

        foreach ($entity->getMetadatas() as $metadata) {
            if ($metadata instanceof Metadata) {
                $metadata
                    ->setHash($this->getMetadatableManager()->generateHash($entity))
                    ->setObjectClassName($this->getMetadatableManager()->getObjectClassName($entity))
                    ->setObjectId($this->getMetadatableManager()->getObjectId($entity))
                    ->setObject($entity)
                ;
                $entityManager->persist($metadata);
            }
        }
    }
708849
private function resolveManyMigrations(array $migrationClasses) : array
    {
        $migrations = [];

        foreach ($migrationClasses as $migrationClass) {
            $migrations[] = $this->migrationResolver->resolve($migrationClass);
        }

        return $migrations;
    }
716578
protected function destroyProxyClasses(EntityManagerInterface $em)
    {
        $config = $em->getConfiguration();
        $proxyGenerator = new ProxyGenerator($config->getProxyDir(), $config->getProxyNamespace());

        $classes = $em->getMetadataFactory()->getAllMetadata();
        foreach ($classes as $class) {
            // We have to do this check because we include core entities in this list because without it packages that extend
            // the core will complain.
            if (strpos($class->getName(), 'Concrete\Core\Entity') === 0) {
                continue;
            }
            $proxyFileName = $proxyGenerator->getProxyFileName($class->getName(), $config->getProxyDir());
            if (file_exists($proxyFileName)) {
                @unlink($proxyFileName);
            }
        }
    }
130423
private function updateCompressedHubProperty(EntityManager $em, $entity)
    {
        $entityClass = get_class($entity);
        $hash = spl_object_hash($entity);
        $classMetadata = $em->getClassMetadata($entityClass);

        $pathHub = MetadataLayer::PATH_HUB;
        $pathMaskGrouped = MetadataLayer::PATH_MASK_BY_HUB;

        $maskListGrouped = !empty($classMetadata->$pathMaskGrouped) ? $classMetadata->$pathMaskGrouped : [];
        $hubList = !empty($classMetadata->$pathHub) ? $classMetadata->$pathHub : [];

        $is_updated = false;
        foreach ($hubList as $hubData) {
            /** @var \ReflectionProperty $hubReflection */
            $hubReflection = $hubData['reflection'];

            $valueList = [];
            if (!isset($maskListGrouped[$hubReflection->getName()])) {
                continue;
            }

            foreach ($maskListGrouped[$hubReflection->getName()] as $maskData) {
                /** @var \ReflectionProperty $maskReflection */
                $maskReflection = $maskData['reflection'];
                $value = $maskReflection->getValue($entity);
                if (isset($this->originalData[$entityClass][$hash][$maskReflection->getName()])) {
                    if ($this->originalData[$entityClass][$hash][$maskReflection->getName()] == $value) {
                        // nothing was changed, we can skip it
                        continue;
                    }
                }
                if (!$value) {
                    $value = 0;
                }
                $valueList[$maskReflection->getName()] = $value;
            }

            if (empty($valueList)) {
                continue;
            }

            $oldHubValue = $hubReflection->getValue($entity);
            if (!$oldHubValue) {
                $oldHubValue = 0;
            }
            $newHubValue = $this->engine->getPackedValue(
                $oldHubValue,
                $maskListGrouped[$hubReflection->getName()],
                $valueList
            );
            if ($oldHubValue !== $newHubValue) {
                $hubReflection->setValue($entity, $newHubValue);
                $is_updated = true;
            }
        }

        return $is_updated;
    }
106824
public static function getScheduledEntityInsertionsByClassname(EntityManager $em, $classnames)
    {
        $entities = array();
        $classnames = (array) $classnames;

        foreach ($em->getUnitOfWork()->getScheduledEntityInsertions() as $entity) {
            if (true === in_array(ClassUtils::getRealClass($entity), $classnames)) {
                $entities[] = $entity;
            }
        }

        return $entities;
    }
291827
private function getGeneratorTablesFor(ClassMetadata $class)
    {
        $tables = [];

        foreach ($class->getGeneratedProperties() as $mapping) {
            if ($mapping->generator instanceof IncrementGenerator) {
                $table = $mapping->generator->getTable();

                if (!isset($tables[$table])) {
                    $tables[$table] = $mapping->generator->getTableDefinition();
                }
            }
        }

        return $tables;
    }
921207
public function generate(EntityManager $em, $entity)
    {
        $class      = $em->getClassMetadata(get_class($entity));
        $idFields   = $class->getIdentifierFieldNames();
        $identifier = array();

        foreach ($idFields as $idField) {
            $value = $class->getFieldValue($entity, $idField);

            if ( ! isset($value)) {
                throw ORMException::entityMissingAssignedIdForField($entity, $idField);
            }

            if (isset($class->associationMappings[$idField])) {
                // NOTE: Single Columns as associated identifiers only allowed - this constraint it is enforced.
                $value = $em->getUnitOfWork()->getSingleIdentifierValue($value);
            }

            $identifier[$idField] = $value;
        }

        return $identifier;
    }
1136374
protected function eagerLoadRelations(array $entities)
    {
        if (empty($entities)) {
            return;
        }

        if ($this->class === null) {
            throw new LogicException('A class must be specified for Eager Loading using the `asClass` method.');
        }

        foreach ($this->with as $method) {
            $relation = $this->getRelation($entities[0], $method);
            $relation->addEagerConstraints($entities);
            $relationEntities = $relation->getEager();
            /** @var Model $entity */
            foreach ($entities as $entity) {
                $id = $entity->getId();
                $entity->setRelationEntities($method, isset($relationEntities[$id]) ? $relationEntities[$id] : null);
            }
        }
    }
228157
public function loadClassMetadata(LoadClassMetadataEventArgs $args)
    {
        $cm = $args->getClassMetadata();

        if (isset($this->classes[$cm->name])) {
            $mapping = [
                'targetEntity'  => $this->classes[$cm->name],
                'fieldName'     => 'data',
                'mappedBy'      => 'entity',
                'cascade'       => ['persist', 'remove'],
                'orphanRemoval' => true,
            ];

            $cm->mapOneToMany($mapping);
        } elseif (in_array($cm->name, $this->classes)) {
            $mapping = [
                'targetEntity' => array_search($cm->name, $this->classes),
                'fieldName'    => 'entity',
                'inversedBy'   => 'data',
            ];

            $cm->mapManyToOne($mapping);

            $cm->table['uniqueConstraints']['eav_data_idx'] = [
                'columns' => ['entity_id', 'key'],
            ];
        }
    }