嵌套CollectionType在ArrayCollection中保存实体

时间:2017-01-02 08:25:31

标签: php doctrine-orm symfony

我想存储一些数据

class Offer
{
    /**
     * @ORM\Column(type="array")
     */
    private $meterPoints;


    public function __construct()
    {
        $this->meterPoints = new ArrayCollection();
    }
}

作为CollectionType的商品。

class OfferType extends AbstractType
{
    $builder
        ->add('meterPoints', CollectionType::class, array(
            'entry_type' => OfferMeterPointType::class,
            'allow_add' => true,
            'allow_delete' => true,
            'prototype' => true,
            'prototype_name' => '__mp_name__',
        ))
}

在OfferMeterPointType中,我还有一个EntityType

class OfferMeterPointType extends AbstractType
{
    $builder
        ->add('meterPoint', EntityType::class, array(
            'attr' => array(
                'class' => 'chosen-select'
            ),
            'class' => 'AppBundle:MeterPoint',
            'choice_label' => 'meterPoint',
        ))
        ->add('billData', CollectionType::class, array(
            'label' => false,
            'entry_type' => OfferBillType::class,
            'allow_add' => true,
            'allow_delete' => true,
            'entry_options' => array(
                'label' => false
            )
        ));

}

现在当我坚持该实体时,整个AppBundle:MeterPoint对象被序列化而不仅仅是id。我有点理解为什么教义会这样做,但是我可以改变它以便只存储id吗?

当我想编辑优惠时

$offer = $em->getRepository('AppBundle:Offer')->findOneById(2);
$form = $this->createForm(OfferType::class, $offer);

我得到例外

  

必须管理传递到选择字段的实体。也许坚持他们在实体经理?

我想解决方案是为OfferMeterPointType创建一个实体,但我真的不想那样做。因为我几乎从不需要那些数据。

更新

我试着像马丁建议的那样。现在异常消失但它仍然保存完整的对象

$meterPoints = $this->em->getRepository('AppBundle:MeterPoint')->findAll();
    //dump($meterPoints);
    $builder
        ->add('meterPoint', ChoiceType::class, array(
            'label' => 'offerMeterPoint.meterPoint',
            'attr' => array(
                'class' => 'chosen-selesct',
                'placeholder' => 'ob.to'
            ),
            'choices' => $meterPoints,
            'choice_label' => function($meterPoint) {
                return $meterPoint->getMeterPoint();
            },
            'choice_value' => function($meterPoint) {
                if($meterPoint === null){
                    return null;
                }
                dump($meterPoint);
                return $meterPoint->getId();
            },
            'placeholder' => 'global.plz_select'
        ))

更新2 搞定了 改变了ChoiceType

        $meterPoints = $this->em->getRepository('AppBundle:MeterPoint')->findAll();
    $mps = array();
    foreach($meterPoints as $mp){
        $mps [$mp->getMeterPoint()] = $mp->getId();
    }
    //dump($meterPoints);
    $builder
        ->add('meterPoint', ChoiceType::class, array(
            'label' => 'offerMeterPoint.meterPoint',
            'attr' => array(
                'class' => 'chosen-selesct',
                'placeholder' => 'ob.to'
            ),
            'choices' => $mps,
            'placeholder' => 'global.plz_select'
        ))

1 个答案:

答案 0 :(得分:0)

  1. 您获得序列化的对象,因为您的列类型为array,而EntityType会自动将对象替换为选择值。

    然而choice_value也接受了一个可调用的,所以我试着摆弄它,也许你可以让它只返回id(也许是强制字符串类型?)。

    如果这没有帮助,那么可能只使用ChoiceType并自行处理逻辑。

  2. 这是因为Doctrine会自动将您尝试用作$meterPoints的实体的EntityType对象反序列化。这些对象显然不是由Doctrine Entity管理器管理的。因此错误。

    如果您想避免创建更多关系,我认为您必须在使用$meterPoints之前将$this->createForm(...)转换为数据库实体。最终,甚至更简单的方法是编写一个可以为您执行此操作的自定义Doctrine类型:

相关问题