Symfony,集合,多个实体,得到arrayCollection,需要实体

问题描述 投票:0回答:1

在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;
            }
        ))
    ;
symfony formbuilder symfony-2.8
1个回答
1
投票

好吧,据我所知,DataSourceType只能处理一个DataSource(不是它们的数组)。

正如我从数据转换器中假设的那样,dsList1是一个多对多的字段,因此可能来自学说的数组或ArrayCollection(或类似的)。它可能是ArrayCollectionDataSource

现在,给出的错误消息恰好表明这就是问题所在,你提供了一个ArrayCollection,其中DataSource是预期的。

在我看来,你有两个选择:

option 1. really just render the first data source

如果你的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变成ArrayCollectionDataSources,这是

$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]); 
        }
    ))
;

option 2. just render it as a collection

将你的(“父”)形成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)

option 3. multiplexing like crazy - don't do it!

现在,据我所知,你想通过提供DataSourceType选项将你的DataSource变成能够处理多个multiples。要做到这一点,你必须做一些邪恶的逻辑来以某种方式管理这个,将ArrayCollectionDataSource多路复用到形式期望的单个DataSource(逻辑TBD)作为数据转换器并反向执行相同的操作(逻辑TBD如好吧,它是摇摇欲坠的af)。

我建议反对它,你使用DataSource的data_class删除几乎所有的优点,闯入一些乱伦的伪DataSource或甚至可能是一个类似于DataSource的数组。只是为了能够使用相同的形式。它真的不值得。保持对象。如果您确定dsList [123]中始终只有一个数据源,那么只需使用其他选项之一。如果可能有其他数据源,则选项2可能是首选数据源。我更喜欢它,TBH。

© www.soinside.com 2019 - 2024. All rights reserved.