<?php
namespace App\Entity;
use App\Repository\ShopReviewRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass: ShopReviewRepository::class)]
#[ORM\Table(name: 'shop_reviews')]
#[ORM\HasLifecycleCallbacks]
class ShopReview
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\ManyToOne(targetEntity: User::class)]
#[ORM\JoinColumn(nullable: false)]
private ?User $user = null;
#[ORM\ManyToOne(targetEntity: Shop::class, inversedBy: 'reviews')]
#[ORM\JoinColumn(nullable: false)]
private ?Shop $shop = null;
#[ORM\Column(type: Types::TEXT)]
#[Assert\NotBlank(message: 'Le commentaire est obligatoire')]
#[Assert\Length(min: 10, max: 1000, minMessage: 'Le commentaire doit contenir au moins {{ limit }} caractères', maxMessage: 'Le commentaire ne peut pas dépasser {{ limit }} caractères')]
private ?string $comment = null;
#[ORM\Column(type: Types::INTEGER)]
#[Assert\Range(min: 1, max: 5, notInRangeMessage: 'La note doit être entre {{ min }} et {{ max }}')]
private ?int $rating = null;
#[ORM\Column(type: Types::BOOLEAN)]
private bool $isVerified = false;
#[ORM\Column(type: Types::BOOLEAN)]
private bool $isVisible = true;
#[ORM\Column(type: Types::BOOLEAN)]
private bool $isHelpful = false;
#[ORM\Column(type: Types::INTEGER)]
private int $helpfulCount = 0;
#[ORM\Column(type: Types::INTEGER)]
private int $notHelpfulCount = 0;
#[ORM\Column(type: Types::DATETIME_IMMUTABLE)]
private ?\DateTimeImmutable $createdAt = null;
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)]
private ?\DateTimeImmutable $updatedAt = null;
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)]
private ?\DateTimeImmutable $verifiedAt = null;
// Constantes pour les types de review
public const TYPE_PRODUCT_QUALITY = 'product_quality';
public const TYPE_SHIPPING_SPEED = 'shipping_speed';
public const TYPE_CUSTOMER_SERVICE = 'customer_service';
public const TYPE_COMMUNICATION = 'communication';
public const TYPE_PACKAGING = 'packaging';
#[ORM\Column(type: Types::STRING, length: 50, nullable: true)]
private ?string $reviewType = null;
#[ORM\OneToMany(targetEntity: ShopReviewVote::class, mappedBy: 'review', cascade: ['remove'])]
private Collection $votes;
public function __construct()
{
$this->createdAt = new \DateTimeImmutable();
$this->votes = new ArrayCollection();
}
#[ORM\PreUpdate]
public function setUpdatedAtValue(): void
{
$this->updatedAt = new \DateTimeImmutable();
}
public function getId(): ?int
{
return $this->id;
}
public function getUser(): ?User
{
return $this->user;
}
public function setUser(?User $user): static
{
$this->user = $user;
return $this;
}
public function getShop(): ?Shop
{
return $this->shop;
}
public function setShop(?Shop $shop): static
{
$this->shop = $shop;
return $this;
}
public function getComment(): ?string
{
return $this->comment;
}
public function setComment(string $comment): static
{
$this->comment = $comment;
return $this;
}
public function getRating(): ?int
{
return $this->rating;
}
public function setRating(int $rating): static
{
$this->rating = $rating;
return $this;
}
public function isVerified(): bool
{
return $this->isVerified;
}
public function setIsVerified(bool $isVerified): static
{
$this->isVerified = $isVerified;
if ($isVerified && !$this->verifiedAt) {
$this->verifiedAt = new \DateTimeImmutable();
}
return $this;
}
public function isVisible(): bool
{
return $this->isVisible;
}
public function setIsVisible(bool $isVisible): static
{
$this->isVisible = $isVisible;
return $this;
}
public function isHelpful(): bool
{
return $this->isHelpful;
}
public function setIsHelpful(bool $isHelpful): static
{
$this->isHelpful = $isHelpful;
return $this;
}
public function getHelpfulCount(): int
{
return $this->helpfulCount;
}
public function setHelpfulCount(int $helpfulCount): static
{
$this->helpfulCount = $helpfulCount;
return $this;
}
public function incrementHelpfulCount(): static
{
$this->helpfulCount++;
return $this;
}
public function getNotHelpfulCount(): int
{
return $this->notHelpfulCount;
}
public function setNotHelpfulCount(int $notHelpfulCount): static
{
$this->notHelpfulCount = $notHelpfulCount;
return $this;
}
public function incrementNotHelpfulCount(): static
{
$this->notHelpfulCount++;
return $this;
}
public function getCreatedAt(): ?\DateTimeImmutable
{
return $this->createdAt;
}
public function setCreatedAt(\DateTimeImmutable $createdAt): static
{
$this->createdAt = $createdAt;
return $this;
}
public function getUpdatedAt(): ?\DateTimeImmutable
{
return $this->updatedAt;
}
public function setUpdatedAt(?\DateTimeImmutable $updatedAt): static
{
$this->updatedAt = $updatedAt;
return $this;
}
public function getVerifiedAt(): ?\DateTimeImmutable
{
return $this->verifiedAt;
}
public function setVerifiedAt(?\DateTimeImmutable $verifiedAt): static
{
$this->verifiedAt = $verifiedAt;
return $this;
}
public function getReviewType(): ?string
{
return $this->reviewType;
}
public function setReviewType(?string $reviewType): static
{
$this->reviewType = $reviewType;
return $this;
}
public function getRatingStars(): string
{
$stars = '';
for ($i = 1; $i <= 5; $i++) {
$stars .= $i <= $this->rating ? '★' : '☆';
}
return $stars;
}
public function getRatingPercentage(): float
{
return ($this->rating / 5) * 100;
}
public function getHelpfulnessPercentage(): float
{
$total = $this->helpfulCount + $this->notHelpfulCount;
if ($total === 0) {
return 0;
}
return ($this->helpfulCount / $total) * 100;
}
public function getTimeAgo(): string
{
$now = new \DateTimeImmutable();
$diff = $now->diff($this->createdAt);
if ($diff->y > 0) {
return $diff->y . ' an' . ($diff->y > 1 ? 's' : '');
} elseif ($diff->m > 0) {
return $diff->m . ' mois';
} elseif ($diff->d > 0) {
return $diff->d . ' jour' . ($diff->d > 1 ? 's' : '');
} elseif ($diff->h > 0) {
return $diff->h . ' heure' . ($diff->h > 1 ? 's' : '');
} else {
return $diff->i . ' minute' . ($diff->i > 1 ? 's' : '');
}
}
public static function getReviewTypes(): array
{
return [
self::TYPE_PRODUCT_QUALITY => 'Qualité du produit',
self::TYPE_SHIPPING_SPEED => 'Vitesse de livraison',
self::TYPE_CUSTOMER_SERVICE => 'Service client',
self::TYPE_COMMUNICATION => 'Communication',
self::TYPE_PACKAGING => 'Emballage'
];
}
public function getReviewTypeLabel(): string
{
$types = self::getReviewTypes();
return $types[$this->reviewType] ?? 'Non spécifié';
}
/**
* @return Collection<int, ShopReviewVote>
*/
public function getVotes(): Collection
{
return $this->votes;
}
public function addVote(ShopReviewVote $vote): static
{
if (!$this->votes->contains($vote)) {
$this->votes->add($vote);
$vote->setReview($this);
}
return $this;
}
public function removeVote(ShopReviewVote $vote): static
{
if ($this->votes->removeElement($vote)) {
if ($vote->getReview() === $this) {
$vote->setReview(null);
}
}
return $this;
}
}