在symfony 2.8的旧项目中,
我有3种类型的值(computedValue,manualData,probeData)我有一个实体名称'dataSource',其中包含3个源,但只能设置一个(另外2个设置为null)
我有其他实体包含3个DataSource和3个DataCource的ArrayCollection。
我的表格是这样的:
...
->add('dsRef1', DataSourceType::class, [
'site' => $site,
'multiple' => false,
'label_format' => 'form.%name%Ref1',
])
->add('dsList1', DataSourceType::class, [
'site' => $site,
'multiple' => true,
'label_format' => 'form.%name%List1',
])
... ( 3 time , dsRef1 - 3 , dlList1 - 3 )
我的DataSourceType是:
$builder
// This value is added for force symfony to think the form is submit when the form need to be empty
->add('hiddenCrapValue', HiddenType::class, [
'required' => false,
'mapped' => false,
'attr' => [
'front-attr' => [
'render' => 'hidden',
],
],
])
->add(DataSourceInterface::DATA_SOURCE, ChoiceType::class, [
'choices' => $site->getDataSources(),
'choices_as_values' => true,
'multiple' => $multiple,
'mapped' => false,
'required' => false,
'label_format' => $labelFormat,
])
->add(DataSourceInterface::PROBE_DATA, EntityType::class, [
'class' => ProbeData::class,
'required' => false,
'multiple' => $multiple,
'attr' => [
'front-attr' => [
'render' => 'hidden',
],
],
])
->add(DataSourceInterface::MANUAL_DATA, EntityType::class, [
'class' => ManualData::class,
'required' => false,
'multiple' => $multiple,
'attr' => [
'front-attr' => [
'render' => 'hidden',
],
],
])
->add(DataSourceInterface::COMPUTED_VALUE, EntityType::class, [
'class' => ComputedValue::class,
'required' => false,
'multiple' => $multiple,
'attr' => [
'front-attr' => [
'render' => 'hidden',
],
],
])
;
这适用于我的ref(dsRef1,dsRef2,dsRef3)...但是当我添加dsList1时,我有一个错误,说:
"The form's view data is expected to be an instance of class EnergySolution\\ApiBundle\\Entity\\DataSource, but is an instance of class Doctrine\\Common\\Collections\\ArrayCollection. You can avoid this error by setting the \"data_class\" option to null or by adding a view transformer that transforms an instance of class Doctrine\\Common\\Collections\\ArrayCollection to an instance of EnergySolution\\ApiBundle\\Entity\\DataSource.""
为什么我的多选项似乎不起作用?
编辑添加映射:
$table = $builder->getClassMetadata()->getTableName();
$builder
->setTable('chart_energy_goal')
->createField('name', Type::STRING)
->nullable()
->build()
->createField('title1', Type::STRING)
->nullable()
->build()
->createManyToOne('dsRef1', DataSource::class)
->cascadeAll()
->build()
->createManyToMany('dsList1', DataSource::class)
->setJoinTable("{$table}_dsList1")
->addJoinColumn("{$table}_id", 'id')
->build()
->createField('goal1', Type::FLOAT)
->build()
->createField('title2', Type::STRING)
->nullable()
->build()
->createManyToOne('dsRef2', DataSource::class)
->cascadeAll()
->build()
->createManyToMany('dsList2', DataSource::class)
->setJoinTable("{$table}_dsList2")
->addJoinColumn("{$table}_id", 'id')
->build()
->createField('goal2', Type::FLOAT)
->build()
->createField('title3', Type::STRING)
->nullable()
->build()
->createManyToOne('dsRef3', DataSource::class)
->cascadeAll()
->build()
->createManyToMany('dsList3', DataSource::class)
->setJoinTable("{$table}_dsList3")
->addJoinColumn("{$table}_id", 'id')
->build()
->createField('goal3', Type::FLOAT)
->build()
;
数据源::类
$builder = new ClassMetadataBuilder($metadata);
$builder
->setTable('data_sources')
->setCustomRepositoryClass(EntityRepository::class)
->createField('id', Type::INTEGER)
->columnName('id')
->makePrimaryKey()
->generatedValue()
->build()
->addManyToOne('computedValue', ComputedValue::class)
->addManyToOne('probeData', ProbeData::class)
->addManyToOne('probeData', ManualData::class)
;
编辑垃圾解决方案:
经过多次尝试后,我发现我的formBuilder返回了类似的内容
['computedValue' => [], 'probeData' => [], 'probeData' => []]
代替
[dataSource ...]
所以我Transforme像这样的数据。
$builder->get('dsList1')
->addModelTransformer(new CallbackTransformer(
function ($dsListAsArray) {
// never edit the form
return $dsListAsArray;
},
function ($ArrayOfDataSources) {
// transform list of 'dataSource' to liste of dataSource obj.
$collection = new ArrayCollection();
$propertyAccessor = PropertyAccess::createPropertyAccessorBuilder()
->enableExceptionOnInvalidIndex()
->getPropertyAccessor()
;
foreach ($ArrayOfDataSources as $dataSourceType => $dataSourcesArray) {
foreach ($dataSourcesArray as $dataSourceArray) {
$dataSource = new DataSource();
$propertyAccessor->setValue($dataSource, $dataSourceType, $dataSourceArray);
$collection->add($dataSource);
}
}
return $collection;
}
))
;
好吧,据我所知,DataSourceType
只能处理一个DataSource
(不是它们的数组)。
正如我从数据转换器中假设的那样,dsList1
是一个多对多的字段,因此可能来自学说的数组或ArrayCollection
(或类似的)。它可能是ArrayCollection
的DataSource
?
现在,给出的错误消息恰好表明这就是问题所在,你提供了一个ArrayCollection
,其中DataSource
是预期的。
在我看来,你有两个选择:
如果你的dsList1实际上只是一个实体(虽然问题是,为什么它是多对多的,但让我们说遗留的原因),你可以通过相应调整数据转换器来访问集合中的第一个数据源:
$builder->get('dsList1')
->addModelTransformer(new CallbackTransformer(
function ($dsListAsArray) {
// ### here you get a list, but want only the first entry? ###
return reset($dsListAsArray); // returns first element
},
function ($ArrayOfDataSources) {
$collection = new ArrayCollection();
// stuff you already wrote, BUT, see text below
return $collection;
}
))
;
然而,你在回调变换器中的第二个函数得到一个DataSource
,因此必须将一个DataSource
变成ArrayCollection
的DataSources
,这是
$builder->get('dsList1')
->addModelTransformer(new CallbackTransformer(
function ($dsListAsArray) {
// ### here you get a list, but want only the first entry? ###
return reset($dsListAsArray); // returns first element
},
function ($dataSource) {
return new ArrayCollection([$dataSource]);
}
))
;
将你的(“父”)形成dsList1
字段形成一个集合,因为它只应该有一个条目:
// in the file header part add (if not already there):
// use Symfony\Component\Form\Extension\Core\Type\CollectionType;
->add('dsList1', CollectionType::class, [
'entry_type' => DataSourceType::class,
'entry_options' => [
'site' => $site,
'multiple' => true, // <-- can probably scrap this one?!
'label_format' => 'form.%name%List1',
],
])
而你应该是金色的。在逻辑形式的东西。但是,模板会渲染这个奇怪的,可能......但你可以通过用一些自定义的block_prefix或其他东西覆盖form_widget代码来更新你的表单渲染。 (我想你可以从symfony文档中找到这个)
另外,查看CollectionType选项,你可以(并且可能应该)拒绝添加/删除(我相信默认是,你无论如何都不能)并制定约束,总是有一个(或没有?)。
作为评论:我建议不要在ArrayCollection
上从实体返回get{CollectionField}()
,并且在set{CollectionField}
期望一个数组并在那里创建ArrayCollection
(或更好:修改现有的,因此避免不必要的更新... )
和强制性通知:因为symfony 2.8不再维护......你应该考虑升级......但我想这不会发生。 ; O)
现在,据我所知,你想通过提供DataSourceType
选项将你的DataSource
变成能够处理多个multiple
s。要做到这一点,你必须做一些邪恶的逻辑来以某种方式管理这个,将ArrayCollection
的DataSource
多路复用到形式期望的单个DataSource
(逻辑TBD)作为数据转换器并反向执行相同的操作(逻辑TBD如好吧,它是摇摇欲坠的af)。
我建议反对它,你使用DataSource
的data_class删除几乎所有的优点,闯入一些乱伦的伪DataSource
或甚至可能是一个类似于DataSource
的数组。只是为了能够使用相同的形式。它真的不值得。保持对象。如果您确定dsList [123]中始终只有一个数据源,那么只需使用其他选项之一。如果可能有其他数据源,则选项2可能是首选数据源。我更喜欢它,TBH。