<?php
namespace App\Entity;
use App\Entity\Menu\Item;
use App\Entity\Utils\IntlInterface;
use App\Entity\Utils\Traits\TimestampTrait;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\PersistentCollection;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Class Menu.
*/
#[ORM\Table(name: 'menu')]
#[ORM\Entity(repositoryClass: \App\Repository\MenuRepository::class)]
class Menu implements IntlInterface
{
use TimestampTrait;
/**
* Id.
*/
#[ORM\Id]
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER)]
#[ORM\GeneratedValue]
protected int $id;
/**
* Name.
*/
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 255)]
#[Assert\NotBlank(message: 'form.error.required')]
protected string $name;
/**
* Reference.
*/
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 255)]
#[Assert\Length(max: 255, maxMessage: 'form.error.long')]
#[Assert\Regex(pattern: '/^[a-zA-Z0-9-]+$/i', match: true, message: 'form.error.reference')]
protected string $reference;
/**
* Locale.
*/
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 255)]
#[Assert\NotBlank(message: 'form.error.required')]
protected string $locale = 'en';
/**
* Translations.
*/
#[ORM\OneToMany(targetEntity: 'Menu', mappedBy: 'master', cascade: ['detach'])]
protected Collection $translations;
/**
* Master.
*/
#[ORM\ManyToOne(targetEntity: 'Menu', inversedBy: 'translations', cascade: ['detach'])]
#[ORM\JoinColumn(name: 'master_id')]
protected ?Menu $master = null;
/**
* Items.
*
* @var \Doctrine\Common\Collections\Collection<int, \App\Entity\Menu\Item>|\App\Entity\Menu\Item[]
*/
#[Assert\Valid]
#[ORM\OrderBy(['id' => 'asc'])]
#[ORM\OneToMany(targetEntity: \App\Entity\Menu\Item::class, mappedBy: 'menu', cascade: ['all'], orphanRemoval: true)]
protected Collection $items;
/**
* Menu constructor.
*/
public function __construct()
{
$this->items = new ArrayCollection();
$this->translations = new ArrayCollection();
}
public function setId(int $id): void
{
$this->id = $id;
}
public function getId(): int
{
return $this->id;
}
public function getName(): string
{
return $this->name;
}
public function setName(string $name): void
{
$this->name = $name;
}
public function getReference(): string
{
return $this->reference;
}
public function setReference(string $reference): void
{
$this->reference = $reference;
}
public function getLocale(): string
{
return $this->locale;
}
public function setLocale(string $locale): void
{
$this->locale = $locale;
}
public function getExistingLocales(): array
{
$locales = [];
$master = $this->getMaster();
$locales[] = $master->getLocale();
/** @var Menu $translation */
foreach ($this->getTranslations() as $translation) {
$locales[] = $translation->getLocale();
}
return $locales;
}
public function getTranslations(): Collection
{
$master = $this->getMaster();
return $master->translations;
}
/**
* @return mixed|null
*/
public function getTranslation(string $locale)
{
$master = $this->getMaster();
if ($master->getLocale() == $locale) {
return $master;
}
/** @var Menu $translation */
foreach ($master->getTranslations() as $translation) {
if ($translation->getLocale() == $locale) {
return $translation;
}
}
return null;
}
public function addTranslation(object $translation): void
{
$this->translations[] = $translation;
$translation->setMaster($this);
}
public function removeTranslation(object $translation): void
{
$this->translations->removeElement($translation);
$translation->setMaster(null);
}
public function removeAllTranslation(): void
{
foreach ($this->translations as $translation) {
$this->removeTranslation($translation);
}
}
public function isMaster(): bool
{
return !$this->master;
}
public function getMaster(): ?Menu
{
if (!$this->master) {
return $this;
}
return $this->master;
}
public function setMaster(?object $master): void
{
$this->master = $master;
}
public function addItem(Item $item): Menu
{
$this->items[] = $item;
$item->setMenu($this);
return $this;
}
public function removeItem(Item $item): void
{
$this->items->removeElement($item);
$item->setMenu(null);
}
/**
* @return Collection
*/
public function getItems()
{
return $this->items;
}
public function setItems(Collection $items): void
{
foreach ($items as $b) {
$this->addItem($b);
}
}
public function removeAllItems(): void
{
if (count($this->items)) {
foreach ($this->items as $b) {
$this->removeItem($b);
}
}
}
public function reorderItems(string $field): void
{
/** @var PersistentCollection $items */
$items = $this->items;
if (!$items->isInitialized()) {
$items->initialize();
}
$criteria = Criteria::create()
->orderBy([$field => Criteria::ASC]);
$items = $items->matching($criteria);
if (!$this->items->isInitialized()) {
$this->items->initialize();
}
$this->items->clear();
/** @var Item $item */
foreach ($items as $key => $item) {
$item->reorderChildren($field);
$this->items->set($key, $item);
}
}
public function import(array $data, bool $partial = false): void
{
$fields = $this->getArrayModel();
foreach ($fields as $field) {
if (isset($data[$field])) {
$setter = 'set'.ucfirst((string) $field);
$fields[$field] = $this->{$setter}($data[$field]);
}
}
if (!$partial) {
$this->removeAllItems();
$this->items->clear();
$cpt = 0;
foreach ($data['items'] as $itemData) {
$item = new Item();
$item->setArrayData($itemData);
$item->setPosition($cpt);
$this->addItem($item);
++$cpt;
}
}
}
public function export(?string $locale = null): array
{
$items = [];
$fields = [];
/** @var Item $item */
foreach ($this->items as $item) {
$items[] = $item->getArrayData();
}
foreach ($this->getArrayModel() as $field) {
$getter = 'get'.ucfirst((string) $field);
$fields[$field] = $this->{$getter}();
}
if ($locale) {
$fields['locale'] = $locale;
}
return array_merge(
$fields,
['items' => $items]
);
}
public function getArrayModel(): array
{
return [
'name',
'reference',
'locale',
];
}
}