From c3f585bf2be76ab4d1b27122682a45b899ca7cc4 Mon Sep 17 00:00:00 2001 From: Serreau Jovann Date: Wed, 28 Jan 2026 09:38:27 +0100 Subject: [PATCH] =?UTF-8?q?```=20=E2=9C=A8=20feat(Formules.php):=20Ajoute?= =?UTF-8?q?=20les=20champs=20description=20et=20isPublish=20=C3=A0=20l'ent?= =?UTF-8?q?it=C3=A9=20Formules.=20=E2=9C=A8=20feat(add.twig):=20Ajoute=20l?= =?UTF-8?q?e=20champ=20description=20au=20formulaire=20d'ajout=20de=20form?= =?UTF-8?q?ules.=20=E2=9C=A8=20feat(FormulesType.php):=20Ajoute=20le=20cha?= =?UTF-8?q?mp=20description=20au=20formulaire=20FormulesType.=20=E2=9C=A8?= =?UTF-8?q?=20feat(Dashboard/FormulesController.php):=20G=C3=A8re=20l'ajou?= =?UTF-8?q?t,=20la=20suppression=20et=20la=20vue=20des=20formules.=20?= =?UTF-8?q?=E2=9C=A8=20feat(view.twig):=20Cr=C3=A9e=20la=20vue=20pour=20mo?= =?UTF-8?q?difier=20les=20d=C3=A9tails=20d'une=20formule.=20=E2=9C=A8=20fe?= =?UTF-8?q?at(formules.twig):=20Affiche=20la=20liste=20des=20formules=20av?= =?UTF-8?q?ec=20actions=20et=20statut.=20```?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- migrations/Version20260128082804.php | 32 +++++ migrations/Version20260128083151.php | 32 +++++ .../Dashboard/FormulesController.php | 81 ++++++++++- src/Entity/Formules.php | 31 ++++ src/Form/AccountType.php | 4 +- src/Form/CustomerAddAddressType.php | 4 +- src/Form/CustomerAddType.php | 4 +- src/Form/CustomerType.php | 4 +- src/Form/FormulesType.php | 10 +- src/Form/NewDevisType.php | 2 +- src/Form/OptionsType.php | 4 +- src/Form/ProductDocType.php | 4 +- src/Form/ProductType.php | 4 +- templates/dashboard/formules.twig | 89 ++++++++++-- templates/dashboard/formules/add.twig | 9 ++ templates/dashboard/formules/view.twig | 132 ++++++++++++++++++ 16 files changed, 417 insertions(+), 29 deletions(-) create mode 100644 migrations/Version20260128082804.php create mode 100644 migrations/Version20260128083151.php create mode 100644 templates/dashboard/formules/view.twig diff --git a/migrations/Version20260128082804.php b/migrations/Version20260128082804.php new file mode 100644 index 0000000..e8c20a9 --- /dev/null +++ b/migrations/Version20260128082804.php @@ -0,0 +1,32 @@ +addSql('ALTER TABLE formules ADD is_publish BOOLEAN DEFAULT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE SCHEMA public'); + $this->addSql('ALTER TABLE formules DROP is_publish'); + } +} diff --git a/migrations/Version20260128083151.php b/migrations/Version20260128083151.php new file mode 100644 index 0000000..b032442 --- /dev/null +++ b/migrations/Version20260128083151.php @@ -0,0 +1,32 @@ +addSql('ALTER TABLE formules ADD description TEXT DEFAULT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE SCHEMA public'); + $this->addSql('ALTER TABLE formules DROP description'); + } +} diff --git a/src/Controller/Dashboard/FormulesController.php b/src/Controller/Dashboard/FormulesController.php index 7d71b25..18fa8ba 100644 --- a/src/Controller/Dashboard/FormulesController.php +++ b/src/Controller/Dashboard/FormulesController.php @@ -38,19 +38,57 @@ class FormulesController extends AbstractController 'formules' => $paginator->paginate($formulesRepository->findBy([],['id'=>'asc']), $request->query->getInt('page', 1), 10), ]); } - #[Route(path: '/crm/formules/add', name: 'app_crm_formules_add', methods: ['GET'])] - public function formulesAdd(PaginatorInterface $paginator,AppLogger $appLogger,Request $request,FormulesRepository $formulesRepository): Response + #[Route(path: '/crm/formules/delete/{id}', name: 'app_crm_formules_delete', methods: ['POST', 'GET'])] + public function formulesDelete( + ?Formules $formules, + AppLogger $appLogger, + EntityManagerInterface $entityManager, + Request $request + ): Response { + // 1. Vérification de l'existence de la formule + if (!$formules instanceof Formules) { + $this->addFlash('error', 'Formule introuvable.'); + return $this->redirectToRoute('app_crm_formules'); + } + + // 2. Vérification du jeton CSRF (Sécurité contre les suppressions malveillantes) + // Note: Dans ton Twig, tu passes déjà le token en query string + if ($this->isCsrfTokenValid('delete' . $formules->getId(), $request->query->get('_token'))) { + $nomFormule = $formules->getName(); + + // 3. Suppression + foreach ($formules->getFormulesProductIncluses() as $formulesProductInclus) + $entityManager->remove($formulesProductInclus); + $entityManager->remove($formules); + $entityManager->flush(); + + // 4. Logging & Feedback + $appLogger->record('DELETE', 'Suppression définitive de la formule : ' . $nomFormule); + $this->addFlash('success', 'La formule "' . $nomFormule . '" a été supprimée.'); + } else { + $this->addFlash('error', 'Jeton de sécurité invalide.'); + } + + return $this->redirectToRoute('app_crm_formules'); + } + #[Route(path: '/crm/formules/add', name: 'app_crm_formules_add', methods: ['GET','POST'])] + public function formulesAdd(EntityManagerInterface $entityManager,PaginatorInterface $paginator,AppLogger $appLogger,Request $request,FormulesRepository $formulesRepository): Response { $appLogger->record('VIEW', 'Consultation page création formules'); $formules = new Formules(); + $formules->setIsPublish(false); $formules->setUpdatedAt(new \DateTimeImmutable()); $formules->setType($request->get('type',"pack")); // pack selected // free add listing allow product $form = $this->createForm(FormulesType::class,$formules); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - + $entityManager->persist($formules); + $entityManager->flush(); + $appLogger->record('CREATED', "Création de la formule : " . $formules->getName()); + $this->addFlash("success", "La formule a été créée avec succès."); + return $this->redirectToRoute('app_crm_formules_view',['id'=>$formules->getId()]); } return $this->render('dashboard/formules/add.twig', [ @@ -60,4 +98,41 @@ class FormulesController extends AbstractController ]); } + #[Route(path: '/crm/formules/{id}', name: 'app_crm_formules_view', methods: ['GET'])] + public function formulesView(?Formules $formules,Request $request,EntityManagerInterface $entityManager, AppLogger $appLogger): Response + { + if (!$formules instanceof Formules) { + $this->addFlash('error', 'Formule introuvable.'); + return $this->redirectToRoute('app_crm_formules'); + } + + $appLogger->record('VIEW', 'Consultation page formule ' . $formules->getName()); + + if ($request->get('act') === 'togglePublish') { + $status = $request->get('status') === 'true'; + $formules->setIsPublish($status); + $entityManager->flush(); + + $appLogger->record('UPDATE', ($status ? 'Publication' : 'Désactivation') . ' de la formule ' . $formules->getName()); + $this->addFlash('success', 'Statut mis à jour avec succès.'); + + return $this->redirectToRoute('app_crm_formules_view', ['id' => $formules->getId()]); + } + + $form = $this->createForm(FormulesType::class,$formules); + $form->handleRequest($request); + if ($form->isSubmitted() && $form->isValid()) { + $entityManager->persist($formules); + $entityManager->flush(); + $appLogger->record('CREATED', "Modification de la formule : " . $formules->getName()); + $this->addFlash("success", "La formule a été modifié avec succès."); + return $this->redirectToRoute('app_crm_formules_view',['id'=>$formules->getId()]); + } + return $this->render('dashboard/formules/view.twig', [ + 'formule' => $formules, + 'form' => $form->createView(), + 'type' => $formules->getType(), + ]); + } + } diff --git a/src/Entity/Formules.php b/src/Entity/Formules.php index 7801004..aa10289 100644 --- a/src/Entity/Formules.php +++ b/src/Entity/Formules.php @@ -5,6 +5,7 @@ namespace App\Entity; use App\Repository\FormulesRepository; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\HttpFoundation\File\File; use Vich\UploaderBundle\Mapping\Attribute\Uploadable; @@ -43,6 +44,12 @@ class Formules #[ORM\OneToMany(targetEntity: FormulesProductInclus::class, mappedBy: 'formules')] private Collection $formulesProductIncluses; + #[ORM\Column(nullable: true)] + private ?bool $isPublish = null; + + #[ORM\Column(type: Types::TEXT, nullable: true)] + private ?string $description = null; + public function __construct() { $this->formulesProductIncluses = new ArrayCollection(); @@ -171,4 +178,28 @@ class Formules return $this; } + + public function isPublish(): ?bool + { + return $this->isPublish; + } + + public function setIsPublish(bool $isPublish): static + { + $this->isPublish = $isPublish; + + return $this; + } + + public function getDescription(): ?string + { + return $this->description; + } + + public function setDescription(?string $description): static + { + $this->description = $description; + + return $this; + } } diff --git a/src/Form/AccountType.php b/src/Form/AccountType.php index 0462156..837dabd 100644 --- a/src/Form/AccountType.php +++ b/src/Form/AccountType.php @@ -12,7 +12,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; class AccountType extends AbstractType { - public function buildForm(FormBuilderInterface $builder, array $options) + public function buildForm(FormBuilderInterface $builder, array $options): void { $builder ->add('username',TextType::class,[ @@ -33,7 +33,7 @@ class AccountType extends AbstractType ]); } - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefault('data_class',Account::class); } diff --git a/src/Form/CustomerAddAddressType.php b/src/Form/CustomerAddAddressType.php index 0ee5264..1275c3a 100644 --- a/src/Form/CustomerAddAddressType.php +++ b/src/Form/CustomerAddAddressType.php @@ -15,7 +15,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; class CustomerAddAddressType extends AbstractType { - public function buildForm(FormBuilderInterface $builder, array $options) + public function buildForm(FormBuilderInterface $builder, array $options): void { $builder @@ -50,7 +50,7 @@ class CustomerAddAddressType extends AbstractType ; } - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'data_class' => CustomerAddress::class, diff --git a/src/Form/CustomerAddType.php b/src/Form/CustomerAddType.php index f7f2169..bf651c3 100644 --- a/src/Form/CustomerAddType.php +++ b/src/Form/CustomerAddType.php @@ -14,7 +14,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; class CustomerAddType extends AbstractType { - public function buildForm(FormBuilderInterface $builder, array $options) + public function buildForm(FormBuilderInterface $builder, array $options): void { $builder ->add('civ', ChoiceType::class, [ @@ -99,7 +99,7 @@ class CustomerAddType extends AbstractType ; } - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'data_class' => Customer::class, diff --git a/src/Form/CustomerType.php b/src/Form/CustomerType.php index fbf0f93..7a09b15 100644 --- a/src/Form/CustomerType.php +++ b/src/Form/CustomerType.php @@ -14,7 +14,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; class CustomerType extends AbstractType { - public function buildForm(FormBuilderInterface $builder, array $options) + public function buildForm(FormBuilderInterface $builder, array $options): void { $builder ->add('civ', ChoiceType::class, [ @@ -63,7 +63,7 @@ class CustomerType extends AbstractType ]); } - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'data_class' => Customer::class, diff --git a/src/Form/FormulesType.php b/src/Form/FormulesType.php index f14e40f..95fb8bc 100644 --- a/src/Form/FormulesType.php +++ b/src/Form/FormulesType.php @@ -5,18 +5,22 @@ namespace App\Form; use App\Entity\Formules; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\FileType; +use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; class FormulesType extends AbstractType { - public function buildForm(FormBuilderInterface $builder, array $options) + public function buildForm(FormBuilderInterface $builder, array $options): void { $builder ->add('name',TextType::class,[ 'label' => 'Nom de la formule', ]) + ->add('description',TextareaType::class,[ + 'label' => 'Description de la formule', + ]) ->add('imageFile',FileType::class,[ 'label' => 'Image de la formule', 'required' => false, @@ -24,8 +28,8 @@ class FormulesType extends AbstractType ; } - public function configureOptions(OptionsResolver $resolver) - { + public function configureOptions(OptionsResolver $resolver): void + { $resolver->setDefault('data_class',Formules::class); } } diff --git a/src/Form/NewDevisType.php b/src/Form/NewDevisType.php index 320883e..8967f26 100644 --- a/src/Form/NewDevisType.php +++ b/src/Form/NewDevisType.php @@ -14,7 +14,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; class NewDevisType extends AbstractType { - public function buildForm(FormBuilderInterface $builder, array $options) + public function buildForm(FormBuilderInterface $builder, array $options): void { $builder ->add('num', TextType::class, [ diff --git a/src/Form/OptionsType.php b/src/Form/OptionsType.php index ea8794a..6ab359d 100644 --- a/src/Form/OptionsType.php +++ b/src/Form/OptionsType.php @@ -18,7 +18,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; class OptionsType extends AbstractType { - public function buildForm(FormBuilderInterface $builder, array $options) + public function buildForm(FormBuilderInterface $builder, array $options): void { $builder ->add('name',TextType::class,[ @@ -36,7 +36,7 @@ class OptionsType extends AbstractType ; } - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'data_class' => Options::class, diff --git a/src/Form/ProductDocType.php b/src/Form/ProductDocType.php index a9cf4ae..4d8c27b 100644 --- a/src/Form/ProductDocType.php +++ b/src/Form/ProductDocType.php @@ -18,7 +18,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; class ProductDocType extends AbstractType { - public function buildForm(FormBuilderInterface $builder, array $options) + public function buildForm(FormBuilderInterface $builder, array $options): void { $builder ->add('name', TextType::class, [ @@ -40,7 +40,7 @@ class ProductDocType extends AbstractType ; } - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'data_class' => ProductDoc::class, diff --git a/src/Form/ProductType.php b/src/Form/ProductType.php index 54ed388..69ad92d 100644 --- a/src/Form/ProductType.php +++ b/src/Form/ProductType.php @@ -17,7 +17,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; class ProductType extends AbstractType { - public function buildForm(FormBuilderInterface $builder, array $options) + public function buildForm(FormBuilderInterface $builder, array $options): void { $builder ->add('name',TextType::class,[ @@ -81,7 +81,7 @@ class ProductType extends AbstractType ; } - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'data_class' => Product::class, diff --git a/templates/dashboard/formules.twig b/templates/dashboard/formules.twig index 1297984..27ca42c 100644 --- a/templates/dashboard/formules.twig +++ b/templates/dashboard/formules.twig @@ -1,15 +1,17 @@ {% extends 'dashboard/base.twig' %} {% block title %}Catalogue Formules{% endblock %} -{% block title_header %}Gestion du Formules{% endblock %} +{% block title_header %}Gestion des Formules{% endblock %} {% block actions %}
-
{% endblock %} @@ -22,17 +24,90 @@ Visuel Désignation + Type + Statut Tarif Actions {% for formule in formules %} + + {# VISUEL #} + +
+ {% if formule.imageName %} + + {% else %} +
+ +
+ {% endif %} +
+ + {# NOM & REF #} + +
+ + {{ formule.name }} + +
+ + + {# TYPE #} + + + {{ formule.type }} + + + + {# STATUT #} + + {% if formule.isPublish %} + + + En ligne + + {% else %} + + Brouillon + + {% endif %} + + + {# TARIF #} + +
+ {{ formule.price|default('0.00') }} € +
+ + + {# ACTIONS #} + +
+ + + + + + + +
+ + {% else %} - -

Aucune formules

+ +
+
+ +
+

Aucune formule dans le catalogue

+
{% endfor %} @@ -48,8 +123,6 @@ {% endif %} - -