Symfony 5.2 - Form - CollectionType -表单的视图数据应该是“App\Entity\...",但它是一个数组

koaltpgm  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(66)

当我尝试呈现表单AvisType时,我遇到了这个错误:
表单的视图数据应为“App\Entity\DTO\DocumentDTO”,但它是“数组”。可以通过将“data_class”选项设置为null或添加将“数组”转换为“App\Entity\DTO\DocumentDTO”示例的视图转换器Transformer来避免此错误。
我有一个AvisType表单:

<?php

namespace App\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\OptionsResolver\OptionsResolver;

use App\Entity\DTO\AvisDTO;
use App\Entity\DTO\NomenclatureDTO;
use App\Entity\DTO\DataFormMapper\DataAvis;
use App\Entity\DTO\DocumentDTO;

class AvisType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('nomAuteur', TextType::class, [
                'label' => "Nom",
            ])
            ->add('prenomAuteur', TextType::class, [
                'label' => "Prénom"
            ])
            ->add('boEstTacite', ChoiceType::class, [
                'required' => true,
                'label' => "L'avis est-il tacite ?",
                'label_attr' => [
                    'class' => "font-weight-bold"
                ],
                'expanded' => true,
                'multiple' => false,
                'choices' => [
                    'Oui' => true,
                    'Non' => false,
                ],
            ])
            ->add('nomNatureAvisRendu', ChoiceType::class, [
                'label' => "Nature de l'avis rendu",
                'required' => false,
                'choices' => $options['dataPostAvis']->nomNatureAvisRendu,
                'choice_label' => function ($choice) {
                    return $choice->libNom;
                },
                'setter' => function (AvisDTO &$avisDto, NomenclatureDTO $nomenclatureDto) {
                    if ($nomenclatureDto) {
                        $avisDto->nomNatureAvisRendu = $nomenclatureDto->idNom;
                    }
                }
            ])
            ->add('nomTypeAvis', ChoiceType::class, [
                'label' => "Type d'avis",
                'required' => false,
                'choices' => $options['dataPostAvis']->nomTypeAvis,
                'choice_label' => function ($choice) {
                    return $choice->libNom;
                },
                'setter' => function (AvisDTO &$avisDto, NomenclatureDTO $nomenclatureDto) {
                    if ($nomenclatureDto) {
                        $avisDto->nomTypeAvis = $nomenclatureDto->idNom;
                    }
                }
            ])
            ->add('documents', CollectionType::class, [
                'entry_type' => DocumentType::class,
                'entry_options' => [
                    'data' => $options,
                ],
                'prototype' => true,                
                'allow_add' => true,
                'by_reference' => false,                
            ])
            ->add('txAvis', TextareaType::class, [
                'required' => true,
                'attr' => [
                    'placeholder' => "Avis favorable avec prescriptions. \nPremière prescription : Les volets doivent être en bois"
                ]
            ])
            ->add('txFondementAvis', TextareaType::class, [
                'attr' => [
                    'placeholder' => "L'avis de l'ABF est rendu en application de l'article R. 425-30 du Code de l'urbanisme."
                ]
            ])
            ->add('txHypotheses', TextareaType::class, [
                'attr' => [
                    'placeholder' => "Dans l'hypothèse où la puissance électrique nécessaire est de x alors le coût de raccordement est de y"
                ]
            ])
            ->add('txQualiteAuteur', TextareaType::class, [
                'attr' => [
                    'placeholder' => "Qualité"
                ]
            ])
            ->add('Envoyer', SubmitType::class);
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => AvisDTO::class,
            'dataPostAvis' => DataAvis::class,
        ]);
    }
}

这是我的AvisDTO类:

<?php

namespace App\Entity\DTO;

use Symfony\Component\Serializer\Annotation\Groups;
use Doctrine\Common\Collections\ArrayCollection;

class AvisDTO
{
    public string $dtAvis;
    public string $dtEmission;
    public string $idActeurAuteur;
    public string $nomAuteur;
    public string $prenomAuteur;
    public bool $boEstTacite;
    public ArrayCollection $documents;
    public string $idConsultation;
    public array $idsPieces;
    public int $nomNatureAvisRendu;
    public int $nomTypeAvis;
    public string $txAvis;
    public string $txFondementAvis;
    public string $txHypotheses;
    public string $txQualiteAuteur;

    public function __construct()
    {
        $this->documents = new ArrayCollection();
    }
}

最后是我的DocumentType

<?php
namespace App\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints\File;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;

use App\Entity\DTO\DocumentDTO;
use App\Entity\DTO\NomenclatureDTO;

class DocumentType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {   
        // dd($options);
        $builder
            ->add('nomTypeDocument', ChoiceType::class, [
                'label' => "Type de document",
                'required' => false,                
                'choices' => $options['data']['dataPostAvis']->nomTypeDocument,
                'choice_label' => function ($choice) {
                    return $choice->libNom;
                },                              
                'setter' => function(DocumentDTO &$documentDto, NomenclatureDTO $nomenclatureDto) {                         
                    if ($nomenclatureDto) {                     
                        $documentDto->nomTypeDocument = $nomenclatureDto->idNom;
                    }
                }               
            ])
            ->add('nomTypeProducteurDoc', ChoiceType::class, [
                'label' => "Type de producteur du document",
                'required' => false,                
                'choices' => $options['data']['dataPostAvis']->nomTypeProducteurDoc,
                'choice_label' => function ($choice) {
                    return $choice->libNom;
                },              
                'setter' => function(DocumentDTO &$documentDto, NomenclatureDTO $nomenclatureDto) {
                    if ($nomenclatureDto) {
                        $documentDto->nomTypeProducteurDoc = $nomenclatureDto->idNom;
                    }
                }
            ])
            ->add('upload_file', FileType::class, [
                'label' => false,
                'mapped' => false,
                'attr' => [
                    'data-dossier-target' => 'fileName',
                    'data-action' => 'change->dossier#getFileName'
                ],
                'constraints' => [
                    new File([
                        'mimeTypes' => [
                            'application/pdf', //PDF
                            'application/msword', //DOC
                            'application/vnd.openxmlformats-officedocument.wordprocessingml.document', //DOCX
                            'application/vnd.oasis.opendocument.spreadsheet', //ODS
                            'application/vnd.oasis.opendocument.text', //ODT
                            'application/vnd.ms-excel', //XLS
                            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', //XLSX
                            'image/bmp', //BMP
                            'image/x-ms-bmp', //BMP
                            'image/png', //PNG
                            'image/gif', //GIF
                            'image/tiff', //TIF & TIFF
                            'image/jpeg', //JPEG & JPG
                            'image/dib', //DIB
                        ],
                        'mimeTypesMessage' => "Ce document n'est pas valide.",
                    ])
                ]
            ])
            ->add('fileId', HiddenType::class)
            ->add('folderId', HiddenType::class)
            ->add('dtProduction', HiddenType::class)
            ->add('idActeurProducteur', HiddenType::class)
            ->add('idsPersonnesProductrices', HiddenType::class);
    }
    
    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => DocumentDTO::class,         
            'dataPostAvis' => DataAvisType::class,
        ]);
    }
}

DocumentDTO

<?php

namespace App\Entity\DTO;

class DocumentDTO
{
    public string $fileId;
    public string $folderId;
    public string $dtProduction;
    public string $idActeurProducteur;
    public array $idsPersonnesProductrices;
    public int $nomTypeDocument;
    public int $nomTypeProducteurDoc;
}

我的控制器

$avis = new AvisDTO();
$avis->idConsultation = $idConsultation;
$avis->idActeurAuteur = $idActeurAppelant; // A verifier    
$avis->idsPieces = $idPiecesList;        

$form = $this->createForm(AvisType::class, $avis, $options);
$form->handleRequest($request);

所以我理解的是,Symfony不能创建DocumentType表单,因为它从AvisType接收数组。我需要这个嵌套表单是“动态的”,我的用户必须能够添加新的文档到AvisType
我一直在关注这个文档:https://symfony.com/doc/current/form/form_collections.html#allowing-new-tags-with-the-prototype
如何在不将DocumentTypedata_class设置为null的情况下解决此错误?

uqxowvwt

uqxowvwt1#

您可以在DocumentDTO类中添加方法来转换数组。如果您这样做,则该类将如下所示:

<?php

namespace App\Entity\DTO;

class DocumentDTO
{
    public string $fileId;
    public string $folderId;
    public string $dtProduction;
    public string $idActeurProducteur;
    public array $idsPersonnesProductrices;
    public int $nomTypeDocument;
    public int $nomTypeProducteurDoc;

    public static function fromArray($data): self {
        $dto = new self();
        $dto->fileId = $data['fileId'] ?? null;
        $dto->folderId = $data['folderId'] ?? null;
        $dto->dtProduction = $data['dtProduction'] ?? null;
        $dto->idActeurProducteur = $data['idActeurProducteur'] ?? null;
        $dto->idsPersonnesProductrices = $data['idsPersonnesProductrices'] ?? null;
        $dto->nomTypeDocument = $data['nomTypeDocument'] ?? null;
        $dto->nomTypeProducteurDoc = $data['nomTypeProducteurDoc'] ?? null;

        return $dto;
    }

    public function toArray(): array
    {
        return [
            'fileId' => $this->fileId,
            'folderId' => $this->folderId,
            'dtProduction' => $this->dtProduction,
            'idActeurProducteur' => $this->idActeurProducteur,
            'idsPersonnesProductrices' => $this->idsPersonnesProductrices,
            'nomTypeDocument' => $this->nomTypeDocument,
            'nomTypeProducteurDoc' => $this->nomTypeProducteurDoc,
        ];
    }
}

您可以在DocumentType类中添加一个viewTransformer,在其中使用dto类中的方法来转换数据对象。如果您这样做,App\Form\DocumentType将如下所示:

<?php
namespace App\Form;

use App\DataObject\PaymentProviderCredentialsDto;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\CallbackTransformer;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints\File;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;

use App\Entity\DTO\DocumentDTO;
use App\Entity\DTO\NomenclatureDTO;

class DocumentType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // dd($options);
        $builder
            ->add('nomTypeDocument', ChoiceType::class, [
                'label' => "Type de document",
                'required' => false,
                'choices' => $options['data']['dataPostAvis']->nomTypeDocument,
                'choice_label' => function ($choice) {
                    return $choice->libNom;
                },
                'setter' => function(DocumentDTO &$documentDto, NomenclatureDTO $nomenclatureDto) {
                    if ($nomenclatureDto) {
                        $documentDto->nomTypeDocument = $nomenclatureDto->idNom;
                    }
                }
            ])
            ->add('nomTypeProducteurDoc', ChoiceType::class, [
                'label' => "Type de producteur du document",
                'required' => false,
                'choices' => $options['data']['dataPostAvis']->nomTypeProducteurDoc,
                'choice_label' => function ($choice) {
                    return $choice->libNom;
                },
                'setter' => function(DocumentDTO &$documentDto, NomenclatureDTO $nomenclatureDto) {
                    if ($nomenclatureDto) {
                        $documentDto->nomTypeProducteurDoc = $nomenclatureDto->idNom;
                    }
                }
            ])
            ->add('upload_file', FileType::class, [
                'label' => false,
                'mapped' => false,
                'attr' => [
                    'data-dossier-target' => 'fileName',
                    'data-action' => 'change->dossier#getFileName'
                ],
                'constraints' => [
                    new File([
                        'mimeTypes' => [
                            'application/pdf', //PDF
                            'application/msword', //DOC
                            'application/vnd.openxmlformats-officedocument.wordprocessingml.document', //DOCX
                            'application/vnd.oasis.opendocument.spreadsheet', //ODS
                            'application/vnd.oasis.opendocument.text', //ODT
                            'application/vnd.ms-excel', //XLS
                            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', //XLSX
                            'image/bmp', //BMP
                            'image/x-ms-bmp', //BMP
                            'image/png', //PNG
                            'image/gif', //GIF
                            'image/tiff', //TIF & TIFF
                            'image/jpeg', //JPEG & JPG
                            'image/dib', //DIB
                        ],
                        'mimeTypesMessage' => "Ce document n'est pas valide.",
                    ])
                ]
            ])
            ->add('fileId', HiddenType::class)
            ->add('folderId', HiddenType::class)
            ->add('dtProduction', HiddenType::class)
            ->add('idActeurProducteur', HiddenType::class)
            ->add('idsPersonnesProductrices', HiddenType::class);

        $builder->addViewTransformer(new CallbackTransformer(
            function ($documentDto) {
                if (!is_array($documentDto)) {
                    return $documentDto;
                }

                return DocumentDTO::fromArray($documentDto);
            },
            function ($documentDto) {
                if (!$documentDto instanceof DocumentDTO) {
                    return $documentDto;
                }

                return $documentDto->toArray();
            }
        ));
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => DocumentDTO::class,
            'dataPostAvis' => DataAvisType::class,
        ]);
    }
}

现在,每次加载表单视图时,都会调用Transformer,并将数据转换为正确的格式。您应该更改我建议的转换方法,以更好地满足项目的需要。

相关问题