Search code examples
symfonyeasyadminsymfony5

How to create an entity with several dates in a single form with EasyAdmin


I am trying to develop my first symfony web-app and I have decided to use the bundle EasyAdmin.

In this web-app, I would like to define the following model : an Event with several dates.

In order to create this, I have create 2 entities with the help of the symfony console : Event and EventDate:

<?php

namespace App\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass="App\Repository\EventRepository")
 */
class Event
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $name;

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\EventDate", mappedBy="event", orphanRemoval=true)
     */
    private $dates;

    public function __construct()
    {
        $this->dates = new ArrayCollection();
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getName(): ?string
    {
        return $this->name;
    }

    public function setName(string $name): self
    {
        $this->name = $name;

        return $this;
    }

    /**
     * @return Collection|EventDate[]
     */
    public function getDates(): Collection
    {
        return $this->dates;
    }

    public function addDate(EventDate $date): self
    {
        if (!$this->dates->contains($date)) {
            $this->dates[] = $date;
            $date->setEvent($this);
        }

        return $this;
    }

    public function removeDate(EventDate $date): self
    {
        if ($this->dates->contains($date)) {
            $this->dates->removeElement($date);
            // set the owning side to null (unless already changed)
            if ($date->getEvent() === $this) {
                $date->setEvent(null);
            }
        }

        return $this;
    }

    public function __toString(): String
    {
        return $this->name;
    }

}
<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass="App\Repository\EventDateRepository")
 */
class EventDate
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="date")
     */
    private $date;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Event", inversedBy="dates")
     * @ORM\JoinColumn(nullable=false)
     */
    private $event;

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getDate(): ?\DateTimeInterface
    {
        return $this->date;
    }

    public function setDate(\DateTimeInterface $date): self
    {
        $this->date = $date;

        return $this;
    }

    public function getEvent(): ?Event
    {
        return $this->event;
    }

    public function setEvent(?Event $event): self
    {
        $this->event = $event;

        return $this;
    }
}

In order to be user-friendly, I would like to "customize" the form of an Event in order to allow the user to create in the same form the event and its dates.

In order to do this, I have define the Event entity's form like that:

easy_admin:
  entities:
    Event:
      class: App\Entity\Event
      form:
        fields:
          - {property: 'name'}
          - {property: 'dates', type: 'collection'}

The render of the collection is right because I can add or remove a date:

enter image description here

But As you can see, the field that represent the EventDate is an edit text. I think it's because the field represent the EventDate class and not only the date attribute.

The aim is to have the date selector that I have if I add a new EventDate in EasyAdmin:

enter image description here

So the question is: How to custom EasyAdmin in order to add an Event and its dates in a single form?

Thank you for your help!


Solution

  • I found the way to do it.

    I need to modify my yaml EasyAdmin file in order to introduce an entry_type:

    easy_admin:
      entities:
        Event:
          class: App\Entity\Event
          form:
            fields:
              - {property: 'name'}
              - {property: 'dates', type: 'collection', type_options: {entry_type: 'App\Form\EventDateForm', by_reference: false}}
    

    Then, I have to create the EventDateForm class:

    <?php
    
    namespace App\Form;
    
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormBuilderInterface;
    use Symfony\Component\OptionsResolver\OptionsResolver;
    
    class EventDateForm extends AbstractType
    {
    
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder->add('date');
        }
    
        public function configureOptions(OptionsResolver $resolver)
        {
            $resolver->setDefaults(array(
                'data_class' => 'App\Entity\EventDate'
            ));
        }
    
    }
    

    I also need to update the $date attribut of my Event entity like this:

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\EventDate", mappedBy="event", orphanRemoval=true, cascade={"persist", "remove"})
    */
    private $dates;
    

    The render is not very beautiful but it works:

    enter image description here