<?php
namespace App\Entity;
use App\Repository\ShopRepository;
use DateTimeImmutable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: ShopRepository::class)]
class Shop
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\OneToMany(targetEntity: Notification::class, mappedBy: 'shop')]
private Collection $notifications;
#[ORM\Column(length: 100, unique:true)]
private ?string $name = null;
#[ORM\Column(length: 120, unique:true)]
private ?string $slug = null;
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $description = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $logo = null;
#[ORM\ManyToOne(inversedBy: 'shops')]
#[ORM\JoinColumn(nullable: false)]
private ?ShopCategory $shopCategory = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $address = null;
#[ORM\OneToMany(targetEntity: Product::class, mappedBy: 'shop')]
private Collection $products;
#[ORM\OneToMany(targetEntity: ShopFollow::class, mappedBy: 'shop')]
private Collection $follows;
#[ORM\OneToMany(targetEntity: ShopReview::class, mappedBy: 'shop')]
private Collection $reviews;
#[ORM\Column(length: 50, nullable: true)]
private ?string $phoneNumber = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $email = null;
#[ORM\Column]
private ?bool $isActive = null;
#[ORM\Column]
private ?DateTimeImmutable $createdAt = null;
#[ORM\Column(nullable: true)]
private ?DateTimeImmutable $updatedAt = null;
#[ORM\ManyToMany(targetEntity: User::class, inversedBy: 'shops')]
private Collection $manager;
#[ORM\Column]
private ?int $currentProducts = null;
#[ORM\Column]
private ?int $currentEmployees = null;
#[ORM\Column]
private ?int $currentOrders = null;
#[ORM\Column(type: Types::DECIMAL, precision: 15, scale: 3)]
private ?string $currentRevenue = null;
#[ORM\Column]
private ?int $currentStorage = null;
#[ORM\ManyToOne(inversedBy: 'shops')]
private ?ShopPlan $plan = null;
#[ORM\Column]
private ?int $currentCaLimit = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $siretNif = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $iban = null;
// Nouveaux champs pour améliorer la boutique
#[ORM\Column(length: 255, nullable: true)]
private ?string $website = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $facebook = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $instagram = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $twitter = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $youtube = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $tiktok = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $whatsapp = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $telegram = null;
#[ORM\Column(type: Types::JSON, nullable: true)]
private ?array $bannerImages = null;
#[ORM\Column]
private ?int $viewCount = 0;
#[ORM\Column]
private ?int $followerCount = 0;
#[ORM\Column]
private ?float $averageRating = 0.0;
#[ORM\Column]
private ?int $reviewCount = 0;
#[ORM\Column(length: 50, nullable: true)]
private ?string $status = 'pending'; // pending, active, suspended, closed
#[ORM\Column(length: 255, nullable: true)]
private ?string $verificationStatus = 'unverified'; // unverified, pending, verified, rejected
#[ORM\Column(nullable: true)]
private ?DateTimeImmutable $verifiedAt = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $businessHours = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $deliveryAreas = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $paymentMethods = null;
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $returnPolicy = null;
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $shippingPolicy = null;
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $privacyPolicy = null;
#[ORM\Column]
private ?bool $isVerified = false;
#[ORM\Column]
private ?bool $isPremium = false;
#[ORM\Column]
private ?bool $allowReviews = true;
#[ORM\Column]
private ?bool $allowMessages = true;
#[ORM\Column]
private ?bool $showContactInfo = true;
#[ORM\Column]
private ?bool $showSocialLinks = true;
public function __construct()
{
$this->notifications = new ArrayCollection();
$this->products = new ArrayCollection();
$this->follows = new ArrayCollection();
$this->reviews = new ArrayCollection();
$this->manager = new ArrayCollection();
$this->createdAt = new DateTimeImmutable();
$this->isActive = true;
$this->currentProducts = 0;
$this->currentEmployees = 0;
$this->currentOrders = 0;
$this->currentRevenue = '0.000';
$this->currentStorage = 0;
$this->currentCaLimit = 0;
$this->viewCount = 0;
$this->followerCount = 0;
$this->averageRating = 0.0;
$this->reviewCount = 0;
$this->isVerified = false;
$this->isPremium = false;
$this->allowReviews = true;
$this->allowMessages = true;
$this->showContactInfo = true;
$this->showSocialLinks = true;
}
public function getId(): ?int
{
return $this->id;
}
/**
* @return Collection<int, Notification>
*/
public function getNotifications(): Collection
{
return $this->notifications;
}
public function addNotification(Notification $notification): static
{
if (!$this->notifications->contains($notification)) {
$this->notifications->add($notification);
$notification->setShop($this);
}
return $this;
}
public function removeNotification(Notification $notification): static
{
if ($this->notifications->removeElement($notification)) {
// set the owning side to null (unless already changed)
if ($notification->getShop() === $this) {
$notification->setShop(null);
}
}
return $this;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): static
{
$this->name = $name;
return $this;
}
public function getSlug(): ?string
{
return $this->slug;
}
public function setSlug(string $slug): static
{
$this->slug = $slug;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): static
{
$this->description = $description;
return $this;
}
public function getLogo(): ?string
{
return $this->logo;
}
public function setLogo(?string $logo): static
{
$this->logo = $logo;
return $this;
}
public function getShopCategory(): ?ShopCategory
{
return $this->shopCategory;
}
public function setShopCategory(?ShopCategory $shopCategory): static
{
$this->shopCategory = $shopCategory;
return $this;
}
public function getAddress(): ?string
{
return $this->address;
}
public function setAddress(?string $address): static
{
$this->address = $address;
return $this;
}
/**
* @return Collection<int, Product>
*/
public function getProducts(): Collection
{
return $this->products;
}
public function addProduct(Product $product): static
{
if (!$this->products->contains($product)) {
$this->products->add($product);
$product->setShop($this);
}
return $this;
}
public function removeProduct(Product $product): static
{
if ($this->products->removeElement($product)) {
// set the owning side to null (unless already changed)
if ($product->getShop() === $this) {
$product->setShop(null);
}
}
return $this;
}
public function getPhoneNumber(): ?string
{
return $this->phoneNumber;
}
public function setPhoneNumber(?string $phoneNumber): static
{
$this->phoneNumber = $phoneNumber;
return $this;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(?string $email): static
{
$this->email = $email;
return $this;
}
public function isIsActive(): ?bool
{
return $this->isActive;
}
public function setIsActive(bool $isActive): static
{
$this->isActive = $isActive;
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;
}
/**
* @return Collection<int, User>
*/
public function getManager(): Collection
{
return $this->manager;
}
public function addManager(User $manager): static
{
if (!$this->manager->contains($manager)) {
$this->manager->add($manager);
}
return $this;
}
public function removeManager(User $manager): static
{
$this->manager->removeElement($manager);
return $this;
}
public function getCurrentProducts(): ?int
{
return $this->currentProducts;
}
public function setCurrentProducts(int $currentProducts): static
{
$this->currentProducts = $currentProducts;
return $this;
}
public function getCurrentEmployees(): ?int
{
return $this->currentEmployees;
}
public function setCurrentEmployees(int $currentEmployees): static
{
$this->currentEmployees = $currentEmployees;
return $this;
}
public function getCurrentOrders(): ?int
{
return $this->currentOrders;
}
public function setCurrentOrders(int $currentOrders): static
{
$this->currentOrders = $currentOrders;
return $this;
}
public function getCurrentRevenue(): ?string
{
return $this->currentRevenue;
}
public function setCurrentRevenue(string $currentRevenue): static
{
$this->currentRevenue = $currentRevenue;
return $this;
}
public function getCurrentStorage(): ?int
{
return $this->currentStorage;
}
public function setCurrentStorage(int $currentStorage): static
{
$this->currentStorage = $currentStorage;
return $this;
}
public function getPlan(): ?ShopPlan
{
return $this->plan;
}
public function setPlan(?ShopPlan $plan): static
{
$this->plan = $plan;
return $this;
}
public function getCurrentCaLimit(): ?int
{
return $this->currentCaLimit;
}
public function setCurrentCaLimit(int $currentCaLimit): static
{
$this->currentCaLimit = $currentCaLimit;
return $this;
}
public function getSiretNif(): ?string
{
return $this->siretNif;
}
public function setSiretNif(?string $siretNif): static
{
$this->siretNif = $siretNif;
return $this;
}
public function getIban(): ?string
{
return $this->iban;
}
public function setIban(?string $iban): static
{
$this->iban = $iban;
return $this;
}
// Getters et setters pour les nouveaux champs
public function getWebsite(): ?string
{
return $this->website;
}
public function setWebsite(?string $website): static
{
$this->website = $website;
return $this;
}
public function getFacebook(): ?string
{
return $this->facebook;
}
public function setFacebook(?string $facebook): static
{
$this->facebook = $facebook;
return $this;
}
public function getInstagram(): ?string
{
return $this->instagram;
}
public function setInstagram(?string $instagram): static
{
$this->instagram = $instagram;
return $this;
}
public function getTwitter(): ?string
{
return $this->twitter;
}
public function setTwitter(?string $twitter): static
{
$this->twitter = $twitter;
return $this;
}
public function getYoutube(): ?string
{
return $this->youtube;
}
public function setYoutube(?string $youtube): static
{
$this->youtube = $youtube;
return $this;
}
public function getTiktok(): ?string
{
return $this->tiktok;
}
public function setTiktok(?string $tiktok): static
{
$this->tiktok = $tiktok;
return $this;
}
public function getWhatsapp(): ?string
{
return $this->whatsapp;
}
public function setWhatsapp(?string $whatsapp): static
{
$this->whatsapp = $whatsapp;
return $this;
}
public function getTelegram(): ?string
{
return $this->telegram;
}
public function setTelegram(?string $telegram): static
{
$this->telegram = $telegram;
return $this;
}
public function getBannerImages(): ?array
{
return $this->bannerImages;
}
public function setBannerImages(?array $bannerImages): static
{
$this->bannerImages = $bannerImages;
return $this;
}
public function addBannerImage(string $imagePath): static
{
if ($this->bannerImages === null) {
$this->bannerImages = [];
}
if (!in_array($imagePath, $this->bannerImages)) {
$this->bannerImages[] = $imagePath;
}
return $this;
}
public function removeBannerImage(string $imagePath): static
{
if ($this->bannerImages !== null) {
$this->bannerImages = array_values(array_filter($this->bannerImages, function($img) use ($imagePath) {
return $img !== $imagePath;
}));
}
return $this;
}
public function getAllBannerImages(): array
{
return $this->bannerImages ?? [];
}
public function getFirstBannerImage(): ?string
{
return !empty($this->bannerImages) ? $this->bannerImages[0] : null;
}
public function getViewCount(): ?int
{
return $this->viewCount;
}
public function setViewCount(int $viewCount): static
{
$this->viewCount = $viewCount;
return $this;
}
public function incrementViewCount(): static
{
$this->viewCount = ($this->viewCount ?? 0) + 1;
return $this;
}
public function getFollowerCount(): ?int
{
return $this->followerCount;
}
public function setFollowerCount(int $followerCount): static
{
$this->followerCount = $followerCount;
return $this;
}
public function setAverageRating(float $averageRating): static
{
$this->averageRating = $averageRating;
return $this;
}
public function getReviewCount(): ?int
{
return $this->reviewCount;
}
public function setReviewCount(int $reviewCount): static
{
$this->reviewCount = $reviewCount;
return $this;
}
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(string $status): static
{
$this->status = $status;
return $this;
}
public function getVerificationStatus(): ?string
{
return $this->verificationStatus;
}
public function setVerificationStatus(string $verificationStatus): static
{
$this->verificationStatus = $verificationStatus;
return $this;
}
public function getVerifiedAt(): ?DateTimeImmutable
{
return $this->verifiedAt;
}
public function setVerifiedAt(?DateTimeImmutable $verifiedAt): static
{
$this->verifiedAt = $verifiedAt;
return $this;
}
public function getBusinessHours(): ?string
{
return $this->businessHours;
}
public function setBusinessHours(?string $businessHours): static
{
$this->businessHours = $businessHours;
return $this;
}
public function getDeliveryAreas(): ?string
{
return $this->deliveryAreas;
}
public function setDeliveryAreas(?string $deliveryAreas): static
{
$this->deliveryAreas = $deliveryAreas;
return $this;
}
public function getPaymentMethods(): ?string
{
return $this->paymentMethods;
}
public function setPaymentMethods(?string $paymentMethods): static
{
$this->paymentMethods = $paymentMethods;
return $this;
}
public function getReturnPolicy(): ?string
{
return $this->returnPolicy;
}
public function setReturnPolicy(?string $returnPolicy): static
{
$this->returnPolicy = $returnPolicy;
return $this;
}
public function getShippingPolicy(): ?string
{
return $this->shippingPolicy;
}
public function setShippingPolicy(?string $shippingPolicy): static
{
$this->shippingPolicy = $shippingPolicy;
return $this;
}
public function getPrivacyPolicy(): ?string
{
return $this->privacyPolicy;
}
public function setPrivacyPolicy(?string $privacyPolicy): static
{
$this->privacyPolicy = $privacyPolicy;
return $this;
}
public function isIsVerified(): ?bool
{
return $this->isVerified;
}
public function setIsVerified(bool $isVerified): static
{
$this->isVerified = $isVerified;
return $this;
}
public function isIsPremium(): ?bool
{
return $this->isPremium;
}
public function setIsPremium(bool $isPremium): static
{
$this->isPremium = $isPremium;
return $this;
}
public function isAllowReviews(): ?bool
{
return $this->allowReviews;
}
public function setAllowReviews(bool $allowReviews): static
{
$this->allowReviews = $allowReviews;
return $this;
}
public function isAllowMessages(): ?bool
{
return $this->allowMessages;
}
public function setAllowMessages(bool $allowMessages): static
{
$this->allowMessages = $allowMessages;
return $this;
}
public function isShowContactInfo(): ?bool
{
return $this->showContactInfo;
}
public function setShowContactInfo(bool $showContactInfo): static
{
$this->showContactInfo = $showContactInfo;
return $this;
}
public function isShowSocialLinks(): ?bool
{
return $this->showSocialLinks;
}
public function setShowSocialLinks(bool $showSocialLinks): static
{
$this->showSocialLinks = $showSocialLinks;
return $this;
}
// Méthodes utilitaires
public function getSocialLinks(): array
{
$links = [];
if ($this->website) $links['website'] = $this->website;
if ($this->facebook) $links['facebook'] = $this->facebook;
if ($this->instagram) $links['instagram'] = $this->instagram;
if ($this->twitter) $links['twitter'] = $this->twitter;
if ($this->youtube) $links['youtube'] = $this->youtube;
if ($this->tiktok) $links['tiktok'] = $this->tiktok;
if ($this->whatsapp) $links['whatsapp'] = $this->whatsapp;
if ($this->telegram) $links['telegram'] = $this->telegram;
return $links;
}
public function getActiveProductsCount(): int
{
return $this->products->filter(fn($product) => $product->isIsActive())->count();
}
public function getTotalRevenue(): float
{
return (float) $this->currentRevenue;
}
public function getFormattedRevenue(): string
{
return number_format($this->getTotalRevenue(), 2, '.', ' ') . ' HTG';
}
public function isActive(): bool
{
return $this->isActive && $this->status === 'active';
}
public function isVerified(): bool
{
return $this->isVerified && $this->verificationStatus === 'verified';
}
public function canReceiveOrders(): bool
{
return $this->isActive() && $this->getActiveProductsCount() > 0;
}
/**
* @return Collection<int, ShopFollow>
*/
public function getFollows(): Collection
{
return $this->follows;
}
public function addFollow(ShopFollow $follow): static
{
if (!$this->follows->contains($follow)) {
$this->follows->add($follow);
$follow->setShop($this);
}
return $this;
}
public function removeFollow(ShopFollow $follow): static
{
if ($this->follows->removeElement($follow)) {
// set the owning side to null (unless already changed)
if ($follow->getShop() === $this) {
$follow->setShop(null);
}
}
return $this;
}
/**
* Compte le nombre de followers actifs
*/
public function getActiveFollowersCount(): int
{
return $this->follows->filter(function(ShopFollow $follow) {
return $follow->isActive();
})->count();
}
/**
* Vérifie si un utilisateur suit cette boutique
*/
public function isFollowedBy(User $user): bool
{
return $this->follows->exists(function($key, ShopFollow $follow) use ($user) {
return $follow->getUser() === $user && $follow->isActive();
});
}
/**
* Récupère le follow d'un utilisateur pour cette boutique
*/
public function getFollowByUser(User $user): ?ShopFollow
{
foreach ($this->follows as $follow) {
if ($follow->getUser() === $user && $follow->isActive()) {
return $follow;
}
}
return null;
}
/**
* @return Collection<int, ShopReview>
*/
public function getReviews(): Collection
{
return $this->reviews;
}
public function addReview(ShopReview $review): static
{
if (!$this->reviews->contains($review)) {
$this->reviews->add($review);
$review->setShop($this);
}
return $this;
}
public function removeReview(ShopReview $review): static
{
if ($this->reviews->removeElement($review)) {
// set the owning side to null (unless already changed)
if ($review->getShop() === $this) {
$review->setShop(null);
}
}
return $this;
}
/**
* Obtenir la note moyenne des avis
*/
public function getAverageRating(): float
{
$totalRating = 0;
$reviewCount = 0;
foreach ($this->reviews as $review) {
if ($review->isVisible()) {
$totalRating += $review->getRating();
$reviewCount++;
}
}
return $reviewCount > 0 ? round($totalRating / $reviewCount, 1) : 0;
}
/**
* Obtenir le nombre d'avis visibles
*/
public function getVisibleReviewsCount(): int
{
$count = 0;
foreach ($this->reviews as $review) {
if ($review->isVisible()) {
$count++;
}
}
return $count;
}
public function __toString(): string
{
return $this->name ?? 'Boutique sans nom';
}
}