使用 Symfony Form Builder 保存多个嵌入式表单,多个主菜在 1 层深时工作正常,在 2 层深时出错。 (一对多),
Saving multiple embedded forms using Symfony's Formbuilder, multiple entrees work fine 1 level deep, goes wrong 2 levels deep. (1-to-many),
我遇到的问题是关于 Symfony 的 (3) formbuilder。我有 3 个实体,我为其创建了 3 个 FormType。见下文;代码下方的实际问题。
我有以下实体:
DocumentBaldoc 1 -> * DocumentBaldocConnectionPoint 1 -> * DocumentBaldocAccount
我尝试实现以下目标。我想为 DocumentBaldoc 创建一个表单,我想为 DocumentBaldocConnectionPoints 创建多个表单,我想为 DocumentBaldocConnectionPointAccounts 创建多个表单。保存时,这些需要使用关系 (fk) 存储在数据库中。
我有以下 class DocumentBaldoc(表格)
namespace FooBundle\Form\Documents\Baldoc;
use FooBundle\Entity\Documents\Baldoc\DocumentBaldoc;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
class DocumentBaldocType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('document_release')
->add('identification')
->add('version')
->add('type')
->add('creationDateTime')
->add('validityPeriod')
->add('contractReference')
->add('contractType')
->add('issuerMarketParticipantIdentification')
->add('issuerMarketParticipantIdentificationCodingScheme')
->add('issuerMarketParticipantMarketRoleCode')
->add('recipientMarketParticipantIdentification')
->add('recipientMarketParticipantIdentificationCodingScheme')
->add('recipientMarketParticipantMarketRoleCode')
->add('applicationContext')
->add('applicationContextCodingScheme')
->add('connectionPoints', CollectionType::class, [
'entry_type' => DocumentBaldocConnectionPointType::class,
'allow_add' => true,
'by_reference' => false,
])
->add('save', SubmitType::class);
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => DocumentBaldoc::class
));
}
}
我有以下 class 用于 DocumentBaldocConnectionPoint(表单)
namespace FooBundle\Form\Documents\Baldoc;
use FooBundle\Entity\Documents\Baldoc\DocumentBaldocConnectionPoint;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class DocumentBaldocConnectionPointType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('identification')
->add('identificationCodingScheme')
->add('measureUnitCode')
->add('accounts', CollectionType::class, [
'entry_type' => DocumentBaldocAccountType::class,
'allow_add' => true,
'by_reference' => false,
]);
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => DocumentBaldocConnectionPoint::class
));
}
}
我有以下 class 用于 DocumentBaldocAccount(表单)
namespace FooBundle\Form\Documents\Baldoc;
use FooBundle\Entity\Documents\Baldoc\DocumentBaldocAccount;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class DocumentBaldocAccountType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('identification')
->add('identificationCodingScheme')
->add('accountTso')
->add('accountTsoCodingScheme');
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => DocumentBaldocAccount::class
));
}
}
我使用 Symfony 的表单构建器为 DocumentBaldoc 实体生成表单。通过添加一个 CollectionType 和 DocumentBaldocConnectionPoint 作为 entry_type 让我能够在模板中使用原型变量。
{% block DOCUMENT %}
{{ form_start(form) }}
<ul class="connectionPoints"
data-prototype="{{ form_widget(form.connectionPoints.vars.prototype)|e('html_attr') }}">
{{ form_widget(form) }}
</ul>
{{ form_end(form) }}
{% endblock %}
在此之后,我可以使用一些 Javascript 创建无穷无尽的 DocumentBaldocConnectionPoint 表单流,当我按下保存这些表单时(多个!!)DocumentBaldocConnectionPoints 存储在数据库中,并带有父 DocumentBaldoc 的 FK。
到目前为止,这工作得很好,但当我想为 DocumentBaldocConnectionPointAccount 做同样的事情时,问题就来了。页面加载时不存在 DocumentBaldocConnectionPoint 表单,因此我无法直接访问原型属性,我通过创建一些 Javascript 逻辑来解决此问题,该逻辑在创建 DocumentBaldocConenctionPoint 表单时触发。然后它遵循与其父级相同的逻辑。我遇到的问题是我无法保存多个 DocumentBaldocConenctionPointAccounts,它总是保存最后一个,这让我觉得过程中某处它没有保存为数组,或者数组被最后一个条目覆盖。我已经对它进行了几天的修改,但在逻辑上找不到任何差异(表单类型或实体,关系定义遵循相同的结构)这让我觉得我没有使用它,因为它应该被使用.
这些是两个实体的注释关系定义,$connectionPoints 和 $accounts 都在实体的构造函数中实例化为 ArrayCollections。
// DocumentBalcon
@ORM\OneToMany(targetEntity="DocumentBaldocConnectionPoint", mappedBy="document", cascade={"persist"})
private $connectionPoints;
// DocumentBalconConnectionPoint
@ORM\OneToMany(targetEntity="DocumentBaldocAccount", mappedBy="connectionPoint", cascade={"persist"})
private $accounts;
唯一突出的是 DocumentBaldocConnectionPoint 表单的原型是使用 __name__ 语法呈现的,需要用唯一标识符替换,并且当我抓住DocumentBaldocConnectionPointAccount 原型,我通过创建一个自己的标识符来保证唯一性来解决这个问题。
我已经阅读了有关 formbuilder 和创建此类嵌入式表单的 Symfony 文档,但该文档仅说明我正在尝试做的事情是可能的,没有示例。我不知道我正在做的是处理这些嵌入式表单的正确方法,还是我遗漏了过程中的某些步骤。
非常欢迎有关此问题的任何信息或帮助!
问题已解决。
第一个子窗体 DocumentBaldocConnectionPoint 还包含属性原型,其中包含 DocumentBaldocConnectionPointAccount 的窗体。当更改 DocumentBaldocConnectionPoint 中的 __name__ 值时,DocumentBaldocConnectionPointAccount 的值也被无意中更改,这导致了意外行为,即每个 DocumentBaldocConnectionPointAccount 表单都被放置在值为 'index' 的键上的数组中,仅更改每个 DocumentConnectionPoint。
我使用的解决方案如下:
在函数 buildForm 的 DocumentBaldocConnectionPointType class 中,我添加了值为 "accounts" 的原型键,这让我可以通过名称引用获取原型表单。
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('identification')
->add('identificationCodingScheme')
->add('measureUnitCode')
->add('accounts', CollectionType::class, [
'entry_type' => DocumentBaldocAccountType::class,
'allow_add' => true,
'by_reference' => false,
'prototype' => 'accounts'
]);
}
在树枝模板中我添加了一个 div 如下:
<div id="prototypes"
data-prototype-account="{{ form_widget(form.connectionPoints.vars.prototype.children['accounts'].vars.prototype) | e }}"
data-prototype-connection-point="{{ form_widget(form.connectionPoints.vars.prototype) | e }}">
</div>
这导致 div 存储原型表单,让我可以在需要时轻松查询和使用它们。
我遇到的问题是关于 Symfony 的 (3) formbuilder。我有 3 个实体,我为其创建了 3 个 FormType。见下文;代码下方的实际问题。
我有以下实体:
DocumentBaldoc 1 -> * DocumentBaldocConnectionPoint 1 -> * DocumentBaldocAccount
我尝试实现以下目标。我想为 DocumentBaldoc 创建一个表单,我想为 DocumentBaldocConnectionPoints 创建多个表单,我想为 DocumentBaldocConnectionPointAccounts 创建多个表单。保存时,这些需要使用关系 (fk) 存储在数据库中。
我有以下 class DocumentBaldoc(表格)
namespace FooBundle\Form\Documents\Baldoc;
use FooBundle\Entity\Documents\Baldoc\DocumentBaldoc;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
class DocumentBaldocType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('document_release')
->add('identification')
->add('version')
->add('type')
->add('creationDateTime')
->add('validityPeriod')
->add('contractReference')
->add('contractType')
->add('issuerMarketParticipantIdentification')
->add('issuerMarketParticipantIdentificationCodingScheme')
->add('issuerMarketParticipantMarketRoleCode')
->add('recipientMarketParticipantIdentification')
->add('recipientMarketParticipantIdentificationCodingScheme')
->add('recipientMarketParticipantMarketRoleCode')
->add('applicationContext')
->add('applicationContextCodingScheme')
->add('connectionPoints', CollectionType::class, [
'entry_type' => DocumentBaldocConnectionPointType::class,
'allow_add' => true,
'by_reference' => false,
])
->add('save', SubmitType::class);
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => DocumentBaldoc::class
));
}
}
我有以下 class 用于 DocumentBaldocConnectionPoint(表单)
namespace FooBundle\Form\Documents\Baldoc;
use FooBundle\Entity\Documents\Baldoc\DocumentBaldocConnectionPoint;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class DocumentBaldocConnectionPointType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('identification')
->add('identificationCodingScheme')
->add('measureUnitCode')
->add('accounts', CollectionType::class, [
'entry_type' => DocumentBaldocAccountType::class,
'allow_add' => true,
'by_reference' => false,
]);
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => DocumentBaldocConnectionPoint::class
));
}
}
我有以下 class 用于 DocumentBaldocAccount(表单)
namespace FooBundle\Form\Documents\Baldoc;
use FooBundle\Entity\Documents\Baldoc\DocumentBaldocAccount;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class DocumentBaldocAccountType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('identification')
->add('identificationCodingScheme')
->add('accountTso')
->add('accountTsoCodingScheme');
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => DocumentBaldocAccount::class
));
}
}
我使用 Symfony 的表单构建器为 DocumentBaldoc 实体生成表单。通过添加一个 CollectionType 和 DocumentBaldocConnectionPoint 作为 entry_type 让我能够在模板中使用原型变量。
{% block DOCUMENT %}
{{ form_start(form) }}
<ul class="connectionPoints"
data-prototype="{{ form_widget(form.connectionPoints.vars.prototype)|e('html_attr') }}">
{{ form_widget(form) }}
</ul>
{{ form_end(form) }}
{% endblock %}
在此之后,我可以使用一些 Javascript 创建无穷无尽的 DocumentBaldocConnectionPoint 表单流,当我按下保存这些表单时(多个!!)DocumentBaldocConnectionPoints 存储在数据库中,并带有父 DocumentBaldoc 的 FK。
到目前为止,这工作得很好,但当我想为 DocumentBaldocConnectionPointAccount 做同样的事情时,问题就来了。页面加载时不存在 DocumentBaldocConnectionPoint 表单,因此我无法直接访问原型属性,我通过创建一些 Javascript 逻辑来解决此问题,该逻辑在创建 DocumentBaldocConenctionPoint 表单时触发。然后它遵循与其父级相同的逻辑。我遇到的问题是我无法保存多个 DocumentBaldocConenctionPointAccounts,它总是保存最后一个,这让我觉得过程中某处它没有保存为数组,或者数组被最后一个条目覆盖。我已经对它进行了几天的修改,但在逻辑上找不到任何差异(表单类型或实体,关系定义遵循相同的结构)这让我觉得我没有使用它,因为它应该被使用.
这些是两个实体的注释关系定义,$connectionPoints 和 $accounts 都在实体的构造函数中实例化为 ArrayCollections。
// DocumentBalcon
@ORM\OneToMany(targetEntity="DocumentBaldocConnectionPoint", mappedBy="document", cascade={"persist"})
private $connectionPoints;
// DocumentBalconConnectionPoint
@ORM\OneToMany(targetEntity="DocumentBaldocAccount", mappedBy="connectionPoint", cascade={"persist"})
private $accounts;
唯一突出的是 DocumentBaldocConnectionPoint 表单的原型是使用 __name__ 语法呈现的,需要用唯一标识符替换,并且当我抓住DocumentBaldocConnectionPointAccount 原型,我通过创建一个自己的标识符来保证唯一性来解决这个问题。
我已经阅读了有关 formbuilder 和创建此类嵌入式表单的 Symfony 文档,但该文档仅说明我正在尝试做的事情是可能的,没有示例。我不知道我正在做的是处理这些嵌入式表单的正确方法,还是我遗漏了过程中的某些步骤。
非常欢迎有关此问题的任何信息或帮助!
问题已解决。
第一个子窗体 DocumentBaldocConnectionPoint 还包含属性原型,其中包含 DocumentBaldocConnectionPointAccount 的窗体。当更改 DocumentBaldocConnectionPoint 中的 __name__ 值时,DocumentBaldocConnectionPointAccount 的值也被无意中更改,这导致了意外行为,即每个 DocumentBaldocConnectionPointAccount 表单都被放置在值为 'index' 的键上的数组中,仅更改每个 DocumentConnectionPoint。
我使用的解决方案如下:
在函数 buildForm 的 DocumentBaldocConnectionPointType class 中,我添加了值为 "accounts" 的原型键,这让我可以通过名称引用获取原型表单。
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('identification')
->add('identificationCodingScheme')
->add('measureUnitCode')
->add('accounts', CollectionType::class, [
'entry_type' => DocumentBaldocAccountType::class,
'allow_add' => true,
'by_reference' => false,
'prototype' => 'accounts'
]);
}
在树枝模板中我添加了一个 div 如下:
<div id="prototypes"
data-prototype-account="{{ form_widget(form.connectionPoints.vars.prototype.children['accounts'].vars.prototype) | e }}"
data-prototype-connection-point="{{ form_widget(form.connectionPoints.vars.prototype) | e }}">
</div>
这导致 div 存储原型表单,让我可以在需要时轻松查询和使用它们。