Symfony 5:在没有“by_reference”的情况下从 MappedBy Side 添加时,多对多关系不会持续存在=> false

问题描述 投票:0回答:1

背景:

我正在开发一个 Symfony 5 应用程序,其中实体

InventaireActif
TypeActif
具有多对多关系。通过 Symfony 表单管理这种关系时会出现问题。

问题:

在我的

TypeActif
表单中,当我添加
InventaireActif
实体时,除非我在表单生成器中设置
'by_reference' => false
选项,否则它们不会持久保存到数据库中。我想在不依赖此选项的情况下实现正确的行为。

实体配置:

InventaireActif.php:

/**
 * @ORM\ManyToMany(targetEntity=TypeActif::class, inversedBy="lesActifs")
 */
private $lesTypesActifs;

public function __construct()
{
    $this->lesTypesActifs = new ArrayCollection();
    // ... other initializations ...
}

/**
 * @return Collection<int, TypeActif>
*/
public function getLesTypesActifs(): Collection
    {
        return $this->lesTypesActifs;
    }

    public function addLesTypesActif(TypeActif $lesTypesActif): self
    {
        if (!$this->lesTypesActifs->contains($lesTypesActif)) {
            $this->lesTypesActifs[] = $lesTypesActif;
        }

        return $this;
    }

    public function removeLesTypesActif(TypeActif $lesTypesActif): self
    {
        $this->lesTypesActifs->removeElement($lesTypesActif);

        return $this;
    }

TypeActif.php:

/**
 * @ORM\ManyToMany(targetEntity=InventaireActif::class, mappedBy="lesTypesActifs")
 */
private $lesActifs;

public function __construct()
{
    $this->lesActifs = new ArrayCollection();
    // ... other initializations ...
}

public function getLesActifs(): Collection
{
    return $this->lesActifs;
}

public function addLesActif(InventaireActif $lesActif): self
{
    if (!$this->lesActifs->contains($lesActif)) {
        $this->lesActifs[] = $lesActif;
        $lesActif->addLesTypesActif($this);
    }
    return $this;
}

public function removeLesActif(InventaireActif $lesActif): self
{
    if ($this->lesActifs->removeElement($lesActif)) {
        $lesActif->removeLesTypesActif($this);
    }
    return $this;
}

TypeActifType.php 中的表单配置:

public function buildForm(FormBuilderInterface $builder, array $options): void
{
    $builder
        // ... other fields ...
        ->add('lesActifs', EntityType::class, [
            'required' => false,
            'class' => InventaireActif::class,
            'choice_label' => 'libelle',
            // 'by_reference' => false,
            'multiple' => true,
            'query_builder' => function (InventaireActifRepository $repo) {
                return $repo->lesActifsReformesSortedASC();
            },
        ]);
}

在 TypeActifController.php 中编辑路由:

public function new(Request $request, TypeActifRepository $typeActifRepository, EntityManagerInterface $entityManager): Response
    {
        $typeActif = new TypeActif();
        $form = $this->createForm(TypeActifType::class, $typeActif);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $typeActifRepository->add($typeActif, true);

            return $this->redirectToRoute('app_type_actif_index', [], Response::HTTP_SEE_OTHER);
        }

        return $this->renderForm('type_actif/new.html.twig', [
            'type_actif' => $typeActif,
            'form' => $form,
        ]);
    }

“by_reference”问题:

  • 'by_reference' => false
    取消注释时,表单工作正常,并且 ManyToMany 关系按预期更新。

  • 但是,我想避免使用

    'by_reference' => false
    。如果没有此选项,通过
    InventaireActif
    表单添加
    TypeActif
    实体不会保留更改。

尝试解决:

  • 确保两个实体中的

    add
    remove
    方法同步。

  • 审查了 Dotrine 配置和注释。

预期行为:

通过

InventaireActif
表单添加
TypeActif
实体时,应将更改保存到数据库,而不需要设置
'by_reference' => false

当前行为:

如果没有

'by_reference' => false
,更改不会持久。没有显示错误,日志也没有显示任何异常。

forms entity-relationship symfony5 mappedby
1个回答
0
投票

如果

by_reference
设置为
true
(或被省略),Symfony 的表单系统只是使用
ArrayCollection
类的方法将选定的实体添加到指定的属性。如果
by_reference
设置为
false
,它将使用您指定的自定义添加/删除方法。

将实体保存到数据库时,仅保存对多对多关系的owning侧所做的更改。代码中的拥有方是

$lesTypesActifs
类中的
InventaireActif
属性。

在您的表单中,如果没有

by_reference = false
,您仅更新
$lesActifs
实体的
TypeActif
属性,这是关系的 inverse 方面,因此这就是不保存更改的原因。但如果您添加
by_reference = false
,自定义添加/删除方法可确保拥有方也已更新,因此更改将被保存。

我不确定您是否还有一个通过修改

InventaireActif
属性来更新
$lesTypeActif
实体的表单,但如果没有,您可能只需切换实体的拥有和反面即可摆脱
by_reference = false

class TypeActif {
    /**
     * @ORM\ManyToMany(targetEntity=InventaireActif::class, inversedBy="lesTypesActifs")
     */
    private $lesActifs;

    public function __construct()
    {
        $this->lesActifs = new ArrayCollection();
        // ... other initializations ...
    }

    public function getLesActifs(): Collection
    {
        return $this->lesActifs;
    }
}

class InventaireActif {
    /**
     * @ORM\ManyToMany(targetEntity=TypeActif::class, mappedBy="lesActifs")
     */
    private $lesTypesActifs;

    public function __construct()
    {
        $this->lesTypesActifs = new ArrayCollection();
        // ... other initializations ...
    }

    /**
     * @return Collection<int, TypeActif>
     */
    public function getLesTypesActifs(): Collection
    {
        return $this->lesTypesActifs;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.