Init project
This commit is contained in:
0
src/Controller/.gitignore
vendored
Normal file
0
src/Controller/.gitignore
vendored
Normal file
38
src/Controller/BaseAdminController.php
Normal file
38
src/Controller/BaseAdminController.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
final class BaseAdminController extends AbstractController
|
||||
{
|
||||
#[Route('/admin', name: 'admin_dashboard')]
|
||||
public function admin(): Response
|
||||
{
|
||||
return $this->render('base-admin/index.html.twig', []);
|
||||
}
|
||||
|
||||
#[Route('/sidebar', name: 'admin_sidebar')]
|
||||
public function sidebar(string $path): Response
|
||||
{
|
||||
return $this->render('base-admin/sidebar.html.twig', [
|
||||
'path' => $path,
|
||||
'title' => $this->mapPathToFrenchTitle($path)
|
||||
]);
|
||||
}
|
||||
|
||||
private function mapPathToFrenchTitle(string $path): string
|
||||
{
|
||||
$mapping = [
|
||||
'/admin' => 'Tableau de bord',
|
||||
'/admin/module' => 'Module',
|
||||
'/admin/news' => 'Actualité',
|
||||
'/admin/image' => 'Image',
|
||||
'/admin/news/add' => 'Ajouter une actualité',
|
||||
];
|
||||
|
||||
return $mapping[$path] ?? 'Inconnu';
|
||||
}
|
||||
}
|
||||
22
src/Controller/BaseController.php
Normal file
22
src/Controller/BaseController.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
final class BaseController extends AbstractController
|
||||
{
|
||||
#[Route('/header', name: 'header')]
|
||||
public function header(): Response
|
||||
{
|
||||
return $this->render('base/header.html.twig', []);
|
||||
}
|
||||
|
||||
#[Route('/footer', name: 'footer')]
|
||||
public function footer(): Response
|
||||
{
|
||||
return $this->render('base/footer.html.twig', []);
|
||||
}
|
||||
}
|
||||
28
src/Controller/FeatureController.php
Normal file
28
src/Controller/FeatureController.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\Feature;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
final class FeatureController extends AbstractController
|
||||
{
|
||||
private EntityManagerInterface $entityManager;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
#[Route('/admin/feature', name: 'admin_feature_index')]
|
||||
public function index(): Response
|
||||
{
|
||||
$features = $this->entityManager->getRepository(Feature::class)->findAll();
|
||||
return $this->render('feature/index.html.twig', [
|
||||
'features' => $features,
|
||||
]);
|
||||
}
|
||||
}
|
||||
89
src/Controller/ImageController.php
Normal file
89
src/Controller/ImageController.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\Image;
|
||||
use App\Service\ImageService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Dom\Entity;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
final class ImageController extends AbstractController
|
||||
{
|
||||
private EntityManagerInterface $entityManager;
|
||||
private ImageService $imageService;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, ImageService $imageService)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->imageService = $imageService;
|
||||
}
|
||||
#[Route('/admin/image', name: 'admin_image_index')]
|
||||
public function index(): Response
|
||||
{
|
||||
$images = $this->entityManager->getRepository(Image::class)->findAll();
|
||||
|
||||
return $this->render('image/index.html.twig', [
|
||||
'images' => $images,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/admin/image/add', name: 'admin_image_add')]
|
||||
public function add(): Response
|
||||
{
|
||||
return $this->render('image/add.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/admin/image/upload', name: 'admin_image_upload', methods: ['POST'])]
|
||||
public function upload(Request $request): JsonResponse
|
||||
{
|
||||
$files = $request->files->get('file-upload', []);
|
||||
|
||||
foreach ($files as $file) {
|
||||
if ($file && $file->isValid()) {
|
||||
$originalName = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
|
||||
$extension = $file->getClientOriginalExtension();
|
||||
|
||||
$filename = strtolower($originalName . '-' . uniqid() . '.' . $extension);
|
||||
$stream = fopen($file->getPathname(), 'rb');
|
||||
|
||||
// Upload vers MinIO
|
||||
$result = $this->imageService->upload($filename, $stream);
|
||||
|
||||
if ($result === true) {
|
||||
$image = new Image();
|
||||
$image->setName($filename);
|
||||
$image->setUrl($this->getParameter('minio_endpoint') . '/' . $this->getParameter('minio_bucket') . '/' . $filename);
|
||||
$image->setSize($file->getSize());
|
||||
$this->entityManager->persist($image);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->entityManager->flush();
|
||||
|
||||
return new JsonResponse([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/admin/image/delete/{id}', name: 'admin_image_delete', methods: ['GET', 'POST'])]
|
||||
public function delete(Request $request, Image $image, EntityManagerInterface $em): Response
|
||||
{
|
||||
$submittedToken = $request->request->get('_token');
|
||||
if ($this->isCsrfTokenValid('delete_image' . $image->getId(), $submittedToken)) {
|
||||
$result = $this->imageService->delete($image);
|
||||
if ($result === true) {
|
||||
$em->remove($image);
|
||||
$em->flush();
|
||||
} else {
|
||||
$this->addFlash('error', 'L\'image est utilisée et ne peut pas être supprimée.');
|
||||
}
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('admin_image_index');
|
||||
}
|
||||
}
|
||||
184
src/Controller/NewsController.php
Normal file
184
src/Controller/NewsController.php
Normal file
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\Image;
|
||||
use App\Entity\News;
|
||||
use App\Entity\NewsImage;
|
||||
use App\Form\NewsType;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\Form\FormError;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\String\Slugger\SluggerInterface;
|
||||
|
||||
final class NewsController extends AbstractController
|
||||
{
|
||||
private EntityManagerInterface $entityManager;
|
||||
private SluggerInterface $slugger;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, SluggerInterface $slugger)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->slugger = $slugger;
|
||||
}
|
||||
|
||||
#[Route('/admin/news', name: 'admin_news_index')]
|
||||
public function index(Request $request): Response
|
||||
{
|
||||
$news = $this->entityManager->getRepository(News::class)->findBy([], ['ordre' => 'ASC']);
|
||||
|
||||
return $this->render('news/index.html.twig', [
|
||||
'news' => $news
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/admin/news/add', name: 'admin_news_add')]
|
||||
public function add(Request $request): Response
|
||||
{
|
||||
$form = $this->createForm(NewsType::class);
|
||||
$images = $this->entityManager->getRepository(Image::class)->findAll();
|
||||
|
||||
$form->handleRequest($request);
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$news = $form->getData();
|
||||
$slug = strtolower($this->slugger->slug($news->getTitle()));
|
||||
if ($this->entityManager->getRepository(News::class)->findOneBy(['slug' => $slug])) {
|
||||
$this->addFlash('error', 'Le titre est déjà utilisé.');
|
||||
return $this->redirectToRoute('admin_news_add');
|
||||
}
|
||||
$news->setSlug($slug);
|
||||
$lastestNews = $this->entityManager->getRepository(News::class)->findOneBy([], ['ordre' => 'DESC']);
|
||||
$newsOrdre = $lastestNews ? $lastestNews->getOrdre() + 1 : 1;
|
||||
$news->setOrdre($newsOrdre);
|
||||
$news->setCreatedAt(new \DateTimeImmutable());
|
||||
$news->setUpdatedAt(new \DateTimeImmutable());
|
||||
$news->setIsActive(true);
|
||||
$this->entityManager->persist($news);
|
||||
|
||||
$selectedImageIds = $request->request->all('selectedImages');
|
||||
|
||||
if (!empty($selectedImageIds)) {
|
||||
$imageRepository = $this->entityManager->getRepository(Image::class);
|
||||
|
||||
foreach ($selectedImageIds as $key => $imageId) {
|
||||
$image = $imageRepository->find($imageId);
|
||||
$newsImage = new NewsImage();
|
||||
$newsImage->setNews($news);
|
||||
$newsImage->setImage($image);
|
||||
$newsImage->setOrdre($key);
|
||||
$this->entityManager->persist($newsImage);
|
||||
}
|
||||
}
|
||||
$this->entityManager->flush();
|
||||
return $this->redirectToRoute('admin_news_index');
|
||||
}
|
||||
return $this->render('news/add.html.twig', [
|
||||
'form' => $form->createView(),
|
||||
'images' => $images,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/admin/news/edit/{id}', name: 'admin_news_edit')]
|
||||
public function edit(Request $request, News $news): Response
|
||||
{
|
||||
$form = $this->createForm(NewsType::class, $news);
|
||||
$images = $this->entityManager->getRepository(Image::class)->findAll();
|
||||
$selectedImages = [];
|
||||
foreach ($news->getNewsImages() as $newsImage) {
|
||||
$selectedImages[] = $newsImage->getImage();
|
||||
}
|
||||
|
||||
$form->handleRequest($request);
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$news = $form->getData();
|
||||
$news->setUpdatedAt(new \DateTimeImmutable());
|
||||
|
||||
foreach ($news->getNewsImages() as $newsImage) {
|
||||
$this->entityManager->remove($newsImage);
|
||||
}
|
||||
|
||||
$selectedImageIds = $request->request->all('selectedImages');
|
||||
|
||||
if (!empty($selectedImageIds)) {
|
||||
$imageRepository = $this->entityManager->getRepository(Image::class);
|
||||
|
||||
foreach ($selectedImageIds as $key => $imageId) {
|
||||
$image = $imageRepository->find($imageId);
|
||||
$newsImage = new NewsImage();
|
||||
$newsImage->setNews($news);
|
||||
$newsImage->setImage($image);
|
||||
$newsImage->setOrdre($key);
|
||||
$this->entityManager->persist($newsImage);
|
||||
}
|
||||
}
|
||||
|
||||
$this->entityManager->flush();
|
||||
|
||||
return $this->redirectToRoute('admin_news_index');
|
||||
}
|
||||
|
||||
return $this->render('news/edit.html.twig', [
|
||||
'form' => $form->createView(),
|
||||
'images' => $images,
|
||||
'selectedImages' => $selectedImages,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/admin/news/delete/{id}', name: 'admin_news_delete', methods: ['POST'])]
|
||||
public function delete(Request $request, News $news): Response
|
||||
{
|
||||
$submittedToken = $request->request->get('_token');
|
||||
if ($this->isCsrfTokenValid('delete' . $news->getId(), $submittedToken)) {
|
||||
$newsImages = $news->getNewsImages();
|
||||
foreach ($newsImages as $newsImage) {
|
||||
$this->entityManager->remove($newsImage);
|
||||
}
|
||||
$this->entityManager->remove($news);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$allNews = $this->entityManager->getRepository(News::class)->findBy([], ['ordre' => 'ASC']);
|
||||
|
||||
foreach ($allNews as $index => $item) {
|
||||
$item->setOrdre($index + 1);
|
||||
}
|
||||
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('admin_news_index');
|
||||
}
|
||||
|
||||
#[Route('/admin/news/reorder', name: 'admin_news_reorder', methods: ['POST'])]
|
||||
public function reorder(Request $request, EntityManagerInterface $em): JsonResponse
|
||||
{
|
||||
$data = json_decode($request->getContent(), true);
|
||||
|
||||
foreach ($data['order'] as $item) {
|
||||
$news = $em->getRepository(News::class)->find($item['id']);
|
||||
if ($news) {
|
||||
$news->setOrdre($item['position']);
|
||||
}
|
||||
}
|
||||
|
||||
$em->flush();
|
||||
|
||||
return new JsonResponse(['status' => 'ok']);
|
||||
}
|
||||
|
||||
#[Route('/admin/news/toggle-active/{id}', name: 'admin_news_toggle_active', methods: ['POST'])]
|
||||
public function toggleActive(Request $request, News $news, EntityManagerInterface $em): Response
|
||||
{
|
||||
$token = $request->request->get('_token');
|
||||
if ($this->isCsrfTokenValid('toggle' . $news->getId(), $token)) {
|
||||
$current = (bool) $request->request->get('active', 0);
|
||||
$news->setIsActive(!$current);
|
||||
$em->flush();
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('admin_news_index');
|
||||
}
|
||||
}
|
||||
68
src/Controller/PageController.php
Normal file
68
src/Controller/PageController.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\News;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
final class PageController extends AbstractController
|
||||
{
|
||||
private EntityManagerInterface $entityManager;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
#[Route('/', name: 'home')]
|
||||
public function index(): Response
|
||||
{
|
||||
return $this->render('page/home.html.twig', []);
|
||||
}
|
||||
|
||||
#[Route('/a-propos', name: 'about')]
|
||||
public function about(): Response
|
||||
{
|
||||
return $this->render('page/about.html.twig', []);
|
||||
}
|
||||
|
||||
#[Route('/projets-artistiques', name: 'project')]
|
||||
public function project(): Response
|
||||
{
|
||||
return $this->render('page/project.html.twig', []);
|
||||
}
|
||||
|
||||
#[Route('/projets-manuels-et-creatifs', name: 'manualproject')]
|
||||
public function manualproject(): Response
|
||||
{
|
||||
return $this->render('page/manual-project.html.twig', []);
|
||||
}
|
||||
|
||||
#[Route('/show', name: 'show')]
|
||||
public function show(): Response
|
||||
{
|
||||
return $this->render('page/show.html.twig', []);
|
||||
}
|
||||
|
||||
#[Route('/mentions-legales', name: 'legalmentions')]
|
||||
public function legalmentions(): Response
|
||||
{
|
||||
return $this->render('page/legal-mentions.html.twig', []);
|
||||
}
|
||||
|
||||
#[Route('/politique-de-confidentialite', name: 'confidentialitypolicy')]
|
||||
public function confidentialitypolicy(): Response
|
||||
{
|
||||
return $this->render('page/confidentiality-policy.html.twig', []);
|
||||
}
|
||||
|
||||
#[Route('/actualites/{slug}', name: 'actualites')]
|
||||
public function actualites(string $slug): Response
|
||||
{
|
||||
$news = $this->entityManager->getRepository(News::class)->findOneBy(['slug' => $slug]);
|
||||
return $this->render('page/news.html.twig', ['news' => $news]);
|
||||
}
|
||||
}
|
||||
30
src/Controller/RenderFeatureController.php
Normal file
30
src/Controller/RenderFeatureController.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\News;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
#[Route('/render/feature', name: 'render_feature_')]
|
||||
final class RenderFeatureController extends AbstractController
|
||||
{
|
||||
private EntityManagerInterface $entityManager;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
#[Route('/news', name: 'news')]
|
||||
public function news($isCarousel): Response
|
||||
{
|
||||
$news = $this->entityManager->getRepository(News::class)->findBy([], ['ordre' => 'ASC']);
|
||||
return $this->render('render_feature/news.html.twig', [
|
||||
'news' => $news,
|
||||
'isCarousel' => $isCarousel
|
||||
]);
|
||||
}
|
||||
}
|
||||
28
src/Controller/SecurityController.php
Normal file
28
src/Controller/SecurityController.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Service\KeycloakClientService;
|
||||
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
|
||||
class SecurityController extends AbstractController
|
||||
{
|
||||
private KeycloakClientService $keycloakClientService;
|
||||
|
||||
public function __construct(KeycloakClientService $keycloakClientService)
|
||||
{
|
||||
$this->keycloakClientService = $keycloakClientService;
|
||||
}
|
||||
|
||||
#[Route('/connect/keycloak', name: 'connect_keycloak')]
|
||||
public function connectKeycloak(ClientRegistry $clientRegistry): RedirectResponse
|
||||
{
|
||||
$client = $clientRegistry->getClient('keycloak');
|
||||
|
||||
return $client->redirect(['openid', 'profile', 'email'], []);
|
||||
}
|
||||
}
|
||||
56
src/Controller/SitemapController.php
Normal file
56
src/Controller/SitemapController.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\News;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
final class SitemapController extends AbstractController
|
||||
{
|
||||
#[Route('/sitemap.xml', name: 'sitemap', defaults: ['_format' => 'xml'])]
|
||||
public function sitemap(EntityManagerInterface $entityManager): Response
|
||||
{
|
||||
// Routes statiques
|
||||
$urls = [
|
||||
[
|
||||
'loc' => $this->generateUrl('home'),
|
||||
'priority' => '1.0',
|
||||
],
|
||||
[
|
||||
'loc' => $this->generateUrl('about'),
|
||||
'priority' => '0.8',
|
||||
],
|
||||
[
|
||||
'loc' => $this->generateUrl('project'),
|
||||
'priority' => '0.8',
|
||||
],
|
||||
[
|
||||
'loc' => $this->generateUrl('manualproject'),
|
||||
'priority' => '0.8',
|
||||
],
|
||||
[
|
||||
'loc' => $this->generateUrl('show'),
|
||||
'priority' => '0.7',
|
||||
],
|
||||
];
|
||||
|
||||
// Routes dynamiques (actualités)
|
||||
$newsList = $entityManager->getRepository(News::class)->findAll();
|
||||
|
||||
foreach ($newsList as $news) {
|
||||
$urls[] = [
|
||||
'loc' => $this->generateUrl('actualites', [
|
||||
'slug' => $news->getSlug()
|
||||
]),
|
||||
'priority' => '0.6',
|
||||
];
|
||||
}
|
||||
|
||||
return $this->render('sitemap/sitemap.xml.twig', [
|
||||
'urls' => $urls,
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user