src/Entity/Order/OrderItemPhoto.php line 32

  1. <?php
  2. /*
  3.  * This file is part of the Pellipop project.
  4.  *
  5.  * (c) Mobizel
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. declare(strict_types=1);
  11. namespace App\Entity\Order;
  12. use App\Entity\Media\File;
  13. use App\OrderItemPhotoStates;
  14. use App\Repository\Order\OrderItemPhotoRepository;
  15. use App\Validator\Constraints\OrderItemPhotosMaxCount;
  16. use Doctrine\ORM\Mapping as ORM;
  17. use Monofony\Contracts\Core\Model\Media\FileInterface;
  18. use Symfony\Component\Serializer\Annotation\Groups;
  19. use Symfony\Component\Validator\Constraints as Assert;
  20. use Vich\UploaderBundle\Mapping\Annotation as Vich;
  21. /**
  22.  * @Vich\Uploadable
  23.  */
  24. #[ORM\Entity(repositoryClass: OrderItemPhotoRepository::class)]
  25. #[ORM\Table(name: 'app_order_item_photo')]
  26. #[OrderItemPhotosMaxCount()]
  27. class OrderItemPhoto extends File implements FileInterface
  28. {
  29.     /**
  30.      * @Vich\UploadableField(mapping="order_item_photo", fileNameProperty="path")
  31.      */
  32.     #[Assert\Image(maxSize: '100M')]
  33.     protected ?\SplFileInfo $file = null;
  34.     #[ORM\ManyToOne(inversedBy: 'photos')]
  35.     #[ORM\JoinColumn(nullable: false)]
  36.     private ?OrderItem $orderItem = null;
  37.     #[ORM\Column(length: 255, nullable: true)]
  38.     #[Groups(['image:read'])]
  39.     private ?string $fujiHash = null;
  40.     #[ORM\Column(length: 20)]
  41.     #[Groups(['image:read'])]
  42.     private ?string $state = null;
  43.     #[ORM\Column(length: 1000, nullable: true)]
  44.     #[Groups(['image:read'])]
  45.     private ?string $tag = null;
  46.     /**
  47.      * Centre du cadrage utilisateur, normalisé (0..1) dans l'image originale.
  48.      * Null = pas de cadrage utilisateur transmis (anciennes commandes) : fallback sur le
  49.      * recadrage centré automatique existant (voir ResizePhotoFileModifier).
  50.      */
  51.     #[ORM\Column(type: 'float', nullable: true)]
  52.     #[Groups(['image:read'])]
  53.     private ?float $cropOffsetX = null;
  54.     #[ORM\Column(type: 'float', nullable: true)]
  55.     #[Groups(['image:read'])]
  56.     private ?float $cropOffsetY = null;
  57.     /**
  58.      * Zoom du cadrage utilisateur : 1.0 = cadrage "ajusté" (le plus grand rectangle au ratio
  59.      * impression centré sur cropOffsetX/Y), > 1.0 = recadrage plus serré.
  60.      */
  61.     #[ORM\Column(type: 'float', nullable: true)]
  62.     #[Groups(['image:read'])]
  63.     private ?float $cropZoom = null;
  64.     /**
  65.      * Rotation par quart de tour appliquée avant le cadrage : 0, 1, 2 ou 3 (× 90°).
  66.      */
  67.     #[ORM\Column(type: 'smallint', nullable: true)]
  68.     #[Groups(['image:read'])]
  69.     private ?int $cropRotationQuarterTurns = null;
  70.     /**
  71.      * Vrai si le cadre d'impression est pivoté (portrait <-> paysage) indépendamment de
  72.      * cropRotationQuarterTurns — permet un cadre paysage sur une photo portrait (ou l'inverse)
  73.      * sans faire pivoter les pixels de l'image elle-même.
  74.      */
  75.     #[ORM\Column(type: 'boolean', nullable: true)]
  76.     #[Groups(['image:read'])]
  77.     private ?bool $cropFrameSwapped = null;
  78.     /**
  79.      * Nom de fichier d'une copie de la photo originale, prise juste avant le tout premier
  80.      * recadrage (voir ResizePhotoFileModifier::resize()) — uniquement pour l'affichage
  81.      * avant/après dans le BO (OrderItemPhotoComparisonController). `path` reste le fichier
  82.      * "actuel" envoyé à Fuji, inchangé : ce champ n'affecte jamais l'envoi. Reste `null` pour les
  83.      * photos déjà traitées avant l'ajout de cette fonctionnalité (original perdu, écrasé en place
  84.      * par l'ancien comportement) — le BO doit gérer ce cas en affichant "original non disponible".
  85.      */
  86.     #[ORM\Column(type: 'string', nullable: true)]
  87.     #[Groups(['image:read'])]
  88.     private ?string $originalPath = null;
  89.     public function __construct()
  90.     {
  91.         $this->state = OrderItemPhotoStates::STATE_NEW;
  92.         parent::__construct();
  93.     }
  94.     public function getOrderItem(): ?OrderItem
  95.     {
  96.         return $this->orderItem;
  97.     }
  98.     public function setOrderItem(?OrderItem $orderItem): self
  99.     {
  100.         $this->orderItem = $orderItem;
  101.         return $this;
  102.     }
  103.     public function getFujiHash(): ?string
  104.     {
  105.         return $this->fujiHash;
  106.     }
  107.     public function setFujiHash(?string $fujiHash): self
  108.     {
  109.         $this->fujiHash = $fujiHash;
  110.         return $this;
  111.     }
  112.     public function getState(): ?string
  113.     {
  114.         return $this->state;
  115.     }
  116.     public function setState(string $state): self
  117.     {
  118.         $this->state = $state;
  119.         return $this;
  120.     }
  121.     public function getTag(): ?string
  122.     {
  123.         return $this->tag;
  124.     }
  125.     public function setTag(?string $tag): void
  126.     {
  127.         $this->tag = $tag;
  128.     }
  129.     public function getCropOffsetX(): ?float
  130.     {
  131.         return $this->cropOffsetX;
  132.     }
  133.     public function setCropOffsetX(?float $cropOffsetX): void
  134.     {
  135.         $this->cropOffsetX = $cropOffsetX;
  136.     }
  137.     public function getCropOffsetY(): ?float
  138.     {
  139.         return $this->cropOffsetY;
  140.     }
  141.     public function setCropOffsetY(?float $cropOffsetY): void
  142.     {
  143.         $this->cropOffsetY = $cropOffsetY;
  144.     }
  145.     public function getCropZoom(): ?float
  146.     {
  147.         return $this->cropZoom;
  148.     }
  149.     public function setCropZoom(?float $cropZoom): void
  150.     {
  151.         $this->cropZoom = $cropZoom;
  152.     }
  153.     public function getCropRotationQuarterTurns(): ?int
  154.     {
  155.         return $this->cropRotationQuarterTurns;
  156.     }
  157.     public function setCropRotationQuarterTurns(?int $cropRotationQuarterTurns): void
  158.     {
  159.         $this->cropRotationQuarterTurns = $cropRotationQuarterTurns;
  160.     }
  161.     public function getCropFrameSwapped(): ?bool
  162.     {
  163.         return $this->cropFrameSwapped;
  164.     }
  165.     public function setCropFrameSwapped(?bool $cropFrameSwapped): void
  166.     {
  167.         $this->cropFrameSwapped = $cropFrameSwapped;
  168.     }
  169.     public function getOriginalPath(): ?string
  170.     {
  171.         return $this->originalPath;
  172.     }
  173.     public function setOriginalPath(?string $originalPath): void
  174.     {
  175.         $this->originalPath = $originalPath;
  176.     }
  177.     /**
  178.      * Vrai si l'app a transmis un cadrage utilisateur complet pour cette photo.
  179.      * Si faux, ResizePhotoFileModifier doit garder le recadrage centré automatique existant.
  180.      */
  181.     public function hasUserCrop(): bool
  182.     {
  183.         return null !== $this->cropOffsetX
  184.             && null !== $this->cropOffsetY
  185.             && null !== $this->cropZoom;
  186.     }
  187. }