Symfony\Bridge\Doctrine\Form\ChoiceList\IdReader::getIdValue(): Argument #1 ($object) must be of type ?object, string given

huangapple go评论64阅读模式
英文:

Symfony\Bridge\Doctrine\Form\ChoiceList\IdReader::getIdValue(): Argument #1 ($object) must be of type ?object, string given

问题

这个错误信息表明在 Symfony 6.3 应用程序中修改联系人时出现了问题,具体是在表单处理过程中。错误消息指出在 Symfony\Bridge\Doctrine\Form\ChoiceList\IdReader::getIdValue() 方法中,参数 #1 的类型应该是 ?object,但实际上传递了一个字符串。这个问题通常是由于表单字段的某些配置或数据传递不正确导致的。

要解决这个问题,你可以执行以下步骤:

  1. 检查你的表单字段配置,特别是那些与关联实体相关的字段。确保它们正确地与相关的实体类联系在一起。

  2. 检查在修改联系人时如何传递联系人对象。你可以在控制器中的编辑操作中检查一下,确保正确地获取并传递了联系人对象。

  3. 确保联系人对象的数据是有效的,没有任何意外的数据类型问题。你可以在编辑操作中打印联系人对象的内容来进行调试,确保它是一个有效的 Contact 对象。

  4. 如果有必要,可以查看你的 ContactType 表单类,确保其中的字段配置正确。特别关注那些可能导致类型不匹配问题的字段。

  5. 最后,检查你的实体类 Contact,确保属性与数据库字段的映射正确,并且 getter 和 setter 方法的类型和返回类型也正确。

通过仔细检查这些方面,你应该能够找到并解决引发该错误的问题。如果问题仍然存在,可以提供更多关于具体配置和数据的信息,以便进一步帮助你解决问题。

英文:

I'm working on a form to manage contacts within a Symfony 6.3 application. Contact creation works well.
However, when I try to modify a contact, instead of the form that would normally show up, there is the following error message:
> Symfony\Bridge\Doctrine\Form\ChoiceList\IdReader::getIdValue(): Argument #1 ($object) must be of type ?object, string given, called in D:\2. TDEKDO\vendor\symfony\form\ChoiceList\ArrayChoiceList.php on line 134
>
screenshot of the error message

And when I dump the contact variable before assigning it to the form, it comes up as being an object:
contact variable as an object

This is my ContactType form:

`<?php

namespace App\Form;

use App\Entity\Contact;
use App\Entity\Adherent;
use App\Entity\TypeVoie;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TelType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;

class ContactType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $typevoies = $options['typevoies'];
        $adherents = $options['adherents'];

        $builder
            ->add('politesse', ChoiceType::class, [
                'label' => 'Politesse',
                'required' => true,
                'multiple' => false,
                'expanded' => false,
                'choices' => [
                    'Mr' => 'Mr',
                    'Mme' => 'Mme'
                ]
            ])
            ->add('nom', TextType::class, [
                'label' => 'Nom',
                'constraints' => new Length([
                    'min' => 2,
                    'max' =>  30
                ]),                    
                'required' => true,
                'attr' => [
                    'placeholder' => "Merci de saisir le nom de contact"
                ]
            ])
            ->add('prenom', TextType::class, [
                'label' => 'Prénom',
                'constraints' => new Length([
                    'min' => 2,
                    'max' =>  30
                ]),                    
                'required' => true,
                'attr' => [
                    'placeholder' => "Merci de saisir le prénom de contact"
                ]
            ])
            ->add('tel', TelType::class, [
                'label' => 'Téléphone',                   
                'attr' => [
                    'placeholder' => "Merci de saisir le numero de téléphone"
                ]
            ])
            ->add('mobile', TelType::class, [
                'label' => 'Mobile',                   
                'attr' => [
                    'placeholder' => "Merci de saisir le numero de mobile"
                ]
            ])
            ->add('mail', TextType::class, [
                'label' => 'Mail',                    
                'attr' => [
                    'placeholder' => "Merci de saisir le mail"
                ]
            ])
            ->add('fonction', TextType::class, [
                'label' => 'Fonction',                    
                'attr' => [
                    'placeholder' => "Merci de saisir la fonction"
                ]
            ])
            ->add('annule')
            ->add('numvoie', TextType::class, [
                'label' => 'Numero',                    
                'attr' => [
                    'placeholder' => "Voie"
                ]
            ])
            ->add('typevoie', EntityType::class, [
                'label' => 'Type de voie',
                'class' => TypeVoie::class,
                'choices' => $typevoies,
                'choice_label' => 'libelle',
                'required' => true,
                'attr' => [
                    'placeholder' => "Merci de choisir le type de voie"
                ]
            ])
            ->add('adresse1')
            ->add('adresse2')
            ->add('adresse3')
            ->add('postal')
            ->add('ville')
            ->add('adherent', EntityType::class, [
                'label' => 'Adhérent',
                'class' => Adherent::class,
                'choices' => $adherents,
                'choice_label' => 'nom'
            ])
            ->add('submit', SubmitType::class, [
                'label' => 'Inserer',
                'attr' => [
                    'class' => 'btn btn-success w-100'
                ]
            ])
        ;
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => Contact::class,
            'typevoies' => [],
            'adherents' => []
        ]);
    }
}`

This is my ContactController:

`<?php

namespace App\Controller;

use App\Entity\Contact;
use App\Entity\Adherent;
use App\Entity\TypeVoie;
use App\Form\ContactType;
use App\Entity\Utilisateur;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

class ContactController extends AbstractController
{
    private $entityManager;
    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;
    }

    #[Route('/administration/contacts', name: 'app_admin_contacts')]
    public function admin(): Response
    {
        $adherents = $this->entityManager->getRepository(Adherent::class)->findAll();
        $contacts = [];
        foreach ($adherents as $key => $adherent) {
            $contacts[] = $this->entityManager->getRepository(Contact::class)->contactsByAdherentId($adherent->getId());
        }  
        return $this->render('contact/index.html.twig', [
            'contacts' => $contacts,
        ]);
    }

    #[Route('/utilisateur/{user_id}/contacts', name: 'app_user_contacts')]
    public function user($user_id): Response
    {
        $loggedInUser = $this->getUser()->getId();
        $user = $this->entityManager->getRepository(Utilisateur::class)->find($user_id);
        if ($loggedInUser !== $user->getId()) {
            return $this->redirectToRoute('app_login');
        }
        $association_id = $user->getAssociation()->getId();
        $adherents = $this->entityManager->getRepository(Adherent::class)->adherentsByAssocId($association_id);
        $contacts = [];
        foreach ($adherents as $key => $adherent) {
            $contacts[] = $this->entityManager->getRepository(Contact::class)->contactsByAdherentId($adherent->getId());
        }        
        return $this->render('contact/index.html.twig', [
            'contacts' => $contacts,
        ]);
    }

    #[Route('/contact/ajouter', name: 'app_add_contact')]
    public function add(Request $request): Response
    {
        $user = $this->getUser();
        $associationId = $user->getAssociation()->getId();

        if ($associationId === 1) {
            $typevoies = $this->entityManager->getRepository(TypeVoie::class)->findAll();
            $adherents = $this->entityManager->getRepository(Adherent::class)->findAll();
        } 
        if ($associationId > 1) {
            $typevoies = $this->entityManager->getRepository(TypeVoie::class)->typevoiesByAssocId($associationId);
            $adherents = $this->entityManager->getRepository(Adherent::class)->adherentsByAssocId($associationId);
        }
        $contact = new Contact();
        $form = $this->createForm(ContactType::class, $contact, [
            'typevoies' => $typevoies,
            'adherents' => $adherents
        ]);

        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
            $this->entityManager->persist($contact);
            $this->entityManager->flush();
            if ($user->getRoles() === 'ROLE_ADMIN') {
                return $this->redirectToRoute('app_admin_contacts');
            }
            return $this->redirectToRoute('app_user_contacts', [
                'user_id' => $user->getId()
            ]);
        }
        return $this->render('contact/new.html.twig', [
            'form' => $form->createView(),
        ]);
    }

    #[Route('/contact/modifier/{contactId}', name: 'app_edit_contact')]
    public function edit($contactId): Response
    {
        $user = $this->getUser();
        $associationId = $user->getAssociation()->getId();

        if ($associationId === 1) {
            $typevoies = $this->entityManager->getRepository(TypeVoie::class)->findAll();
            $adherents = $this->entityManager->getRepository(Adherent::class)->findAll();
        } 
        if ($associationId > 1) {
            $typevoies = $this->entityManager->getRepository(TypeVoie::class)->typevoiesByAssocId($associationId);
            $adherents = $this->entityManager->getRepository(Adherent::class)->adherentsByAssocId($associationId);
        }

        $contact = $this->entityManager->getRepository(Contact::class)->findOneById($contactId);
        //dd($contact);
        $form = $this->createForm(ContactType::class, $contact, [
            'typevoies' => $typevoies,
            'adherents' => $adherents
        ]);
        
        return $this->render('contact/new.html.twig', [
            'form' => $form->createView()
        ]);
    }
}`

And this is my Contact entity:

`<?php

namespace App\Entity;

use App\Repository\ContactRepository;
use Doctrine\ORM\Mapping as ORM;

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

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

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

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

    #[ORM\Column(length: 20, nullable: true)]
    private ?string $tel = null;

    #[ORM\Column(length: 20, nullable: true)]
    private ?string $mobile = null;

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

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

    #[ORM\Column]
    private ?bool $annule = null;

    #[ORM\Column(length: 5, nullable: true)]
    private ?string $numvoie = null;

    #[ORM\Column(length: 20, nullable: true)]
    private ?string $typevoie = null;

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

    #[ORM\Column(length: 50, nullable: true)]
    private ?string $adresse2 = null;

    #[ORM\Column(length: 50, nullable: true)]
    private ?string $adresse3 = null;

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

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

    #[ORM\ManyToOne(inversedBy: 'contacts')]
    #[ORM\JoinColumn(nullable: false)]
    private ?Adherent $adherent = null;

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

    public function getPolitesse(): ?string
    {
        return $this->politesse;
    }

    public function setPolitesse(string $politesse): self
    {
        $this->politesse = $politesse;

        return $this;
    }

    public function getNom(): ?string
    {
        return $this->nom;
    }

    public function setNom(string $nom): self
    {
        $this->nom = $nom;

        return $this;
    }

    public function getPrenom(): ?string
    {
        return $this->prenom;
    }

    public function setPrenom(string $prenom): self
    {
        $this->prenom = $prenom;

        return $this;
    }

    public function getTel(): ?string
    {
        return $this->tel;
    }

    public function setTel(?string $tel): self
    {
        $this->tel = $tel;

        return $this;
    }

    public function getMobile(): ?string
    {
        return $this->mobile;
    }

    public function setMobile(?string $mobile): self
    {
        $this->mobile = $mobile;

        return $this;
    }

    public function getMail(): ?string
    {
        return $this->mail;
    }

    public function setMail(string $mail): self
    {
        $this->mail = $mail;

        return $this;
    }

    public function getFonction(): ?string
    {
        return $this->fonction;
    }

    public function setFonction(string $fonction): self
    {
        $this->fonction = $fonction;

        return $this;
    }

    public function isAnnule(): ?bool
    {
        return $this->annule;
    }

    public function setAnnule(bool $annule): self
    {
        $this->annule = $annule;

        return $this;
    }

    public function getNumvoie(): ?string
    {
        return $this->numvoie;
    }

    public function setNumvoie(?string $numvoie): self
    {
        $this->numvoie = $numvoie;

        return $this;
    }

    public function getTypevoie(): ?string
    {
        return $this->typevoie;
    }

    public function setTypevoie(?string $typevoie): self
    {
        $this->typevoie = $typevoie;

        return $this;
    }

    public function getAdresse1(): ?string
    {
        return $this->adresse1;
    }

    public function setAdresse1(string $adresse1): self
    {
        $this->adresse1 = $adresse1;

        return $this;
    }

    public function getAdresse2(): ?string
    {
        return $this->adresse2;
    }

    public function setAdresse2(?string $adresse2): self
    {
        $this->adresse2 = $adresse2;

        return $this;
    }

    public function getAdresse3(): ?string
    {
        return $this->adresse3;
    }

    public function setAdresse3(?string $adresse3): self
    {
        $this->adresse3 = $adresse3;

        return $this;
    }

    public function getPostal(): ?string
    {
        return $this->postal;
    }

    public function setPostal(string $postal): self
    {
        $this->postal = $postal;

        return $this;
    }

    public function getVille(): ?string
    {
        return $this->ville;
    }

    public function setVille(string $ville): self
    {
        $this->ville = $ville;

        return $this;
    }

    public function getAdherent(): ?Adherent
    {
        return $this->adherent;
    }

    public function setAdherent(?Adherent $adherent): self
    {
        $this->adherent = $adherent;

        return $this;
    }
}`

What is missing here?

Thanks in advance.

答案1

得分: 3

我通过将以下代码片段添加到表单中成功解决了这个问题:

'multiple' => false,
'expanded' => false,
'mapped' => false

它已添加到表单的 'typevoie' 元素中。

英文:

I managed to resolve the issue by adding the following piece of the code to the form:

'multiple' => false,
'expanded' => false,
'mapped' => false

It has been added to 'typevoie' element of the form.

答案2

得分: 0

worked for symfony 6.3, 6.4 Entitytype form field

'query_builder' => MUST RETURN QueryBuilder OBJECT not real results

solution:

->add('yourAnyField', EntityType::class, [
    'class' => Your!!ANY!!EntityClassToFullFillSelectFormChoices::class,
	'query_builder' => function (YourEntityClassRepository $repo): QueryBuilder {
					return  $repo->findGroupOptionsList(17);
				},

	'choice_label' => 'variableName',
	'choice_value' => 'id',


inject repository in FORMTYPE by constructor, 


repository MUST RETURN **QueryBuilder** OBJECT not real results 

	/**
	 * @param $value
	 * @return QueryBuilder
	 */
	public function findByLinkUpstreamManyToOne($value): QueryBuilder
	{
		
		$qb = $this->createQueryBuilder('m');

		return = $qb
			->andWhere('m.linkUpstreamManyToOneEntityFieldName = :val')
			->setParameter('val', $value)
			->orderBy('m.id', 'ASC')
				;

	}

note:

  1. adding query into repository make it flexible, accessible by any service in the future

  2. choice label is verry flexible callback function, you can generate "name" even from many ManyToOne sources [table levels]

    'choice_label' => function ($linkUpstreamMegaMenuSection) {
    return '[menu] .$linkUpstreamMegaMenuSection->getLinkUpstreamMegaMenu()->getMegaMenuName().' | [section] '
    .$linkUpstreamMegaMenuSection->getSectionName();
    },

I'm using own notation in entity for field names to describe relations in database may it be also usefull for you

linkUpstreamEntityCalled for ManyToOne [A] <= [B,B,B,B]

linkStreamEntityCalled for OneToMany [A] => [B,B,B,B]

it gives me better view what data i'm looking at programing level

英文:

worked for symfony 6.3, 6.4 Entitytype form field

'query_builder' => MUST RETURN QueryBuilder OBJECT not real results

solution:

-&gt;add(&#39;yourAnyField&#39;, EntityType::class, [
    &#39;class&#39; =&gt; Your!!ANY!!EntityClassToFullFillSelectFormChoices::class,
	&#39;query_builder&#39; =&gt; function (YourEntityClassRepository $repo): QueryBuilder {
					return  $repo-&gt;findGroupOptionsList(17);
				},

	&#39;choice_label&#39; =&gt; &#39;variableName&#39;,
	&#39;choice_value&#39; =&gt; &#39;id&#39;,


inject repository in FORMTYPE by constructor, 


repository MUST RETURN **QueryBuilder** OBJECT not real results 

	/**
	 * @param $value
	 * @return QueryBuilder
	 */
	public function findByLinkUpstreamManyToOne($value): QueryBuilder
	{
		
		$qb = $this-&gt;createQueryBuilder(&#39;m&#39;);

		return = $qb
			-&gt;andWhere(&#39;m.linkUpstreamManyToOneEntityFieldName = :val&#39;)
			-&gt;setParameter(&#39;val&#39;, $value)
			-&gt;orderBy(&#39;m.id&#39;, &#39;ASC&#39;)
				;

	}

note:

  1. adding query into repository make it flexible, accessible by any service in the future

  2. choice label is verry flexible callback function, you can generate "name" even from many ManyToOne sources [table levels]

    'choice_label' => function ($linkUpstreamMegaMenuSection) {
    return '[menu] .$linkUpstreamMegaMenuSection->getLinkUpstreamMegaMenu()->getMegaMenuName().' | [section] '
    .' '.$linkUpstreamMegaMenuSection->getSectionName();
    },

I'm using own notation in entity for field names to describe relations in database may it be also usefull for you

linkUpstreamEntityCalled for ManyToOne [A] <= [B,B,B,B]

linkStreamEntityCalled for OneToMany [A] => [B,B,B,B]

it gives me better view what data i'm looking at programing level

huangapple
  • 本文由 发表于 2023年6月13日 02:03:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/76459226.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定