@下面更新
我已阅读https://symfony.com/doc/current/form/form_collections.html并且它与本文档中的示例完美配合。现在我想反向执行(零件->票证 - 使用票证数据渲染零件)
我希望能够更新多个表单的数据,然后一键提交。在这种情况下,每个部分都是单独的形式。 现在我所实现的就是将多个 formView() 放入一个数组中然后渲染它 - 它有来自数据库的数据,但这些是不同的形式:(。
主要问题是,当我创建新表单 PartCollectionType 并传递多个零件对象时,它不会将其呈现在页面上,但我可以添加新的 PartsType 表单。我认为问题要么与关系有关(ManyToOne - 每个部分只能有一张票),要么与 PartCollectionType 的“data_class”有关。
票务.php
#[ORM\OneToMany(mappedBy: 'ticket', targetEntity: Part::class , cascade: ['persist'])]
private Collection $parts;
部分.php
#[ORM\ManyToOne(inversedBy: 'parts')]
private ?Ticket $ticket = null;
据我了解,这是一个包含其他表单的表单,因此我应该能够使用“UpdateAllParts”按钮提交每个子表单,并且 Doctrine 将完成其余的工作
class PartColletionType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('UpdateAllParts' , SubmitType::class , [])
->add('partsType' , CollectionType::class , [
'entry_type' => PartsType::class,
'allow_add' => true,
'mapped' => false,
'allow_delete' => true
]);;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
//I dont know if I have to set there data_class if yes which type?
// 'data_class' => null,
// 'data_class' => PartsType::class,
]);
}
}
class PartsType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('submit' , SubmitType::class , [])
->add('partNumber' , TextType::class , [])
->add('distribution' , TextType::class , [])
->add('upsTrack' , TextType::class , [])
->add('returnalbe' , TextType::class , [])
->add('sendDate' , DateType::class , [])
->add('SOID' , TextType::class , [])
//It's a form to display additional Part's Ticket data
->add('ticket' , TicketPartType::class , [
]);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Part::class,
]);
}
}
补充部分:
class TicketPartType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('Institution')
->add('productName')
->add('productSerialNumber')
->add('externalTicketID')
->add('realisationTechnican' , EntityType::class , [
'mapped' => true,
'class' => Technican::class,
'choice_label' => function (Technican $t): string {
return $t->getTechnicanSurname() . ' ' . $t->getCity();
}]);
}
在控制器中我传递了多张票
$parts = $doctrine->getRepository(Part::class)->findAll();
$parts = $formFactory->createNamed('ticketsparts' , PartColletionType::class , $parts);
return $this->renderForm('mba/ticketparts.html.twig' , ['parts' => $parts ]);
这是我的树枝模板
{% macro printPartForm(partsType , productSerialNumber) %}
{{form(partsType)}}
{% endmacro %}
{% import _self as formMacros %}
<div class="parts0 row g-0" style="background:#CCC;"
data-index="{{ parts.partsType|length > 0 ? p.parts|last.vars.name + 1 : 0 }}"
data-prototype='{{ formMacros.printPartForm(parts.partsType.vars.prototype)|e('html_attr') }}'>
{% for part in parts.partsType %}
<div class="row part" >
{{ formMacros.printPartForm(part)}}
</div>
{% endfor %}
</div>
更新 所以现在我将 PartCollectionType 数据类设置为:
'data_class' => PartRepository::class
然后将零件存储库传递给表单
$parts = $formFactory->createNamed('ticketsparts' , PartColletionType::class , $doctrine->getRepository(Part::class));
现在在 twig 中,我可以通过调用传递给 TWIG(“部分”)的传递参数上的方法来访问所需的实体,并且所有内容都会正确呈现。
{% form_theme parts 'bootstrap_5_layout.html.twig' %}
{{form_start(parts, {'attr': {'class':''}}) }}
{{form_row(parts.field_name)}}
{% for item in parts.findByExampleField %}
<div class="row bg-warning m-5 ">
<div class="div col-1 ps-2 pe-2 bg-warning">{{form_row(item.ticket.id)}}</div>
<div class="div col-2 ps-2 pe-2 bg-warning">{{form_row(item.ticket.externalTicketID)}}</div>
<div class="div col-1 ps-2 pe-2 bg-warning">{{form_row(item.returnalbe)}}</div>
<div class="div col-1 ps-2 pe-2 bg-warning">{{form_row(item.sendDate)}}</div>
<div class="div col-1 ps-2 pe-2 bg-warning">{{form_row(item.SOID)}}</div>
</div>
{% endfor %}
{{form_end(parts)}}
现在的问题是如何妥善处理?
@编辑2 好的...很轻松:0
if(isset($_POST['ticketsparts'])){
$parts->handleRequest($request);
if($parts->isSubmitted() && $parts->isValid()){
var_dump('submitted and valid');
$submittedParts= $parts->get('findByExampleField')->getData();
foreach($submittedParts as $c){
$doctrine->getManager()->persist($c);
}
$doctrine->getManager()->flush();
}
}
分辨率是不是很混乱?考虑到我们将存储库传递给twig,它对性能有多大影响。在我的例子中,“selectByExampleField”将被限制为约 100 个实体,因此可能不会成为问题,但每次编辑单个对象都会发送整个数据......
谢谢您的帮助
所以...上面的分辨率...很糟糕。您无法控制要显示的内容。 所以可以说 - 对于每个排序方向,您都必须制作单独的表格..
//控制器.php
$collection_data = $doctrine->getRepository(Part::class)->findAll();
$form = $this->createForm(PartColletionType::class , null , ['collection_data' => $collection_data]);
if(isset($_POST['part_colletion'])){
if(isset($_POST['part_colletion']['unsent']))
{
$collection_data = $doctrine->getRepository(Part::class)->findUnsentParts();
$form = $this->createForm(PartColletionType::class , null , ['collection_data' => $collection_data]);
return $this->renderForm('mba/ticketparts.html.twig' , ['parts' => $form ]);
}
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()){
$czesci = $form->get('collection')->getData();
foreach($czesci as $c){
$doctrine->getManager()->persist($c);
}
$doctrine->getManager()->flush();
}
}
return $this->renderForm('mba/ticketparts.html.twig' , ['parts' => $form ]);
}
//PartCollectionType.php
class PartColletionType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('submit' , SubmitType::class , [
'attr' => ['class' => 'btn btn-success']])
->add('collection' , CollectionType::class , [
'entry_type' => PartsType::class,
'allow_add' => true,
'mapped' => false,
'data' => $options['collection_data'],
]);
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => null,
'collection_data' => null
]);
$resolver->setAllowedTypes('collection_data', 'array');
}
}