src/Admin/ProgrammeAdmin.php line 39

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Admin;
  4. use App\Entity\Lot;
  5. use App\Admin\LotAdmin;
  6. use App\Entity\Documents;
  7. use App\Form\BlockType;
  8. use App\Form\ImageType;
  9. use App\Entity\Programme;
  10. use App\Form\FichierType;
  11. use App\Security\ProgrammeVoter;
  12. use App\Service\ImagePdf;
  13. use App\Entity\PieceJointe;
  14. use App\Entity\Utilisateur;
  15. use App\Form\VilleAutocompleteType;
  16. use Sonata\AdminBundle\Datagrid\ProxyQueryInterface;
  17. use Sonata\AdminBundle\Form\FormMapper;
  18. use App\Repository\PieceJointeRepository;
  19. use Sonata\AdminBundle\Datagrid\ListMapper;
  20. use Sonata\AdminBundle\Admin\AdminInterface;
  21. use Sonata\AdminBundle\Datagrid\DatagridMapper;
  22. use Knp\Menu\ItemInterface as MenuItemInterface;
  23. use Sonata\AdminBundle\Route\RouteCollectionInterface;
  24. use Symfony\Component\Validator\Constraints\File;
  25. use Sonata\AdminBundle\Datagrid\DatagridInterface;
  26. use Sonata\AdminBundle\FieldDescription\FieldDescriptionInterface;
  27. use Sonata\Form\Type\CollectionType;
  28. use Symfony\Component\Form\Extension\Core\Type\ButtonType;
  29. use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
  30. use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
  31. use Symfony\Component\Form\Extension\Core\Type\TextareaType;
  32. use Symfony\Component\HttpFoundation\File\Exception\FileException;
  33. use function Sodium\add;
  34. final class ProgrammeAdmin extends AbstractAdmin
  35. {
  36.     protected $datagridValues = [
  37.         '_page' => 1,
  38.         '_sort_order' => 'DESC',
  39.         '_sort_by' => 'id',
  40.         '_per_page' => 250,
  41.     ];
  42.     private $tokenStorage;
  43.     private $originalLivraison;
  44.     public function setSecurityTokenStorage($tokenStorage)
  45.     {
  46.         $this->tokenStorage $tokenStorage;
  47.     }
  48.     public function getUser()
  49.     {
  50.         $token $this->tokenStorage->getToken();
  51.         if (null !== $token) {
  52.             return $token->getUser();
  53.         }
  54.         return null;
  55.     }
  56.     protected function configureDefaultSortValues(array &$sortValues): void
  57.     {
  58.         $sortValues[DatagridInterface::PAGE] = 1;
  59.         $sortValues[DatagridInterface::SORT_ORDER] = 'DESC';
  60.         $sortValues[DatagridInterface::SORT_BY] = 'id';
  61.         $sortValues[DatagridInterface::PER_PAGE] = 250;
  62.     }
  63.     protected function configureRoutes(RouteCollectionInterface $collection): void
  64.     {
  65.         $collection->add('requete_supp'$this->getRouterIdParameter().'/requete_supp');
  66.         $collection->remove('delete');
  67.     }
  68.     public function configureQuery(ProxyQueryInterface $query): ProxyQueryInterface
  69.     {
  70.         $queryBuilder $query->getQueryBuilder();
  71.         $user $this->getUser();
  72.     
  73.         if (!$user instanceof Utilisateur || !in_array('ROLE_MASTER'$user->getRoles())) {
  74.             if ($user->getEntreprise() !== null) {
  75.                 $queryBuilder
  76.                     ->innerJoin('o.entreprise''e')
  77.                     ->andWhere('e.id = :entrepriseId')
  78.                     ->setParameter('entrepriseId'$user->getEntreprise()->getId());
  79.             }
  80.             if (in_array('ROLE_PARTENAIRE'$user->getRoles())) {
  81.                 if (!$user->getallProgrammes()) {
  82.                     $programmes $user->getPrescripteurProgrammes();
  83.                     if($programmes->count()) {
  84.                         $queryBuilder->andWhere('o.id IN (' implode(','array_map(function($p){ return $p->getId(); }, $programmes->toArray())) . ')');
  85.                     } else {
  86.                         $queryBuilder->andWhere('o.id IN (0)');
  87.                     }
  88.                 }
  89.             }
  90.     
  91.             $query->andWhere('o.demandeSuppression IS NULL');
  92.         }
  93.         return $query;
  94.     }
  95.     protected function configureBatchActions(array $actions): array
  96.     {
  97.         $actions['requete_supp'] = [
  98.             'label' => 'Requête de suppression',
  99.             'ask_confirmation' => true,
  100.             'confirmation_message' => 'Êtes-vous sûr de vouloir supprimer ces éléments ?',
  101.         ];
  102.         return $actions;
  103.     }
  104.     protected function configureTabMenu(MenuItemInterface $menustring $action, ?AdminInterface $childAdmin null): void
  105.     {
  106.         if (!$childAdmin && !in_array($action, ['edit''show'])) {
  107.             return;
  108.         }
  109.         $admin $this->isChild() ? $this->getParent() : $this;
  110.         $id $admin->getRequest()->get('id');
  111.         $user $this->getUser();
  112.         if ($this->isGranted('EDIT') && !($childAdmin && in_array($action, ['edit''show''create'])) && $action != 'edit') {
  113.             if ($user && $user->peutModifierContenu()) {
  114.                 $menu->addChild('Modifier le programme'$admin->generateMenuUrl('edit', ['id' => $id]));
  115.             } else {
  116.                 $menu->addChild('Voir le programme'$admin->generateMenuUrl('edit', ['id' => $id]));
  117.             }
  118.         } elseif ($this->isGranted('EDIT') && !($childAdmin && $action == 'edit')) {
  119.             $url $admin->getRouteGenerator()->generate('admin_app_programme_lot_list', [
  120.                 'id' => $admin->getRequest()->get('id')
  121.             ]);
  122.             $menu->addChild('Voir les lots du programme', [
  123.                 'uri' => $url 
  124.             ]);
  125.         }
  126.     }
  127.     public function prePersist(object $programme): void
  128.     {
  129.         $files $this->getRequest()->files->get($this->getForm()->getName());
  130.         if(isset($files['_image'])) $this->manageImage($files['_image'], $programme);
  131.         if(isset($files['_brochure'])) $this->manageBrochure($files['_brochure'], $programme);
  132.         if(isset($files['_plan_masse'])) $this->managePlanMasse($files['_plan_masse'], $programme);
  133.         
  134.         $user $this->getUser();
  135.         if ($user instanceof Utilisateur && $user->getEntreprise() !== null) {
  136.             $programme->setEntreprise($user->getEntreprise());
  137.         }
  138.         if(isset($files['pjs'])) $this->managePiecesJointes($files['pjs'], $programme);
  139.         if(isset($files['documents'])) $this->manageDocuments($files['documents'], $programme);
  140.     }
  141.     public function preUpdate(object $programme): void
  142.     {
  143.         // Stocker l'ancienne valeur de livraison avant la modification
  144.         $this->originalLivraison $this->getOriginalEntityData($programme'livraison');
  145.         $files $this->getRequest()->files->get($this->getForm()->getName());
  146.         $fields $this->getRequest()->request->get($this->getForm()->getName());
  147.         
  148.         if(isset($files['_image'])) $this->manageImage($files['_image'], $programme);
  149.         if(isset($files['_brochure'])) $this->manageBrochure($files['_brochure'], $programme);
  150.         if(isset($files['_plan_masse'])) $this->managePlanMasse($files['_plan_masse'], $programme);
  151.         if(isset($fields['_image']) && $fields['_image'] == '__delete__'$this->manageImage(null$programme);
  152.         if(isset($fields['_brochure']) && $fields['_brochure'] == '__delete__'$this->manageBrochure(null$programme);
  153.         if(isset($fields['_plan_masse']) && $fields['_plan_masse'] == '__delete__'$this->managePlanMasse(null$programme);
  154.         $this->saveLotsCascade($programme);
  155.         $pjs = isset($files['pjs']) ? $files['pjs'] : [];
  156.         $this->managePiecesJointes($pjs$programme);
  157.         
  158.         if(isset($files['documents'])) $this->manageDocuments($files['documents'], $programme);
  159.         $this->manageHeritagePiecesJointes($programme);
  160.     }
  161.     /**
  162.      * Récupère la valeur originale d'un champ avant modification
  163.      */
  164.     private function getOriginalEntityData($entity$field)
  165.     {
  166.         $em $this->getModelManager()->getEntityManager($entity);
  167.         $uow $em->getUnitOfWork();
  168.         $originalData $uow->getOriginalEntityData($entity);
  169.         return isset($originalData[$field]) ? $originalData[$field] : null;
  170.     }
  171.     private function manageHeritagePiecesJointes($programme) {
  172.         foreach ($programme->getLots() as $lot) {
  173.             foreach ($lot->getPjs() as $pj) {
  174.                 $mere $pj->getPieceJointeMere();
  175.                 if ($mere) {
  176.                     if ($programme->getPjs()->contains($mere)) {
  177.                         $pj->setFilename($mere->getFilename());
  178.                         $pj->setDescriptionCourte($mere->getDescriptionCourte());
  179.                     } else {
  180.                         $lot->removePj($pj);
  181.                     }
  182.                 }
  183.             }
  184.             $idsMeresPjs = [];
  185.             foreach ($lot->getPjs() as $pj) {
  186.                 $mere $pj->getPieceJointeMere();
  187.                 if ($mere) {
  188.                     $idsMeresPjs[] = $mere->getId();
  189.                 }
  190.             }
  191.             foreach ($programme->getPjs() as $programmePj) {
  192.                 if (!in_array($programmePj->getId(), $idsMeresPjs)) {
  193.                     $fille = clone $programmePj;
  194.                     $fille->setPieceJointeMere($programmePj);
  195.                     $fille->setProgramme(null);
  196.                     $fille->setOrdre(0);
  197.                     $lot->addPj($fille);
  198.                 }
  199.             }
  200.         }
  201.     }
  202.     private function manageDocuments($docs$programme) {
  203.         $programmeDocs $programme->getDocuments()->toArray();
  204.         foreach($docs as $n => $doc) {
  205.             if($doc['fichier'] && isset($programmeDocs[$n])) {
  206.                 $fichier $doc['fichier'];
  207.                 $originalFilename pathinfo($fichier->getClientOriginalName(), PATHINFO_FILENAME);
  208.                 $safeFilename $this->slugify($originalFilename);
  209.                 $newFilename $safeFilename '-' uniqid() . '.' $fichier->guessExtension();
  210.                 try {
  211.                     $fichier->move(Documents::SAVE_PATH$newFilename);
  212.                 } catch (FileException $e) {
  213.                     // ... handle exception if something happens during file upload
  214.                 }
  215.                 $programme->getDocuments()[$n]->setFilename($newFilename);
  216.             }
  217.         }
  218.     }
  219.     private function managePiecesJointes($pjs$programme) {
  220.         $programmePjs $programme->getPjs()->toArray();
  221.     
  222.         foreach($pjs as $n => $pj) {
  223.             if($pj['fichier'] && isset($programmePjs[$n])) {
  224.                 $fichier $pj['fichier'];
  225.                 $originalFilename pathinfo($fichier->getClientOriginalName(), PATHINFO_FILENAME);
  226.                 $safeFilename $this->slugify($originalFilename);
  227.                 $newFilename $safeFilename '-' uniqid() . '.' $fichier->guessExtension();
  228.     
  229.                 try {
  230.                     $fichier->move(PieceJointe::SAVE_PATH$newFilename);
  231.                 } catch (FileException $e) {
  232.                     // ... handle exception if something happens during file upload
  233.                 }
  234.     
  235.                 if(strpos($newFilename'.pdf') !== false) {
  236.                     $newFilename ImagePdf::convertToImage(PieceJointe::SAVE_PATH.$newFilename);
  237.                 }
  238.     
  239.                 $programme->getPjs()[$n]->setFilename($newFilename);
  240.             }
  241.         }
  242.     }
  243.     private function manageImage($imageFile$programme
  244.     {
  245.         if($imageFile == null) {
  246.             $programme->setImage(null);
  247.         } else {
  248.             $originalFilename pathinfo($imageFile->getClientOriginalName(), PATHINFO_FILENAME);
  249.             $safeFilename $this->slugify($originalFilename);
  250.             $newFilename $safeFilename '-' uniqid() . '.' $imageFile->guessExtension();
  251.             try {
  252.                 $imageFile->move(Lot::IMAGE_SAVE_PATH$newFilename);
  253.             } catch (FileException $e) {
  254.                 // ... handle exception if something happens during file upload
  255.             }
  256.             $programme->setImage($newFilename);
  257.         }
  258.     }
  259.     private function manageBrochure($brochureFile$programme
  260.     {
  261.         if($brochureFile == null) {
  262.             $programme->setBrochure(null);
  263.         } else {
  264.             $originalFilename pathinfo($brochureFile->getClientOriginalName(), PATHINFO_FILENAME);
  265.             $safeFilename $this->slugify($originalFilename);
  266.             $newFilename $safeFilename '-' uniqid() . '.' $brochureFile->guessExtension();
  267.             try {
  268.                 $brochureFile->move(Lot::BROCHURE_SAVE_PATH$newFilename);
  269.             } catch (FileException $e) {
  270.                 // ... handle exception if something happens during file upload
  271.             }
  272.             $programme->setBrochure($newFilename);
  273.         }
  274.     }
  275.     private function managePlanMasse($planMasseFile$programme)
  276.     {
  277.         if ($planMasseFile == null) {
  278.             $programme->setPlanMasse(null);
  279.             
  280.         } else {
  281.             $originalFilename pathinfo($planMasseFile->getClientOriginalName(), PATHINFO_FILENAME);
  282.             $safeFilename $this->slugify($originalFilename);
  283.             $newFilename $safeFilename '-' uniqid() . '.' $planMasseFile->guessExtension();
  284.             try {
  285.                 $planMasseFile->move(Lot::PLAN_MASSE_SAVE_PATH$newFilename);
  286.             } catch (FileException $e) {
  287.                 // ... handle exception if something happens during file upload
  288.             }
  289.             if (strpos($newFilename'.pdf') !== false) {
  290.                 $newFilename ImagePdf::convertToImage(Lot::PLAN_MASSE_SAVE_PATH $newFilename);
  291.             }
  292.             $programme->setPlanMasse($newFilename);
  293.         }
  294.     }
  295.     private function saveLotsCascade($programme
  296.     {
  297.         foreach($programme->getLots() as $lot) {
  298.             $lot->setAdresse($programme->getAdresse());
  299.             $lot->setVille($programme->getVille());
  300.             $lot->setCodePostal($programme->getCodePostal());
  301.             $lot->setLatitude($programme->getLatitude());
  302.             $lot->setLongitude($programme->getLongitude());
  303.             $lotLivraison $lot->getLivraison();
  304.             $originalLivraison $this->originalLivraison;
  305.             $lotLivraisonUpper $lotLivraison strtoupper(trim($lotLivraison)) : null;
  306.             $originalLivraisonUpper $originalLivraison strtoupper(trim($originalLivraison)) : null;
  307.             if ($lotLivraisonUpper === $originalLivraisonUpper ||
  308.                 $lotLivraison === null ||
  309.                 trim($lotLivraison) === '') {
  310.                 $lot->setLivraison($programme->getLivraison());
  311.             }
  312.             $lot->setProgramme($programme->getNom());
  313.             $lot->setImage($programme->getImage());
  314.             $lot->setBrochure($programme->getBrochure());
  315.             $lot->setPlanMasse($programme->getPlanMasse());
  316.             $lot->setPromoteur($programme->getPromoteur());
  317.         }
  318.     }
  319.     protected function configureDatagridFilters(DatagridMapper $filter): void
  320.     {
  321.         $filter
  322.             ->add('adresse')
  323.             ->add('ville'null, [
  324.                 'show_filter' => true
  325.             ])
  326.             ->add('codePostal')
  327.             ->add('dateLivraison')
  328.             ->add('latitude')
  329.             ->add('longitude')
  330.             ->add('livraison')
  331.             ->add('promoteur')
  332.             ->add('nom'null, [
  333.                 'show_filter' => true,
  334.                 'label' => 'Nom du programme'
  335.             ])
  336.             ->add('image')
  337.             ->add('brochure')
  338.             ->add('planMasse')
  339.             ;
  340.     }
  341.     protected function configureListFields(ListMapper $list): void
  342.     {
  343.         $list
  344.             ->addIdentifier('nom'FieldDescriptionInterface::TYPE_STRING, [
  345.                 'template' => 'sonata/list_fields/list_programme_child_identifier.html.twig'
  346.             ])
  347.             ->add('lots'Lot::class, [
  348.                 'template' => 'sonata/list_fields/list_programme_lots.html.twig'
  349.             ])
  350.             ->addIdentifier('promoteur'FieldDescriptionInterface::TYPE_STRING, [
  351.                 'template' => 'sonata/list_fields/list_programme_child_identifier.html.twig'
  352.             ])
  353.             ->addIdentifier('livraison'FieldDescriptionInterface::TYPE_STRING, [
  354.                 'template' => 'sonata/list_fields/list_programme_child_identifier.html.twig'
  355.             ])
  356.             ->addIdentifier('ville'FieldDescriptionInterface::TYPE_STRING, [
  357.                 'template' => 'sonata/list_fields/list_programme_child_identifier.html.twig'
  358.             ])
  359.             ->addIdentifier('codePostal'FieldDescriptionInterface::TYPE_STRING, [
  360.                 'template' => 'sonata/list_fields/list_programme_child_identifier.html.twig'
  361.             ])
  362.             ->add('_Suppression''actions', [
  363.                 'actions' => [
  364.                     'requete_supp' => [
  365.                         'template' => 'sonata/Button/list__action_requete_suppression.html.twig',
  366.                     ],
  367.                 ],
  368.             ]);
  369.     }
  370.     protected function configureFormFields(FormMapper $form): void
  371.     {
  372.         $user $this->getUser();
  373.         $isSuperAdmin $user->peutModifierContenu();
  374.         $canModifySensitiveSections in_array('ROLE_SUPERADMIN'$user->getRoles()) ||
  375.             in_array('ROLE_ADMIN'$user->getRoles()) ||
  376.             in_array('ROLE_DIRECTEUR'$user->getRoles()) ||
  377.             in_array('ROLE_SAISIE'$user->getRoles());
  378.         $form
  379.             ->tab('Programme')
  380.                 ->with('Description du programme', ['box_class' => 'inline-fields''class' => 'col-md-6' . ($isSuperAdmin '' ' unauthorized-docs')])
  381.                     ->add('nom'null, [
  382.                         'required' => true,
  383.                         'attr' => [
  384.                             'placeholder' => 'Ex: Garden park'
  385.                         ]
  386.                     ])
  387.                     // ->add('type', null, [
  388.                     //     'required' => true,
  389.                     //     'attr' => [
  390.                     //         'style' => 'width:60%',
  391.                     //         'placeholder' => 'Ex: T4'
  392.                     //     ]
  393.                     // ])
  394.                     ->add('promoteur'null, [
  395.                         'required' => false,
  396.                         'attr' => [
  397.                             'placeholder' => 'Ex: Vinci'
  398.                         ]
  399.                     ])
  400.                     ->add('livraison'null, [
  401.                         'required' => false,
  402.                         'attr' => [
  403.                             'placeholder' => 'Ex: 4T '.date('Y')
  404.                         ]
  405.                     ])
  406.                     ->add('visuLivraison'CheckboxType::class, [
  407.                         'label'    => 'Visibilité Livraison',
  408.                         'required' => false,
  409.                         'help'     => 'Cocher pour afficher la livraison sur l\'espace public',
  410.                     ])                    
  411.                     ->add('adresse')
  412.                     ->add('ville'VilleAutocompleteType::class, [
  413.                         'code_postal_field' => 'codePostal'
  414.                     ])
  415.                     ->add('codePostal'null, [
  416.                         'attr' => [
  417.                             'style' => 'width:50%;margin-left:auto;'
  418.                         ]
  419.                     ])
  420.                     ->add('_geocodeAdresse'BlockType::class, [
  421.                         'mapped' => false,
  422.                         'template' => 'sonata/Block/geocode_adresse.html.twig',
  423.                         'params' => [
  424.                             'fields' => ['adresse''ville''codePostal']
  425.                         ]
  426.                     ])
  427.                     ->add('latitude')
  428.                     ->add('longitude')
  429.                     ->add('typePlan'ChoiceType::class, [
  430.                         'choices' => array_flip(Programme::TYPES_PLANS),
  431.                         'multiple' => false,
  432.                         'expanded' => false,
  433.                         'label' => 'Type de plan'
  434.                     ])
  435.                     ->add('zoomMap'ChoiceType::class, [
  436.                         'choices' => array_flip(Programme::ZOOMS_MAP),
  437.                         'multiple' => false,
  438.                         'expanded' => false,
  439.                         'label' => 'Zoom map'
  440.                     ])
  441.                     ->add('noteGlobale'TextareaType::class, [
  442.                         'label' => 'Notes Globales',
  443.                         'required' => false,
  444.                         'attr' => ['rows' => '2']
  445.                     ])
  446.                 ->end()
  447.                 ->with('Image de couverture', ['box_class' => '''class' => 'col-md-6 file' . ($isSuperAdmin '' ' unauthorized-docs')])
  448.                     ->add('_image'ImageType::class, [// unmapped means that this field is not associated to any entity property
  449.                         'mapped' => false,
  450.                         'save_path' => Lot::IMAGE_SAVE_PATH,
  451.                         'attr' => [
  452.                             'accept' => 'image/jpeg,image/gif,image/png',
  453.                         ],
  454.                         'label' => 'Fichier pour l\'image de couverture',
  455.                         'help' => 'Formats d\'image acceptés : JPG, PNG et GIF',
  456.                         // make it optional so you don't have to re-upload the PDF file
  457.                         // every time you edit the Product details
  458.                         'required' => false,
  459.                         // unmapped fields can't define their validation using annotations
  460.                         // in the associated entity, so you can use the PHP constraint classes
  461.                         'constraints' => [
  462.                             new File([
  463.                                 'maxSize' => '32768k',
  464.                                 'mimeTypes' => [
  465.                                     'image/jpeg',
  466.                                     'image/png',
  467.                                     'image/gif',
  468.                                 ],
  469.                                 'mimeTypesMessage' => 'Vous devez choisir un fichier au format JPG, PNG ou GIF.',
  470.                             ])
  471.                         ]
  472.                     ])
  473.                 ->end()
  474.                 ->with('Brochure', ['box_class' => '''class' => 'col-md-6 file' . ($isSuperAdmin '' ' unauthorized-docs')])
  475.                     ->add('_brochure'FichierType::class, [// unmapped means that this field is not associated to any entity property
  476.                         'mapped' => false,
  477.                         'save_path' => Lot::BROCHURE_SAVE_PATH,
  478.                         'attr' => [
  479.                             'accept' => 'application/pdf,application/x-pdf,image/jpeg,image/gif,image/png',
  480.                         ],
  481.                         'label' => 'Fichier pour la brochure',
  482.                         'help' => 'Formats de fichier acceptés : PDF, JPG, PNG et GIF',
  483.                         // make it optional so you don't have to re-upload the PDF file
  484.                         // every time you edit the Product details
  485.                         'required' => false,
  486.                         // unmapped fields can't define their validation using annotations
  487.                         // in the associated entity, so you can use the PHP constraint classes
  488.                         'constraints' => [
  489.                             new File([
  490.                                 'maxSize' => '32768k',
  491.                                 'mimeTypes' => [
  492.                                     'image/jpeg',
  493.                                     'image/png',
  494.                                     'image/gif',
  495.                                     'application/pdf',
  496.                                     'application/x-pdf',
  497.                                 ],
  498.                                 'mimeTypesMessage' => 'Vous devez choisir un fichier au format PDF, JPG, PNG ou GIF.',
  499.                             ])
  500.                         ]
  501.                     ])
  502.                     ->add('libelleBrochure'null, [
  503.                         'help' => 'Intitulé du bouton de téléchargement de l\'espace public (Laissez vide pour afficher l\'intitulé par défaut "Brochure")',
  504.                         'attr' => [
  505.                             'class' => 'little-input-brochure',
  506.                             'placeholder' => 'Ex: Télécharger la brochure'
  507.                         ],
  508.                         'label' => 'Libellé brochure'
  509.                     ])
  510.                 ->end()
  511.                 ->with('Plan Masse', ['box_class' => '''class' => 'col-md-6 file' . ($isSuperAdmin '' ' unauthorized-docs')])
  512.                     ->add('_plan_masse'FichierType::class, [// unmapped means that this field is not associated to any entity property
  513.                         'mapped' => false,
  514.                         'save_path' => Lot::PLAN_MASSE_SAVE_PATH,
  515.                         'attr' => [
  516.                             'accept' => 'application/pdf,application/x-pdf,image/jpeg,image/gif,image/png',
  517.                         ],
  518.                         'label' => 'Fichier pour le plan masse',
  519.                         'help' => 'Formats de fichier acceptés : PDF, JPG, PNG et GIF',
  520.                         // make it optional so you don't have to re-upload the PDF file
  521.                         // every time you edit the Product details
  522.                         'required' => false,
  523.                         // unmapped fields can't define their validation using annotations
  524.                         // in the associated entity, so you can use the PHP constraint classes
  525.                         'constraints' => [
  526.                             new File([
  527.                                 'maxSize' => '32768k',
  528.                                 'mimeTypes' => [
  529.                                     'image/jpeg',
  530.                                     'image/png',
  531.                                     'image/gif',
  532.                                     'application/pdf',
  533.                                     'application/x-pdf',
  534.                                 ],
  535.                                 'mimeTypesMessage' => 'Vous devez choisir un fichier au format PDF, JPG, PNG ou GIF.',
  536.                             ])
  537.                         ]
  538.                     ])
  539.                 ->end()
  540.             ->end()
  541.             ->tab('Vivier slides')
  542.                     ->with('Vivier slides', ['box_class' => 'no-header''class' => 'col-md-12 programme-slides' . ($canModifySensitiveSections '' ' unauthorized-docs')])
  543.                     ->add('pjs'CollectionType::class, [
  544.                         'label_attr' => [
  545.                             'class' => 'hide'
  546.                         ],
  547.                         'by_reference' => false,
  548.                         'type_options' => [
  549.                             'delete' => true,
  550.                             'delete_options' => [
  551.                                 'type'         => ButtonType::class,
  552.                                 'type_options' => [
  553.                                     'label' => 'Retirer',
  554.                                     'attr' => [
  555.                                     'class' => 'btn btn-danger btn-delete-elements',
  556.                                     'onclick' => "
  557.                                         if(confirm('Voulez-vous vraiment effacer cette ligne ? N\'oubliez pas d\'enregistrer vos modifications.')) {
  558.                                         $(this).closest('tr').remove();
  559.                                         }
  560.                                     "
  561.                                     ]
  562.                                 ]
  563.                             ]
  564.                         ]
  565.                     ], [
  566.                         'edit' => 'inline',
  567.                         'inline' => 'table',
  568.                         'sortable' => 'ordre'
  569.                     ])
  570.                 ->end()
  571.             ->end()
  572.             ->tab('Documents')
  573.                     ->with('Documents', ['box_class' => 'no-header''class' => 'col-md-12' . ($canModifySensitiveSections '' ' unauthorized-docs')])
  574.                     ->add('documents'CollectionType::class, [
  575.                         'label_attr' => [
  576.                             'class' => 'hide'
  577.                         ],
  578.                         'by_reference' => false,
  579.                         'type_options' => [
  580.                             'delete' => true,
  581.                             'delete_options' => [
  582.                                 'type'         => ButtonType::class,
  583.                                 'type_options' => [
  584.                                     'label' => 'Retirer',
  585.                                     'attr' => [
  586.                                     'class' => 'btn btn-danger btn-delete-elements',
  587.                                     'onclick' => "
  588.                                         if(confirm('Voulez-vous vraiment effacer cette ligne ? N\'oubliez pas d\'enregistrer vos modifications.')) {
  589.                                         $(this).closest('tr').remove();
  590.                                         }
  591.                                     "
  592.                                     ]
  593.                                 ]
  594.                             ]
  595.                         ]
  596.                     ], [
  597.                         'edit' => 'inline',
  598.                         'inline' => 'table',
  599.                         'sortable' => 'ordre'
  600.                     ])
  601.                 ->end()
  602.             ->end()
  603.         ;
  604.     }
  605. }