<?php
namespace App\Controller;
use App\Entity\Blog;
use App\Entity\Publication;
use App\Entity\SousThematique;
use App\Entity\PublicationImage;
use App\Entity\Thematique;
use App\Form\BlogType;
use App\Form\SousThematiqueType;
use App\Form\ThematiqueType;
use App\Repository\BlogRepository;
use App\Repository\SousThematiqueRepository;
use App\Repository\ThematiqueRepository;
use App\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
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\Annotation\Route;
class BlogController extends AbstractController
{
/**
* @Route("/admin/blog",name="blog_admin")
* @IsGranted("ROLE_ADMIN")
*/
public function admin_show(
BlogRepository $blogRepository
) {
try {
$publications = $blogRepository->findAll();
return $this->render('admin/blog/index.html.twig', [
'publications' => $publications
]);
} catch (\Throwable $exception) {
// Afficher le message d'erreur dans la réponse HTTP
return new Response('An error occurred: ' . $exception->getMessage(), Response::HTTP_INTERNAL_SERVER_ERROR);
}
// return $this->render('admin/blog/index.html.twig', [
// 'publications' => $blogRepository->findAll()
// ]);
}
/**
* @Route("/admin/thematique/blog/",name="blog_thematique")
* @IsGranted("ROLE_ADMIN")
*/
public function admin_add_thematique(
EntityManagerInterface $entityManager,
Request $request,
ThematiqueRepository $thematiqueRepository
) {
$thematique = new Thematique();
$form = $this->createForm(ThematiqueType::class, $thematique);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$slug = trim($thematique->getSlug());
$slug = str_replace(' ', '-', $slug);
$thematique->setSlug($slug);
$entityManager->persist($thematique);
$entityManager->flush();
return $this->redirectToRoute('blog_admin', [], Response::HTTP_SEE_OTHER);
}
return $this->render('admin/blog/thematique.html.twig', [
'thematiques' => $thematiqueRepository->findAll(),
'form' => $form->createView(),
]);
}
/**
* @Route ("/admin/thematique/delete/blog/{id}",name="delete_thematique", methods={"POST"})
* @IsGranted("ROLE_ADMIN")
*/
public function admin_delete_thematique(
$id,
EntityManagerInterface $entityManager,
Thematique $thematique,
Request $request
) {
if ($this->isCsrfTokenValid('delete' . $thematique->getId(), $request->request->get('_token'))) {
$entityManager->remove($thematique);
$entityManager->flush();
}
return $this->redirectToRoute('blog_thematique', [], Response::HTTP_SEE_OTHER);
}
/**
* @Route("/admin/thematique/update/{id}", name="update_thematique")
* @IsGranted("ROLE_ADMIN")
*/
public function admin_update_thematique(
EntityManagerInterface $entityManager,
Thematique $thematique,
Request $request,
ThematiqueRepository $thematiqueRepository
) {
$form = $this->createForm(ThematiqueType::class, $thematique);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$slug = trim($thematique->getSlug());
$slug = str_replace(' ', '-', $slug);
$thematique->setSlug($slug);
$entityManager->flush();
return $this->redirectToRoute('blog_thematique', [], Response::HTTP_SEE_OTHER);
}
return $this->render('admin/blog/thematique_update.html.twig', [
'thematiques' => $thematiqueRepository->findAll(),
'form' => $form->createView(),
]);
}
/**
* @Route("/admin/ssthematique/blog/",name="blog_ssthematique")
* @IsGranted("ROLE_ADMIN")
*/
public function admin_add_ss_thematique(
EntityManagerInterface $entityManager,
Request $request,
SousThematiqueRepository $sousThematiqueRepository
) {
$ss_thematique = new SousThematique();
$form = $this->createForm(SousThematiqueType::class, $ss_thematique);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
foreach ($ss_thematique->getThematiques() as $thematique) {
$thematique->addSousThematique($ss_thematique);
}
$slug = trim($ss_thematique->getSlug());
$slug = str_replace(' ', '-', $slug);
$ss_thematique->setSlug($slug);
$entityManager->persist($ss_thematique);
$entityManager->flush();
return $this->redirectToRoute('blog_admin', [], Response::HTTP_SEE_OTHER);
}
return $this->render('admin/blog/ss_thematique.html.twig', [
'sousthematiques' => $sousThematiqueRepository->findAll(),
'form' => $form->createView(),
]);
}
/**
* @Route ("/admin/sousthematique/delete/blog/{id}",name="delete_sousthematique", methods={"POST"})
* @IsGranted("ROLE_ADMIN")
*/
public function admin_delete_sousthematique(
$id,
EntityManagerInterface $entityManager,
SousThematique $sousThematique,
Request $request
) {
if ($this->isCsrfTokenValid('delete' . $sousThematique->getId(), $request->request->get('_token'))) {
$entityManager->remove($sousThematique);
$entityManager->flush();
}
return $this->redirectToRoute('blog_ssthematique', [], Response::HTTP_SEE_OTHER);
}
/**
* @Route("/admin/sousthematique/update/{id}", name="update_sousthematique")
* @IsGranted("ROLE_ADMIN")
*/
public function admin_update_sousthematique(
$id,
EntityManagerInterface $entityManager,
SousThematique $sousThematique,
Request $request,
SousThematiqueRepository $sousThematiqueRepository,
ThematiqueRepository $thematiqueRepository
) {
$form = $this->createForm(SousThematiqueType::class, $sousThematique);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// Récupérer les entités Thematique associées actuellement
$currentThematiques = $thematiqueRepository->findBySousThematique($sousThematique);
// Récupérer les identifiants des Thematiques sélectionnées dans la requête
$newThematiquesIds = $form->get('thematiques')->getData()->map(fn($thematique) => $thematique->getId())->toArray();
foreach ($currentThematiques as $currentThematique) {
// Vérifier si la Thematique actuelle n'est pas sélectionnée dans la requête
if (!in_array($currentThematique->getId(), $newThematiquesIds)) {
// Si la Thematique actuelle n'est pas sélectionnée dans la requête, la supprimer de la SousThematique
$sousThematique->removeThematique($currentThematique);
$currentThematique->removeSousThematique($sousThematique);
}
}
// Ajouter les nouvelles Thematiques sélectionnées dans la requête qui ne sont pas déjà associées à la SousThematique
foreach ($newThematiquesIds as $newThematiqueId) {
// Charger l'entité Thematique depuis la base de données
$newThematique = $entityManager->getRepository(Thematique::class)->find($newThematiqueId);
$sousThematique = $sousThematiqueRepository->findOneBy(['id' => $id]);
$sousThematique->addThematique($newThematique);
$newThematique->addSousThematique($sousThematique);
}
$slug = trim($sousThematique->getSlug());
$slug = str_replace(' ', '-', $slug);
$sousThematique->setSlug($slug);
$entityManager->flush();
return $this->redirectToRoute('blog_ssthematique', [], Response::HTTP_SEE_OTHER);
}
return $this->render('admin/blog/ss_thematique_update.html.twig', [
'sousthematiques' => $sousThematiqueRepository->findAll(),
'form' => $form->createView(),
]);
}
/**
* @Route("/admin/delete/blog/{id}", name="blog_delete", methods={"POST"})
* @IsGranted("ROLE_ADMIN")
*/
public function delete(Request $request, Blog $blog, EntityManagerInterface $entityManager): Response
{
if ($this->isCsrfTokenValid('delete' . $blog->getId(), $request->request->get('_token'))) {
$entityManager->remove($blog);
$entityManager->flush();
}
return $this->redirectToRoute('blog_admin', [], Response::HTTP_SEE_OTHER);
}
/**
* @Route("/admin/blog/new",name="blog_new",methods={"GET", "POST"})
* @IsGranted("ROLE_ADMIN")
*/
public function admin_new(
UserRepository $userRepository,
Request $request,
EntityManagerInterface $entityManager
) {
$blog = new Blog();
$blog->setCreatedAt(new \DateTimeImmutable());
$blog->setUpdatedAt(new \DateTimeImmutable());
$form = $this->createForm(BlogType::class, $blog);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
try {
// dd($blog);
// Persister et flusher l'entité Blog
$entityManager->persist($blog);
$entityManager->flush();
return $this->redirectToRoute('blog_admin', [], Response::HTTP_SEE_OTHER);
} catch (\Throwable $exception) {
// Afficher le message d'erreur dans la réponse HTTP
return new Response('An error occurred: ' . $exception->getMessage(), Response::HTTP_INTERNAL_SERVER_ERROR);
}
return $this->redirectToRoute('blog_admin', [], Response::HTTP_SEE_OTHER);
}
return $this->renderForm('admin/blog/new.html.twig', [
'publication' => $blog,
'form' => $form,
'nb_not_verify' => $userRepository->countUserNotVerify()
]);
}
/**
* @Route("/admin/blog/{id}/edit", name="blog_edit", methods={"GET", "POST"})
* @IsGranted("ROLE_ADMIN")
*/
public function blog_edit(Request $request, Blog $blog, EntityManagerInterface $entityManager, UserRepository $userRepository): Response
{
$form = $this->createForm(BlogType::class, $blog, ['is_edit' => true]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$blog->setUpdatedAt(new \DateTimeImmutable());
$entityManager->flush();
return $this->redirectToRoute('blog_admin', [], Response::HTTP_SEE_OTHER);
}
return $this->renderForm('admin/blog/edit.html.twig', [
'publication' => $blog,
'nb_not_verify' => $userRepository->countUserNotVerify(),
'form' => $form,
]);
}
/**
* @Route("/get-sous-thematiques/blog", name="get_sous_thematiques")
*/
public function getSousThematiques(
Request $request,
SousThematiqueRepository $thematiqueRepository
) {
// Récupérez les IDs des thématiques sélectionnées
$thematiqueIds = $request->query->get('thematiques');
if ($thematiqueIds === null) {
// Utiliser findAll si thematiqueIds est null
$sousThematiques = $thematiqueRepository->findAll();
} else {
// Utilisez ces IDs pour récupérer les sous-thématiques correspondantes
$sousThematiques = $thematiqueRepository->findByThematiquesIds($thematiqueIds);
}
// Formatez les données pour les envoyer au format JSON
$formattedData = [];
foreach ($sousThematiques as $sousThematique) {
$formattedData[] = [
'id' => $sousThematique->getId(),
'text' => $sousThematique->getName() // Ou tout autre champ approprié
];
}
// Retournez les données au format JSON
return new JsonResponse($formattedData);
}
/**
* @Route("/get-thematiques-preselectionnees/blog", name="get_thematiques_preselectionnees")
*/
public function getThematiquesPreselectionnees(
Request $request,
ThematiqueRepository $thematiqueRepository
): JsonResponse {
// Récupérer les sous-thématiques sélectionnées depuis la requête
$sousThematiquesIds = $request->query->get('sousThematiques', []);
// Si aucune sous-thématique n'est sélectionnée, retourner une réponse vide
if (empty($sousThematiquesIds)) {
return new JsonResponse([]);
}
// Récupérer les thèmes pré-sélectionnés en fonction des sous-thématiques sélectionnées
$thematiques = $thematiqueRepository->findBySousThematiquesIds($sousThematiquesIds);
// Formater les données pour la réponse JSON
$formattedThematiques = [];
foreach ($thematiques as $thematique) {
$formattedThematiques[] = [
'id' => $thematique->getId(),
'text' => $thematique->getName() // Ou tout autre champ approprié
];
}
// Retourner les thèmes pré-sélectionnés au format JSON
return new JsonResponse($formattedThematiques);
}
/**
* @Route("/blog/", name="blog", methods={"GET"})
*/
public function index(
BlogRepository $blogRepository,
ThematiqueRepository $thematiqueRepository
) {
$dernierBlogs = $blogRepository->findBy([], ['created_at' => 'DESC'], 9);
$thematiques = $thematiqueRepository->findAll();
return $this->render('blog/index.html.twig', [
'blogs' => $dernierBlogs,
'thematiques' => $thematiques
]);
}
/**
* @Route("/blog/{thematique}/{sousThematique}", name="blog_show", methods={"GET"},defaults={"thematique"=null, "sousThematique"=null})
*/
public function show(
$thematique,
$sousThematique,
BlogRepository $blogRepository,
SousThematiqueRepository $sousThematiqueRepository,
ThematiqueRepository $thematiqueRepository,
EntityManagerInterface $entityManager
): Response {
$countResultBySlugFromThematique = $thematiqueRepository->countBySlug($thematique);
if (empty($sousThematique)) {
// le paramètre est donc un thematique quand le comptage est positif
if ($countResultBySlugFromThematique > 0) {
$blogsByThematiqueWithSousThematiqueNull = $blogRepository->findByThematiqueSlug($thematique);
$sousThematiqueByThematique = $sousThematiqueRepository->findByThematiqueSlug($thematique);
//dump($sousThematiqueByThematique);
//dd($blogsByThematiqueWithSousThematiqueNull);
return $this->render('blog/thematique/index.html.twig', [
'blogs' => $blogsByThematiqueWithSousThematiqueNull ?? [],
'sousThematiques' => $sousThematiqueByThematique ?? [],
'thematique' => $thematiqueRepository->findOneBy(['slug' => $thematique]),
]);
} else {
// sinon c'est un article si le slug existe dans la bdd
$blogsBySlug = $blogRepository->findBy(['slug' => $thematique]);
if (empty($blogsBySlug)) {
throw $this->createNotFoundException('La page que vous recherchez n\'existe pas.');
}
//dd($blogsBySlug);
foreach ($blogsBySlug as $blog) {
// Récupérer la valeur actuelle de la vue
$currentViews = $blog->getView();
// Incrémenter le nombre de vues
$newViews = $currentViews + 1;
// Mettre à jour la valeur de la vue
$blog->setView($newViews);
// Enregistrer les modifications dans la base de données
$entityManager->flush();
}
return $this->render('blog/article/index.html.twig', [
'blogs' => $blogsBySlug
]);
}
} else {
if ($countResultBySlugFromThematique > 0) {
$countResultBySlugFromSousThematique = $sousThematiqueRepository->countBySlug($sousThematique);
if ($countResultBySlugFromSousThematique > 0) {
$blogsByThematiqueAndSousThematique = $blogRepository->findByThematiqueAndSousThematique($thematique, $sousThematique);
$sousThematiqueByThematique = $sousThematiqueRepository->findByThematiqueNameNotSsthematiqueEncours($thematique, $sousThematique);
//dd($blogsByThematiqueAndSousThematique);
return $this->render(
'blog/ss_thematique/index.html.twig',
[
'blogs' => $blogsByThematiqueAndSousThematique ?? [],
'sousThematique' => $sousThematiqueRepository->findOneBy(['slug' => $sousThematique]),
'thematique' => $thematiqueRepository->findOneBy(['slug' => $thematique]),
'listeSousThematique' => $sousThematiqueByThematique
]
);
} else {
throw $this->createNotFoundException('La page que vous recherchez n\'existe pas.');
}
} else {
throw $this->createNotFoundException('La page que vous recherchez n\'existe pas.');
}
}
}
/**
* @Route("/admin/blog/update-content", name="update_blog_content", methods={"POST"})
*/
public function updateBlogContent(Request $request, BlogRepository $blogRepository, EntityManagerInterface $em)
{
// Récupérer l'ID du blog envoyé via la requête
$blogId = $request->request->get('blogId');
// Récupérer le blog à partir de son ID
$blog = $blogRepository->find($blogId);
if (!$blog) {
return new JsonResponse(['error' => 'Blog non trouvé'], 404);
}
$currentBigTitle = $blog->getBigtitle();
// Récupérer le contenu actuel du blog
$content = $blog->getContent(); // Assure-toi d'avoir une méthode getContent() dans ton entité Blog
// Récupérer les mots-clés et les URL associés
$keywords = $this->getKeywords($currentBigTitle); // Fonction pour récupérer les mots-clés et leurs URL
// Appliquer les modifications sur le contenu
$modifiedContent = $this->applyKeywords($content, $keywords);
// Mettre à jour le contenu du blog dans la base de données
$blog->setContent($modifiedContent);
$em->flush();
// Retourner une réponse JSON pour indiquer que tout a bien fonctionné
return new JsonResponse(['message' => 'Contenu mis à jour avec succès']);
}
/**
* Fonction pour récupérer les mots-clés et leurs URL
* Ici on récupère tous les blogs pour avoir leur titre et URL
*/
private function getKeywords($currentBigTitle)
{
// Récupère les blogs
$blogRepository = $this->getDoctrine()->getRepository(Blog::class);
$blogs = $blogRepository->createQueryBuilder('b')
->select('b.bigtitle', 'b.slug')
->where('b.bigtitle IS NOT NULL')
->andWhere('b.bigtitle != :currentBigTitle') // Ajout de la condition pour exclure le titre actuel
->setParameter('currentBigTitle', $currentBigTitle) // Assurez-vous de définir le paramètre
->getQuery()
->getResult();
// Récupère les publications
$publicationRepository = $this->getDoctrine()->getRepository(Publication::class);
$publications = $publicationRepository->createQueryBuilder('p')
->select('p.bigtitle', 'p.slug')
->where('p.bigtitle IS NOT NULL')
->andWhere('p.bigtitle != :currentBigTitle') // Ajout de la condition pour exclure le titre actuel
->setParameter('currentBigTitle', $currentBigTitle) // Assurez-vous de définir le paramètre
->getQuery()
->getResult();
$keywords = [];
// Ajoute les blogs à la liste des mots-clés
foreach ($blogs as $blog) {
$normalized = $this->normalize($blog['bigtitle']);
$keywords[$normalized] = [
'title' => $blog['bigtitle'],
'url' => '/blog/' . $blog['slug'],
];
}
// Ajoute les publications à la liste des mots-clés
foreach ($publications as $publication) {
$normalized = $this->normalize($publication['bigtitle']);
// Utilisation de '/page/' pour les publications
$keywords[$normalized] = [
'title' => $publication['bigtitle'],
'url' => '/' . $publication['slug'],
];
}
// dd($keywords);
return $keywords;
}
/**
* Normaliser le titre pour faciliter la recherche dans le texte
* (ici on fait juste une conversion en minuscules)
*/
private function normalize($text)
{
if (class_exists('Normalizer')) {
$text = \Normalizer::normalize($text, \Normalizer::FORM_D);
}
// Supprime les accents
$text = preg_replace('/\p{Mn}/u', '', $text);
return strtolower(trim($text));
}
private function applyKeywords($content, $keywords)
{
$dom = new \DOMDocument();
libxml_use_internal_errors(true);
$dom->loadHTML(mb_convert_encoding('<div>' . $content . '</div>', 'HTML-ENTITIES', 'UTF-8'));
libxml_clear_errors();
$forbiddenTags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'a'];
// Récupère les mots déjà entourés par une balise <a>
$linkedKeywords = [];
$existingLinks = $dom->getElementsByTagName('a');
foreach ($existingLinks as $link) {
$linkedKeywords[] = $this->normalize(trim($link->nodeValue));
}
// Trier les mots-clés du plus long au plus court
uksort($keywords, function ($a, $b) {
return mb_strlen($b) - mb_strlen($a);
});
foreach ($keywords as $keyword => $data) {
$normalizedKeyword = $this->normalize($keyword);
$xpath = new \DOMXPath($dom);
$textNodes = $xpath->query('//text()');
foreach ($textNodes as $textNode) {
$parent = $textNode->parentNode;
// Vérifie si un des ancêtres est une balise interdite
$isForbidden = false;
$current = $parent;
while ($current !== null && $current->nodeName !== 'div') {
if (in_array(strtolower($current->nodeName), $forbiddenTags)) {
$isForbidden = true;
break;
}
$current = $current->parentNode;
}
if ($isForbidden) {
continue;
}
if (in_array($keyword, $linkedKeywords)) {
break;
}
$text = $textNode->nodeValue;
$normalizedText = $this->normalize($text);
$pos = mb_stripos($normalizedText, $normalizedKeyword);
if ($pos !== false) {
$beforeChar = $pos > 0 ? mb_substr($normalizedText, $pos - 1, 1) : '';
$afterPos = $pos + mb_strlen($keyword, 'UTF-8');
$nextChar = mb_substr($normalizedText, $afterPos, 1);
$isBeforeOk = $beforeChar === '' || preg_match('/[\s.,;:(!?\[{<"\']/', $beforeChar);
$isAfterOk = $nextChar === '' || preg_match('/[\s.,;:!?)\]}>"\']/', $nextChar);
if (!$isBeforeOk || !$isAfterOk) {
continue;
}
// Vérifie que le caractère après le mot est une limite valide (ponctuation, espace, fin de texte)
$afterPos = $pos + mb_strlen($keyword, 'UTF-8');
$nextChar = mb_substr($normalizedText, $afterPos, 1);
// Si le mot est collé à un autre mot, on ne fait rien
if ($nextChar !== '' && !preg_match('/[\s.,;:!?)\]}-]/u', $nextChar)) {
continue;
}
$caractPlus = 0;
// Ajuster la position pour ignorer un espace avant le mot (si nécessaire)
if (mb_substr($text, $pos, 1) === ' ') {
$caractPlus++; // Ajouter 1 pour commencer après l'espace
}
$match = mb_substr($text, $pos, mb_strlen($keyword, 'UTF-8'));
if ($this->normalize($match) !== $normalizedKeyword) {
$match = mb_substr($text, $pos + 1, mb_strlen($keyword, 'UTF-8'));
$after = mb_substr($text, $afterPos + 1);
$before = mb_substr($text, 0, $pos + 1);
} else {
$after = mb_substr($text, $afterPos);
$before = mb_substr($text, 0, $pos);
}
// Crée le lien
$link = $dom->createElement('a', $match);
$link->setAttribute('href', $data['url']);
$link->setAttribute('class', 'suggested-link');
// Recompose
$fragment = $dom->createDocumentFragment();
if ($before !== '') {
$fragment->appendChild($dom->createTextNode($before));
}
$fragment->appendChild($link);
if ($after !== '') {
$fragment->appendChild($dom->createTextNode($after));
}
$textNode->parentNode->replaceChild($fragment, $textNode);
$linkedKeywords[] = $keyword;
break;
}
}
}
// Récupère le contenu de notre div temporaire
$body = $dom->getElementsByTagName('div')->item(0);
$newContent = '';
foreach ($body->childNodes as $child) {
$newContent .= $dom->saveHTML($child);
}
return $newContent;
}
}