预期的Symfony必须是Doctrine \ Common \ Collections \ ArrayCollection的实例,给定的Doctrine \ ORM \ PersistentCollection的实例

时间:2019-02-20 08:01:57

标签: many-to-many symfony-2.8 arraycollection

  

我正在使用Symfony 2.8

我在User和Sectors实体之间有很多关系,插入效果很好,但是创建编辑表单(editAction函数)无效。所有代码都在那里:

<?php
namespace UserBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
class User extends BaseUser implements ParticipantInterface
{
/**
 * @ORM\Id
 * @ORM\Column(name="id", type="integer", nullable=false)
 * @ORM\GeneratedValue(strategy="CUSTOM")
 * @ORM\CustomIdGenerator(class="CoreBundle\Model\CustomIdGenerator")
 *
 * @var int
 */
protected $id;

/**
 * @ORM\ManyToMany(targetEntity="UserBundle\Entity\Sectors", fetch="EAGER")
 * @ORM\JoinTable(
 *      joinColumns={@ORM\JoinColumn(onDelete="CASCADE")},
 *      inverseJoinColumns={@ORM\JoinColumn(onDelete="CASCADE")}
 * )
 */
public $sectors;

/**
 * @ORM\ManyToMany(targetEntity="UserBundle\Entity\UserAccreditation")
 * @ORM\JoinTable(
 *      joinColumns={@ORM\JoinColumn(onDelete="CASCADE")},
 *      inverseJoinColumns={@ORM\JoinColumn(onDelete="CASCADE")}
 * )
 */
public $accreditationdata;

/**
 * Constructor.
 */
public function __construct()
{
    $this->accreditationdata = new ArrayCollection();
    $this->sectors = new ArrayCollection();

    parent::__construct();
}

/**
 * Add accreditationdatum
 *
 * @param UserBundle\Entity\UserAccreditation $accreditationdatum
 *
 * @return User
 */
public function addAccreditationdatum(UserBundle\Entity\UserAccreditation $accreditationdatum)
{
    $this->accreditationdata[] = $accreditationdatum;

    return $this;
}

/**
 * Remove accreditationdatum
 *
 * @param UserBundle\Entity\UserAccreditation $accreditationdatum
 */
public function removeAccreditationdatum(UserBundle\Entity\UserAccreditation $accreditationdatum)
{
    $this->accreditationdata->removeElement($accreditationdatum);
}


/**
 * Add sector
 *
 * @param UserBundle\Entity\Sectors $sector
 *
 * @return User
 */
public function addSector(UserBundle\Entity\Sectors $sector)
{
    $this->sectors[] = $sector;

    return $this;
}

/**
 * Remove sector
 *
 * @param UserBundle\Entity\Sectors $sector
 */
public function removeSector(UserBundle\Entity\Sectors $sector)
{
    $this->sectors->removeElement($sector);
}

/**
 * Get sectors
 *
 * @return \Doctrine\Common\Collections\Collection
 */
public function getSectors()
{
    return $this->sectors;
}
}

ProfileAboutMeFormType.php

<?php
namespace UserBundle\Form\Type;

use UserBundle\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\HttpFoundation\RequestStack;  
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;  
use Doctrine\ORM\EntityRepository;    
use Symfony\Component\Form\FormInterface;     
use UserBundle\Entity\Sectors;
use UserBundle\Entity\UserAccreditation;

class ProfileAboutMeFormType extends AbstractType
{ 

/**
 * @param string       $class The User class name
 * @param RequestStack $requestStack
 * @param array        $locales
 */
public function __construct($class, RequestStack $requestStack, $locales)
{
    $this->class = $class;
    $this->request = $requestStack->getCurrentRequest();
    $this->locale = $this->request->getLocale();
    $this->locales = $locales;
}


public function buildForm(FormBuilderInterface $builder, array $options)
{
    /** @var User $user */
    $user = $builder->getData();

        $builder
        ->add('sectors', EntityType::class, array(
            'class'       => 'UserBundle\Entity\Sectors',
            'placeholder' => 'Select Sector ...',
            'label' => 'Sector',
            'required' => false,
            'multiple' => false,
            'expanded' => false,
            'query_builder' => function(EntityRepository $er) {
                return $er->createQueryBuilder('u')
                    ->orderBy('u.name', 'ASC');
            },
        ))
        ->add('accreditationdata', EntityType::class, array(
            'class' => 'UserBundle\Entity\UserAccreditation',
            'label' => 'Accreditation',
            'required' => false,
            'multiple' => true,
            'expanded' => true,
        ))
        ;
    }    

            $formModifier = function (FormInterface $form, UserMake $make = null) {

                $maker = null === $make ? array() : $make->getId();


                $form->add('model', EntityType::class, array(
                        'class' => 'Cocorico\UserBundle\Entity\UserModel',
                        'query_builder' => function(EntityRepository $ert) use ($maker) {
                                $query = $ert->createQueryBuilder('i')
                                    ->select(array('i'))
                                    ->where('i.make = :make_id')
                                    ->setParameter('make_id', $maker)
                                    ->orderBy('i.name', 'ASC');

                                return $query;
                            },
                        //'choices' => array($maker),
                        'required' => false,
                        'placeholder' => 'Select Make First ...',
                        'multiple' => false,
                        'expanded' => false,
                    )
                );
            };

            $builder->addEventListener(FormEvents::PRE_SET_DATA,function (FormEvent $event) use ($formModifier) {
                    $data = $event->getData();
                    $form = $event->getForm();
                    if ($data != null) 
                    $formModifier($event->getForm(), $data->getMakes());
                }
            );

            $builder->get('makes')->addEventListener(FormEvents::POST_SUBMIT,function (FormEvent $event) use ($formModifier) {
                    $make = $event->getForm()->getData();
                    $formModifier($event->getForm()->getParent(), $make);
                }
            );
        /******************************** This event listener is for sector and accreditation dependent fields ***************************************/
            $factory = $builder->getFormFactory();

                $formModify = function (FormInterface $form, \Doctrine\Common\Collections\ArrayCollection $sector, $factory) {

                    $output = [];
                    foreach($sector as $sec) {
                        $output[] = $sec->id;
                    }

                    $formOption = array(
                        'class' => 'UserBundle\Entity\UserAccreditation',
                        'multiple' => true,
                        'auto_initialize' => false,
                        'required' => false,
                        'expanded' => true,
                        'choice_attr' => function ($output) {
                                return ['class' => 'attr_checkbox'];
                        },
                        'query_builder' => function(EntityRepository $ertt) use ($output) {
                            // build a custom query, or call a method on your repository (even better!)
                            $qb = $ertt->createQueryBuilder('g');
                            $qb->select(array('g'));
                            $qb->where('g.sector IN (:sector_id)');
                            $qb->setParameters( array('sector_id' => $output) );
                            $qb->orderBy('g.name', 'ASC');
                            return $qb;
                        },
                    );
                    $form->add($factory->createNamed('accreditationdata', EntityType::class, null, $formOption));
                };

                $builder->addEventListener(FormEvents::PRE_SET_DATA,function (FormEvent $event) use ($formModify,$factory) {
                        $data = $event->getData();
                        $form = $event->getForm();
                        if ($data != null) 
                        //print_r(get_object_vars($data->getSectors()));
                        $formModify($event->getForm(), $data->getSectors(),$factory);
                    }
                );

                $factory = $builder->getFormFactory();
                $builder->get('sectors')->addEventListener(FormEvents::POST_SUBMIT,function (FormEvent $event) use ($formModify,$factory) {
                        $sector = $event->getForm()->getData();
                        $formModify($event->getForm()->getParent(), $sector,$factory);
                    }
                );

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults(
        array(
            'data_class' => $this->class,
            'csrf_token_id' => 'profile',
            'translation_domain' => 'user',
        )
    );
}

/**
 * BC
 * {@inheritdoc}
 */
public function getName()
{
    return $this->getBlockPrefix();
}

/**
 * {@inheritdoc}
 */
public function getBlockPrefix()
{
    return 'user_profile_about_me';
}
}

我得到错误提示:

  

类型错误:传递给UserBundle \ Form \ Type \ ProfileAboutMeFormType :: UserBundle \ Form \ Type {closure}()的参数2必须是Doctrine \ Common \ Collections \ ArrayCollection的实例,Doctrine \ ORM \ PersistentCollection的实例已给定,在第383行的/src/UserBundle/Form/Type/ProfileAboutMeFormType.php中调用

我应该将getSectors方法更改为PersistentCollection吗?还是我需要彻底改变我的方法?

1 个答案:

答案 0 :(得分:1)

是的,基本上回答了我自己的问题。对于这种方法,我有自己的解决方案。我必须将“事件监听器”更改为“编辑表单”。

  

据我了解,当您按存储库查询数据库时,会得到   PersistentCollection,当您与实体合作时,您会得到   ArrayCollection

我在$ formModify函数中将\ Doctrine \ Common \ Collections \ ArrayCollection $ sector更改为数组$ sector。我也更改了PRE_SET_DATA和POST_SUBMIT事件。

下面是更改的事件侦听器的完整代码。

                $factory = $builder->getFormFactory();

                $formModify = function (FormInterface $form, array $sector, $factory) {
                    $output = [];
                    foreach($sector as $sec) {
                        $output[] = $sec;
                    }
                    $formOption = array( 
                        'class' => 'Cocorico\UserBundle\Entity\UserAccreditation',
                        'multiple' => true,
                        'auto_initialize' => false,
                        'required' => false,
                        'expanded' => true,
                        'label' => 'Accreditations',
                        'choice_attr' => function ($output) {
                                return ['class' => 'attr_checkbox'];
                        },
                        'query_builder' => function(EntityRepository $ertt) use ($output) {
                            // build a custom query, or call a method on your repository (even better!)
                            $qb = $ertt->createQueryBuilder('g');
                            $qb->select(array('g'));
                            $qb->where('g.sector IN (:sector_id)');
                            $qb->setParameters( array('sector_id' => $output) );
                            $qb->orderBy('g.name', 'ASC');
                            return $qb;
                        },

                    );

                    $form->add($factory->createNamed('accreditationdata', EntityType::class, null, $formOption));
                };

                $builder->addEventListener(FormEvents::PRE_SET_DATA,function (FormEvent $event) use ($formModify,$factory) {
                        $data = $event->getData();
                        $form = $event->getForm();
                        if ($data != null) 
                        $newarray = [];
                        foreach ($data->getSectors() as $post) {
                            // $post is not an array
                             $newarray[] = $post->id;
                        }
                        $formModify($event->getForm(), $newarray,$factory);
                    }
                );

                $factory = $builder->getFormFactory();
                $builder->get('sectors')->addEventListener(FormEvents::POST_SUBMIT,function (FormEvent $event) use ($formModify,$factory) {
                        $sector = $event->getForm()->getData();
                        $created_array = array($sector->getId());
                        $array = [];
                        foreach($created_array as $secval) {
                            $array[] = $secval;
                        }
                        $formModify($event->getForm()->getParent(), $array,$factory);
                    }
                );    

这对我有用。希望它对这种方法有帮助。