Home > Mobile >  In a form, how to allow only part of the selection of an entity?
In a form, how to allow only part of the selection of an entity?

Time:10-25

I made a form in order to create events. First, the user has to create a profile and be connected. He has a list of his own addresses. Currently, in the form he can select any addresses, even those created by other users. I would like to allow him to see only addresses he has created in drop selection.

  • In EventType file, I used EntityType::class for Location entity, knowing that thanks to it addresses are created.

  • In Entity file for Location, the column 'organizer' is created in order to know who created the address. It's connected with a ManyToOne to User class.

Where do I have to specify that user must select only his own address in the form ?

EventType.php

<?php

namespace App\Form;

use App\Entity\Event;
use App\Entity\Language;
use App\Entity\Location;
use App\Entity\Category;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TimeType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;

class EventType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('title')
            ->add('description', TextareaType::class)
            ->add('spokenlanguage', EntityType::class, [
                'class' => Language::class,
                'choice_label' => 'name',
                'placeholder' => 'Je sélectionne une langue étrangère',
            ])
            ->add('category', EntityType::class, [
                'class' => Category::class,
                'choice_label' => 'title',
                'placeholder' => 'Je sélectionne un type de sortie ou d\'activité',
            ])
            ->add('start', DateTimeType::class, [
                'widget' => 'choice'
            ])
            ->add('end', TimeType::class, [
                'input'  => 'datetime',
                'widget' => 'choice',
            ])
            ->add('address', EntityType::class, [
                'class' => Location::class,
                'choice_label' => 'address',
                'placeholder' => 'Je sélectionne une adresse',
            ])
            ->add('save', SubmitType::class, [
                'attr' => ['class' => 'save'],
            ])
        ;
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => Event::class,
            'translation_domain' => 'forms'
        ]);
    }
}

Location.php

<?php

namespace App\Entity;

use App\Repository\LocationRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: LocationRepository::class)]
class Location
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    private ?string $name = null;

    #[ORM\Column(length: 255)]
    private ?string $number = null;

    #[ORM\Column(length: 255)]
    private ?string $street = null;

    #[ORM\Column(length: 255)]
    private ?string $zipcode = null;

    #[ORM\Column(length: 255)]
    private ?string $city = null;

    #[ORM\ManyToOne(inversedBy: 'locations')]
    private ?BigCity $bigcity = null;

    #[ORM\OneToMany(mappedBy: 'address', targetEntity: Event::class)]
    private Collection $events;

    #[ORM\Column(type: Types::DECIMAL, precision: 10, scale: 7, nullable: true)]
    private ?string $lat = null;

    #[ORM\Column(type: Types::DECIMAL, precision: 10, scale: 7, nullable: true)]
    private ?string $lon = null;

    #[ORM\ManyToOne(inversedBy: 'locations')]
    private ?User $organizer = null;

    public function __construct()
    {
        $this->events = 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;
    }

    public function getNameAndId(): ?string
    {
        $nameandid =$this->getName() . ' (Id : ' . $this->getId() . ')';
        return $nameandid;
    }

    public function getNumber(): ?string
    {
        return $this->number;
    }

    public function setNumber(string $number): self
    {
        $this->number = $number;

        return $this;
    }

    public function getStreet(): ?string
    {
        return $this->street;
    }

    public function setStreet(string $street): self
    {
        $this->street = $street;

        return $this;
    }

    public function getZipcode(): ?string
    {
        return $this->zipcode;
    }

    public function setZipcode(string $zipcode): self
    {
        $this->zipcode = $zipcode;

        return $this;
    }

    public function getCity(): ?string
    {
        return $this->city;
    }

    public function setCity(string $city): self
    {
        $this->city = $city;

        return $this;
    }

    public function getAddress(): ?string
    {
        $address =$this->getName() . ', ' . $this->getNumber() . ' ' . $this->getStreet() . ', ' . $this->getCity();
        return $address;
    }

    public function getBigcity(): ?BigCity
    {
        return $this->bigcity;
    }

    public function setBigcity(?BigCity $bigcity): self
    {
        $this->bigcity = $bigcity;

        return $this;
    }

    /**
     * @return Collection<int, Event>
     */
    public function getEvents(): Collection
    {
        return $this->events;
    }

    public function addEvent(Event $event): self
    {
        if (!$this->events->contains($event)) {
            $this->events->add($event);
            $event->setAddress($this);
        }

        return $this;
    }

    public function removeEvent(Event $event): self
    {
        if ($this->events->removeElement($event)) {
            // set the owning side to null (unless already changed)
            if ($event->getAddress() === $this) {
                $event->setAddress(null);
            }
        }

        return $this;
    }

    public function getLat(): ?string
    {
        return $this->lat;
    }

    public function setLat(?string $lat): self
    {
        $this->lat = $lat;

        return $this;
    }

    public function getLon(): ?string
    {
        return $this->lon;
    }

    public function setLon(?string $lon): self
    {
        $this->lon = $lon;

        return $this;
    }

    public function getOrganizer(): ?User
    {
        return $this->organizer;
    }

    public function setOrganizer(?User $organizer): self
    {
        $this->organizer = $organizer;

        return $this;
    }
}

CodePudding user response:

Here is the solution :

Type.php file

$user = $options['user'];

$builder
    ->add('address', EntityType::class, [
        'class' => Location::class,
        'query_builder' => function (EntityRepository $er) use ($user) {
            return $er
                ->createQueryBuilder('l')
                ->andWhere('l.organizer = :user')
                ->setParameter('user', $user);
        },
        'choice_label' => 'address',
        'placeholder' => 'Je sélectionne une adresse',
    ])

public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => Event::class,
            'user' => User::class
        ]);
    }

Specify user in Controller.php

$form = $this->createForm(EventType::class, $event, ['user' => $user]);

CodePudding user response:

this is possible in different ways

Option 1 a filtered options list from the EventController.php

$form = $this->createForm(EventType::class, $event, [
    'addresses' => $locationRepository->findBy(['organizer' => $user])
]);

More information https://symfony.com/doc/current/forms.html#passing-options-to-forms

and in EventType.php the choice list within the EntityType

->add('address', EntityType::class, [
    'class' => Location::class,
    'choice_label' => 'address',
    'choices' => $options['addresses'],
])

More information https://symfony.com/doc/current/reference/forms/types/entity.html#choices

Option 2 the transfer of the user, as already described above by yourself

EventController.php

$form = $this->createForm(EventType::class, $event, ['user' => $user]);

and build the query with the query_builder option

EventType.php

$user = $options['user'];    
    
$builder
    ...
    ->add('address', EntityType::class, [
        ...
        'query_builder' => function (EntityRepository $er) use ($user) {
            $qb = $er->createQueryBuilder('l');
        
            return $er
                ->andWhere(
                    $qb->expr()->eq('l.user', ':user')
                )
                ->setParameter('user', $user)
            ;
        },
    ])
    ...
;
  • Related