<?php
declare(strict_types=1);
namespace App\Shop\Doctrine\Entity;
use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Program\Doctrine\Entity\Profile;
use App\Shop\Doctrine\Repository\ProductRepository;
use App\Shop\Filter\ProductFilter;
use App\Supplier\Doctrine\Entity\Brand as SupplierBrand;
use App\Supplier\Doctrine\Entity\Supplier;
use App\Supplier\Doctrine\Entity\Taxonomy as SupplierTaxonomy;
use DateTime;
use DateTimeImmutable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\Index;
use Doctrine\ORM\Mapping\ManyToOne;
use Doctrine\ORM\Mapping\OneToMany;
use Doctrine\ORM\Mapping\OneToOne;
use Doctrine\ORM\Mapping\OrderBy;
use Doctrine\ORM\Mapping\Table;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints\Image;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\NotNull;
use Symfony\Component\Validator\Constraints\Valid;
use Vich\UploaderBundle\Mapping\Annotation\Uploadable;
use Vich\UploaderBundle\Mapping\Annotation\UploadableField;
#[ApiResource(
collectionOperations: ['get'],
itemOperations: ['get'],
normalizationContext: ['groups' => ['product', 'Default']],
)]
#[Uploadable]
#[ApiFilter(ProductFilter::class)]
#[Entity(repositoryClass: ProductRepository::class)]
#[Table(name: '`shop_product`')]
#[Index(columns: ['supplier_id', '`reference`'], name: 'supplier_id_reference')]
#[Index(columns: ['supplier_id', 'state'], name: 'supplier_id_state')]
class Product
{
#[Id]
#[Column(type: 'integer')]
#[GeneratedValue]
#[Groups('product')]
private ?int $id = null;
#[ManyToOne(targetEntity: Supplier::class)]
private ?Supplier $supplier = null;
#[Column(name: '`reference`')]
#[Groups('product')]
private string $reference;
#[Column(nullable: true, name: '`reference_comm`')]
#[Groups('product')]
private ?string $referenceComm = null;
#[Column(type: 'datetime_immutable')]
private DateTimeImmutable $updatedAt;
#[Column]
#[NotBlank]
#[Groups('product')]
private string $name;
#[Column(type: 'text')]
#[NotBlank]
#[Groups('product')]
private string $description;
#[Column(nullable: true)]
#[Groups('product')]
private ?string $image = null;
#[Column(nullable: true, type: 'text')]
private ?string $imageUrl = null;
#[UploadableField(mapping: 'images', fileNameProperty: 'image')]
#[NotNull(groups: ['create'])]
#[Image(groups: ['create'])]
private ?File $imageFile = null;
#[ManyToOne(targetEntity: Brand::class, inversedBy: 'products')]
#[Groups('product')]
private ?Brand $brand = null;
#[ManyToOne(targetEntity: Taxonomy::class, inversedBy: 'products')]
#[Groups('product')]
private ?Taxonomy $taxonomy = null;
#[ManyToOne(targetEntity: SupplierBrand::class, inversedBy: 'products')]
private ?SupplierBrand $supplierBrand = null;
#[ManyToOne(targetEntity: SupplierTaxonomy::class, inversedBy: 'products')]
private ?SupplierTaxonomy $supplierTaxonomy = null;
/**
* @var Collection<int, FeatureValue>
*/
#[OneToMany(mappedBy: 'product', targetEntity: FeatureValue::class, cascade: ['persist'], orphanRemoval: true)]
#[Groups('product')]
private Collection $features;
/**
* @var Collection<int, Price>
*/
#[OneToMany(mappedBy: 'product', targetEntity: Price::class)]
#[OrderBy(['createdAt' => 'DESC'])]
private Collection $pricingHistory;
#[OneToOne(targetEntity: Price::class, cascade: ['persist', 'remove'])]
#[Valid]
private ?Price $currentPrice = null;
#[Column]
private string $state = 'draft';
/**
* @var array<array-key, array<string, string>>
*/
#[Column(type: 'array')]
private array $statesHistory = [];
#[Column(type: 'integer')]
private int $stock = 0;
#[Column(nullable: true)]
private ?string $lastState = null;
#[Groups(['product'])]
private int $points = 0;
#[Column(type: 'boolean', options: ['default' => false])]
private $toEdit = false;
#[Column(type: 'datetime', nullable: true)]
private ?DateTime $creationDate = null;
#[Column(nullable: true)]
private ?string $shippingMode = null;
public function __construct()
{
$this->statesHistory[] = ['date' => date('Y-m-d H:i:s'), 'state' => 'draft'];
$this->features = new ArrayCollection();
$this->pricingHistory = new ArrayCollection();
$this->updatedAt = new DateTimeImmutable();
}
public function __toString(): string
{
return $this->getName();
}
public function getId(): ?int
{
return $this->id;
}
public function getReference(): string
{
return $this->reference;
}
public function setReference(string $reference): void
{
$this->reference = $reference;
}
public function getName(): string
{
return $this->name;
}
public function setName(string $name): void
{
$this->name = $name;
}
public function getDescription(): string
{
return $this->description;
}
public function setDescription(string $description): void
{
$this->description = $description;
}
public function getImage(): ?string
{
return $this->image;
}
public function setImage(?string $image): void
{
$this->image = $image;
}
public function getBrand(): ?Brand
{
return $this->brand;
}
public function setBrand(?Brand $brand): void
{
$this->brand = $brand;
}
public function getTaxonomy(): ?Taxonomy
{
return $this->taxonomy;
}
public function setTaxonomy(?Taxonomy $taxonomy): void
{
$this->taxonomy = $taxonomy;
}
/**
* @return Collection<int, FeatureValue>
*/
public function getFeatures(): Collection
{
return $this->features;
}
public function addFeature(FeatureValue $featureValue): void
{
if ($this->features->contains($featureValue)) {
return;
}
$featureValue->setProduct($this);
$this->features->add($featureValue);
}
public function removeFeature(FeatureValue $featureValue): void
{
if (!$this->features->contains($featureValue)) {
return;
}
$featureValue->setProduct(null);
$this->features->removeElement($featureValue);
}
public function getFeature(Feature|string $feature): ?FeatureValue
{
/** @var Collection<int, FeatureValue> $features */
$features = $this->features
->filter(static fn (FeatureValue $featureValue) => is_string($feature)
? $featureValue->getFeature()->getCode() === $feature
: $featureValue->getFeature() === $feature);
return false === $features->first() ? null : $features->first();
}
/**
* @return Collection<int, Price>
*/
public function getPricingHistory(): Collection
{
return $this->pricingHistory;
}
public function getCurrentPrice(): ?Price
{
return $this->currentPrice;
}
public function setCurrentPrice(?Price $currentPrice): void
{
$this->currentPrice = $currentPrice;
if (null !== $this->currentPrice) {
$this->currentPrice->setProduct($this);
}
}
public function getImageFile(): ?File
{
return $this->imageFile;
}
public function setImageFile(?File $imageFile): void
{
$this->imageFile = $imageFile;
}
public function getUpdatedAt(): DateTimeImmutable
{
return $this->updatedAt;
}
public function setUpdatedAt(DateTimeImmutable $updatedAt): void
{
$this->updatedAt = $updatedAt;
}
public function getState(): string
{
return $this->state;
}
public function setState(string $state): void
{
$this->state = $state;
}
/**
* @return array<array-key, array<string, string>>
*/
public function getStatesHistory(): array
{
return $this->statesHistory;
}
public function addStateHistory(string $state): void
{
$this->statesHistory[] = ['date' => date('Y-m-d H:i:s'), 'state' => $state];
}
public function getSupplier(): ?Supplier
{
return $this->supplier;
}
public function setSupplier(?Supplier $supplier): void
{
$this->supplier = $supplier;
}
public function getSupplierBrand(): ?SupplierBrand
{
return $this->supplierBrand;
}
public function setSupplierBrand(?SupplierBrand $supplierBrand): void
{
$this->supplierBrand = $supplierBrand;
}
public function getSupplierTaxonomy(): ?SupplierTaxonomy
{
return $this->supplierTaxonomy;
}
public function setSupplierTaxonomy(?SupplierTaxonomy $supplierTaxonomy): void
{
$this->supplierTaxonomy = $supplierTaxonomy;
}
public function getStock(): int
{
return $this->stock;
}
public function setStock(int $stock): void
{
$this->stock = $stock;
}
public function getLastState(): ?string
{
return $this->lastState;
}
public function setLastState(?string $lastState): void
{
$this->lastState = $lastState;
}
public function setPoints(Shop $shop, Profile $profile): void
{
$price = $shop->getPriceValuation()->evaluate($this);
$this->points = intval($profile->getProgram()->getCurrencyToPoint()->evaluate($price));
}
public function getPoints(): int
{
return $this->points;
}
public function getImageUrl(): ?string
{
return $this->imageUrl;
}
public function setImageUrl(?string $imageUrl): void
{
$this->imageUrl = $imageUrl;
}
public function isToEdit(): bool
{
return $this->toEdit;
}
public function setToEdit(bool $toEdit): void
{
$this->toEdit = $toEdit;
}
public function getCreationDate(): ?DateTime
{
return $this->creationDate;
}
public function setCreationDate(?DateTime $creationDate): void
{
$this->creationDate = $creationDate;
}
public function getShippingMode(): ?string
{
return $this->shippingMode;
}
public function setShippingMode(?string $shippingMode): void
{
$this->shippingMode = $shippingMode;
}
public function getReferenceComm(): ?string
{
return $this->referenceComm;
}
public function setReferenceComm(?string $referenceComm): void
{
$this->referenceComm = $referenceComm;
}
}