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 将不会被执行。
我的问题和这个差不多:
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 将不会被执行。