/** * {@inheritdoc} */ public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array('constraints' => [new Assert\NotBlank()])); $constraintsNormalizer = function (Options $options, $constraints) { /** @var FieldConfigId $fieldConfigId */ $fieldConfigId = $options['config_id']; if (!$this->typeHelper->hasEnumCode($fieldConfigId->getClassName(), $fieldConfigId->getFieldName())) { // validations of new enum $constraints[] = new Assert\Length(['max' => $this->nameGenerator->getMaxEnumCodeSize()]); $constraints[] = new Assert\Regex(['pattern' => '/^[\\w- ]*$/', 'message' => self::INVALID_NAME_MESSAGE]); $callback = function ($value, ExecutionContext $context) { if (!empty($value)) { $code = ExtendHelper::buildEnumCode($value, false); if (empty($code)) { $context->addViolation(self::INVALID_NAME_MESSAGE, ['{{ value }}' => $value]); } } }; $constraints[] = new Assert\Callback([$callback]); $constraints[] = new UniqueEnumName(['entityClassName' => $fieldConfigId->getClassName(), 'fieldName' => $fieldConfigId->getFieldName()]); } else { // validations of existing enum $constraints[] = new Assert\Length(['max' => 255]); } return $constraints; }; $resolver->setNormalizers(['constraints' => $constraintsNormalizer, 'disabled' => function (Options $options, $value) { return $this->isReadOnly($options) ? true : $value; }, 'validation_groups' => function (Options $options, $value) { return $options['disabled'] ? false : $value; }]); }
/** * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function testPreUpdate() { $entityConfig1 = new Config(new EntityConfigId('extend', 'Test\\EnumValue1')); $entityConfig1->set('is_extend', true); $entityConfig2 = new Config(new EntityConfigId('extend', 'Test\\EnumValue2')); $fieldConfig1 = new Config(new FieldConfigId('extend', 'Test\\EnumValue1', 'field1', 'enum')); $fieldConfig1->set('state', ExtendScope::STATE_NEW); $fieldConfig2 = new Config(new FieldConfigId('extend', 'Test\\EnumValue1', 'field2', 'multiEnum')); $fieldConfig2->set('state', ExtendScope::STATE_NEW); $fieldConfig3 = new Config(new FieldConfigId('extend', 'Test\\EnumValue1', 'field3', 'enum')); $fieldConfig3->set('state', ExtendScope::STATE_UPDATE); $fieldConfig4 = new Config(new FieldConfigId('extend', 'Test\\EnumValue1', 'field4', 'manyToOne')); $fieldConfig4->set('state', ExtendScope::STATE_NEW); $fieldConfig5 = new Config(new FieldConfigId('extend', 'Test\\EnumValue1', 'field5', 'enum')); $fieldConfig5->set('state', ExtendScope::STATE_NEW); $enumFieldConfig1 = new Config(new FieldConfigId('enum', 'Test\\EnumValue1', 'field1', 'enum')); $enumFieldConfig1->set('enum_name', 'Test Enum 1'); $enumFieldConfig1->set('enum_public', true); $enumFieldConfig2 = new Config(new FieldConfigId('enum', 'Test\\EnumValue1', 'field2', 'enum')); $enumFieldConfig2->set('enum_name', 'Test Enum 2'); $enumFieldConfig2->set('enum_public', true); $enumFieldConfig5 = new Config(new FieldConfigId('enum', 'Test\\EnumValue1', 'field5', 'enum')); $entityConfigs = [$entityConfig1, $entityConfig2]; $fieldConfigs = [$fieldConfig1, $fieldConfig2, $fieldConfig3, $fieldConfig4, $fieldConfig5]; $enumCode1 = ExtendHelper::buildEnumCode('Test Enum 1'); $enumCode2 = ExtendHelper::buildEnumCode('Test Enum 2'); $enumCode5 = ExtendHelper::generateEnumCode('Test\\EnumValue1', 'field5'); $enumValueClassName1 = ExtendHelper::buildEnumValueClassName($enumCode1); $enumValueClassName2 = ExtendHelper::buildEnumValueClassName($enumCode2); $enumValueClassName5 = ExtendHelper::buildEnumValueClassName($enumCode5); $extendConfigProvider = $this->getMockBuilder('Oro\\Bundle\\EntityConfigBundle\\Provider\\ConfigProvider')->disableOriginalConstructor()->getMock(); $enumConfigProvider = $this->getMockBuilder('Oro\\Bundle\\EntityConfigBundle\\Provider\\ConfigProvider')->disableOriginalConstructor()->getMock(); $this->configManager->expects($this->any())->method('getProvider')->will($this->returnValueMap([['extend', $extendConfigProvider], ['enum', $enumConfigProvider]])); $extendConfigProvider->expects($this->at(0))->method('getConfigs')->will($this->returnValue($entityConfigs)); $extendConfigProvider->expects($this->at(1))->method('getConfigs')->with($entityConfig1->getId()->getClassName())->will($this->returnValue($fieldConfigs)); $enumConfigProvider->expects($this->at(0))->method('getConfig')->with($entityConfig1->getId()->getClassName(), 'field1')->will($this->returnValue($enumFieldConfig1)); $enumConfigProvider->expects($this->at(1))->method('getConfig')->with($entityConfig1->getId()->getClassName(), 'field2')->will($this->returnValue($enumFieldConfig2)); $enumConfigProvider->expects($this->at(2))->method('getConfig')->with($entityConfig1->getId()->getClassName(), 'field5')->will($this->returnValue($enumFieldConfig5)); $this->configManager->expects($this->exactly(3))->method('hasConfigEntityModel')->will($this->returnValueMap([[$enumValueClassName1, false], [$enumValueClassName2, true], [$enumValueClassName5, true]])); $configManagerAt = 3; $this->configManager->expects($this->at($configManagerAt++))->method('createConfigEntityModel')->with($enumValueClassName1, ConfigModelManager::MODE_HIDDEN); $relationBuilderAt = 0; $this->relationBuilder->expects($this->at($relationBuilderAt++))->method('updateEntityConfigs')->with($enumValueClassName1, ['entity' => ['label' => ExtendHelper::getEnumTranslationKey('label', $enumCode1), 'plural_label' => ExtendHelper::getEnumTranslationKey('plural_label', $enumCode1), 'description' => ExtendHelper::getEnumTranslationKey('description', $enumCode1)], 'extend' => ['owner' => ExtendScope::OWNER_SYSTEM, 'is_extend' => true, 'table' => $this->nameGenerator->generateEnumTableName($enumCode1), 'inherit' => ExtendHelper::BASE_ENUM_VALUE_CLASS], 'enum' => ['code' => $enumCode1, 'public' => true, 'multiple' => false]]); $this->setAddEnumValueEntityFieldsExpectations($enumValueClassName1, $enumCode1, $configManagerAt, $relationBuilderAt); $this->relationBuilder->expects($this->at($relationBuilderAt++))->method('addManyToOneRelation')->with($this->identicalTo($entityConfig1), $enumValueClassName1, 'field1', 'name', ['enum' => ['enum_code' => $enumCode1]], 'enum'); $this->relationBuilder->expects($this->at($relationBuilderAt++))->method('updateEntityConfigs')->with($enumValueClassName2, ['enum' => ['public' => true]]); $this->relationBuilder->expects($this->at($relationBuilderAt++))->method('addManyToManyRelation')->with($this->identicalTo($entityConfig1), $enumValueClassName2, 'field2', ['name'], ['name'], ['name'], ['enum' => ['enum_code' => $enumCode2], 'extend' => ['without_default' => true]], 'multiEnum'); $this->relationBuilder->expects($this->at($relationBuilderAt++))->method('addManyToOneRelation')->with($this->identicalTo($entityConfig1), $enumValueClassName5, 'field5', 'name', ['enum' => ['enum_code' => $enumCode5]], 'enum'); $this->extension->preUpdate(); }
/** * {@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); } } } }
/** * Post submit event handler * * @param FormEvent $event * * @SuppressWarnings(PHPMD.NPathComplexity) */ public function postSubmit(FormEvent $event) { $form = $event->getForm(); $configModel = $form->getConfig()->getOption('config_model'); if (!$configModel instanceof FieldConfigModel) { return; } if (!in_array($configModel->getType(), ['enum', 'multiEnum'])) { return; } if (!$form->isValid()) { return; } $data = $event->getData(); $enumConfig = $configModel->toArray('enum'); $enumName = $this->getValue($data['enum'], 'enum_name'); $enumCode = $this->getValue($enumConfig, 'enum_code'); if (empty($enumCode)) { $enumCode = $enumName !== null ? ExtendHelper::buildEnumCode($enumName) : ExtendHelper::generateEnumCode($configModel->getEntity()->getClassName(), $configModel->getFieldName()); } $locale = $this->translator->getLocale(); $enumValueClassName = ExtendHelper::buildEnumValueClassName($enumCode); $enumConfigProvider = $this->configManager->getProvider('enum'); if ($enumConfigProvider->hasConfig($enumValueClassName)) { // existing enum if ($configModel->getId()) { if ($enumName !== null) { $this->enumSynchronizer->applyEnumNameTrans($enumCode, $enumName, $locale); } $enumOptions = $this->getValue($data['enum'], 'enum_options'); if ($enumOptions !== null) { $this->enumSynchronizer->applyEnumOptions($enumValueClassName, $enumOptions, $locale); } $enumPublic = $this->getValue($data['enum'], 'enum_public'); if ($enumPublic !== null) { $this->enumSynchronizer->applyEnumEntityOptions($enumValueClassName, $enumPublic); } } unset($data['enum']['enum_name']); unset($data['enum']['enum_options']); unset($data['enum']['enum_public']); $event->setData($data); } else { // new enum $this->sortOptions($data['enum']['enum_options']); $data['enum']['enum_locale'] = $locale; $event->setData($data); } }
/** * Creates a table that is used to store enum values for the enum with the given code. * * @param Schema $schema * @param string $enumCode The unique identifier of an enum * @param bool $isMultiple Indicates whether several options can be selected for this enum * or it supports only one selected option * @param bool $isPublic Indicates whether this enum can be used by any entity or * it is designed to use in one entity only * @param bool|string[] $immutable Indicates whether the changing the list of enum values and * public flag is allowed or not. More details can be found * in entity_config.yml * @param array $options * * @return Table A table that is used to store enum values * * @throws \InvalidArgumentException * * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function createEnum(Schema $schema, $enumCode, $isMultiple = false, $isPublic = false, $immutable = false, array $options = []) { if ($enumCode !== ExtendHelper::buildEnumCode($enumCode)) { new \InvalidArgumentException(sprintf('The enum code "%s" must contain only lower alphabetical symbols, numbers and underscore.', $enumCode)); } $tableName = $this->nameGenerator->generateEnumTableName($enumCode); $className = ExtendHelper::buildEnumValueClassName($enumCode); $options = array_replace_recursive([ExtendOptionsManager::MODE_OPTION => ConfigModelManager::MODE_HIDDEN, ExtendOptionsManager::ENTITY_CLASS_OPTION => $className, 'entity' => ['label' => ExtendHelper::getEnumTranslationKey('label', $enumCode), 'plural_label' => ExtendHelper::getEnumTranslationKey('plural_label', $enumCode), 'description' => ExtendHelper::getEnumTranslationKey('description', $enumCode)], 'extend' => ['owner' => ExtendScope::OWNER_SYSTEM, 'is_extend' => true, 'table' => $tableName, 'inherit' => ExtendHelper::BASE_ENUM_VALUE_CLASS], 'enum' => ['code' => $enumCode, 'public' => $isPublic, 'multiple' => $isMultiple]], $options); if ($immutable) { $options['enum']['immutable'] = true; } $table = $schema->createTable($tableName); $this->entityMetadataHelper->registerEntityClass($tableName, $className); $table->addOption(OroOptions::KEY, $options); $table->addColumn('id', 'string', ['length' => ExtendHelper::MAX_ENUM_VALUE_ID_LENGTH, OroOptions::KEY => ['entity' => ['label' => ExtendHelper::getEnumTranslationKey('label', $enumCode, 'id'), 'description' => ExtendHelper::getEnumTranslationKey('description', $enumCode, 'id')], 'importexport' => ['identity' => true]]]); $table->addColumn('name', 'string', ['length' => 255, OroOptions::KEY => ['entity' => ['label' => ExtendHelper::getEnumTranslationKey('label', $enumCode, 'name'), 'description' => ExtendHelper::getEnumTranslationKey('description', $enumCode, 'name')], 'datagrid' => ['is_visible' => false]]]); $table->addColumn('priority', 'integer', [OroOptions::KEY => ['entity' => ['label' => ExtendHelper::getEnumTranslationKey('label', $enumCode, 'priority'), 'description' => ExtendHelper::getEnumTranslationKey('description', $enumCode, 'priority')], 'datagrid' => ['is_visible' => false]]]); $table->addColumn('is_default', 'boolean', [OroOptions::KEY => [ExtendOptionsManager::FIELD_NAME_OPTION => 'default', 'entity' => ['label' => ExtendHelper::getEnumTranslationKey('label', $enumCode, 'default'), 'description' => ExtendHelper::getEnumTranslationKey('description', $enumCode, 'default')], 'datagrid' => ['is_visible' => false]]]); $table->setPrimaryKey(['id']); return $table; }
/** * @dataProvider buildEnumCodeForInvalidEnumNameProvider */ public function testBuildEnumCodeForInvalidEnumNameIgnoreException($enumValueName) { $this->assertSame('', ExtendHelper::buildEnumCode($enumValueName, false)); }
/** * Checks if an enum with the given code already exist * * @param string $enumCode * @param string $entityClassName * @param string $fieldName * * @return bool * * @SuppressWarnings(PHPMD.NPathComplexity) */ protected function isExistingEnum($enumCode, $entityClassName, $fieldName) { $extendConfigProvider = $this->configManager->getProvider('extend'); $enumConfigProvider = $this->configManager->getProvider('enum'); // at first check if an enum entity with the given code is already exist $entityConfigs = $extendConfigProvider->getConfigs(null, true); foreach ($entityConfigs as $entityConfig) { if (!$entityConfig->is('inherit', ExtendHelper::BASE_ENUM_VALUE_CLASS)) { continue; } $enumEntityConfig = $enumConfigProvider->getConfig($entityConfig->getId()->getClassName()); if ($enumCode === $enumEntityConfig->get('code')) { return true; } } // if an enum entity with the given code was not found than check if there is new field with // the given enum code $entityConfigs = $extendConfigProvider->getConfigs(); foreach ($entityConfigs as $entityConfig) { if (!$entityConfig->is('is_extend')) { continue; } if (!$entityConfig->in('state', [ExtendScope::STATE_NEW, ExtendScope::STATE_UPDATE])) { continue; } $fieldConfigs = $extendConfigProvider->getConfigs($entityConfig->getId()->getClassName()); foreach ($fieldConfigs as $fieldConfig) { /** @var FieldConfigId $fieldConfigId */ $fieldConfigId = $fieldConfig->getId(); if ($fieldConfigId->getFieldName() === $fieldName && $fieldConfigId->getClassName() === $entityClassName) { // ignore a field for which the validation was called continue; } if (!in_array($fieldConfigId->getFieldType(), ['enum', 'multiEnum'])) { continue; } if (!$fieldConfig->in('state', [ExtendScope::STATE_NEW])) { continue; } $enumFieldConfig = $enumConfigProvider->getConfig($fieldConfigId->getClassName(), $fieldConfigId->getFieldName()); $existingEnumName = $enumFieldConfig->get('enum_name'); if (!empty($existingEnumName) && $enumCode === ExtendHelper::buildEnumCode($existingEnumName)) { return true; } } } return false; }