编辑并解决+更新
我 am 找不到找到以下内容的窍门。
说我有两个df.Number = df.Number.astype(int)
:Entity
和Main
,Minor
一对多Main
,Minor
是外键领域。
我希望同时具有(次要)形式来创建mainId
对象,以便用户可以从已经可用的Minor
对象列表中选择其Main
对象,以及(主要)形式来一次创建Main
对象和可能同时创建许多不同的Main
(子)对象的表单。
问题是是在后一种情况下,我 am 无法保存外键。
在Minor
类中,我拥有Main
属性
Minors
/**
* @ORM\OneToMany(targetEntity="App\Entity\Minor", mappedBy="Main", cascade={"persist"})
*/
private $Minors; NOTE: cascade={"persist"} HELPS!!!!
与
setter/getter
对于次要表格,我定义:
/**
* @return Collection|Minor[]
*/
public function getMinors(): Collection
{
return $this->Minors;
}
public function addMinor(Minor $minor): self
{
if (!$this->Minors->contains($minor)) {
$this->Minors[] = $minor;
$minor->setMain($this); <<< THIS HELPS!!!
}
return $this;
}
public function removeMinor(Minor $minor): self
{
if ($this->Minors->contains($minor)) {
$this->Minors->removeElement($minor);
// set the owning side to null (unless already changed)
if ($minor->getMain() === $this) {
$minor->setMain(null);
}
}
return $this;
}
对于主表单,我尝试过:
....
$builder ->add('minorTitle')
->add('Main', EntityType::class, array(
'class' => Main::class,
'choice_label' => 'mainTtile',
'label' => 'main'));
if(empty($options['remove_main_field'])) {
// field is the same, but isn't added always, due to 'if'
$builder->add('Main', EntityType::class, array(
'class' => Main::class,
'choice_label' => 'mainTitle',
'label' => 'Main',
));
}
.....
$resolver->setDefaults([
'data_class' => Minor::class,
'remove_main_field' => false, <<< THIS HELPS!!!
]);
因此,次要表单确实是作为主表单中的子表单嵌入的。要添加更多子表单,我有CollectionType中建议的一些JS。感谢....
$builder
->add('mainTitle')
->add('Minors', CollectionType::class, array(
'entry_type' => MinorType::class,
'entry_options' => ['label' => true, 'remove_main_field' => true], <<< THIS HELPS!!!
'allow_add' => true,
'label' => 'Minor'
))
.....
'data_class' => Main::class`
,不再需要以下技巧。 为了避免在次要子窗体中显示 remove_main_field
字段,我对Main
进行了一些修改,例如:
prototype
用户可以创建一个Main对象,也可以创建许多次要对象,但是前一个的作为后者的外键。最终,我得到了有效的代码:/* newWidget = newWidget.replace(newWidget.match(/\B<div class="form-group"><label class="required" for="main_Minors___name_Main">Main<\/label><select id="main_Minors___name_Main" name="main\[Minors\]\[__name__\]\[Main\]" class="form-control">.*<\/select>\B/g),""); */
被保存为
id
已解决编辑问题!!我不需要如下定义public function new(Request $request): Response {
$em = $this->getDoctrine()->getManager();
$main = new Main();
$form = $this->createForm(MainType::class, $main);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
postData
,但要么不起作用,要么保存两次相同的子对象(只有一次使用正确的外键保存)。
非常感谢Jakumi!
答案 0 :(得分:2)
只有一些提示。
data_class
选项设置为适当的类。$form->getData()
就可以得到适当的实体(或者,您可能已经注意到,当您给createForm
调用实体时,该实体将通过以下形式进行修改:组件-可能并非总是有意的。请在不需要时考虑使用数据传输对象(DTO)。CollectionType
字段应将选项 byReference
设置为false
,以便在设置字段上使用设置者(Main::setMinors
,在这种情况下)。通常一对多的一面(即Main
类)可以摆脱:
public function setMinors(array $minors) {
foreach($minors as $minor) {
$minor->setMain($this); // set the main, just to be safe
}
$this->minors = $minors; // set the property Main.minors
}
但是您也应该也不相反地在setMain
中执行此操作(这也不是那么简单。setMinors
的替代方法是addMinor
和{{1} },这两种解决方案都有其优点和成本,但是当涉及到形式时,我认为它们是相当的。
removeMinor
上的如果您在Main
(即cascade={"PERSIST"}
)上设置了OneToMany
选项,则不必显式地对所有未成年人呼叫持久化,则只要您持久(并刷新)@ORM\OneToMany(targetEntity="App\Entity\Minor", cascade={"PERSIST"})
对象/实例,它们就会持久化。
Main
表单字段,或者添加一个没有{{1}的新表单类型main
(或其他任何内容) }表单字段(扩展MainMinorType
并删除main
字段)。这消除了肮脏的黑客的必要; o)但是,总的来说,如果您没有以双向关系将未成年人设置在主体上,则结果将无法明确定义。 (假设一会儿,A有一个到B的链接,但是B没有到A的链接,但是应该有一个链接,因为它是双向关系。这可能意味着必须建立链接。它也可能意味着应该删除该链接。因此,为了安全起见并清楚地传达意图,请设置双方!)最终,这可能是其无法按预期工作的原因。
更新
要详细说明第7点,您的MinorType
可以这样修改:
main
在您的MinorType
中,以下项已添加了新选项
class MinorType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
// ... other fields before
if(empty($options['remove_main_field'])) {
// field is the same, but isn't added always, due to 'if'
$builder->add('main', EntityType::class, [
'class' => Main::class,
'choice_label' => 'mainTtile',
'label' => 'main'
]);
}
// ... rest of form
}
public function configureOptions(OptionsResolver $resolver) {
// maybe parent call ...
$resolver->setDefaults([
// your other defaults
'remove_main_field' => false, // add new option, self-explanatory
]);
}
}
现在,当主表单中的 embedded 时,这将从未成年人表单中删除该主字段。但是默认设置是不删除主字段,因此当您自己编辑次要对象时,将显示主字段,就像以前一样……除非我在代码中输入错误;否则)