<?php
namespace App\Controller\Admin;
use App\Entity\Article;
use App\Entity\MediaAsset;
use App\Form\ArticleType;
use App\Repository\ArticleRepository;
use App\Service\ImageGenerationService;
use App\Service\ModerationService;
use App\Service\SocialPublisherService;
use Doctrine\ORM\EntityManagerInterface;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\String\Slugger\SluggerInterface;
/**
* @Route("/admin/articles")
*/
class ArticleAdminController extends AbstractController
{
/**
* @Route("", name="admin_articles")
*/
public function index(
Request $request,
ArticleRepository $articleRepo,
PaginatorInterface $paginator
): Response {
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$status = $request->query->get('status', '');
$qb = $articleRepo->createQueryBuilder('a')
->orderBy('a.createdAt', 'DESC');
if ($status) {
$qb->where('a.status = :status')
->setParameter('status', $status);
}
$articles = $paginator->paginate(
$qb->getQuery(),
$request->query->getInt('page', 1),
20
);
return $this->render('admin/article/index.html.twig', [
'articles' => $articles,
'current_status' => $status,
]);
}
/**
* @Route("/new", name="admin_article_new")
*/
public function new(
Request $request,
EntityManagerInterface $em,
SluggerInterface $slugger
): Response {
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$article = new Article();
$form = $this->createForm(ArticleType::class, $article);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$imageFile = $form->get('imageFile')->getData();
if ($imageFile) {
$mediaAsset = $this->handleImageUpload($imageFile, $slugger, $em);
if ($mediaAsset) {
$article->setFeaturedImage($mediaAsset);
}
}
$em->persist($article);
$em->flush();
$this->addFlash('success', 'Article créé avec succès');
return $this->redirectToRoute('admin_article_edit', ['id' => $article->getId()]);
}
return $this->render('admin/article/new.html.twig', [
'form' => $form->createView(),
]);
}
/**
* @Route("/{id}/edit", name="admin_article_edit")
*/
public function edit(
Article $article,
Request $request,
EntityManagerInterface $em,
SluggerInterface $slugger
): Response {
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$form = $this->createForm(ArticleType::class, $article);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$imageFile = $form->get('imageFile')->getData();
if ($imageFile) {
$oldImage = $article->getFeaturedImage();
$mediaAsset = $this->handleImageUpload($imageFile, $slugger, $em);
if ($mediaAsset) {
$article->setFeaturedImage($mediaAsset);
if ($oldImage && $oldImage->getIsAiGenerated()) {
$oldPath = $this->getParameter('kernel.project_dir') . '/public/' . $oldImage->getPath();
if (file_exists($oldPath)) {
@unlink($oldPath);
}
$em->remove($oldImage);
}
}
}
$em->flush();
$this->addFlash('success', 'Article mis à jour');
return $this->redirectToRoute('admin_article_edit', ['id' => $article->getId()]);
}
return $this->render('admin/article/edit.html.twig', [
'article' => $article,
'form' => $form->createView(),
]);
}
/**
* @Route("/{id}/publish", name="admin_article_publish", methods={"POST"})
*/
public function publish(
Article $article,
EntityManagerInterface $em,
SocialPublisherService $socialPublisher
): Response {
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$article->publish();
$em->flush();
$socialPublisher->publishToAllPlatforms($article);
$this->addFlash('success', 'Article publié et diffusé sur les réseaux sociaux');
return $this->redirectToRoute('admin_articles');
}
/**
* @Route("/{id}/validate", name="admin_article_validate", methods={"POST"})
*/
public function validate(
Article $article,
Request $request,
ModerationService $moderation
): Response {
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$approved = $request->request->get('approved') === '1';
$notes = $request->request->get('notes');
$moderation->validateManually($article, $approved, $notes);
$this->addFlash(
'success',
$approved ? 'Article approuvé' : 'Article rejeté'
);
return $this->redirectToRoute('admin_articles', ['status' => 'pending']);
}
/**
* @Route("/{id}/delete", name="admin_article_delete", methods={"POST"})
*/
public function delete(
Article $article,
EntityManagerInterface $em
): Response {
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$em->remove($article);
$em->flush();
$this->addFlash('success', 'Article supprimé');
return $this->redirectToRoute('admin_articles');
}
/**
* @Route("/{id}/generate-image", name="admin_article_generate_image", methods={"POST"})
*/
public function generateImage(
Article $article,
Request $request,
ImageGenerationService $imageGenerator,
EntityManagerInterface $em
): JsonResponse {
$this->denyAccessUnlessGranted('ROLE_ADMIN');
try {
$title = $request->request->get('title', $article->getTitle());
$excerpt = $request->request->get('excerpt', $article->getExcerpt());
$mediaAsset = $imageGenerator->generateArticleImage($title, $excerpt);
if (!$mediaAsset) {
return $this->json([
'success' => false,
'message' => 'Échec de la génération de l\'image'
], 500);
}
$oldImage = $article->getFeaturedImage();
$article->setFeaturedImage($mediaAsset);
$em->flush();
if ($oldImage && $oldImage->getIsAiGenerated()) {
$oldPath = $this->getParameter('kernel.project_dir') . '/public/' . $oldImage->getPath();
if (file_exists($oldPath)) {
@unlink($oldPath);
}
$em->remove($oldImage);
$em->flush();
}
return $this->json([
'success' => true,
'message' => 'Image générée avec succès!',
'image_url' => '/' . $mediaAsset->getPath(),
'media_id' => $mediaAsset->getId(),
]);
} catch (\Exception $e) {
return $this->json([
'success' => false,
'message' => 'Erreur: ' . $e->getMessage()
], 500);
}
}
private function handleImageUpload($imageFile, SluggerInterface $slugger, EntityManagerInterface $em): ?MediaAsset
{
$originalFilename = pathinfo($imageFile->getClientOriginalName(), PATHINFO_FILENAME);
$safeFilename = $slugger->slug($originalFilename);
$newFilename = $safeFilename . '-' . uniqid() . '.' . $imageFile->guessExtension();
$uploadDir = $this->getParameter('kernel.project_dir') . '/public/uploads/media';
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0777, true);
}
try {
$imageFile->move($uploadDir, $newFilename);
$mediaAsset = new MediaAsset();
$mediaAsset->setType(MediaAsset::TYPE_IMAGE);
$mediaAsset->setPath('uploads/media/' . $newFilename);
$mediaAsset->setIsAiGenerated(false);
$mediaAsset->setFileSize(filesize($uploadDir . '/' . $newFilename));
$mediaAsset->setMimeType($imageFile->getMimeType());
$mediaAsset->setTitle($originalFilename);
$em->persist($mediaAsset);
$em->flush();
return $mediaAsset;
} catch (FileException $e) {
$this->addFlash('error', 'Erreur lors de l\'upload de l\'image: ' . $e->getMessage());
return null;
}
}
}