<?php
namespace App\Repository;
use App\Entity\Shop;
use App\Entity\ShopReview;
use App\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<ShopReview>
*/
class ShopReviewRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, ShopReview::class);
}
/**
* Récupérer les avis d'une boutique
*/
public function findByShop(Shop $shop, bool $onlyVisible = true): array
{
$qb = $this->createQueryBuilder('sr')
->where('sr.shop = :shop')
->setParameter('shop', $shop)
->orderBy('sr.createdAt', 'DESC');
if ($onlyVisible) {
$qb->andWhere('sr.isVisible = :visible')
->setParameter('visible', true);
}
return $qb->getQuery()->getResult();
}
/**
* Trouver les avis d'un utilisateur
*/
public function findByUser(User $user): array
{
return $this->createQueryBuilder('sr')
->where('sr.user = :user')
->setParameter('user', $user)
->orderBy('sr.createdAt', 'DESC')
->getQuery()
->getResult();
}
/**
* Vérifier si un utilisateur a déjà laissé un avis pour une boutique
*/
public function hasUserReviewedShop(User $user, Shop $shop): bool
{
$result = $this->createQueryBuilder('sr')
->select('COUNT(sr.id)')
->where('sr.user = :user')
->andWhere('sr.shop = :shop')
->setParameter('user', $user)
->setParameter('shop', $shop)
->getQuery()
->getSingleScalarResult();
return $result > 0;
}
/**
* Obtenir les statistiques d'avis d'une boutique
*/
public function getShopReviewStats(Shop $shop): array
{
$qb = $this->createQueryBuilder('sr')
->select([
'AVG(sr.rating) as averageRating',
'COUNT(sr.id) as totalReviews',
'SUM(CASE WHEN sr.rating = 5 THEN 1 ELSE 0 END) as fiveStars',
'SUM(CASE WHEN sr.rating = 4 THEN 1 ELSE 0 END) as fourStars',
'SUM(CASE WHEN sr.rating = 3 THEN 1 ELSE 0 END) as threeStars',
'SUM(CASE WHEN sr.rating = 2 THEN 1 ELSE 0 END) as twoStars',
'SUM(CASE WHEN sr.rating = 1 THEN 1 ELSE 0 END) as oneStar',
'SUM(CASE WHEN sr.isVerified = true THEN 1 ELSE 0 END) as verifiedReviews'
])
->where('sr.shop = :shop')
->andWhere('sr.isVisible = :visible')
->setParameter('shop', $shop)
->setParameter('visible', true);
$result = $qb->getQuery()->getSingleResult();
return [
'averageRating' => round($result['averageRating'] ?? 0, 1),
'totalReviews' => (int) ($result['totalReviews'] ?? 0),
'fiveStars' => (int) ($result['fiveStars'] ?? 0),
'fourStars' => (int) ($result['fourStars'] ?? 0),
'threeStars' => (int) ($result['threeStars'] ?? 0),
'twoStars' => (int) ($result['twoStars'] ?? 0),
'oneStar' => (int) ($result['oneStar'] ?? 0),
'verifiedReviews' => (int) ($result['verifiedReviews'] ?? 0),
'positivePercentage' => $this->calculatePositivePercentage($result)
];
}
/**
* Calculer le pourcentage d'avis positifs (4-5 étoiles)
*/
private function calculatePositivePercentage(array $stats): float
{
$total = $stats['totalReviews'] ?? 0;
if ($total === 0) {
return 0;
}
$positive = ($stats['fiveStars'] ?? 0) + ($stats['fourStars'] ?? 0);
return round(($positive / $total) * 100, 1);
}
/**
* Obtenir les avis récents
*/
public function findRecentReviews(int $limit = 10): array
{
return $this->createQueryBuilder('sr')
->where('sr.isVisible = :visible')
->setParameter('visible', true)
->orderBy('sr.createdAt', 'DESC')
->setMaxResults($limit)
->getQuery()
->getResult();
}
/**
* Obtenir les avis par note
*/
public function findByRating(Shop $shop, int $rating): array
{
return $this->createQueryBuilder('sr')
->where('sr.shop = :shop')
->andWhere('sr.rating = :rating')
->andWhere('sr.isVisible = :visible')
->setParameter('shop', $shop)
->setParameter('rating', $rating)
->setParameter('visible', true)
->orderBy('sr.createdAt', 'DESC')
->getQuery()
->getResult();
}
/**
* Obtenir les avis vérifiés uniquement
*/
public function findVerifiedReviews(Shop $shop): array
{
return $this->createQueryBuilder('sr')
->where('sr.shop = :shop')
->andWhere('sr.isVerified = :verified')
->andWhere('sr.isVisible = :visible')
->setParameter('shop', $shop)
->setParameter('verified', true)
->setParameter('visible', true)
->orderBy('sr.createdAt', 'DESC')
->getQuery()
->getResult();
}
/**
* Rechercher des avis par mot-clé
*/
public function searchReviews(Shop $shop, string $keyword): array
{
return $this->createQueryBuilder('sr')
->where('sr.shop = :shop')
->andWhere('sr.comment LIKE :keyword')
->andWhere('sr.isVisible = :visible')
->setParameter('shop', $shop)
->setParameter('keyword', '%' . $keyword . '%')
->setParameter('visible', true)
->orderBy('sr.createdAt', 'DESC')
->getQuery()
->getResult();
}
/**
* Obtenir les avis les plus utiles
*/
public function findMostHelpfulReviews(Shop $shop, int $limit = 5): array
{
return $this->createQueryBuilder('sr')
->where('sr.shop = :shop')
->andWhere('sr.isVisible = :visible')
->setParameter('shop', $shop)
->setParameter('visible', true)
->orderBy('sr.helpfulCount', 'DESC')
->addOrderBy('sr.createdAt', 'DESC')
->setMaxResults($limit)
->getQuery()
->getResult();
}
/**
* Obtenir les statistiques globales des avis
*/
public function getGlobalStats(): array
{
$qb = $this->createQueryBuilder('sr')
->select([
'AVG(sr.rating) as averageRating',
'COUNT(sr.id) as totalReviews',
'COUNT(DISTINCT sr.shop) as shopsWithReviews',
'SUM(CASE WHEN sr.isVerified = true THEN 1 ELSE 0 END) as verifiedReviews'
])
->where('sr.isVisible = :visible')
->setParameter('visible', true);
$result = $qb->getQuery()->getSingleResult();
return [
'averageRating' => round($result['averageRating'] ?? 0, 1),
'totalReviews' => (int) ($result['totalReviews'] ?? 0),
'shopsWithReviews' => (int) ($result['shopsWithReviews'] ?? 0),
'verifiedReviews' => (int) ($result['verifiedReviews'] ?? 0)
];
}
}