I have Week and WeekDays. I need to edit a Week with all possible WeekDays (monday at lunch, monday at dinner, tuesday at lunch, tuesday at dinner, etc...) even if they are not persisted.
Week :
<?php
namespace App\Entity;
use App\Repository\WeekRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Uid\Uuid;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Entity(repositoryClass=WeekRepository::class)
*/
class Week
{
/**
* @ORM\Id
* @ORM\Column(type="uuid", unique=true)
*/
private Uuid $id;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank(message="Merci de donner un nom à votre semaine type.")
* @Assert\Length(max=255, maxMessage="Le nom de votre semaine type ne peut pas faire plus de 255 caractères.")
*/
private ?string $name;
/**
* @ORM\ManyToOne(targetEntity=User::class, inversedBy="weeks")
* @ORM\JoinColumn(nullable=false)
*/
private ?User $user;
/**
* @ORM\OneToMany(targetEntity=WeekDay::class, mappedBy="week", orphanRemoval=true, cascade={"persist"})
*/
private Collection $days;
public function __construct()
{
$this->id = Uuid::v6();
$this->days = new ArrayCollection();
}
public function getId(): Uuid
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(?string $name): self
{
$this->name = $name;
return $this;
}
public function getUser(): ?User
{
return $this->user;
}
public function setUser(?User $user): self
{
$this->user = $user;
return $this;
}
public function hasDay(WeekDay $checkday): bool
{
foreach ($this->getDays() as $day) {
if (
$day->getDay() === $checkday->getDay() &&
$day->getTime() === $checkday->getTime()
) {
return true;
}
}
return false;
}
public function getDays(): Collection
{
return $this->days;
}
public function addDay(WeekDay $day): void
{
if (!$this->hasDay($day)) {
$this->days[$day->getDay().$day->getTime()] = $day;
$day->setWeek($this);
}
}
public function removeDay(WeekDay $day): void
{
$this->days->removeElement($day);
$day->setWeek(null);
}
}
WeekDay :
<?php
namespace App\Entity;
use App\Repository\WeekDayRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Uid\Uuid;
/**
* @ORM\Entity(repositoryClass=WeekDayRepository::class)
*/
class WeekDay
{
private const MONDAY = 1;
private const TUESDAY = 2;
private const WEDNESDAY = 3;
private const THURSDAY = 4;
private const FRIDAY = 5;
private const SATURDAY = 6;
private const SUNDAY = 7;
private const TIME_LUNCH = 1;
private const TIME_DINNER = 2;
/**
* @ORM\Id
* @ORM\Column(type="uuid", unique=true)
*/
private Uuid $id;
/**
* @ORM\Column(type="integer")
*/
private int $day;
/**
* @ORM\Column(type="integer")
*/
private int $time;
/**
* @ORM\Column(type="boolean")
*/
private bool $used = false;
/**
* @ORM\ManyToOne(targetEntity=Week::class, inversedBy="days")
* @ORM\JoinColumn(nullable=false)
*/
private ?Week $week;
/**
* @ORM\ManyToMany(targetEntity=Theme::class)
*/
private Collection $themes;
/**
* @ORM\Column(type="array", nullable=true)
*/
private array $preparations = [];
public function __construct()
{
$this->id = Uuid::v6();
$this->themes = new ArrayCollection();
}
public function getId(): Uuid
{
return $this->id;
}
public function getDay(): ?int
{
return $this->day;
}
public function setDay(int $day): self
{
$this->day = $day;
return $this;
}
public static function getDays(): array
{
return [
self::MONDAY => 'monday',
self::TUESDAY => 'tuesday',
self::WEDNESDAY => 'wednesday',
self::THURSDAY => 'thursday',
self::FRIDAY => 'friday',
self::SATURDAY => 'saturday',
self::SUNDAY => 'sunday',
];
}
public function getDayLabel()
{
$labels = self::getDays();
return $labels[$this->getDay()] ?? '-';
}
public function getTime(): ?int
{
return $this->time;
}
public function setTime(int $time): self
{
$this->time = $time;
return $this;
}
public static function getTimes(): array
{
return [
self::TIME_LUNCH => 'lunch',
self::TIME_DINNER => 'dinner',
];
}
public function getTimeLabel()
{
$labels = self::getTimes();
return $labels[$this->getTime()] ?? '-';
}
public function isUsed(): bool
{
return $this->used;
}
public function setUsed(bool $used): self
{
$this->used = $used;
return $this;
}
public function getWeek(): ?Week
{
return $this->week;
}
public function setWeek(?Week $week): self
{
$this->week = $week;
return $this;
}
}
My actual form :
class WeekType extends AbstractType
{
private WeekService $service;
public function __construct(WeekService $service)
{
$this->service = $service;
}
/** {@inheritdoc} **/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('days', CollectionType::class, [
'entry_type' => WeekDayType::class,
'by_reference' => false,
'allow_add' => true,
'allow_delete' => true,
'data' => $this->service->getAllSortedDays($builder->getData()),
])
;
$builder->addEventListener(FormEvents::SUBMIT, function (FormEvent $event) {
$form = $event->getForm();
$data = $event->getForm()->getData();
$form
->add('days', CollectionType::class, [
'entry_type' => WeekDayType::class,
'by_reference' => false,
'allow_add' => true,
'allow_delete' => true,
'data' => $this->service->getAllSortedDays($data),
])
;
});
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Week::class,
]);
}
}
Method to get all sorted days :
public function getAllSortedDays(Week $week): Collection
{
$weekDays = WeekDay::getDays();
$times = WeekDay::getTimes();
foreach (array_keys($weekDays) as $dayId) {
foreach (array_keys($times) as $timeId) {
$weekDay = (new WeekDay())
->setDay($dayId)
->setTime($timeId)
;
$week->addDay($weekDay);
}
}
$orderBy = (Criteria::create())->orderBy([
'day' => Criteria::ASC,
'time' => Criteria::ASC,
]);
return $week->getDays()->matching($orderBy);
}
For now, the form on page load is OK, I get all WeekDays.
I subscribed to SUBMIT event to show all WeekDays if I have error on submit : if I don't do that, I only have submitted WeekDays.
The problem now is if I submit like this, it save all WeekDays, even empty ones, and I would prefer to avoid it.
CodePudding user response:
I have removed allow_delete option, so I can get ride of SUBMIT event, defaults empties objects are not automatically deleted anymore.
So I get them if there are errors in form, but I have to remove them manually in a POST_SUBMIT event to avoid persistence.
$builder
->add('name')
->add('days', CollectionType::class, [
'entry_type' => WeekDayType::class,
'by_reference' => false,
'data' => $this->service->getAllSortedDays($builder->getData()),
])
;
$builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
$data = $event->getForm()->getData();
foreach ($data->getDays() as $day) {
if (
false === $day->isUsed() &&
0 === count($day->getThemes()) &&
0 === count($day->getPreparations())
) {
$data->removeDay($day);
}
}
});