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
相关产品推荐
相关产品推荐

