You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EasyAdmin中Acao与Modulo多对多关联报错:传入字符串而非实体实例

问题解决:多对多关联提交时的类型错误

错误信息

添加Acao实体(与Modulo为多对多关联)时触发错误:

Expected argument of type "App\Entity\Modulo", "string" given at property path "modulos".

相关代码

Acao 实体

<?php

namespace App\Entity;

use App\Repository\AcaoRepository;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;

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

    #[ORM\Column]
    private ?int $number = null;

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

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

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

    public function setNumber(int $number): self
    {
        $this->number = $number;
        return $this;
    }

    public function getNome(): ?string
    {
        return $this->nome;
    }

    public function setNome(string $nome): self
    {
        $this->nome = $nome;
        return $this;
    }

    /**
     * @ORM\ManyToMany(targetEntity="App\Entity\Modulo")
     * @ORM\JoinTable(name="acao_modulo",
     *      joinColumns={@ORM\JoinColumn(name="acao_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="modulo_id", referencedColumnName="id")}
     * )
     */
    private $modulos;

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

    /**
     * @return Collection|Modulo[]
     */
    public function getModulos(): Collection
    {
        return $this->modulos ?: new ArrayCollection();
    }

    public function addModulo(Modulo $modulo): self
    {
        if (!$this->modulos->contains($modulo)) {
            $this->modulos[] = $modulo;
        }

        return $this;
    }

    public function removeModulo(Modulo $modulo): self
    {
        $this->modulos->removeElement($modulo);

        return $this;
    }

    public function __toString()
    {
        return (string)$this->nome;
    }
}

AcaoCrudController 原代码

<?php

namespace App\Controller\Admin;

use App\Entity\Acao;
use App\Form\ModuloType;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use EasyCorp\Bundle\EasyAdminBundle\Field\NumberField;
use EasyCorp\Bundle\EasyAdminBundle\Field\CollectionField;
use EasyCorp\Bundle\EasyAdminBundle\Field\ArrayField;


class AcaoCrudController extends AbstractCrudController
{
    public static function getEntityFqcn(): string
    {
        return Acao::class;
    }

    
    public function configureFields(string $pageName): iterable
    {
        return [
            NumberField::new('number'),
            TextField::new('nome'),
            
            // Define the Many-to-Many relationship field
            CollectionField::new('modulos')
                //->setEntryType(ModuloType::class) // Replace ModuloType with your form type for Modulo entity
                ->setEntryIsComplex(false) // Set to true if related entity is complex
                ->setFormTypeOptions([
                    'by_reference' => false, // Ensure that the form is processed correctly for Many-to-Many
                ])
                ->onlyOnForms(), // Display this field only on forms
        ];
    }

}

Modulo 实体

<?php

namespace App\Entity;

use App\Repository\ModuloRepository;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;

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

    #[ORM\Column]
    private ?int $number = null;

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

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

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

    public function setNumber(int $number): static
    {
        $this->number = $number;

        return $this;
    }

    public function getNome(): ?string
    {
        return $this->nome;
    }

    public function setNome(string $nome): static
    {
        $this->nome = $nome;

        return $this;
    }

    /**
     * @ORM\ManyToMany(targetEntity=Acao::class, mappedBy="modulos")
     */
    private $acoes;

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

    /**
     * @return Collection|Acao[]
     */
    public function getAcoes(): Collection
    {
        return $this->acoes;
    }

    public function addAcao(Acao $acao): self
    {
        if (!$this->acoes->contains($acao)) {
            $this->acoes[] = $acao;
            $acao->addModulo($this);
        }

        return $this;
    }

    public function removeAcao(Acao $acao): self
    {
        if ($this->acoes->removeElement($acao)) {
            $acao->removeModulo($this);
        }

        return $this;
    }
}

问题原因

你错误使用了CollectionField处理多对多关联。CollectionField主要用于简单数据集合或自定义嵌套表单,它会将表单提交内容视为字符串类型,无法自动转换为Modulo实体实例,与Acao实体中modulos属性的类型要求不匹配。

解决方案

将CollectionField替换为EasyAdmin专门处理实体关联的AssociationField,它会自动处理实体实例的加载与转换,适配多对多场景:

修改后的AcaoCrudController代码

<?php

namespace App\Controller\Admin;

use App\Entity\Acao;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use EasyCorp\Bundle\EasyAdminBundle\Field\NumberField;


class AcaoCrudController extends AbstractCrudController
{
    public static function getEntityFqcn(): string
    {
        return Acao::class;
    }

    
    public function configureFields(string $pageName): iterable
    {
        return [
            NumberField::new('number'),
            TextField::new('nome'),
            
            // 用AssociationField处理多对多关联
            AssociationField::new('modulos')
                ->setLabel('Modulos')
                ->allowMultipleChoices() // 开启多选,匹配多对多关系
                ->onlyOnForms(),
        ];
    }

}

额外说明

  • AssociationField会自动渲染合适的表单控件(如多选框或下拉选择器),并将提交选项转换为对应的Modulo实体实例。
  • 确保Modulo实体已定义__toString()方法(你已实现),EasyAdmin才能正确显示实体名称。

内容的提问来源于stack exchange,提问作者Pedro Carvalho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 14:15:58