Doctrine Array 类型字段未更新

Doctrine Array type field not being updated

我的问题和这个差不多:

How to force Doctrine to update array type fields?

但由于某种原因,该解决方案对我不起作用,所以一定有一个细节是我遗漏的,如果有人能向我指出,我会很高兴。

上下文是一个使用了 Doctrine ^2.7 的 Symfony 5.2 应用程序。

实体-Class-摘录:

class MyEntity {
    // some properties

    /**
     * @var string[]
     * @Groups("read")
     * @ORM\Column(type="array")
     * @Assert\Valid
     */
    protected array $abbreviations = [];

    
    public function getAbbreviations(): ?array
    {
        return $this->abbreviations;
    }

    //this is pretty much the same set-function as in the question I referenced
    public function setAbbreviations(array $abbreviations)
    {
        if (!empty($abbreviations) && $abbreviations === $this->abbreviations) {
            reset($abbreviations);
            $abbreviations[key($abbreviations)] = clone current($abbreviations);
        }
        $this->abbreviations = $abbreviations;
    }

    public function addAbbreviation(LocalizableStringEmbeddable $abbreviation): self
    {
        foreach ($this->abbreviations as $existingAbbreviation) {
            if ($abbreviation->equals($abbreviation)) {
                return $this;
            }
        }

        $this->abbreviations[] = $abbreviation;
        return $this;
    }

    public function removeAbbreviation(LocalizableStringEmbeddable $abbreviation): self
    {
        foreach ($this->abbreviations as $i => $existingAbbreviation) {
            if ($abbreviation->equals($existingAbbreviation)) {
                array_splice($this->abbreviations, $i, 1);
                return $this;
            }
        }

        return $this;
    }
}

但是这些方法中的 none 一直被调用(我也尝试删除 add-/removeAbbreviation 只留下 get/set)。

LocalizableStringEmbeddable 是一个像这样的 Embeddable:

* @ORM\Embeddable
 */
class LocalizableStringEmbeddable
{
    /**
     * @var string|null
     * @Groups("read")
     * @ORM\Column(type="string", nullable=false)
     */
    private ?string $text;

    /**
     * @var string|null
     * @Groups("read")
     * @ORM\Column(type="string", nullable=true)
     * @Assert\Language
     */
    private ?string $language;

    //getters/setters/equals/@Assert\Callback
}

通过使用 dd(...) 我可以进一步说在我的控制器中提交

$myEntity = $form->getData();

使用更新的数组生成正确填充的 MyEntity 但我随后调用

$entityManager->persist($myEntity);
$entityManager->flush();

不更改数据库。

我错过了什么?

编辑:我被要求提供有关我使用的类型的信息。这是一个基于此 class 的自定义。所以从技术上讲,我使用的是集合类型。

abstract class AbstractLocalizableUnicodeStringArrayType extends AbstractType implements DataMapperInterface
{
    abstract public function getDataClassName(): string;

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('items', CollectionType::class, [
                'entry_type' => LocalizedStringEmbeddableType::class,
                'entry_options' => [
                    'data_class' => $this->getDataClassName(),
                    'attr' => ['class' => 'usa-item-list--item-box'],
                ],
                'allow_add' => true,
                'allow_delete' => true,
                'prototype' => true,
            ])
        ;

        $builder->setDataMapper($this);
    }

    public function mapDataToForms($viewData, iterable $forms): void
    {
        $forms = iterator_to_array($forms);
        if (null === $viewData) {
            return;
        }

        if (!is_array($viewData)) {
            throw new UnexpectedTypeException($viewData, "array");
        }

        $forms['items']->setData($viewData);
    }

    public function mapFormsToData(iterable $forms, &$viewData): void
    {
        $forms = iterator_to_array($forms);
        $viewData = $forms['items']->getData();
    }
}

我发现这可以通过结合另一个 post 在 SO 上的两个答案来解决(在我看来以一种不优雅的方式,但在出现更好的情况之前我想说明这一点):

这意味着将实体中的预刷新挂钩 class 与相关数组的“假更改”相结合。

请注意,在 setter/adder/remover 中进行假更改对我不起作用,因为在编辑现有实体时不会调用这些更改。在这种情况下,只会调用数组中已更改对象的设置器,从而使 Doctrine 无法识别数组本身的更改,因为似乎没有进行深度检查。

另一个帖子中没有说明的另一件事我想指出:

不要忘记用

注释您的实体 class
@ORM\HasLifecycleCallbacks

否则你的 preflush-hook 将不会被执行。