src/Form/DevisType.php line 29

Open in your IDE?
  1. <?php
  2. namespace App\Form;
  3. use App\Entity\{DevisDevisTravelReasonDevisLuggageDevisEquipmentDevisBudget};
  4. use Symfony\Component\Form\AbstractType;
  5. use Symfony\Bridge\Doctrine\Form\Type\EntityType;
  6. use Symfony\Component\Form\Extension\Core\Type\TextType;
  7. use Symfony\Component\Validator\Constraints\Callback;
  8. use Symfony\Component\Form\Extension\Core\Type\DateType;
  9. use Symfony\Component\Form\Extension\Core\Type\TimeType;
  10. use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
  11. use Symfony\Component\Form\Extension\Core\Type\NumberType;
  12. use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
  13. use Symfony\Component\Form\Extension\Core\Type\TextareaType;
  14. use Symfony\Component\Form\Extension\Core\Type\CollectionType;
  15. use Symfony\Component\Form\FormBuilderInterface;
  16. use Symfony\Component\Form\FormEvents
  17. use Symfony\Component\Form\FormEvent;
  18. use Symfony\Component\Form\FormError;
  19. use Symfony\Component\OptionsResolver\OptionsResolver;
  20. use Doctrine\ORM\EntityRepository;
  21. use Symfony\Component\Validator\Constraints\NotBlank;
  22. use Symfony\Component\Validator\Constraints\Length;
  23. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  24. use Symfony\Component\Validator\Context\ExecutionContextInterface;
  25. class DevisType extends AbstractType
  26. {
  27.     private $session;
  28.     public function __construct(SessionInterface $session)
  29.     {
  30.         $this->session $session;
  31.     }
  32.     public function buildForm(FormBuilderInterface $builder, array $options): void
  33.     {
  34.         $previousTypeOfTrip $this->session->get('typeOfTrip''Aller simple'); 
  35.         $previousNeedVehicleOnSite $this->session->get('needVehicleOnSite''Non'); 
  36.         $previousAddPdfDocument $this->session->get('addPdfDocument''Non'); 
  37.         if ($options['step'] === 'step1') {
  38.             $builder
  39.                 ->add('typeOfTrip'ChoiceType::class, [
  40.                     'label' => false,
  41.                     'choices' => [
  42.                         'Aller simple' => 'Aller simple',
  43.                         'Aller-Retour' => 'Aller-Retour',
  44.                         'Séjours' => 'Séjours'
  45.                     ],
  46.                     'expanded' => true,
  47.                     'multiple' => false,
  48.                     'required' => true,
  49.                     'data' => $previousTypeOfTrip ?: 'Aller simple',              
  50.                     'constraints' => [
  51.                         new NotBlank([
  52.                             'message' => 'Veuillez sélectionner un type de trajet !',
  53.                         ]),
  54.                     ] 
  55.                 ])
  56.                 ->add('departureAddress'TextType::class, [
  57.                     'label' => '<i class="fal fa-map-marker-alt"></i> Lieu de départ',
  58.                     'label_html' => true,
  59.                     'constraints' => [
  60.                         new NotBlank([
  61.                             'message' => 'Veuillez entrer votre lieu de départ !',
  62.                         ]),
  63.                         new Length([
  64.                             'min' => 3,
  65.                             'minMessage' => 'Lieu départ doit avoir au moins {{ limit }} caractères.',
  66.                         ]),
  67.                     ],
  68.                     'attr' => [
  69.                         'placeholder' => 'Choisissez votre adresse de départ',
  70.                         'autocomplete' => 'off',
  71.                         'class' => 'autocomplete-input'
  72.                     ],
  73.                     'required' => true
  74.                 ])
  75.                 ->add('arrivalAddress'TextType::class, [
  76.                     'label' => '<i class="fal fa-map-marker-alt"></i> Lieu d\'arrivée',
  77.                     'label_html' => true,
  78.                     'constraints' => [
  79.                         new NotBlank([
  80.                             'message' => 'Veuillez entrer votre lieu d\'arrivée !',
  81.                         ]),
  82.                         new Length([
  83.                             'min' => 3,
  84.                             'minMessage' => 'Lieu d\'arrivée doit avoir au moins {{ limit }} caractères.',
  85.                         ]),
  86.                     ],
  87.                     'attr' => [
  88.                         'placeholder' => 'Choisissez votre adresse d\'arrivée',
  89.                         'autocomplete' => 'off',
  90.                         'class' => 'autocomplete-input'
  91.                     ],
  92.                     'required' => true
  93.                 ])
  94.                 ->add('departureDate'DateType::class, [
  95.                     'label' => '<i class="fal fa-calendar-check"></i> Date de départ',
  96.                     'label_html' => true,
  97.                     'widget' => 'single_text',
  98.                     'html5' => false,
  99.                     'format' => 'dd-MM-yyyy',
  100.                     'attr' => [
  101.                         'class' => 'flatpickr-devis-depart',
  102.                         'placeholder' => 'jj-mm-aaaa',
  103.                         'readonly' => true
  104.                     ],
  105.                     'required' => true,
  106.                     'constraints' => [
  107.                         new NotBlank([
  108.                             'message' => 'Veuillez entrer votre date de départ !',
  109.                         ])
  110.                     ]
  111.                 ])
  112.                 ->add('returnDate'DateType::class, [
  113.                     'label' => '<i class="fal fa-calendar-check"></i> Date de retour',
  114.                     'label_html' => true,
  115.                     'widget' => 'single_text',
  116.                     'html5' => false,
  117.                     'format' => 'dd-MM-yyyy',
  118.                     'attr' => [
  119.                         'class' => 'flatpickr-devis-retour',
  120.                         'placeholder' => 'jj-mm-aaaa',
  121.                         'readonly' => true
  122.                     ],
  123.                     'required' => false,
  124.                     'constraints' => [
  125.                         new Callback(function ($valueExecutionContextInterface $context) {
  126.                             $form $context->getRoot(); 
  127.                             $typeOfTrip $form->get('typeOfTrip')->getData(); 
  128.                             $departureDate $form->get('departureDate')->getData();
  129.                             if (in_array($typeOfTrip, ['Séjours']) && empty($value)) {
  130.                                 $context->buildViolation('Veuillez entrer votre date de retour !')
  131.                                     ->atPath('returnDate'
  132.                                     ->addViolation();
  133.                             }
  134.                             if (!empty($value) && $departureDate && $value $departureDate) {
  135.                                 $context->buildViolation('La date de retour doit être postérieure à la date de départ.')
  136.                                     ->atPath('returnDate')
  137.                                     ->addViolation();
  138.                             }
  139.                         }),
  140.                     ],
  141.                 ])
  142.                 ->add('departureTime'TimeType::class, [
  143.                     'label' => '<i class="fal fa-clock"></i> Heure de départ',
  144.                     'label_html' => true,
  145.                     'input' => 'datetime',
  146.                     'widget' => 'single_text',
  147.                     'constraints' => [
  148.                         new NotBlank([
  149.                             'message' => 'Veuillez entrer votre heure de départ !',
  150.                         ]),
  151.                     ],
  152.                     'html5' => false,
  153.                     'attr' => [
  154.                         'class' => 'flatpickr-devis-depart-time',
  155.                         'placeholder' => 'hh:mm',
  156.                         'readonly' => true
  157.                     ],
  158.                     'required' => true
  159.                 ])
  160.                 ->add('returnTime'TimeType::class, [
  161.                     'label' => '<i class="fal fa-clock"></i> Heure de retour',
  162.                     'label_html' => true,
  163.                     'input' => 'datetime',
  164.                     'widget' => 'single_text',
  165.                     'html5' => false,
  166.                     'attr' => [
  167.                         'class' => 'flatpickr-devis-retour-time',
  168.                         'placeholder' => 'hh:mm',
  169.                         'readonly' => true
  170.                     ],
  171.                     'required' => false,
  172.                     'constraints' => [
  173.                         new Callback(function ($valueExecutionContextInterface $context) {
  174.                             $form $context->getRoot(); 
  175.                             $typeOfTrip $form->get('typeOfTrip')->getData(); 
  176.                             $departureTime $form->get('departureTime')->getData();
  177.                             $departureDate $form->get('departureDate')->getData();
  178.                             $returnDate $form->get('returnDate')->getData();
  179.                             if (in_array($typeOfTrip, ['Aller-Retour''Séjours']) && empty($value)) {
  180.                                 $context->buildViolation('Veuillez entrer votre heure de retour !')
  181.                                     ->atPath('returnTime'
  182.                                     ->addViolation();
  183.                             }
  184.                             if (!empty($value)) {
  185.                                 if ($returnDate == $departureDate || empty($returnDate)) {
  186.                                     if ($value <= $departureTime) {
  187.                                         $context->buildViolation('L\'heure de retour doit être après l\'heure de départ.')
  188.                                             ->atPath('returnTime')
  189.                                             ->addViolation();
  190.                                     }
  191.                                 }
  192.                             }
  193.                         }),
  194.                     ],
  195.                 ])            
  196.                 ->add('numberOfPeople'NumberType::class, [
  197.                     'label' => 'Total passagers, enfants compris',
  198.                     'attr' => [
  199.                         'pattern' => '[0-9]+'// + pour indiquer un ou plusieurs chiffres
  200.                         'min' => 1,
  201.                         'step' => 1
  202.                     ],
  203.                     'data' => 1,
  204.                     'constraints' => [
  205.                         new NotBlank([
  206.                             'message' => 'Veuillez indiquer le nombre de passagers !',
  207.                         ])
  208.                     ],
  209.                     'required' => true,
  210.                     'html5' => true,
  211.                     'data' => $options['data']->getNumberOfPeople() ?? 1
  212.                 ])
  213.             ;
  214.         }
  215.         if ($options['step'] === 'step2') {
  216.             $builder
  217.                 ->add('needVehicleOnSite'ChoiceType::class, [
  218.                     'label' => 'Une fois sur place avez vous besoin du véhicule?',
  219.                     'choices' => [
  220.                         'Oui' => 'Oui',
  221.                         'Non' => 'Non'
  222.                     ],
  223.                     'expanded' => true,
  224.                     'multiple' => false,
  225.                     // 'required' => false,
  226.                     'data' => $previousNeedVehicleOnSite ?: 'Non',  
  227.                     'constraints' => [
  228.                         new Callback(function ($valueExecutionContextInterface $context) use ($options) {
  229.                             $form $context->getRoot(); 
  230.                             $typeOfTrip $form->getData()->getTypeOfTrip(); 
  231.                             $vehicleDetails $form->getData()->getVehicleDetails();
  232.                             if (in_array($typeOfTrip, ['Aller-Retour''Séjours'])) {
  233.                                 if ($value === 'Oui' && count($vehicleDetails) === 0) {
  234.                                     $context->buildViolation('Veuillez indiquer si vous avez besoin d\'un véhicule sur place !')
  235.                                         ->atPath('vehicleDetails')
  236.                                         ->addViolation();
  237.                                 }
  238.                     
  239.                                 if (empty($value)) {
  240.                                     $context->buildViolation('Veuillez sélectionner OUI ou NON avant de continuer !')
  241.                                         ->atPath('needVehicleOnSite')
  242.                                         ->addViolation();
  243.                                 }
  244.                             }
  245.                         }),
  246.                     ],      
  247.                 ])
  248.                 ->add('vehicleDetails'CollectionType::class, [
  249.                     'entry_type' => DevisVehicleDetatilsType::class,
  250.                     'entry_options' => [
  251.                         'label' => false,
  252.                         'add_delete' => true
  253.                     ],
  254.                     'allow_add' => true,
  255.                     'allow_delete' => true,
  256.                     'prototype' => true,
  257.                     'by_reference' => false,
  258.                     'required' => false
  259.                 ])   
  260.                 ->add('addPdfDocument'ChoiceType::class, [
  261.                     'label' => 'Voulez vous ajouter un document en PDF?',
  262.                     'choices' => [
  263.                         'Oui' => 'Oui',
  264.                         'Non' => 'Non'
  265.                     ],
  266.                     'expanded' => true,
  267.                     'multiple' => false,
  268.                     'data' => $previousAddPdfDocument ?: 'Non',  
  269.                     'constraints' => [
  270.                         new Callback(function ($valueExecutionContextInterface $context) use ($options) {
  271.                             $form $context->getRoot(); 
  272.                             $typeOfTrip $form->getData()->getTypeOfTrip(); 
  273.                             $attachments $form->getData()->getAttachments();
  274.                             if (in_array($typeOfTrip, ['Aller-Retour''Séjours'])) {
  275.                                 if ($value === 'Oui' && count($attachments) === 0) {
  276.                                     $context->buildViolation('Vous devez ajouter au moins l\'un de ces documents : PDF, JPEG, JPG, PNG.')
  277.                                         ->atPath('attachments')
  278.                                         ->addViolation();
  279.                                 }
  280.                     
  281.                                 if (empty($value)) {
  282.                                     $context->buildViolation('Veuillez sélectionner OUI ou NON avant de continuer !')
  283.                                         ->atPath('addPdfDocument')
  284.                                         ->addViolation();
  285.                                 }
  286.                             }
  287.                         })
  288.                     ]
  289.                 ])
  290.                 ->add('attachments'CollectionType::class, [
  291.                     'entry_type' => DevisAttachmentType::class,
  292.                     'entry_options' => [
  293.                         'label' => false,
  294.                         'add_delete' => true
  295.                     ],
  296.                     'allow_add' => true,
  297.                     'allow_delete' => true,
  298.                     'by_reference' => false
  299.                     'required' => false
  300.                 ])
  301.                 ->add('devisTravelReason'EntityType::class, [
  302.                     'label' => 'Motif de déplacement',
  303.                     'attr' => [
  304.                         'class' => 'chosen-select no-search-select pl-3 mb-0',
  305.                     ],
  306.                     'placeholder' => 'Sélectionner',
  307.                     'class' => devisTravelReason::class,
  308.                     'choice_label' => function (devisTravelReason $motif) {
  309.                         return $motif->getName();
  310.                     },
  311.                     'query_builder' => function (EntityRepository $er) {
  312.                         return $er->createQueryBuilder('dt')
  313.                                 ->orderBy('dt.id''DESC');
  314.                     },
  315.                     'constraints' => [
  316.                         new NotBlank([
  317.                             'message' => 'Veuillez sélectionner un motif de déplacement !',
  318.                         ])
  319.                     ],
  320.                     'required' => true
  321.                 ])
  322.                 ->add('devisLuggage'EntityType::class, [
  323.                     'label' => 'Bagages',
  324.                     'attr' => [
  325.                         'class' => 'chosen-select no-search-select pl-3 mb-0',
  326.                     ],
  327.                     'placeholder' => 'Sélectionner',
  328.                     'class' => DevisLuggage::class,
  329.                     'choice_label' => function (DevisLuggage $bagage) {
  330.                         return $bagage->getName();
  331.                     },
  332.                     'query_builder' => function (EntityRepository $er) {
  333.                         return $er->createQueryBuilder('dl')
  334.                                 ->orderBy('dl.id''DESC');
  335.                     },
  336.                     'constraints' => [
  337.                         new NotBlank([
  338.                             'message' => 'Veuillez indiquer vos bagages !',
  339.                         ])
  340.                     ],
  341.                     'required' => true
  342.                 ])
  343.                 ->add('infos'TextareaType::class, [
  344.                     'label' => 'Avez-vous d\'autres informations à transmettre aux transporteurs?',
  345.                     'attr' => [
  346.                         'class' => 'form-control',
  347.                         'cols' => '40',
  348.                         'rows' => '5',
  349.                         'maxlength' => '1000',
  350.                         'placeholder' => 'Ne pas indiquer de coordonnées personnelles (e-mail, téléphone, nom, prénom, ...)'
  351.                     ],
  352.                     'constraints' => [
  353.                         new Length([
  354.                             'max' => 1000,
  355.                             'maxMessage' => 'Votre information ne doit pas dépasser {{ limit }} caractères.',
  356.                         ]),
  357.                     ],
  358.                     'required' => false
  359.                 ])
  360.                 ->add('devisBudget'EntityType::class, [
  361.                     'label' => 'Avez-vous une idée du budget que vous souhaitez consacrer à ce voyage?',
  362.                     'attr' => [
  363.                         'class' => 'chosen-select no-search-select pl-3 mb-0',
  364.                     ],
  365.                     'placeholder' => 'Sélectionner',
  366.                     'class' => DevisBudget::class,
  367.                     'choice_label' => function (DevisBudget $budget) {
  368.                         return $budget->getName();
  369.                     },
  370.                     'query_builder' => function (EntityRepository $er) {
  371.                         return $er->createQueryBuilder('db')
  372.                                 ->orderBy('db.id''DESC');
  373.                     },
  374.                     'constraints' => [
  375.                         new NotBlank([
  376.                             'message' => 'Veuillez indiquer un budget !',
  377.                         ])
  378.                     ],
  379.                     'required' => true
  380.                 ])
  381.                 ->add('devisEquipment'EntityType::class, [
  382.                     'label' => 'Equipement spécifique indispensable?',
  383.                     'class' => DevisEquipment::class,
  384.                     'choice_label' => 'name',
  385.                     'multiple' => true,
  386.                     'expanded' => true,
  387.                     'required' => false,
  388.                     'query_builder' => function (EntityRepository $er) {
  389.                         return $er->createQueryBuilder('de')
  390.                                 ->orderBy('de.id''DESC');
  391.                     },
  392.                 ])
  393.             ;
  394.         }
  395.         if ($options['step'] === 'step3') {
  396.             $builder
  397.                 ->add('miseEnAvance'CheckboxType::class, [
  398.                     'label' => 'Mise en avant de votre demande : 6 Crédits'
  399.                     'required' => false,        
  400.                     'attr' => ['class' => 'checkbox'], 
  401.                 ])
  402.                 ->add('remonteEnTeteDeListe'CheckboxType::class, [
  403.                     'label' => 'Remonter en tête de liste tout les jours : 8 Crédits',
  404.                     'required' => false,
  405.                     'attr' => ['class' => 'checkbox'],
  406.                 ])
  407.                 ->add('demandeUrgente'CheckboxType::class, [
  408.                     'label' => 'Logo demande urgente : 3 Crédits',
  409.                     'required' => false,
  410.                     'attr' => ['class' => 'checkbox'],
  411.                 ])
  412.             ;
  413.         }
  414.     }
  415.     public function configureOptions(OptionsResolver $resolver): void
  416.     {
  417.         $resolver->setDefaults([
  418.             'data_class' => Devis::class,
  419.             'step' => 'step1'
  420.         ]);
  421.     }
  422.     public function getBlockPrefix()
  423.     {
  424.         return 'sg_devis';
  425.     }
  426. }