/** * @param string $tableName * @param string $columnName * @param array $options * * @SuppressWarnings(PHPMD.NPathComplexity) * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function addColumnOptions($tableName, $columnName, $options) { $entityClassName = $this->getEntityClassName($tableName, null, false); if (!$entityClassName) { return; } $newColumnName = $this->getAndRemoveOption($options, ExtendOptionsManager::NEW_NAME_OPTION); if ($newColumnName) { $this->result[ExtendConfigProcessor::RENAME_CONFIGS][$entityClassName][$columnName] = $newColumnName; if (empty($options)) { return; } } $fieldName = $this->getAndRemoveOption($options, ExtendOptionsManager::FIELD_NAME_OPTION); if (!$fieldName) { $fieldName = $this->getFieldName($tableName, $columnName); } $columnType = $this->getAndRemoveOption($options, ExtendOptionsManager::TYPE_OPTION); $columnMode = $this->getAndRemoveOption($options, ExtendOptionsManager::MODE_OPTION); $columnUnderlyingType = $this->fieldTypeHelper->getUnderlyingType($columnType); if (in_array($columnUnderlyingType, ['oneToMany', 'manyToOne', 'manyToMany'])) { if (!isset($options['extend'])) { $options['extend'] = []; } $target = $this->getAndRemoveOption($options, ExtendOptionsManager::TARGET_OPTION); foreach ($target as $optionName => $optionValue) { switch ($optionName) { case 'table_name': $options['extend']['target_entity'] = $this->getEntityClassName($optionValue); break; case 'column': $options['extend']['target_field'] = $this->getFieldName($target['table_name'], $optionValue); break; case 'columns': foreach ($optionValue as $group => $columns) { $values = []; foreach ($columns as $column) { $values[] = $this->getFieldName($target['table_name'], $column); } $options['extend']['target_' . $group] = $values; } break; } } $options['extend']['relation_key'] = ExtendHelper::buildRelationKey($entityClassName, $fieldName, $columnUnderlyingType, $options['extend']['target_entity']); } $this->result[$entityClassName]['fields'][$fieldName] = []; if (!empty($options)) { $this->result[$entityClassName]['fields'][$fieldName]['configs'] = $options; } if ($columnType) { $this->result[$entityClassName]['fields'][$fieldName]['type'] = $columnType; } if ($columnMode) { $this->result[$entityClassName]['fields'][$fieldName]['mode'] = $columnMode; } }
/** * {@inheritdoc} */ public function beforeValueRender(ValueRenderEvent $event) { $value = $event->getFieldValue(); $type = $event->getFieldConfigId()->getFieldType(); /** Prepare Relation field type */ if ($value && $value instanceof Collection) { $viewData = $this->getValueForCollection($value, $event->getFieldConfigId()); $event->setFieldViewValue($viewData); return; } $underlyingFieldType = $this->fieldTypeHelper->getUnderlyingType($type); if ($value && $underlyingFieldType === RelationType::MANY_TO_ONE) { $viewData = $this->getValueForManyToOne($value, $this->extendProvider->getConfigById($event->getFieldConfigId())); $event->setFieldViewValue($viewData); } }
/** * Check fields parameters and update field config * * @param string $entityName * @param ConfigInterface $fieldConfig * @param array $relationProperties * @param array $defaultProperties * @param array $properties * @param array $doctrine */ protected function checkFields($entityName, ConfigInterface $fieldConfig, array &$relationProperties, array &$defaultProperties, array &$properties, array &$doctrine) { if ($fieldConfig->is('is_extend')) { /** @var FieldConfigId $fieldConfigId */ $fieldConfigId = $fieldConfig->getId(); $fieldName = $fieldConfigId->getFieldName(); $fieldType = $fieldConfigId->getFieldType(); $underlyingFieldType = $this->fieldTypeHelper->getUnderlyingType($fieldType); if (in_array($underlyingFieldType, array_merge(RelationType::$anyToAnyRelations, ['optionSet']))) { $relationProperties[$fieldName] = $fieldName; if ($underlyingFieldType !== RelationType::MANY_TO_ONE && !$fieldConfig->is('without_default')) { $defaultName = self::DEFAULT_PREFIX . $fieldName; $defaultProperties[$defaultName] = $defaultName; } } else { $properties[$fieldName] = $fieldName; $doctrine[$entityName]['fields'][$fieldName] = ['column' => $fieldName, 'type' => $fieldType, 'nullable' => true, 'length' => $fieldConfig->get('length'), 'precision' => $fieldConfig->get('precision'), 'scale' => $fieldConfig->get('scale')]; } } if ($fieldConfig->is('state', ExtendScope::STATE_DELETE)) { $fieldConfig->set('is_deleted', true); } else { $fieldConfig->set('state', ExtendScope::STATE_ACTIVE); } }
/** * Check fields parameters and update field config * * @param string $entityName * @param ConfigInterface $fieldConfig * @param array $relationProperties * @param array $defaultProperties * @param array $properties * @param array $doctrine */ protected function checkFieldSchema($entityName, ConfigInterface $fieldConfig, array &$relationProperties, array &$defaultProperties, array &$properties, array &$doctrine) { if ($fieldConfig->is('is_extend')) { /** @var FieldConfigId $fieldConfigId */ $fieldConfigId = $fieldConfig->getId(); $fieldName = $fieldConfigId->getFieldName(); $fieldType = $fieldConfigId->getFieldType(); $isDeleted = $fieldConfig->is('is_deleted'); $underlyingFieldType = $this->fieldTypeHelper->getUnderlyingType($fieldType); if (in_array($underlyingFieldType, RelationType::$anyToAnyRelations, true)) { $relationProperties[$fieldName] = []; if ($isDeleted) { $relationProperties[$fieldName]['private'] = true; } if ($underlyingFieldType !== RelationType::MANY_TO_ONE && !$fieldConfig->is('without_default')) { $defaultName = self::DEFAULT_PREFIX . $fieldName; $defaultProperties[$defaultName] = []; if ($isDeleted) { $defaultProperties[$defaultName]['private'] = true; } } } else { $properties[$fieldName] = []; if ($isDeleted) { $properties[$fieldName]['private'] = true; } $doctrine[$entityName]['fields'][$fieldName] = ['column' => $fieldName, 'type' => $fieldType, 'nullable' => true, 'length' => $fieldConfig->get('length'), 'precision' => $fieldConfig->get('precision'), 'scale' => $fieldConfig->get('scale')]; } } }
/** * {@inheritdoc} * * @SuppressWarnings(PHPMD.NPathComplexity) */ public function preUpdate() { $enumConfigProvider = $this->configManager->getProvider('enum'); $extendConfigProvider = $this->configManager->getProvider('extend'); $entityConfigs = $extendConfigProvider->getConfigs(); foreach ($entityConfigs as $entityConfig) { if (!$entityConfig->is('is_extend')) { continue; } $fieldConfigs = $extendConfigProvider->getConfigs($entityConfig->getId()->getClassName()); foreach ($fieldConfigs as $fieldConfig) { if (!$fieldConfig->in('state', [ExtendScope::STATE_NEW, ExtendScope::STATE_UPDATE])) { continue; } /** @var FieldConfigId $fieldConfigId */ $fieldConfigId = $fieldConfig->getId(); $fieldType = $fieldConfigId->getFieldType(); if (!in_array($fieldType, ['enum', 'multiEnum'])) { continue; } // prepare input parameters $fieldOptions = []; $enumFieldConfig = $enumConfigProvider->getConfig($fieldConfigId->getClassName(), $fieldConfigId->getFieldName()); $enumCode = $enumFieldConfig->get('enum_code'); $enumName = $enumFieldConfig->get('enum_name'); $isPublic = $enumFieldConfig->get('enum_public'); if (empty($enumCode) && $isPublic && empty($enumName)) { throw new \LogicException(sprintf('Both "enum_code" and "enum_name" cannot be empty for a public enum. Field: %s::%s.', $fieldConfigId->getClassName(), $fieldConfigId->getFieldName())); } if (empty($enumCode)) { $enumCode = $enumName !== null ? ExtendHelper::buildEnumCode($enumName) : ExtendHelper::generateEnumCode($fieldConfigId->getClassName(), $fieldConfigId->getFieldName()); $fieldOptions['enum']['enum_code'] = $enumCode; } $isMultiple = $this->fieldTypeHelper->getUnderlyingType($fieldType) === RelationType::MANY_TO_MANY; $enumValueClassName = ExtendHelper::buildEnumValueClassName($enumCode); // create an entity is used to store enum values $this->createEnumValueConfigEntityModel($enumValueClassName, $enumCode, $isMultiple, $isPublic); // create a relation if ($isMultiple) { $fieldOptions['extend']['without_default'] = true; $this->relationBuilder->addManyToManyRelation($entityConfig, $enumValueClassName, $fieldConfigId->getFieldName(), ['name'], ['name'], ['name'], $fieldOptions, $fieldType); } else { $this->relationBuilder->addManyToOneRelation($entityConfig, $enumValueClassName, $fieldConfigId->getFieldName(), 'name', $fieldOptions, $fieldType); } } } }
/** * Determines whether the index for the given field is needed or not. * All relation type fields should be excluded. * Index requirement is determined by visibility of a field on a grid. * * @param string $className * @param string $fieldName * @param string $fieldType * * @return bool */ protected function isIndexRequired($className, $fieldName, $fieldType) { $underlyingType = $this->fieldTypeHelper->getUnderlyingType($fieldType); if (!$this->fieldTypeHelper->isRelation($underlyingType)) { $datagridConfigProvider = $this->configManager->getProvider('datagrid'); if ($datagridConfigProvider->hasConfig($className, $fieldName)) { $datagridConfig = $datagridConfigProvider->getConfig($className, $fieldName); return $datagridConfig->get('is_visible', false, false); } } return false; }
/** * @param string $columnName * @param array $options * @param string $className * @param Table $table */ protected function buildIndex($columnName, $options, $className, $table) { $columnType = $this->fieldTypeHelper->getUnderlyingType($options[ExtendOptionsManager::TYPE_OPTION]); if ($this->fieldTypeHelper->isRelation($columnType) || in_array($columnType, [Type::TEXT])) { return; } $indexName = $this->nameGenerator->generateIndexNameForExtendFieldVisibleInGrid($className, $columnName); if ($this->isEnabled($options) && $this->isExtended($options) && !$table->hasIndex($indexName)) { $table->addIndex([$columnName], $indexName); } elseif (!$this->isEnabled($options) && $table->hasIndex($indexName)) { $table->dropIndex($indexName); } }
/** * @param LoggerInterface $logger * @param bool $dryRun */ public function doExecute(LoggerInterface $logger, $dryRun = false) { $classNames = $this->getAllConfigurableEntities($logger); foreach ($classNames as $className) { $fieldConfigs = $this->loadFieldConfigs($logger, $className); foreach ($fieldConfigs as $fieldConfig) { $data = $fieldConfig['data']; if (!isset($data['extend'])) { // skip because this field has no any attributes in 'extend' scope continue; } if (isset($data['extend']['is_extend']) || array_key_exists('is_extend', $data['extend'])) { // remove old extend.is_extend attribute unset($data['extend']['is_extend']); } if (isset($data['extend']['extend']) || array_key_exists('extend', $data['extend'])) { // rename extend.extend to extend.is_extend $data['extend']['is_extend'] = $data['extend']['extend']; unset($data['extend']['extend']); } if (isset($data['extend']['relation_key']) && is_string($data['extend']['relation_key'])) { $parts = explode('|', $data['extend']['relation_key']); if (count($parts) === 4 && $parts[0] !== $this->fieldTypeHelper->getUnderlyingType($parts[0])) { // change field type to relation type in extend.relation_key attribute $parts[0] = $this->fieldTypeHelper->getUnderlyingType($parts[0]); $data['extend']['relation_key'] = implode('|', $parts); } } $query = 'UPDATE oro_entity_config_field SET data = :data WHERE id = :id'; $params = ['data' => $data, 'id' => $fieldConfig['id']]; $types = ['data' => 'array', 'id' => 'integer']; $this->logQuery($logger, $query, $params, $types); if (!$dryRun) { $this->connection->executeUpdate($query, $params, $types); } } } }
/** * Determines whether the index for the given field is needed or not * * @param string $className * @param string $fieldName * @param string $fieldType * * @return bool */ protected function isIndexRequired($className, $fieldName, $fieldType) { $underlyingType = $this->fieldTypeHelper->getUnderlyingType($fieldType); if (in_array($underlyingType, ['oneToMany', 'manyToOne', 'manyToMany'])) { // relation fields already have an index return false; } $result = false; $datagridConfigProvider = $this->configManager->getProvider('datagrid'); if ($datagridConfigProvider->hasConfig($className, $fieldName)) { $datagridConfig = $datagridConfigProvider->getConfig($className, $fieldName); if ($datagridConfig->get('is_visible')) { $result = true; } } return $result; }
/** * @param ConfigInterface $fieldConfig * @param string $relationKey */ protected function createTargetRelation(ConfigInterface $fieldConfig, $relationKey) { /** @var FieldConfigId $fieldConfigId */ $fieldConfigId = $fieldConfig->getId(); $selfFieldId = new FieldConfigId('extend', $fieldConfigId->getClassName(), $fieldConfigId->getFieldName(), $this->fieldTypeHelper->getUnderlyingType($fieldConfigId->getFieldType())); $targetEntityClass = $fieldConfig->get('target_entity'); $selfConfig = $this->extendConfigProvider->getConfig($selfFieldId->getClassName()); $selfRelations = $selfConfig->get('relation'); $selfRelationConfig =& $selfRelations[$relationKey]; $selfRelationConfig['field_id'] = $selfFieldId; $targetConfig = $this->extendConfigProvider->getConfig($targetEntityClass); $targetRelations = $targetConfig->get('relation'); $targetRelationConfig =& $targetRelations[$relationKey]; $targetRelationConfig['target_field_id'] = $selfFieldId; $selfConfig->set('relation', $selfRelations); $targetConfig->set('relation', $targetRelations); $this->extendConfigProvider->persist($targetConfig); }
/** * @param ConfigInterface $config * @return bool */ public function filterFields(ConfigInterface $config) { $extendConfig = $this->extendProvider->getConfigById($config->getId()); /** @var FieldConfigId $fieldConfigId */ $fieldConfigId = $extendConfig->getId(); // skip system, new and deleted fields if (!$config->is('owner', ExtendScope::OWNER_CUSTOM) || $config->is('state', ExtendScope::STATE_NEW) || $config->is('is_deleted')) { return false; } // skip invisible fields if (!$this->viewProvider->getConfigById($config->getId())->is('is_displayable')) { return false; } // skip relations if they are referenced to deleted entity $underlyingFieldType = $this->fieldTypeHelper->getUnderlyingType($fieldConfigId->getFieldType()); if (in_array($underlyingFieldType, RelationType::$anyToAnyRelations) && $this->extendProvider->getConfig($extendConfig->get('target_entity'))->is('is_deleted', true)) { return false; } return true; }
/** * @param ConfigInterface $config * @return bool */ public function filterFields(ConfigInterface $config) { $extendConfig = $this->extendProvider->getConfigById($config->getId()); /** @var FieldConfigId $fieldConfigId */ $fieldConfigId = $extendConfig->getId(); // skip system and not accessible fields if (!$config->is('owner', ExtendScope::OWNER_CUSTOM) || !ExtendHelper::isFieldAccessible($config)) { return false; } // skip invisible fields if (!$this->viewProvider->getConfigById($config->getId())->is('is_displayable')) { return false; } // skip relations if they are referenced to not accessible entity $underlyingFieldType = $this->fieldTypeHelper->getUnderlyingType($fieldConfigId->getFieldType()); if (in_array($underlyingFieldType, RelationType::$anyToAnyRelations, true) && !ExtendHelper::isEntityAccessible($this->extendProvider->getConfig($extendConfig->get('target_entity')))) { return false; } return true; }
/** * @return string[] */ public function getFields() { if (empty($this->fields)) { $this->fields = []; $fieldConfigs = $this->configManager->getConfigs('extend', self::CALENDAR_PROPERTY_CLASS); foreach ($fieldConfigs as $fieldConfig) { if (!ExtendHelper::isFieldAccessible($fieldConfig)) { continue; } /** @var FieldConfigId $fieldId */ $fieldId = $fieldConfig->getId(); $fieldType = $fieldId->getFieldType(); $underlyingFieldType = $this->fieldTypeHelper->getUnderlyingType($fieldType); if (in_array($underlyingFieldType, RelationType::$toManyRelations, true)) { // ignore to-many relations continue; } $this->fields[$fieldId->getFieldName()] = $fieldType; } } return $this->fields; }
/** * @return string[] */ public function getFields() { if (empty($this->fields)) { $this->fields = []; $fieldConfigs = $this->configManager->getConfigs('extend', self::CALENDAR_PROPERTY_CLASS); foreach ($fieldConfigs as $fieldConfig) { if ($fieldConfig->is('state', ExtendScope::STATE_NEW) || $fieldConfig->is('is_deleted')) { continue; } /** @var FieldConfigId $fieldId */ $fieldId = $fieldConfig->getId(); $fieldType = $fieldId->getFieldType(); $underlyingFieldType = $this->fieldTypeHelper->getUnderlyingType($fieldType); if (in_array($underlyingFieldType, ['ref-many', 'manyToMany', 'oneToMany'])) { // ignore multiple relations continue; } $this->fields[$fieldId->getFieldName()] = $fieldType; } } return $this->fields; }
/** * Makes sure that both source and target entities know about a reverse relation * * @param ConfigInterface $fieldConfig */ protected function ensureReverseRelationCompleted(ConfigInterface $fieldConfig) { /** @var FieldConfigId $fieldConfigId */ $fieldConfigId = $fieldConfig->getId(); $relationKey = $fieldConfig->get('relation_key'); $selfConfig = $this->extendConfigProvider->getConfig($fieldConfigId->getClassName()); $selfRelations = $selfConfig->get('relation', false, []); if (isset($selfRelations[$relationKey]['field_id']) && $selfRelations[$relationKey]['field_id']) { return; } $targetConfig = $this->extendConfigProvider->getConfig($fieldConfig->get('target_entity')); $targetRelations = $targetConfig->get('relation', false, []); if (!isset($targetRelations[$relationKey])) { return; } $selfFieldId = new FieldConfigId('extend', $fieldConfigId->getClassName(), $fieldConfigId->getFieldName(), $this->fieldTypeHelper->getUnderlyingType($fieldConfigId->getFieldType())); $selfRelations[$relationKey]['field_id'] = $selfFieldId; $targetRelations[$relationKey]['target_field_id'] = $selfFieldId; $selfConfig->set('relation', $selfRelations); $targetConfig->set('relation', $targetRelations); $this->configManager->persist($selfConfig); $this->configManager->persist($targetConfig); }
/** * @dataProvider getUnderlyingTypeProvider */ public function testGetUnderlyingType($type, $expectedType) { $this->assertEquals($expectedType, $this->helper->getUnderlyingType($type)); }
/** * @param array $field * @return bool */ public function isMultipleRelation(array $field) { return $this->isRelation($field) && in_array($this->fieldTypeHelper->getUnderlyingType($field['relation_type']), ['ref-many', 'oneToMany', 'manyToMany']); }
/** * Gets a relation type * * @param string $relationFieldType * * @return string */ protected function getRelationType($relationFieldType) { return $this->fieldTypeHelper->getUnderlyingType($relationFieldType); }
/** * @param ConfigInterface $fieldConfig * * @return FieldConfigId */ protected function createFieldConfigId(ConfigInterface $fieldConfig) { /** @var FieldConfigId $fieldConfigId */ $fieldConfigId = $fieldConfig->getId(); return new FieldConfigId('extend', $fieldConfigId->getClassName(), $fieldConfigId->getFieldName(), $this->fieldTypeHelper->getUnderlyingType($fieldConfigId->getFieldType())); }