src/Entity/WhileProject/MissionsCategories.php line 34

Open in your IDE?
  1. <?php
  2. namespace App\Entity\WhileProject;
  3. use Doctrine\Common\Collections\ArrayCollection;
  4. use Doctrine\Common\Collections\Collection;
  5. use Doctrine\ORM\Mapping as ORM;
  6. /**
  7.  * Catégories de missions WhileProject.
  8.  *
  9.  * Modèle "1 row = 1 langue" :
  10.  *   - `locale` (fr|en|...) identifie la langue de la traduction
  11.  *   - `code` est l'identifiant stable cross-langue
  12.  *     (ex: "dev-web" existe en FR ET en EN, avec un name différent)
  13.  *   - `slug` est l'URL-friendly, peut différer par locale
  14.  *
  15.  * Hiérarchie : self-FK via `parent` / `children`. Une sous-catégorie DOIT
  16.  * avoir la même locale que son parent (validé en service à l'import).
  17.  *
  18.  * @ORM\Entity(repositoryClass="App\Repository\WhileProject\MissionsCategoriesRepository")
  19.  * @ORM\Table(name="whileproject_missions_categories",
  20.  *     uniqueConstraints={
  21.  *         @ORM\UniqueConstraint(name="uk_missions_categories_locale_slug", columns={"locale","slug"}),
  22.  *         @ORM\UniqueConstraint(name="uk_missions_categories_locale_code", columns={"locale","code"})
  23.  *     },
  24.  *     indexes={
  25.  *         @ORM\Index(name="idx_missions_categories_parent",  columns={"parent_id"}),
  26.  *         @ORM\Index(name="idx_missions_categories_locale",  columns={"locale"}),
  27.  *         @ORM\Index(name="idx_missions_categories_enabled", columns={"enabled"})
  28.  *     }
  29.  * )
  30.  */
  31. class MissionsCategories
  32. {
  33.     /**
  34.      * @ORM\Id()
  35.      * @ORM\GeneratedValue()
  36.      * @ORM\Column(type="integer")
  37.      */
  38.     private $id;
  39.     /**
  40.      * Langue de cette traduction. Ex: "fr", "en", "de", "es".
  41.      *
  42.      * @ORM\Column(type="string", length=5)
  43.      */
  44.     private $locale 'fr';
  45.     /**
  46.      * Identifiant stable cross-langue (ex: "dev-web").
  47.      * Permet de relier la version FR et EN d'une même catégorie.
  48.      *
  49.      * @ORM\Column(type="string", length=80)
  50.      */
  51.     private $code;
  52.     /**
  53.      * Slug URL-friendly (peut être différent du code, et différent par langue).
  54.      *
  55.      * @ORM\Column(type="string", length=140)
  56.      */
  57.     private $slug;
  58.     /**
  59.      * @ORM\Column(type="string", length=120)
  60.      */
  61.     private $name;
  62.     /**
  63.      * @ORM\Column(type="text", nullable=true)
  64.      */
  65.     private $description;
  66.     /**
  67.      * @ORM\Column(type="string", length=80, nullable=true)
  68.      */
  69.     private $icon;
  70.     /**
  71.      * @ORM\Column(type="string", length=20, nullable=true)
  72.      */
  73.     private $color;
  74.     /**
  75.      * @ORM\Column(type="string", length=180, nullable=true)
  76.      */
  77.     private $seoTitle;
  78.     /**
  79.      * @ORM\Column(type="string", length=250, nullable=true)
  80.      */
  81.     private $seoDescription;
  82.     /**
  83.      * @ORM\Column(type="integer")
  84.      */
  85.     private $position 0;
  86.     /**
  87.      * @ORM\Column(type="boolean")
  88.      */
  89.     private $enabled true;
  90.     /**
  91.      * Catégorie parente (NULL = racine).
  92.      *
  93.      * @ORM\ManyToOne(targetEntity="App\Entity\WhileProject\MissionsCategories", inversedBy="children")
  94.      * @ORM\JoinColumn(name="parent_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
  95.      */
  96.     private $parent;
  97.     /**
  98.      * Sous-catégories.
  99.      *
  100.      * @ORM\OneToMany(targetEntity="App\Entity\WhileProject\MissionsCategories", mappedBy="parent")
  101.      * @ORM\OrderBy({"position"="ASC", "name"="ASC"})
  102.      */
  103.     private $children;
  104.     /**
  105.      * @ORM\Column(type="datetime")
  106.      */
  107.     private $createdAt;
  108.     /**
  109.      * @ORM\Column(type="datetime")
  110.      */
  111.     private $updatedAt;
  112.     public function __construct()
  113.     {
  114.         $this->children  = new ArrayCollection();
  115.         $this->createdAt = new \DateTime('now');
  116.         $this->updatedAt = new \DateTime('now');
  117.     }
  118.     // ----- Getters / setters --------------------------------------------------
  119.     public function getId(): ?int { return $this->id; }
  120.     public function getLocale(): string { return $this->locale; }
  121.     public function setLocale(string $v): self $this->locale strtolower($v); return $this; }
  122.     public function getCode(): ?string { return $this->code; }
  123.     public function setCode(string $v): self $this->code $v; return $this; }
  124.     public function getSlug(): ?string { return $this->slug; }
  125.     public function setSlug(string $v): self $this->slug $v; return $this; }
  126.     public function getName(): ?string { return $this->name; }
  127.     public function setName(string $v): self $this->name $v; return $this; }
  128.     public function getDescription(): ?string { return $this->description; }
  129.     public function setDescription(?string $v): self $this->description $v; return $this; }
  130.     public function getIcon(): ?string { return $this->icon; }
  131.     public function setIcon(?string $v): self $this->icon $v; return $this; }
  132.     public function getColor(): ?string { return $this->color; }
  133.     public function setColor(?string $v): self $this->color $v; return $this; }
  134.     public function getSeoTitle(): ?string { return $this->seoTitle; }
  135.     public function setSeoTitle(?string $v): self $this->seoTitle $v; return $this; }
  136.     public function getSeoDescription(): ?string { return $this->seoDescription; }
  137.     public function setSeoDescription(?string $v): self $this->seoDescription $v; return $this; }
  138.     public function getPosition(): int { return $this->position; }
  139.     public function setPosition(int $v): self $this->position $v; return $this; }
  140.     public function isEnabled(): bool { return $this->enabled; }
  141.     public function setEnabled(bool $v): self $this->enabled $v; return $this; }
  142.     public function getParent(): ?self { return $this->parent; }
  143.     public function setParent(?self $v): self
  144.     {
  145.         // Sécurité : un parent doit être dans la même locale
  146.         if ($v !== null && $v->getLocale() !== $this->locale) {
  147.             throw new \InvalidArgumentException(sprintf(
  148.                 'Parent locale (%s) doit correspondre à child locale (%s)',
  149.                 $v->getLocale(),
  150.                 $this->locale
  151.             ));
  152.         }
  153.         // Sécurité : pas d'auto-référence
  154.         if ($v !== null && $v === $this) {
  155.             throw new \InvalidArgumentException('Une catégorie ne peut pas être son propre parent');
  156.         }
  157.         $this->parent $v;
  158.         return $this;
  159.     }
  160.     /** @return Collection<int, self> */
  161.     public function getChildren(): Collection { return $this->children; }
  162.     public function addChild(self $child): self
  163.     {
  164.         if (!$this->children->contains($child)) {
  165.             $this->children->add($child);
  166.             $child->setParent($this);
  167.         }
  168.         return $this;
  169.     }
  170.     public function removeChild(self $child): self
  171.     {
  172.         if ($this->children->removeElement($child)) {
  173.             if ($child->getParent() === $this) {
  174.                 $child->setParent(null);
  175.             }
  176.         }
  177.         return $this;
  178.     }
  179.     public function getCreatedAt(): ?\DateTimeInterface { return $this->createdAt; }
  180.     public function setCreatedAt(\DateTimeInterface $v): self $this->createdAt $v; return $this; }
  181.     public function getUpdatedAt(): ?\DateTimeInterface { return $this->updatedAt; }
  182.     public function setUpdatedAt(\DateTimeInterface $v): self $this->updatedAt $v; return $this; }
  183.     // ----- Helpers ------------------------------------------------------------
  184.     public function isRoot(): bool { return $this->parent === null; }
  185.     public function hasChildren(): bool { return !$this->children->isEmpty(); }
  186.     /** Profondeur dans l'arbre (0 = racine). */
  187.     public function getDepth(): int
  188.     {
  189.         $depth 0;
  190.         $current $this->parent;
  191.         while ($current !== null) {
  192.             $depth++;
  193.             $current $current->getParent();
  194.             if ($depth 10) break; // garde-fou anti-boucle
  195.         }
  196.         return $depth;
  197.     }
  198. }