src/Form/Website/Type/Contact/ContactType.php line 22

Open in your IDE?
  1. <?php
  2. namespace App\Form\Website\Type\Contact;
  3. use Symfony\Component\Form\AbstractType;
  4. use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
  5. use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
  6. use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
  7. use Symfony\Component\Form\Extension\Core\Type\EmailType;
  8. use Symfony\Component\Form\Extension\Core\Type\TelType;
  9. use Symfony\Component\Form\Extension\Core\Type\TextareaType;
  10. use Symfony\Component\Form\Extension\Core\Type\TextType;
  11. use Symfony\Component\Form\FormBuilderInterface;
  12. use Symfony\Component\Form\FormEvent;
  13. use Symfony\Component\Form\FormEvents;
  14. use Symfony\Component\OptionsResolver\OptionsResolver;
  15. use Symfony\Component\Validator\Constraints\Email;
  16. use Symfony\Component\Validator\Constraints\IsTrue;
  17. use Symfony\Component\Validator\Constraints\NotBlank;
  18. use Symfony\Component\Validator\Constraints\Regex;
  19. class ContactType extends AbstractType
  20. {
  21. public function buildForm(FormBuilderInterface $builder, array $options): void
  22. {
  23. $builder
  24. // Civilité - Radio buttons
  25. ->add('civility', ChoiceType::class, [
  26. 'label' => 'Civilité',
  27. 'required' => true,
  28. 'choices' => [
  29. 'M.' => 'M.',
  30. 'Mme' => 'Mme',
  31. ],
  32. 'expanded' => true,
  33. 'multiple' => false,
  34. 'constraints' => [
  35. new NotBlank([
  36. 'message' => 'Veuillez sélectionner une civilité.',
  37. ]),
  38. ],
  39. ])
  40. // Nom
  41. ->add('lastName', TextType::class, [
  42. 'label' => 'Nom',
  43. 'required' => true,
  44. 'attr' => [
  45. 'placeholder' => 'Nom',
  46. ],
  47. 'constraints' => [
  48. new NotBlank([
  49. 'message' => 'Le nom est obligatoire.',
  50. ]),
  51. ],
  52. ])
  53. // Prénom
  54. ->add('firstName', TextType::class, [
  55. 'label' => 'Prénom',
  56. 'required' => true,
  57. 'attr' => [
  58. 'placeholder' => 'Prénom',
  59. ],
  60. 'constraints' => [
  61. new NotBlank([
  62. 'message' => 'Le prénom est obligatoire.',
  63. ]),
  64. ],
  65. ])
  66. // Email
  67. ->add('email', EmailType::class, [
  68. 'label' => 'Email',
  69. 'required' => true,
  70. 'attr' => [
  71. 'placeholder' => 'email@exemple.fr',
  72. ],
  73. 'constraints' => [
  74. new NotBlank([
  75. 'message' => 'L\'adresse email est obligatoire.',
  76. ]),
  77. new Email([
  78. 'message' => 'Veuillez saisir une adresse email valide.',
  79. ]),
  80. ],
  81. ])
  82. // Téléphone
  83. ->add('phone', TelType::class, [
  84. 'label' => 'Téléphone',
  85. 'required' => true,
  86. 'attr' => [
  87. 'placeholder' => '+33',
  88. ],
  89. 'constraints' => [
  90. new NotBlank([
  91. 'message' => 'Le numéro de téléphone est obligatoire.',
  92. ]),
  93. // Le JS pré-remplit souvent le champ avec le préfixe pays (+33 ...).
  94. // On considère valide uniquement s'il y a assez de chiffres au-delà du préfixe.
  95. new Regex([
  96. 'pattern' => '/^\\+?[0-9][0-9\\s\\-\\(\\)]{8,}$/',
  97. 'message' => 'Veuillez saisir un numéro de téléphone valide.',
  98. ]),
  99. ],
  100. ])
  101. // Objet - Select
  102. ->add('subject', ChoiceType::class, [
  103. 'label' => 'Objet',
  104. 'required' => true,
  105. 'choices' => [
  106. 'Vous souhaitez faire une réservation, vous avez besoin, d\'un devis, d\'informations complémentaires' => 'reservation_info',
  107. 'Vous avez déjà une réservation, vous avez besoin d\'aide' => 'existing_reservation',
  108. 'Vous avez un projet de voyage en groupe, des questions, besoin d\'aide' => 'group_travel',
  109. 'Autres (précisez votre demande dans la partie message ci-dessous)' => 'other',
  110. ],
  111. 'placeholder' => 'Sélectionnez un objet',
  112. 'constraints' => [
  113. new NotBlank([
  114. 'message' => 'Veuillez sélectionner un objet.',
  115. ]),
  116. ],
  117. ])
  118. // Message - Textarea
  119. ->add('message', TextareaType::class, [
  120. 'label' => 'Message',
  121. 'required' => true,
  122. 'attr' => [
  123. 'placeholder' => 'Décrivez votre message',
  124. ],
  125. 'constraints' => [
  126. new NotBlank([
  127. 'message' => 'Le message est obligatoire.',
  128. ]),
  129. ],
  130. ])
  131. // Je souhaite être rappelé(e) - Radio buttons
  132. ->add('wantsCallback', ChoiceType::class, [
  133. 'label' => 'Je souhaite être rappelé(e)',
  134. 'required' => true,
  135. 'choices' => [
  136. 'Oui' => true,
  137. 'Non' => false,
  138. ],
  139. 'expanded' => true,
  140. 'multiple' => false,
  141. ])
  142. // Date et heure de rappel - Conditionnel
  143. ->add('callbackDateTime', DateTimeType::class, [
  144. 'label' => 'Date et heure de rappel',
  145. 'required' => false,
  146. 'widget' => 'single_text',
  147. 'html5' => false,
  148. 'format' => 'yyyy-MM-dd HH:mm',
  149. 'attr' => [
  150. 'class' => 'form-control callback-field flatpickr-datetime',
  151. 'data-flatpickr' => 'true',
  152. ],
  153. ])
  154. // Checkbox de consentement
  155. ->add('consent', CheckboxType::class, [
  156. 'label' => 'website.forms.contact.label.consent',
  157. 'required' => true,
  158. 'constraints' => [
  159. new IsTrue([
  160. 'message' => 'Vous devez accepter l\'exploitation de vos données.',
  161. ]),
  162. ],
  163. ]);
  164. $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
  165. $form = $event->getForm();
  166. $wantsCallback = $form->get('wantsCallback')->getData();
  167. if ($wantsCallback === null) {
  168. $form->get('wantsCallback')->addError(
  169. new \Symfony\Component\Form\FormError('Veuillez indiquer si vous souhaitez être rappelé(e).')
  170. );
  171. return;
  172. }
  173. $wantsCallbackYes = $wantsCallback === true
  174. || $wantsCallback === 1
  175. || $wantsCallback === '1'
  176. || $wantsCallback === 'true';
  177. if (!$wantsCallbackYes) {
  178. return;
  179. }
  180. $callbackDateTime = $form->get('callbackDateTime')->getData();
  181. if ($callbackDateTime === null || $callbackDateTime === '') {
  182. $form->get('callbackDateTime')->addError(
  183. new \Symfony\Component\Form\FormError('Veuillez sélectionner un créneau de rappel.')
  184. );
  185. }
  186. });
  187. }
  188. public function configureOptions(OptionsResolver $resolver): void
  189. {
  190. $resolver->setDefaults([
  191. 'csrf_protection' => true,
  192. ]);
  193. }
  194. }