以 symfony 形式预先设置集合并只保存不空

Pre set collection in symfony form and save only not empties

我有星期和工作日。我需要用所有可能的 WeekDays(星期一午餐、星期一晚餐、星期二午餐、星期二晚餐等)编辑一周,即使它们没有保留。

周:

<?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);
    }
}

工作日:

<?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;
    }
}

我的实际形态:

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,
        ]);
    }
}

获取所有排序日期的方法:

    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);
    }

现在,页面加载的表单没问题,我得到了所有的工作日。

我订阅了 SUBMIT 事件以在提交时显示所有工作日:如果我不这样做,我只提交了工作日。

现在的问题是,如果我这样提交,它会保存所有的 WeekDays,甚至是空的,我宁愿避免它。

我删除了 allow_delete 选项,这样我就可以使用 SUBMIT 事件,默认清空对象不再自动删除。

所以如果表格有错误我会得到它们,但我必须在 POST_SUBMIT 事件中手动删除它们以避免持久性。

    $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);
            }
        }
    });