/** * Gets a table name for many-to-many relation * * @param string $activityTableName Activity entity table name. It is owning side of the association. * @param string $targetTableName Target entity table name. * * @return string */ public function getAssociationTableName($activityTableName, $targetTableName) { $sourceClassName = $this->extendExtension->getEntityClassByTableName($activityTableName); $targetClassName = $this->extendExtension->getEntityClassByTableName($targetTableName); $associationName = ExtendHelper::buildAssociationName($targetClassName, ActivityScope::ASSOCIATION_KIND); return $this->nameGenerator->generateManyToManyJoinTableName($sourceClassName, $associationName, $targetClassName); }
/** * @param LoggerInterface $logger * @param bool $dryRun */ protected function runActivityLists(LoggerInterface $logger, $dryRun = false) { // @todo: this workaround should be removed in BAP-9156 $this->configManager->clear(); $targetEntities = $this->provider->getTargetEntityClasses(false); $toSchema = clone $this->schema; $hasSchemaChanges = false; foreach ($targetEntities as $targetEntity) { $associationName = ExtendHelper::buildAssociationName($targetEntity, ActivityListEntityConfigDumperExtension::ASSOCIATION_KIND); $relationTableName = $this->nameGenerator->generateManyToManyJoinTableName(ActivityListEntityConfigDumperExtension::ENTITY_CLASS, $associationName, $targetEntity); if (!$toSchema->hasTable($relationTableName)) { $hasSchemaChanges = true; $this->activityListExtension->addActivityListAssociation($toSchema, $this->metadataHelper->getTableNameByEntityClass($targetEntity)); } } if ($hasSchemaChanges) { $comparator = new Comparator(); $platform = $this->connection->getDatabasePlatform(); $schemaDiff = $comparator->compare($this->schema, $toSchema); $queries = $schemaDiff->toSql($platform); foreach ($queries as $query) { $this->logQuery($logger, $query); if (!$dryRun) { $this->connection->executeQuery($query); } } } }
/** * {@inheritdoc} */ public function up(Schema $schema, QueryBag $queries) { $relationTableName = $this->nameGenerator->generateManyToManyJoinTableName('Oro\\Bundle\\EmailBundle\\Entity\\Email', ExtendHelper::buildAssociationName('OroCRM\\Bundle\\SalesBundle\\Entity\\B2bCustomer', ActivityScope::ASSOCIATION_KIND), 'OroCRM\\Bundle\\SalesBundle\\Entity\\B2bCustomer'); if (!$schema->hasTable($relationTableName)) { $this->activityExtension->addActivityAssociation($schema, 'oro_email', 'orocrm_sales_b2bcustomer'); } }
/** * Adds many-to-many relation * * @param Schema $schema * @param Table|string $table A Table object or table name * @param string $associationName The name of a relation field * @param Table|string $targetTable A Table object or table name * @param string[] $targetTitleColumnNames Column names are used to show a title of related entity * @param string[] $targetDetailedColumnNames Column names are used to show detailed info about related entity * @param string[] $targetGridColumnNames Column names are used to show related entity in a grid * @param array $options * @param string $fieldType The field type. By default the field type is manyToMany, * but you can specify another type if it is based on manyToMany. * In this case this type should be registered * in entity_extend.yml under underlying_types section */ public function addManyToManyRelation(Schema $schema, $table, $associationName, $targetTable, array $targetTitleColumnNames, array $targetDetailedColumnNames, array $targetGridColumnNames, array $options = [], $fieldType = RelationType::MANY_TO_MANY) { $this->ensureExtendFieldSet($options); $selfTableName = $this->getTableName($table); $selfTable = $this->getTable($table, $schema); $targetTableName = $this->getTableName($targetTable); $targetTable = $this->getTable($targetTable, $schema); $this->checkColumnsExist($targetTable, $targetTitleColumnNames); $this->checkColumnsExist($targetTable, $targetDetailedColumnNames); $this->checkColumnsExist($targetTable, $targetGridColumnNames); if (!isset($options['extend']['without_default']) || !$options['extend']['without_default']) { $this->addDefaultRelation($selfTable, $associationName, $targetTable); } $selfClassName = $this->getEntityClassByTableName($selfTableName); $targetClassName = $this->getEntityClassByTableName($targetTableName); $joinTableName = $this->nameGenerator->generateManyToManyJoinTableName($selfClassName, $associationName, $targetClassName); $joinTable = $schema->createTable($joinTableName); $selfJoinTableColumnName = $this->nameGenerator->generateManyToManyJoinTableColumnName($selfClassName); $targetJoinTableColumnName = $this->nameGenerator->generateManyToManyJoinTableColumnName($targetClassName); $this->addRelation($joinTable, $selfJoinTableColumnName, $selfTable, [], ['onDelete' => 'CASCADE']); $this->addRelation($joinTable, $targetJoinTableColumnName, $targetTable, [], ['onDelete' => 'CASCADE']); $joinTable->setPrimaryKey([$selfJoinTableColumnName, $targetJoinTableColumnName]); $options[ExtendOptionsManager::TARGET_OPTION] = ['table_name' => $targetTableName, 'columns' => ['title' => $targetTitleColumnNames, 'detailed' => $targetDetailedColumnNames, 'grid' => $targetGridColumnNames]]; $options[ExtendOptionsManager::TYPE_OPTION] = $fieldType; $this->extendOptionsManager->setColumnOptions($selfTableName, $associationName, $options); }
/** * @param ClassMetadataBuilder $metadataBuilder * @param FieldConfigId $fieldId * @param array $relation */ protected function buildManyToManyOwningSideRelation(ClassMetadataBuilder $metadataBuilder, FieldConfigId $fieldId, array $relation) { $targetEntity = $relation['target_entity']; $cascade = !empty($relation['cascade']) ? $relation['cascade'] : []; $builder = $metadataBuilder->createManyToMany($fieldId->getFieldName(), $targetEntity); if (!empty($relation['target_field_id'])) { $builder->inversedBy($relation['target_field_id']->getFieldName()); } $builder->setJoinTable($this->nameGenerator->generateManyToManyJoinTableName($fieldId->getClassName(), $fieldId->getFieldName(), $targetEntity)); foreach ($cascade as $cascadeType) { $builder->{'cascade' . ucfirst($cascadeType)}(); } $builder->build(); }
/** * @param ClassMetadataBuilder $metadataBuilder * @param FieldConfigId $fieldId * @param string $targetEntity * @param FieldConfigId|null $targetFieldId * @param string[] $cascade */ protected function buildManyToManyOwningSideRelation(ClassMetadataBuilder $metadataBuilder, FieldConfigId $fieldId, $targetEntity, FieldConfigId $targetFieldId = null, array $cascade = []) { $builder = $metadataBuilder->createManyToMany($fieldId->getFieldName(), $targetEntity); if ($targetFieldId) { $builder->inversedBy($targetFieldId->getFieldName()); } $builder->setJoinTable($this->nameGenerator->generateManyToManyJoinTableName($fieldId->getClassName(), $fieldId->getFieldName(), $targetEntity)); foreach ($cascade as $cascadeType) { $builder->{'cascade' . ucfirst($cascadeType)}(); } $builder->build(); $extendFieldConfig = $this->extendConfigProvider->getConfigById($fieldId); if (!$extendFieldConfig->is('without_default')) { $this->buildDefaultRelation($metadataBuilder, $fieldId, $targetEntity); } }
/** * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function testBuildManyToManyWithDefaultRelation() { $entityClass = 'Oro\\Bundle\\EntityExtendBundle\\Tests\\Unit\\Fixtures\\TestClass'; $fieldName = 'srcField'; $fieldType = RelationType::MANY_TO_MANY; $fieldId = new FieldConfigId('extend', $entityClass, $fieldName, $fieldType); $fieldConfig = new Config($fieldId, []); $targetEntityClass = 'Oro\\Bundle\\EntityExtendBundle\\Tests\\Unit\\Fixtures\\TestClass2'; $targetFieldName = 'targetField'; $targetFieldType = RelationType::MANY_TO_MANY; $targetFieldId = new FieldConfigId('extend', $targetEntityClass, $targetFieldName, $targetFieldType); $this->configManager->expects($this->once())->method('getFieldConfig')->with('extend', $entityClass, $fieldName)->willReturn($fieldConfig); $metadataBuilder = new ClassMetadataBuilder(new ClassMetadataInfo($entityClass)); $relationKey = ExtendHelper::buildRelationKey($entityClass, $fieldName, RelationType::MANY_TO_ONE, $targetEntityClass); $extendConfig = $this->getEntityConfig($entityClass, ['relation' => [$relationKey => ['field_id' => $fieldId, 'owner' => true, 'target_entity' => $targetEntityClass, 'target_field_id' => $targetFieldId]], 'schema' => ['relation' => [$fieldName => []]]]); $this->builder->build($metadataBuilder, $extendConfig); $result = $metadataBuilder->getClassMetadata()->getAssociationMapping($fieldName); $this->assertEquals(['sourceEntity' => $entityClass, 'targetEntity' => $targetEntityClass, 'fieldName' => $fieldName, 'type' => ClassMetadataInfo::MANY_TO_MANY, 'isOwningSide' => true, 'mappedBy' => null, 'inversedBy' => $targetFieldName, 'cascade' => [], 'joinTable' => ['name' => $this->nameGenerator->generateManyToManyJoinTableName($entityClass, $fieldName, $targetEntityClass), 'joinColumns' => [['name' => 'testclass_id', 'referencedColumnName' => 'id', 'onDelete' => 'CASCADE']], 'inverseJoinColumns' => [['name' => 'testclass2_id', 'referencedColumnName' => 'id', 'onDelete' => 'CASCADE']]], 'joinTableColumns' => ['testclass_id', 'testclass2_id'], 'relationToSourceKeyColumns' => ['testclass_id' => 'id'], 'relationToTargetKeyColumns' => ['testclass2_id' => 'id'], 'fetch' => ClassMetadataInfo::FETCH_LAZY, 'isOnDeleteCascade' => true, 'isCascadeRemove' => false, 'isCascadePersist' => false, 'isCascadeRefresh' => false, 'isCascadeMerge' => false, 'isCascadeDetach' => false, 'orphanRemoval' => false], $result); $defaultRelationFieldName = ExtendConfigDumper::DEFAULT_PREFIX . $fieldName; $this->assertEquals(['sourceEntity' => $entityClass, 'targetEntity' => $targetEntityClass, 'fieldName' => $defaultRelationFieldName, 'type' => ClassMetadataInfo::MANY_TO_ONE, 'isOwningSide' => true, 'mappedBy' => null, 'inversedBy' => null, 'cascade' => [], 'joinColumns' => [['name' => $defaultRelationFieldName . '_id', 'referencedColumnName' => 'id', 'nullable' => true, 'unique' => false, 'onDelete' => 'SET NULL', 'columnDefinition' => null]], 'joinColumnFieldNames' => [$defaultRelationFieldName . '_id' => $defaultRelationFieldName . '_id'], 'sourceToTargetKeyColumns' => [$defaultRelationFieldName . '_id' => 'id'], 'targetToSourceKeyColumns' => ['id' => $defaultRelationFieldName . '_id'], 'fetch' => ClassMetadataInfo::FETCH_LAZY, 'isCascadeRemove' => false, 'isCascadePersist' => false, 'isCascadeRefresh' => false, 'isCascadeMerge' => false, 'isCascadeDetach' => false, 'orphanRemoval' => false], $metadataBuilder->getClassMetadata()->getAssociationMapping($defaultRelationFieldName)); }
protected function renameCustomManyToManyRelationTables(Schema $schema, QueryBag $queries, ConfigManager $configManager) { /** @var EntityConfigId[] $entityConfigIds */ $entityConfigIds = $configManager->getIds('extend'); foreach ($entityConfigIds as $entityConfigId) { if ($configManager->getConfig($entityConfigId)->is('is_extend')) { /** @var FieldConfigId[] $fieldConfigIds */ $fieldConfigIds = $configManager->getIds('extend', $entityConfigId->getClassName()); foreach ($fieldConfigIds as $fieldConfigId) { if ($fieldConfigId->getFieldType() === RelationType::MANY_TO_MANY) { $fieldConfig = $configManager->getConfig($fieldConfigId); $targetClassName = $fieldConfig->get('target_entity'); $oldTableName = $this->generateOldManyToManyJoinTableName($fieldConfigId->getClassName(), $fieldConfigId->getFieldName(), $targetClassName); if ($schema->hasTable($oldTableName)) { $newTableName = $this->nameGenerator->generateManyToManyJoinTableName($fieldConfigId->getClassName(), $fieldConfigId->getFieldName(), $targetClassName); $this->renameExtension->renameTable($schema, $queries, $oldTableName, $newTableName); } } } } } }
/** * @param string $sourceTableName * @param string $targetTableName * @param string $ownerColumnName * @param QueryBag $queries */ public function assignActivities($sourceTableName, $targetTableName, $ownerColumnName, QueryBag $queries) { // prepare select email_id:contact_id sql $fromAndRecipients = ' SELECT DISTINCT email_id, owner_id FROM ( SELECT e.id as email_id, ea.{owner} as owner_id FROM oro_email_address ea INNER JOIN oro_email e ON e.from_email_address_id = ea.id WHERE ea.{owner} IS NOT NULL UNION SELECT er.email_id as email_id, ea.{owner} as owner_id FROM oro_email_address ea INNER JOIN oro_email_recipient er ON er.email_address_id = ea.id WHERE ea.{owner} IS NOT NULL ) as subq'; $sourceClassName = $this->extendExtension->getEntityClassByTableName($sourceTableName); $targetClassName = $this->extendExtension->getEntityClassByTableName($targetTableName); $fromAndRecipients = str_replace('{owner}', $ownerColumnName, $fromAndRecipients); $associationName = ExtendHelper::buildAssociationName($targetClassName, ActivityScope::ASSOCIATION_KIND); $tableName = $this->nameGenerator->generateManyToManyJoinTableName($sourceClassName, $associationName, $targetClassName); $queries->addQuery(sprintf("INSERT INTO %s %s", $tableName, $fromAndRecipients)); }
/** * Adds many-to-many relation * * @param Schema $schema * @param Table|string $table A Table object or table name * @param string $associationName A relation name * @param Table|string $targetTable A Table object or table name * @param string[] $targetTitleColumnNames Column names are used to show a title of related entity * @param string[] $targetDetailedColumnNames Column names are used to show detailed info about related entity * @param string[] $targetGridColumnNames Column names are used to show related entity in a grid * @param array $options * @param string $fieldType The field type. By default the field type is manyToMany, * but you can specify another type if it is based on manyToMany. * In this case this type should be registered * in entity_extend.yml under underlying_types section */ public function addManyToManyRelation(Schema $schema, $table, $associationName, $targetTable, array $targetTitleColumnNames, array $targetDetailedColumnNames, array $targetGridColumnNames, array $options = [], $fieldType = 'manyToMany') { $this->ensureExtendFieldSet($options); $selfTableName = $this->getTableName($table); $selfTable = $this->getTable($table, $schema); $selfClassName = $this->getEntityClassByTableName($selfTableName); $selfRelationName = $this->nameGenerator->generateManyToManyRelationColumnName($selfClassName); $selfPrimaryKeyColumnName = $this->getPrimaryKeyColumnName($selfTable); $selfPrimaryKeyColumn = $selfTable->getColumn($selfPrimaryKeyColumnName); $targetTableName = $this->getTableName($targetTable); $targetTable = $this->getTable($targetTable, $schema); $targetClassName = $this->getEntityClassByTableName($targetTableName); $targetRelationName = $this->nameGenerator->generateManyToManyRelationColumnName($targetClassName); $targetPrimaryKeyColumnName = $this->getPrimaryKeyColumnName($targetTable); $targetPrimaryKeyColumn = $targetTable->getColumn($targetPrimaryKeyColumnName); $this->checkColumnsExist($targetTable, $targetTitleColumnNames); $this->checkColumnsExist($targetTable, $targetDetailedColumnNames); $this->checkColumnsExist($targetTable, $targetGridColumnNames); if (!isset($options['extend']['without_default']) || !$options['extend']['without_default']) { $selfColumnName = $this->nameGenerator->generateRelationDefaultColumnName($associationName); $this->addRelationColumn($selfTable, $selfColumnName, $targetPrimaryKeyColumn, ['notnull' => false]); $selfTable->addUniqueIndex([$selfColumnName]); $selfTable->addForeignKeyConstraint($targetTable, [$selfColumnName], [$targetPrimaryKeyColumnName], ['onDelete' => 'SET NULL']); } $relationsTableName = $this->nameGenerator->generateManyToManyJoinTableName($selfClassName, $associationName, $targetClassName); $relationsTable = $schema->createTable($relationsTableName); $this->addRelationColumn($relationsTable, $selfRelationName, $selfPrimaryKeyColumn); $relationsTable->addIndex([$selfRelationName]); $relationsTable->addForeignKeyConstraint($selfTable, [$selfRelationName], [$selfPrimaryKeyColumnName], ['onDelete' => 'CASCADE']); $this->addRelationColumn($relationsTable, $targetRelationName, $targetPrimaryKeyColumn); $relationsTable->addIndex([$targetRelationName]); $relationsTable->addForeignKeyConstraint($targetTable, [$targetRelationName], [$targetPrimaryKeyColumnName], ['onDelete' => 'CASCADE']); $relationsTable->setPrimaryKey([$selfRelationName, $targetRelationName]); $options[ExtendOptionsManager::TARGET_OPTION] = ['table_name' => $targetTableName, 'columns' => ['title' => $targetTitleColumnNames, 'detailed' => $targetDetailedColumnNames, 'grid' => $targetGridColumnNames]]; $options[ExtendOptionsManager::TYPE_OPTION] = $fieldType; $this->extendOptionsManager->setColumnOptions($selfTableName, $associationName, $options); }
/** * Gets an activity list table name for many-to-many relation * * @param string $targetTableName Target entity table name. * * @return string */ protected function getAssociationActivityListTableName($targetTableName) { $targetClassName = $this->extendExtension->getEntityClassByTableName($targetTableName); $associationName = ExtendHelper::buildAssociationName($targetClassName, ActivityListEntityConfigDumperExtension::ASSOCIATION_KIND); return $this->nameGenerator->generateManyToManyJoinTableName(ActivityListEntityConfigDumperExtension::ENTITY_CLASS, $associationName, $targetClassName); }