Symfony Display errors in for collection

58 views Asked by At

I am working with Symfony 6.3.5. I followed the official documentation to add a dynamic collection type to my form. It works well but validation errors are not displayed anywhere in the form. My guess is that errors need to be passed along with form field widget to the prototype but I'm not quite sure.

Here is my code:

UploadCollectionType.php

class UploadCollectionType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('files', CollectionType::class, [
                'label' => false,
                'entry_type' => DocumentType::class,
                'allow_add' => true,
                'allow_delete' => true,
                'entry_options' => [
                    'attr' => [
                        // styles de chaque ligne type + fichier
                        'class' => 'd-flex align-items-stretch justify-content-between',
                    ],
                ],
                'by_reference' => false,
            ]);
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            // Configure your form options here
        ]);
    }
}

DocumentType.php

class DocumentType extends AbstractType implements DataMapperInterface
{
    private const ALLOWED_EXTENSIONS = [
        'jpeg' => 'image/jpeg',
        'jpg' => 'image/jpeg',
        'png' => 'image/png',
        'gif' => 'image/gif',
        'pdf' => 'application/pdf',
        'xls' => 'application/vnd.ms-excel',
        'xlsx' => ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.ms-excel'],
        'csv' => ['text/plain', 'application/csv'],
        'msg' => ['application/vnd.ms-outlook', 'application/CDFV2-corrupt', 'application/octet-stream'],
        'doc' => 'application/msword',
        'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
        'tiff' => 'image/tiff',
        'tif' => 'image/tiff',
        'oft' => 'application/vnd.ms-outlook',
    ];

    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('pj', ChoiceType::class, [
                'label' => 'Type de document',
                'expanded' => true,
                'multiple' => true,
                'choices' => [
                    'Contrat' => 'CT',
                    'PI' => 'PI',
                    'JD' => 'JD',
                    'RIB' => 'RIB',
                    'Autre' => 'AUT'
                ],
                'label_attr' => [
                    'class' => 'me-3',
                ],
                'attr' => [
                    // styles de la liste de checkbox
                    'class' => 'd-flex'
                ],
            ])
            ->add('path_doc', FileType::class, [
                'label' => 'Fichier',
                'constraints' => [
                    new FileValidator([
                        'extensions' => self::ALLOWED_EXTENSIONS,
                        'extensionsMessage' => 'Extension de fichier non autorisée',
                    ]),
                ],
            ])
            ->setDataMapper($this);
    }

    public function mapDataToForms(mixed $viewData, \Traversable $forms): void
    {
        if (null === $viewData) {
            return;
        }

        if (!\is_array($viewData)) {
            throw new UnexpectedTypeException($viewData, 'array');
        }

        /** @var FormInterface[] $form */
        $form = iterator_to_array($forms);
        $form['pj']->setData($viewData['pj']);
        $form['path_doc']->setData(new File($viewData['path_doc']));
    }

    public function mapFormsToData(\Traversable $forms, mixed &$viewData): void
    {
        /** @var FormInterface[] $form */
        $form = iterator_to_array($forms);
        $viewData = [
            'pj' => $form['pj']->getData(),
            'path_doc' => $form['path_doc']->getData(),
        ];
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            // Configure your form options here
        ]);
    }
}

file_upload.html.twig

<div {{ stimulus_controller('form-collection') }}
        data-form-collection-index-value="{{ form.files|length > 0 ? form.files|last.vars.name + 1 : 0 }}"
        data-form-collection-prototype-value="{{ form_widget(form.files.vars.prototype)|e('html_attr') }}">
    {{ form_start(form) }}
    <div class="modal-header">
        <h1 class="modal-title fs-5" id="uploadModalLabel">Import de documents</h1>
        <button type="button"
                class="btn btn-secondary ms-5" {{ stimulus_action('form-collection', 'addCollectionElement') }}>Ajouter</button>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fermer"></button>
    </div>
    <div class="modal-body">
        <ul {{ stimulus_target('form-collection', 'collectionContainer') }} class="list-group"></ul>
    </div>
    <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
        <button type="submit" class="btn btn-primary">Valider</button>
    </div>
    {{ form_end(form) }}
</div>

form-collection_controller.js

import {Controller} from '@hotwired/stimulus';

export default class extends Controller {
    static targets = [
        'collectionContainer'
    ]

    static values = {
        index: Number,
        prototype: String,
    }

    addCollectionElement(event) {
        const item = document.createElement('li')
        item.classList.add('list-group-item')
        item.innerHTML = this.prototypeValue.replace(/__name__/g, this.indexValue)
        this.collectionContainerTarget.appendChild(item)
        this.indexValue++
    }
}

Does anybody know how to tell Twig to display errors at field level ?

Thank you very much for your help/ideas.

Alex

0

There are 0 answers