已解决 - Symfony 处理表单并将存储库传递到其中

问题描述 投票:0回答:1

@下面更新

我已阅读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 symfony doctrine
1个回答
0
投票

所以...上面的分辨率...很糟糕。您无法控制要显示的内容。 所以可以说 - 对于每个排序方向,您都必须制作单独的表格..

//控制器.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');
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.