Anonymous
Как я могу добавить одну «субперформу» для каждого дня в диапазоне
Сообщение
Anonymous » 28 авг 2025, 12:49
Я сейчас разрабатываю небольшую CRM для отеля, и я сталкиваюсь с проблемой с динамическими формами. В форме Roombooking пользователь предлагается выбрать дату начала и дату окончания бронирования. На данный момент я хочу показать своего рода подразформу, соответствующую завтраку. Я хочу одну из этих подформ для каждой ночи в диапазоне (например: если бронирование длится три ночи, я хочу три подчинка). < /P>
Я попытался использовать динамические формы, но я не смог отобразить какую-либо из форм ... < /p>
PrettyPrint-Override ">
Код: Выделить всё
class RoomBookingsType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('booking_date', DateType::class, [
'attr' => [
'id' => 'booking_date'
]
])
->add('start_date', DateType::class, [
'attr' => [
'id' => 'start_date'
]
])
->add('end_date', DateType::class, [
'attr' => [
'id' => 'end_date'
]
])
->add('client_name')
->add('client_email')
->add('client_phone')
->add('client_country', EntityType::class, [
'class' => Countries::class,
'placeholder' => 'Sélectionnez un pays', // optionnel
])
->add('nb_guest', IntegerType::class, [
'attr' => [
'min' => 1,
'value' => 1
]
])
->add('agency', ChoiceType::class, [
'choices' => [
'La Pèlerine' => 'La Pèlerine',
'La Balagère' => 'La Balagère',
'Follow the Camino' => 'Follow the Camino',
'La Rebène' => 'La Rebène',
'Via Compostella' => 'Via Compostella',
'Trekking Découverte' => 'Trekking Découverte',
'L\'Autre Chemin' => 'L\'Autre Chemin',
'Chemins de France' => 'Chemins de France',
'Sud Randos' => 'Sud Randos',
'S-Cape' => 'S-Cape',
'Grand Angle' => 'Grand Angle',
'Nature Occitane' => 'Nature Occitane',
'Autre' => 'Autre',
],
'placeholder' => 'Sélectionnez une agence', // optionnel
])
->add('booking_by', ChoiceType::class, [
'choices' => [
'Email' => 'Email',
'Téléphone' => 'Téléphone',
'Booking.com' => 'Booking.com',
'En personne' => 'En personne',
'Autre' => 'Autre',
],
'placeholder' => 'Sélectionnez un moyen de réservation', // optionnel
])
->add('payment_method', ChoiceType::class, [
'choices' => [
'Carte' => 'Carte',
'Espèces' => 'Espèces',
'Chèque' => 'Chèque',
'ANCV' => 'ANCV',
'Amex' => 'Amex',
'Virement' => 'Virement',
'Autre' => 'Autre',
],
'placeholder' => 'Sélectionnez une moyen de paiement', // optionnel
])
->add('paid')
->add('comment')
->add('nb_dinner', IntegerType::class, [
'attr' => [
'min' => 0,
'value' => 0
]
])
->add('nb_breakfast', IntegerType::class, [
'attr' => [
'min' => 0,
'value' => 0
]
])
->add('children')
->add('dog')
->add('room', EntityType::class, [
'class' => Rooms::class,
'placeholder' => 'Sélectionnez une chambre', // optionnel
])
;
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event): void {
$form = $event->getForm();
// this would be your entity, i.e. SportMeetup
$data = $event->getData();
$startDate = $data->getStartDate();
$endDate = $data->getEndDate();
$duration = round(($endDate - $startDate) / (60 * 60 * 24));
// ??? what do I do ???
}
);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => RoomBookings::class,
]);
}
}
< /code>
myrabrakingstype: < /p>
class BreakfastsType extends AbstractType
{
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Breakfasts::class,
]);
}
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('date', DateType::class, [
'widget' => 'single_text',
'disabled' => true,
])
->add('isTaken', CheckboxType::class, [
'required' => false,
'mapped' => false,
])
->add('nbGuest', IntegerType::class, [
'required' => true,
])
->add('comment', TextareaType::class, [
'required' => false,
]);
}
}
< /code>
Мой маршрут в комнате в комнате#[Route('/ajouter', name: 'app_room_bookings_new', methods: ['GET', 'POST'])]
public function new(Request $request, EntityManagerInterface $entityManager): Response
{
$roomBooking = new RoomBookings();
$form = $this->createForm(RoomBookingsType::class, $roomBooking);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager->persist($roomBooking);
$entityManager->flush();
return $this->redirectToRoute('app_room_bookings_index', [], Response::HTTP_SEE_OTHER);
}
return $this->render('room_bookings/new.html.twig', [
'room_booking' => $roomBooking,
'form' => $form,
]);
}
< /code>
Вот моя основная форма (Roombookings) < /p>
{{ form_start(form, {'attr': {'class': 'w-full'}}) }}
Chambre
{# Chambre associée (select) #}
Chambre
{{ form_widget(form.room, {
'attr': {'class': 'appearance-none form-select-input'}
}) }}
{{ form_errors(form.room) }}
{# Nombre de personnes #}
Nombre de personnes
{{ form_widget(form.nb_guest, {
'attr': {'class': 'appearance-none form-text-input', 'min': 1, 'max': 5}
}) }}
{{ form_errors(form.nb_guest) }}
Dates
{# Date d'arrivée #}
Date d'arrivée*
{{ form_widget(form.start_date, {
'attr': {'class': 'form-text-input'}
}) }}
{{ form_errors(form.start_date) }}
{# Date de départ #}
Date de départ*
{{ form_widget(form.end_date, {
'attr': {'class': 'form-text-input'}
}) }}
{{ form_errors(form.end_date) }}
class="form-input-container">
{# Date de réservation #}
Date de réservation*
{{ form_widget(form.booking_date, {
'attr': {'class': 'form-text-input'}
}) }}
{{ form_errors(form.booking_date) }}
Informations client
{# Nom du client #}
Nom du client*
{{ form_widget(form.client_name, {
'attr': {'class': 'form-text-input', 'placeholder':'ex: Jean Dupont'}
}) }}
{{ form_errors(form.client_name) }}
{# Nationalité du client #}
Nationalité*
{{ form_widget(form.client_country, {
'attr': {'class': 'appearance-none form-select-input'}
}) }}
{{ form_errors(form.client_country) }}
{# Telephone du client #}
Téléphone*
{{ form_widget(form.client_phone, {
'attr': {'class': 'form-text-input', 'placeholder':'ex: (+33) 06578329'}
}) }}
{{ form_errors(form.client_phone) }}
{# Email du client #}
Email*
{{ form_widget(form.client_email, {
'attr': {'class': 'form-text-input', 'placeholder':'ex: myEmail@mail.com'}
}) }}
{{ form_errors(form.client_email) }}
Détails réservation
{# Agence #}
Agence
{{ form_widget(form.agency, {
'attr': {'class': 'appearance-none form-select-input'}
}) }}
{{ form_errors(form.agency) }}
{# Réservé par #}
Réservé par
{{ form_widget(form.booking_by, {
'attr': {'class': 'appearance-none form-select-input'}
}) }}
{{ form_errors(form.booking_by) }}
{# Méthode de paiement #}
Méthode de paiement
{{ form_widget(form.payment_method, {
'attr': {'class': 'appearance-none form-select-input'}
}) }}
{{ form_errors(form.payment_method) }}
{# Payé (checkbox) #}
Payé
{{ form_widget(form.paid, {
'attr': {'class': 'h-4 w-4 text-orange-600 border-gray-300 rounded'}
}) }}
{{ form_errors(form.paid) }}
{# Nombre de petits-déjeuners #}
Nombre de petits-déjeuners prévus
{{ form_widget(form.nb_breakfast, {
'attr': {'class': 'form-text-input', 'min': 0}
}) }}
{{ form_errors(form.nb_breakfast) }}
{# Nombre de dîners prévu#}
Nombre de dîners prévus
{{ form_widget(form.nb_dinner, {
'attr': {'class': 'form-text-input', 'min': 0}
}) }}
{{ form_errors(form.nb_dinner) }}
{# Enfants (checkbox) #}
Enfant(s)
{{ form_widget(form.children, {
'attr': {'class': 'h-4 w-4 text-orange-600 border-gray-300 rounded'}
}) }}
{{ form_errors(form.children) }}
{# Chien (checkbox) #}
Chien(s)
{{ form_widget(form.dog, {
'attr': {'class': 'h-4 w-4 text-orange-600 border-gray-300 rounded'}
}) }}
{{ form_errors(form.dog) }}
{# Champ Commentaire #}
Commentaire
{{ form_widget(form.comment, {
'attr': {'class': 'form-description-input', 'placeholder':'Notes supplémentaires'}
}) }}
{{ form_errors(form.comment) }}
{# Boutons #}
[url={{ path(]
Retour à la liste
[/url]
{{ button_label|default('Enregistrer') }}
{{ form_end(form) }}
< /code>
и форма завтрака (предположим, дублировать для каждой ночи < /p>
{% for breakfastForm in form.breakfasts %}
{{ form_row(breakfastForm.date) }}
{{ form_row(breakfastForm.isTaken) }}
{{ form_row(breakfastForm.number) }}
{% endfor %}
{% for breakfastForm in form.breakfasts %}
{{ form_row(breakfastForm.date) }}
{{ form_row(breakfastForm.isTaken) }}
{{ form_row(breakfastForm.number) }}
{% endfor %}
Я в основном пробовал решение, найденное в различных учебных пособиях, найденных в Интернете, но ничего не соответствовало моим ожиданиям ...
Подробнее здесь:
https://stackoverflow.com/questions/797 ... in-a-range
1756374553
Anonymous
Я сейчас разрабатываю небольшую CRM для отеля, и я сталкиваюсь с проблемой с динамическими формами. В форме Roombooking пользователь предлагается выбрать дату начала и дату окончания бронирования. На данный момент я хочу показать своего рода подразформу, соответствующую завтраку. Я хочу одну из этих подформ для каждой ночи в диапазоне (например: если бронирование длится три ночи, я хочу три подчинка). < /P> Я попытался использовать динамические формы, но я не смог отобразить какую-либо из форм ... < /p> PrettyPrint-Override ">[code]class RoomBookingsType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options): void { $builder ->add('booking_date', DateType::class, [ 'attr' => [ 'id' => 'booking_date' ] ]) ->add('start_date', DateType::class, [ 'attr' => [ 'id' => 'start_date' ] ]) ->add('end_date', DateType::class, [ 'attr' => [ 'id' => 'end_date' ] ]) ->add('client_name') ->add('client_email') ->add('client_phone') ->add('client_country', EntityType::class, [ 'class' => Countries::class, 'placeholder' => 'Sélectionnez un pays', // optionnel ]) ->add('nb_guest', IntegerType::class, [ 'attr' => [ 'min' => 1, 'value' => 1 ] ]) ->add('agency', ChoiceType::class, [ 'choices' => [ 'La Pèlerine' => 'La Pèlerine', 'La Balagère' => 'La Balagère', 'Follow the Camino' => 'Follow the Camino', 'La Rebène' => 'La Rebène', 'Via Compostella' => 'Via Compostella', 'Trekking Découverte' => 'Trekking Découverte', 'L\'Autre Chemin' => 'L\'Autre Chemin', 'Chemins de France' => 'Chemins de France', 'Sud Randos' => 'Sud Randos', 'S-Cape' => 'S-Cape', 'Grand Angle' => 'Grand Angle', 'Nature Occitane' => 'Nature Occitane', 'Autre' => 'Autre', ], 'placeholder' => 'Sélectionnez une agence', // optionnel ]) ->add('booking_by', ChoiceType::class, [ 'choices' => [ 'Email' => 'Email', 'Téléphone' => 'Téléphone', 'Booking.com' => 'Booking.com', 'En personne' => 'En personne', 'Autre' => 'Autre', ], 'placeholder' => 'Sélectionnez un moyen de réservation', // optionnel ]) ->add('payment_method', ChoiceType::class, [ 'choices' => [ 'Carte' => 'Carte', 'Espèces' => 'Espèces', 'Chèque' => 'Chèque', 'ANCV' => 'ANCV', 'Amex' => 'Amex', 'Virement' => 'Virement', 'Autre' => 'Autre', ], 'placeholder' => 'Sélectionnez une moyen de paiement', // optionnel ]) ->add('paid') ->add('comment') ->add('nb_dinner', IntegerType::class, [ 'attr' => [ 'min' => 0, 'value' => 0 ] ]) ->add('nb_breakfast', IntegerType::class, [ 'attr' => [ 'min' => 0, 'value' => 0 ] ]) ->add('children') ->add('dog') ->add('room', EntityType::class, [ 'class' => Rooms::class, 'placeholder' => 'Sélectionnez une chambre', // optionnel ]) ; $builder->addEventListener( FormEvents::PRE_SET_DATA, function (FormEvent $event): void { $form = $event->getForm(); // this would be your entity, i.e. SportMeetup $data = $event->getData(); $startDate = $data->getStartDate(); $endDate = $data->getEndDate(); $duration = round(($endDate - $startDate) / (60 * 60 * 24)); // ??? what do I do ??? } ); } public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'data_class' => RoomBookings::class, ]); } } < /code> myrabrakingstype: < /p> class BreakfastsType extends AbstractType { public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'data_class' => Breakfasts::class, ]); } public function buildForm(FormBuilderInterface $builder, array $options): void { $builder ->add('date', DateType::class, [ 'widget' => 'single_text', 'disabled' => true, ]) ->add('isTaken', CheckboxType::class, [ 'required' => false, 'mapped' => false, ]) ->add('nbGuest', IntegerType::class, [ 'required' => true, ]) ->add('comment', TextareaType::class, [ 'required' => false, ]); } } < /code> Мой маршрут в комнате в комнате#[Route('/ajouter', name: 'app_room_bookings_new', methods: ['GET', 'POST'])] public function new(Request $request, EntityManagerInterface $entityManager): Response { $roomBooking = new RoomBookings(); $form = $this->createForm(RoomBookingsType::class, $roomBooking); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $entityManager->persist($roomBooking); $entityManager->flush(); return $this->redirectToRoute('app_room_bookings_index', [], Response::HTTP_SEE_OTHER); } return $this->render('room_bookings/new.html.twig', [ 'room_booking' => $roomBooking, 'form' => $form, ]); } < /code> Вот моя основная форма (Roombookings) < /p> {{ form_start(form, {'attr': {'class': 'w-full'}}) }} Chambre {# Chambre associée (select) #} Chambre {{ form_widget(form.room, { 'attr': {'class': 'appearance-none form-select-input'} }) }} {{ form_errors(form.room) }} {# Nombre de personnes #} Nombre de personnes {{ form_widget(form.nb_guest, { 'attr': {'class': 'appearance-none form-text-input', 'min': 1, 'max': 5} }) }} {{ form_errors(form.nb_guest) }} Dates {# Date d'arrivée #} Date d'arrivée* {{ form_widget(form.start_date, { 'attr': {'class': 'form-text-input'} }) }} {{ form_errors(form.start_date) }} {# Date de départ #} Date de départ* {{ form_widget(form.end_date, { 'attr': {'class': 'form-text-input'} }) }} {{ form_errors(form.end_date) }} class="form-input-container"> {# Date de réservation #} Date de réservation* {{ form_widget(form.booking_date, { 'attr': {'class': 'form-text-input'} }) }} {{ form_errors(form.booking_date) }} Informations client {# Nom du client #} Nom du client* {{ form_widget(form.client_name, { 'attr': {'class': 'form-text-input', 'placeholder':'ex: Jean Dupont'} }) }} {{ form_errors(form.client_name) }} {# Nationalité du client #} Nationalité* {{ form_widget(form.client_country, { 'attr': {'class': 'appearance-none form-select-input'} }) }} {{ form_errors(form.client_country) }} {# Telephone du client #} Téléphone* {{ form_widget(form.client_phone, { 'attr': {'class': 'form-text-input', 'placeholder':'ex: (+33) 06578329'} }) }} {{ form_errors(form.client_phone) }} {# Email du client #} Email* {{ form_widget(form.client_email, { 'attr': {'class': 'form-text-input', 'placeholder':'ex: myEmail@mail.com'} }) }} {{ form_errors(form.client_email) }} Détails réservation {# Agence #} Agence {{ form_widget(form.agency, { 'attr': {'class': 'appearance-none form-select-input'} }) }} {{ form_errors(form.agency) }} {# Réservé par #} Réservé par {{ form_widget(form.booking_by, { 'attr': {'class': 'appearance-none form-select-input'} }) }} {{ form_errors(form.booking_by) }} {# Méthode de paiement #} Méthode de paiement {{ form_widget(form.payment_method, { 'attr': {'class': 'appearance-none form-select-input'} }) }} {{ form_errors(form.payment_method) }} {# Payé (checkbox) #} Payé {{ form_widget(form.paid, { 'attr': {'class': 'h-4 w-4 text-orange-600 border-gray-300 rounded'} }) }} {{ form_errors(form.paid) }} {# Nombre de petits-déjeuners #} Nombre de petits-déjeuners prévus {{ form_widget(form.nb_breakfast, { 'attr': {'class': 'form-text-input', 'min': 0} }) }} {{ form_errors(form.nb_breakfast) }} {# Nombre de dîners prévu#} Nombre de dîners prévus {{ form_widget(form.nb_dinner, { 'attr': {'class': 'form-text-input', 'min': 0} }) }} {{ form_errors(form.nb_dinner) }} {# Enfants (checkbox) #} Enfant(s) {{ form_widget(form.children, { 'attr': {'class': 'h-4 w-4 text-orange-600 border-gray-300 rounded'} }) }} {{ form_errors(form.children) }} {# Chien (checkbox) #} Chien(s) {{ form_widget(form.dog, { 'attr': {'class': 'h-4 w-4 text-orange-600 border-gray-300 rounded'} }) }} {{ form_errors(form.dog) }} {# Champ Commentaire #} Commentaire {{ form_widget(form.comment, { 'attr': {'class': 'form-description-input', 'placeholder':'Notes supplémentaires'} }) }} {{ form_errors(form.comment) }} {# Boutons #} [url={{ path(] Retour à la liste [/url] {{ button_label|default('Enregistrer') }} {{ form_end(form) }} < /code> и форма завтрака (предположим, дублировать для каждой ночи < /p> {% for breakfastForm in form.breakfasts %} {{ form_row(breakfastForm.date) }} {{ form_row(breakfastForm.isTaken) }} {{ form_row(breakfastForm.number) }} {% endfor %} {% for breakfastForm in form.breakfasts %} {{ form_row(breakfastForm.date) }} {{ form_row(breakfastForm.isTaken) }} {{ form_row(breakfastForm.number) }} {% endfor %} [/code] Я в основном пробовал решение, найденное в различных учебных пособиях, найденных в Интернете, но ничего не соответствовало моим ожиданиям ... Подробнее здесь: [url]https://stackoverflow.com/questions/79743946/how-can-i-add-one-subform-for-each-day-within-a-range[/url]