Php 如何根据Symfony中的选择动态添加自定义类型?

Php 如何根据Symfony中的选择动态添加自定义类型?,php,forms,symfony,Php,Forms,Symfony,我正在为在symfony演出的门票预订创建一个表单 每个性能都有多个性能数据。在数据库中,performanceData记录包含日期、位置和可用票证类型列表等内容。每个performanceData记录的可用票证类型可能不同 当用户想要预订时,他必须选择一个性能数据。 基于此选择,他应该获得一个包含所有可用票证类型的列表+每个票证类型a(编号)字段,以选择票证数量。这就是我被困的地方 我使用symfony文档创建了一个动态表单,根据用户的选择在下拉列表中加载可用的票证类型。但是如何添加带有可用票

我正在为在symfony演出的门票预订创建一个表单

每个性能都有多个性能数据。在数据库中,performanceData记录包含日期、位置和可用票证类型列表等内容。每个performanceData记录的可用票证类型可能不同

当用户想要预订时,他必须选择一个性能数据。 基于此选择,他应该获得一个包含所有可用票证类型的列表+每个票证类型a(编号)字段,以选择票证数量。这就是我被困的地方

我使用symfony文档创建了一个动态表单,根据用户的选择在下拉列表中加载可用的票证类型。但是如何添加带有可用票证类型+编号字段的列表?此列表应与预订实体中的“票证”对应

我的实体:

性能数据

/**
 * PerformanceData
 *
 * @ORM\Table(name="performance_data")
 * @ORM\Entity
 */
class PerformanceData
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="date", type="datetime", nullable=false)
     */
    private $date;

    /**
     * @var Performance
     *
     * @ORM\ManyToOne(targetEntity="Performance", inversedBy="performanceData")
     */
    private $performance;

    /**
     * @var \AppBundle\Entity\Location
     *
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Location")
     * @ORM\JoinColumn(name="location_id", referencedColumnName="id")
     */
    private $location;

    /**
     * @var ArrayCollection
     *
     * @ORM\ManyToMany(targetEntity="AppBundle\Entity\TicketType")
     * @ORM\JoinTable(name="performance_data_ticket_type",
     *   joinColumns={
     *     @ORM\JoinColumn(name="performance_data_id", referencedColumnName="id")
     *   },
     *   inverseJoinColumns={
     *     @ORM\JoinColumn(name="ticket_type_id", referencedColumnName="id")
     *   }
     * )
     */
    private $availableTicketTypes;

    //getters/setters...

    /**
     * @return string
     */
    public function getDisplayText()
    {
        return $this->getPerformance()->getInfoTitle() . ' - ' . strftime('%A %d %B %Y', $this->getDate()->getTimestamp());
    }
}
保留地

/**
 * Reservation
 *
 * @ORM\Table(name="reservation")
 * @ORM\Entity
 */
class Reservation
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var PerformanceData
     *
     * @ORM\ManyToOne(targetEntity="PerformanceData")
     * @ORM\JoinColumn(name="performance_data_id", referencedColumnName="id")
     */
    private $performanceData;

    /**
     * @var ArrayCollection
     *
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\ReservationTicket", mappedBy="reservation")
     */
    private $tickets;

    //getters/setters...
}
预订票

/**
 * ReservationTicket
 *
 * @ORM\Table(name="reservation_ticket")
 * @ORM\Entity
 */
class ReservationTicket
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var integer
     *
     * @ORM\Column(name="amount", type="smallint", nullable=false)
     */
    private $numberOfTickets;

    /**
     * @var Reservation
     *
     * @ORM\ManyToOne(targetEntity="Reservation", inversedBy="tickets")
     * @ORM\JoinColumn(name="reservation_id", referencedColumnName="id")
     */
    private $reservation;

    /**
     * @var \AppBundle\Entity\TicketType
     *
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\TicketType")
     * @ORM\JoinColumn(name="ticket_type_id", referencedColumnName="id")
     */
    private $ticketType;

    //getters/setters...
}
我的预订类型表

/**
 * Class ReservationType
 * @package AppBundle\Form
 */
class ReservationType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {


        $builder->add('performanceData', EntityType::class,
                array(
                    'label'         => 'Voorstelling',
                    'class'         => 'AppBundle:PerformanceData',
                    'query_builder' => function (EntityRepository $er) {
                        return $this->getOpenReservations($er);
                    },
                    'group_by'      => function ($performanceData) {
                        if ($performanceData instanceof PerformanceData &&
                            $performanceData->getPerformance() instanceof Performance
                        ) {
                            return $performanceData->getPerformance()->getInfoTitle();
                        }

                        return 'Andere voorstellingen';
                    },
                    'choice_label'  => 'displayText',
                    'required'      => true,
                )
            );

        //event listener for ticket types
        $formModifier = function (FormInterface $form, PerformanceData $performanceData = null) {
            $availableTicketTypes = array();
            $reservationTickets   = array();

            if ($performanceData instanceof PerformanceData) {
                $availableTicketTypes = $performanceData->getAvailableTicketTypes();
            }

            foreach ($availableTicketTypes as $availableTicketType) {
                $reservationTickets[] =  $availableTicketType->getDisplayText();

                $form->add('tickets', ChoiceType::class, array(
                    'label' => 'tickets',
                    'choices' => $reservationTickets,
                    'mapped' => false
                ));
            }
        };

        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (FormEvent $event) use ($formModifier) {
                // this would be your entity, i.e. SportMeetup
                $data = $event->getData();

                $formModifier($event->getForm(), $data->getPerformanceData(), $data);
            }
        );

        $builder->get('performanceData')->addEventListener(
            FormEvents::POST_SUBMIT,
            function (FormEvent $event) use ($formModifier) {
                // It's important here to fetch $event->getForm()->getData(), as
                // $event->getData() will get you the client data (that is, the ID)
                $performanceData = $event->getForm()->getData();

                // since we've added the listener to the child, we'll have to pass on
                // the parent to the callback functions!
                $formModifier($event->getForm()->getParent(), $performanceData);
            }
        );
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(
            array(
                'data_class' => Reservation::class
            )
        );
    }
}
谢谢

编辑:

我想我的问题有点模糊。这就是我想要实现的目标:

当用户选择性能数据时:

  • 加载所有可用的票证类型
  • 按可用票证类型:动态添加“数字”输入字段以添加票证数量
  • 将这些字段映射到预订实体中的票证
我有一个预订票实体:

/**
 * ReservationTicket
 *
 * @ORM\Table(name="reservation_ticket")
 * @ORM\Entity
 */
class ReservationTicket
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var integer
     *
     * @ORM\Column(name="amount", type="smallint", nullable=false)
     */
    private $numberOfTickets;

    /**
     * @var Reservation
     *
     * @ORM\ManyToOne(targetEntity="Reservation", inversedBy="tickets")
     * @ORM\JoinColumn(name="reservation_id", referencedColumnName="id")
     */
    private $reservation;

    /**
     * @var \AppBundle\Entity\TicketType
     *
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\TicketType")
     * @ORM\JoinColumn(name="ticket_type_id", referencedColumnName="id")
     */
    private $ticketType;

我认为问题在于预订应该与PerformanceData和TicketType(两者)相关联,因此您的实体预订应该具有这两个关联字段

然后您应该使用EntityType,并作为类使用您的实体。Symfony应自动生成选项列表:

e、 g

之后,你的表格上应该有2个选项。现在可以隐藏其中一个,如果有人从第一个选择列表中选择某个值,则可以显示第二个列表,其中包含过滤后的值


这应该会有帮助。

如果您想动态使用表单,您应该使用JavaScript。 正如您所知,Symfony是一个在服务器端工作的PHP框架。 从控制器一次创建一个表单。事件正在提交前或提交后调用。。。不是在客户端操作期间。 要做您想要做的事情,您必须使用js获取性能数据值,并将其发送(Ajax调用)给控制器,控制器将根据性能数据返回可用的票证。
您可以使用javascript在表单中显示可用的票证

Hi,感谢您的回答!我认为我的问题有点含糊(我的错误),所以我对它进行了编辑不客气。如果我的回答有帮助,你总是可以投赞成票;)当做
$builder->add('users', EntityType::class, array(
    'class' => 'AppBundle:User',
    'query_builder' => function (EntityRepository $er) {
        return $er->createQueryBuilder('u')
            ->orderBy('u.username', 'ASC');
    },
    'choice_label' => 'username',
));