phpsymfonysymfony5

Issue with EntityType Querybuilder


So my problem is that whenever im sumbitting my form after filling in it gives me an error Expected argument of type "string", "App\Entity\User" given at property path "naamklant". i've used every possible method and im trying to solve this issue.

<?php

namespace App\Form;

use App\Entity\Dagrooster;
use App\Entity\User;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class DagroosterType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('klant', TextType::class, [
                'label' => 'Bedrijfsnaam',
            ])
            ->add('kamer', ChoiceType::class, [
                'choices' => [
                    'Kamer 1' => 1,
                    'Kamer 2' => 2,
                    'Kamer 3' => 3,
                ]
            ])
            ->add('naamklant', EntityType::class, array(
                'class' => User::class,
                'query_builder' => function (EntityRepository $er) {
                    return $er->createQueryBuilder('u')
                        ->where('u.roles LIKE :role')
                        ->setParameter('role', '%ROLE_MEMBER%');
                },
                'choice_label' => function($name){
                    return $name->getFname();
                },
                ))

            ->add('onderwerp', TextType::class)
            ->add('datum', DateTimeType::class)
            ->add('sumbit', SubmitType::class)
        ;
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => Dagrooster::class,
            'ROLE_MEMBER' => 0
        ]);
    }
}

I've added querybuilder to try out to only choose role_members and nothing else but it still gives me the same error.

>add('naamklant', EntityType::class, array(
                'class' => User::class,
                'query_builder' => function (EntityRepository $er) {
                    return $er->createQueryBuilder('u')
                        ->where('u.roles LIKE :role')
                        ->setParameter('role', '%ROLE_MEMBER%');
                },
                'choice_label' => function($name){
                    return $name->getFname();
                },
                ))

user entity

<?php

namespace App\Entity;

use App\Repository\UserRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;

#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\Table(name: '`user`')]
#[UniqueEntity(fields: ['email'], message: 'There is already an account with this email')]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 180, unique: true)]
    private ?string $email = null;

    #[ORM\Column]
    private array $roles = [];

    /**
     * @var string The hashed password
     */
    #[ORM\Column]
    private ?string $password = null;

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

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

    #[ORM\OneToMany(mappedBy: 'User', targetEntity: Ziekmelding::class)]
    private Collection $ziekmeldings;

    #[ORM\OneToMany(mappedBy: 'User', targetEntity: Dagrooster::class)]
    private Collection $dagroosters;

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

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

    public function getEmail(): ?string
    {
        return $this->email;
    }

    public function setEmail(string $email): static
    {
        $this->email = $email;

        return $this;
    }

    /**
     * A visual identifier that represents this user.
     *
     * @see UserInterface
     */
    public function getUserIdentifier(): string
    {
        return (string) $this->email;
    }

    /**
     * @deprecated since Symfony 5.3, use getUserIdentifier instead
     */
    public function getUsername(): string
    {
        return (string) $this->email;
    }

    /**
     * @see UserInterface
     */
    public function getRoles(): array
    {
        $roles = $this->roles;
        // guarantee every user at least has ROLE_USER
        $roles[] = 'ROLE_EMPLOYEE';

        return array_unique($roles);
    }

    public function setRoles(array $roles): static
    {
        $this->roles = $roles;

        return $this;
    }

    /**
     * @see PasswordAuthenticatedUserInterface
     */
    public function getPassword(): string
    {
        return $this->password;
    }

    public function setPassword(string $password): static
    {
        $this->password = $password;

        return $this;
    }

    /**
     * Returning a salt is only needed, if you are not using a modern
     * hashing algorithm (e.g. bcrypt or sodium) in your security.yaml.
     *
     * @see UserInterface
     */
    public function getSalt(): ?string
    {
        return null;
    }

    /**
     * @see UserInterface
     */
    public function eraseCredentials(): void
    {
        // If you store any temporary, sensitive data on the user, clear it here
        // $this->plainPassword = null;
    }

    public function getFname(): ?string
    {
        return $this->fname;
    }

    public function setFname(string $fname): static
    {
        $this->fname = $fname;

        return $this;
    }

    public function getLname(): ?string
    {
        return $this->lname;
    }

    public function setLname(string $lname): static
    {
        $this->lname = $lname;

        return $this;
    }

    /**
     * @return Collection<int, Ziekmelding>
     */
    public function getZiekmeldings(): Collection
    {
        return $this->ziekmeldings;
    }

    public function addZiekmelding(Ziekmelding $ziekmelding): static
    {
        if (!$this->ziekmeldings->contains($ziekmelding)) {
            $this->ziekmeldings->add($ziekmelding);
            $ziekmelding->setUser($this);
        }

        return $this;
    }

    public function removeZiekmelding(Ziekmelding $ziekmelding): static
    {
        if ($this->ziekmeldings->removeElement($ziekmelding)) {
            // set the owning side to null (unless already changed)
            if ($ziekmelding->getUser() === $this) {
                $ziekmelding->setUser(null);
            }
        }

        return $this;
    }

    /**
     * @return Collection<int, Dagrooster>
     */
    public function getDagroosters(): Collection
    {
        return $this->dagroosters;
    }

    public function addDagrooster(Dagrooster $dagrooster): static
    {
        if (!$this->dagroosters->contains($dagrooster)) {
            $this->dagroosters->add($dagrooster);
            $dagrooster->setUser($this);
        }

        return $this;
    }

    public function removeDagrooster(Dagrooster $dagrooster): static
    {
        if ($this->dagroosters->removeElement($dagrooster)) {
            // set the owning side to null (unless already changed)
            if ($dagrooster->getUser() === $this) {
                $dagrooster->setUser(null);
            }
        }

        return $this;
    }
}

dagrooster entity

<?php

namespace App\Entity;

use App\Repository\DagroosterRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;

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

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

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

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

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

    #[ORM\Column(type: Types::DATETIME_MUTABLE)]
    private ?\DateTimeInterface $datum = null;

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

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

    public function getKlant(): ?string
    {
        return $this->klant;
    }

    public function setKlant(string $klant): static
    {
        $this->klant = $klant;

        return $this;
    }

    public function getKamer(): ?string
    {
        return $this->kamer;
    }

    public function setKamer(string $kamer): static
    {
        $this->kamer = $kamer;

        return $this;
    }

    public function getNaamklant(): ?string
    {
        return $this->naamklant;
    }

    public function setNaamklant(string $naamklant): static
    {
        $this->naamklant = $naamklant;

        return $this;
    }

    public function getOnderwerp(): ?string
    {
        return $this->onderwerp;
    }

    public function setOnderwerp(string $onderwerp): static
    {
        $this->onderwerp = $onderwerp;

        return $this;
    }

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

    public function setDatum(\DateTimeInterface $datum): static
    {
        $this->datum = $datum;

        return $this;
    }

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

    public function setUser(?User $User): static
    {
        $this->User = $User;

        return $this;
    }
}

Solution

  • In your form, your setting your widget to an EntityType.
    So, after resolution, your submitted value will be an instance of User for the property naamklant.
    Then Symfony will try to set the properties of the underlying object, in this case your entity Dagrooster. It will check of a setter (setNaamklant()) an call it with the submitted value (a User instance).
    As the method is expecting a string and not a User you get this error message.
    The way to solve it, is either by changing the $naamklant property in the Dagrooster from string to User or by changing the property naamKlant to User in the form.

    // In the entity replace this
    #[ORM\Column(length: 255)]
    private ?string $naamklant = null;
    // by
    #[ORM\ManyToOne(targetEntity: User::class)]
    private ?User $naamklant = null
    
    // ------ OR ------
    
    // In the form, replace
    ->add('naamklant', EntityType::class, ...)
    // by
    ->add('User', EntityType::class, ...)
    

    ->add('naamklant', EntityType::class