I'm creating a form for ticket reservations for performances in symfony.
Every performance has multiple performance-data. In the db, the performanceData records contains stuff like a date, a location and a list of available ticket types. The available ticket types might differ per performanceData record.
When a user wants to make a reservation, he has to select a performance-data. Based on this selection, he should get a list with all available ticket types + per ticket type a (number)field to choose the number of tickets. This is where I'm stuck.
I used the symfony documentation to create a dynamic form to load the available ticket types in a dropdown based on the user's selection. But how do I add the list with the available ticket types + number fields? This list should be mapped with the 'tickets' in the Reservation entity.
My entities:
PerformanceData
/**
* 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
/**
* 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
/**
* 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...
}
My Reservation Type form
/**
* 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
)
);
}
}
Thanks!
EDIT:
My question was a bit vague I think. THis is what I want to achieve:
When a user selects a performance-data:
- Load all available ticket types
- Per available ticket type: dynamically add a 'number' input field to add the number of tickets.
- map these fields to tickets in the reservation entity
I have a reservationTicket entity:
/**
* 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;