我正在使用Symfony2 / Doctrine应用程序,它使用类表继承(http://docs.doctrine-project.org/en/2.0.x/reference/inheritance-mapping.html#class-table-inheritance)在咨询中管理投诉.每个咨询都可以有很多投诉(OneToMany),每种不同类型的投诉都有不同的结构和外观.投诉是一个集合,并且使用JS动态添加.
在这一点上,我可以坚持投诉,并将它们连接到Consults,在持久化之前将其重新刻录为Controller中的适当类型.我遇到了一些问题,我正在计划将其迁移到表单事件(http://symfony.com/doc/current/cookbook/form/dynamic_form_generation.html)或其他某种方面来简化流程.
然而,在这一点上我遇到的问题是,我无法使用FormView在视图中显示现有的投诉,因为表单构建器要求我设置要显示的集合的类型.如果每个Consult只有一种类型的投诉,那将会很好,但是它们可以有多种类型,并且将表单构建器中的类型设置为将该类型限制为该类型.
有没有一些方法可以采取阻止FormView从tyring转换为字符串,没有类型或某种方式来动态检测和分配每个投诉的类型(使用$complaint-> getComplaintType(),也许)?
<?PHP namespace Acme\ConsultBundle\Entity; class Consult { /** * @ORM\OneToMany(targetEntity="Acme\ConsultBundle\Entity\ComplaintBase",mappedBy="consult",cascade={"persist","remove"}) */ protected $complaints; } ?> <?PHP namespace Acme\ConsultBundle\Entity; /** * Acme\ConsultBundle\Entity\ConsultBase * * @ORM\Entity * @ORM\Table(name="ConsultComplaintBase") * @ORM\HasLifecycleCallbacks * @ORM\InheritanceType("JOINED") * @ORM\DiscriminatorColumn(name="complaint_name",type="string") * @ORM\DiscriminatorMap({ * "ComplaintDefault" = "Acme\ConsultBundle\Entity\ComplaintDefault",* "ComplaintRosacea" = "Acme\ConsultBundle\Entity\ComplaintRosacea",* "ComplaintBotox" = "Acme\ConsultBundle\Entity\ComplaintBotox",* "ComplaintAcne" = "Acme\ConsultBundle\Entity\ComplaintAcne",* "ComplaintUrticaria" = "Acme\ConsultBundle\Entity\ComplaintUrticaria",* }) */ abstract class ComplaintBase { /** * @ORM\ManyToOne(targetEntity="Acme\ConsultBundle\Entity\Consult",inversedBy="complaints") * @ORM\JoinColumn(name="consult_id",referencedColumnName="id") */ protected $consult; /** * @ORM\Column(type="string",length="255") */ protected $complaintType; } ?> <?PHP namespace Acme\ConsultBundle\Form\Type; class ConsultType extends AbstractType { public function buildForm(FormBuilder $builder,array $options) { $builder ->add('complaints','collection',array( // 'type' => new ComplaintUrticariaType(),'error_bubbling' => true,'allow_add' => true,'allow_delete' => true,'by_reference' => false,)); } } ?>
解决方法
不完全确定它可以与集合一起使用,但它肯定与单个表单一起使用.请尝试这个想法.
首先为您的基本实体投诉基础做一个表单
class ComplaintForm extends AbstractType { public function buildForm(FormBuilderInterface $builder,array $options) { $subscriber = new ComplaintSubscriber($builder); $builder->addEventSubscriber($subscriber); /* your fields */ } public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array( 'data_class' => 'Acme\ConsultBundle\Entity\ComplaintBase',)); } }
然后在订户中,您可以根据提交的实体类型定义其他字段.
class ComplaintSubscriber implements EventSubscriberInterface { private $factory; private $builder; public function __construct(FormBuilderInterface $builder) { $this->factory = $builder->getFormFactory(); $this->builder = $builder; } public static function getSubscribedEvents() { return array( FormEvents::PRE_SET_DATA => 'preSetData',); } public function preSetData(FormEvent $event) { $data = $event->getData(); $form = $event->getForm(); if (null === $data) { return; } $class = get_class($data); if( $class === 'Acme\ConsultBundle\Entity\ComplaintDefault' ) { $this->processDefault($data,$form); } elseif( $class === 'Acme\ConsultBundle\Entity\ComplaintRosacea' ) { $this->processRosacea($data,$form); } elseif( $class === 'Acme\ConsultBundle\Entity\ComplaintBotox' ) { $this->processBotox($data,$form); } else { #NOP } } protected function processDefault(Entity\ComplaintDefault $node,FormInterface &$form) { #NOP } protected function processRosacea(Entity\ComplaintRosacea $node,FormInterface &$form) { $form->add($this->factory->createNamed('some_field','text')); } protected function processBotox(Entity\ComplaintBotox $node,FormInterface &$form) { $form->add($this->factory->createNamed('other_field','text')); } }