<?php
namespace App\Controller;
use App\Entity\Shop;
use App\Entity\ShopReview;
use App\Form\ShopReviewType;
use App\Repository\ShopReviewRepository;
use App\Service\ShopReviewService;
use Doctrine\ORM\EntityManagerInterface;
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;
use Symfony\Component\Security\Http\Attribute\IsGranted;
#[Route('/shop/{slug}/reviews', name: 'shop_reviews_')]
class ShopReviewController extends AbstractController
{
private ShopReviewService $shopReviewService;
private EntityManagerInterface $entityManager;
private ShopReviewRepository $shopReviewRepository;
public function __construct(ShopReviewService $shopReviewService, EntityManagerInterface $entityManager)
{
$this->shopReviewService = $shopReviewService;
$this->entityManager = $entityManager;
$this->shopReviewRepository = $entityManager->getRepository(ShopReview::class);
}
#[Route('', name: 'index', methods: ['GET'])]
public function index(string $slug, Request $request): Response
{
$shop = $this->entityManager->getRepository(Shop::class)->findOneBy(['slug' => $slug]);
if (!$shop) {
throw $this->createNotFoundException('Boutique non trouvée. Le slug "' . $slug . '" ne correspond à aucune boutique.');
}
$page = (int) $request->query->get('page', 1);
$limit = 10;
$filters = [
'rating' => $request->query->get('rating'),
'verified' => $request->query->get('verified') === '1',
'search' => $request->query->get('search')
];
$reviewsData = $this->shopReviewService->getShopReviews($shop, $page, $limit, $filters);
$stats = $this->shopReviewService->getShopReviewStats($shop);
// Vérifier si l'utilisateur connecté peut laisser un avis
$canReview = false;
$userReview = null;
if ($this->getUser()) {
$canReview = !$this->shopReviewRepository->hasUserReviewedShop($this->getUser(), $shop);
if (!$canReview) {
$userReview = $this->shopReviewRepository->findOneBy(['user' => $this->getUser(), 'shop' => $shop]);
}
}
return $this->render('shop/reviews/index.html.twig', [
'shop' => $shop,
'reviews' => $reviewsData['reviews'],
'stats' => $stats,
'pagination' => [
'page' => $reviewsData['page'],
'pages' => $reviewsData['pages'],
'total' => $reviewsData['total']
],
'filters' => $filters,
'canReview' => $canReview,
'userReview' => $userReview
]);
}
#[Route('/new', name: 'new', methods: ['GET', 'POST'])]
#[IsGranted('ROLE_USER')]
public function new(string $slug, Request $request): Response
{
$shop = $this->entityManager->getRepository(Shop::class)->findOneBy(['slug' => $slug]);
if (!$shop) {
throw $this->createNotFoundException('Boutique non trouvée.');
}
// Vérifier si l'utilisateur peut laisser un avis
if ($this->shopReviewRepository->hasUserReviewedShop($this->getUser(), $shop)) {
$this->addFlash('error', 'Vous avez déjà laissé un avis pour cette boutique');
return $this->redirectToRoute('shop_reviews_index', ['slug' => $shop->getSlug()]);
}
$review = new ShopReview();
$form = $this->createForm(ShopReviewType::class, $review);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$data = [
'rating' => $review->getRating(),
'comment' => $review->getComment(),
'reviewType' => $review->getReviewType()
];
$result = $this->shopReviewService->createReview($this->getUser(), $shop, $data);
if ($result['success']) {
$this->addFlash('success', $result['message']);
return $this->redirectToRoute('shop_reviews_index', ['slug' => $shop->getSlug()]);
} else {
$this->addFlash('error', $result['message']);
}
}
return $this->render('shop/reviews/new.html.twig', [
'shop' => $shop,
'form' => $form->createView()
]);
}
#[Route('/{id}/edit', name: 'edit', methods: ['GET', 'POST'])]
#[IsGranted('ROLE_USER')]
public function edit(string $slug, ShopReview $review, Request $request): Response
{
$shop = $this->entityManager->getRepository(Shop::class)->findOneBy(['slug' => $slug]);
if (!$shop) {
throw $this->createNotFoundException('Boutique non trouvée.');
}
// Vérifier que l'utilisateur est le propriétaire de l'avis
if ($review->getUser() !== $this->getUser()) {
throw $this->createAccessDeniedException('Vous ne pouvez pas modifier cet avis');
}
$form = $this->createForm(ShopReviewType::class, $review);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$data = [
'rating' => $review->getRating(),
'comment' => $review->getComment(),
'reviewType' => $review->getReviewType()
];
$result = $this->shopReviewService->updateReview($review, $data);
if ($result['success']) {
$this->addFlash('success', $result['message']);
return $this->redirectToRoute('shop_reviews_index', ['slug' => $shop->getSlug()]);
} else {
$this->addFlash('error', $result['message']);
}
}
return $this->render('shop/reviews/edit.html.twig', [
'shop' => $shop,
'review' => $review,
'form' => $form->createView()
]);
}
#[Route('/{id}/delete', name: 'delete', methods: ['POST'])]
#[IsGranted('ROLE_USER')]
public function delete(string $slug, ShopReview $review, Request $request): Response
{
$shop = $this->entityManager->getRepository(Shop::class)->findOneBy(['slug' => $slug]);
if (!$shop) {
throw $this->createNotFoundException('Boutique non trouvée.');
}
// Vérifier que l'utilisateur est le propriétaire de l'avis
if ($review->getUser() !== $this->getUser()) {
throw $this->createAccessDeniedException('Vous ne pouvez pas supprimer cet avis');
}
if ($this->isCsrfTokenValid('delete' . $review->getId(), $request->request->get('_token'))) {
$result = $this->shopReviewService->deleteReview($review);
$this->addFlash('success', $result['message']);
}
return $this->redirectToRoute('shop_reviews_index', ['slug' => $shop->getSlug()]);
}
#[Route('/{id}/helpful', name: 'helpful', methods: ['POST'])]
public function markAsHelpful(string $slug, ShopReview $review, Request $request): JsonResponse
{
$shop = $this->entityManager->getRepository(Shop::class)->findOneBy(['slug' => $slug]);
if (!$shop) {
return new JsonResponse(['success' => false, 'message' => 'Boutique non trouvée']);
}
if ($request->isXmlHttpRequest()) {
$user = $this->getUser();
$result = $this->shopReviewService->markAsHelpful($review, $user);
return new JsonResponse($result);
}
return new JsonResponse(['success' => false, 'message' => 'Requête invalide']);
}
#[Route('/{id}/not-helpful', name: 'not_helpful', methods: ['POST'])]
public function markAsNotHelpful(string $slug, ShopReview $review, Request $request): JsonResponse
{
$shop = $this->entityManager->getRepository(Shop::class)->findOneBy(['slug' => $slug]);
if (!$shop) {
return new JsonResponse(['success' => false, 'message' => 'Boutique non trouvée']);
}
if ($request->isXmlHttpRequest()) {
$user = $this->getUser();
$result = $this->shopReviewService->markAsNotHelpful($review, $user);
return new JsonResponse($result);
}
return new JsonResponse(['success' => false, 'message' => 'Requête invalide']);
}
#[Route('/stats', name: 'stats', methods: ['GET'])]
public function stats(string $slug): JsonResponse
{
$shop = $this->entityManager->getRepository(Shop::class)->findOneBy(['slug' => $slug]);
if (!$shop) {
return new JsonResponse(['success' => false, 'message' => 'Boutique non trouvée']);
}
$stats = $this->shopReviewService->getShopReviewStats($shop);
return new JsonResponse($stats);
}
#[Route('/filter', name: 'filter', methods: ['GET'])]
public function filter(string $slug, Request $request): JsonResponse
{
$shop = $this->entityManager->getRepository(Shop::class)->findOneBy(['slug' => $slug]);
if (!$shop) {
return new JsonResponse(['success' => false, 'message' => 'Boutique non trouvée']);
}
$page = (int) $request->query->get('page', 1);
$limit = 10;
$filters = [
'rating' => $request->query->get('rating'),
'verified' => $request->query->get('verified') === '1',
'search' => $request->query->get('search')
];
$reviewsData = $this->shopReviewService->getShopReviews($shop, $page, $limit, $filters);
return new JsonResponse([
'reviews' => $reviewsData['reviews'],
'pagination' => [
'page' => $reviewsData['page'],
'pages' => $reviewsData['pages'],
'total' => $reviewsData['total']
]
]);
}
}