Bonjour,

Voilà je rencontre un petit problème avec les formulaire symfony et mes entités qui sont complexes.
J 'entend par complexe qu'elles ne sont pas comme la majorité des entités que l on rencontre dans les exemples et tutos;
mes constructeurs ont des paramètres et j effecture une validation directement dans le constructeur et je fais de même pour les setters,

Voici un exemple d'entité:

<?php

namespace BEF\Entity\Common;

use Doctrine\ORM\Mapping as ORM;
use Assert\Assertion;

/**
 * Address
 */
class Address
{
    /**
     * @var string
     */
    private $street;

    /**
     * @var string
     */
    private $number;

    /**
     * @var string
     */
    private $box;

    /**
     * @var string
     */
    private $zip;

    /**
     * @var string
     */
    private $city;

    /**
     * @var string
     */
    private $state;

    /**
     * @var string
     */
    private $status;

    /**
     * @var string
     */
    private $comment;

    /**
     * @var integer
     */
    private $id;

    /**
     * @var Country
     */
    private $country;

    /**
     * Address constructor.
     *
     * @param string  $street
     * @param string  $zip
     * @param string  $city
     * @param Country $country
     *
     * @throws \Assert\AssertionFailedException
     */
    public function __construct($street, $zip, $city, Country $country)
    {
        $parameters = func_get_args();
        array_walk($parameters, function ($param) {
            Assertion::notEmpty($param);
        });
        $this->street = $street;
        $this->zip = $zip;
        $this->city = $city;
        $this->country = $country;
    }

    /**
     * Set street
     *
     * @param string $street
     *
     * @throws \Assert\AssertionFailedException
     *
     * @return Address
     */
    public function setStreet($street)
    {
        Assertion::notEmpty($street);
        $this->street = $street;

        return $this;
    }

    /**
     * Get street
     *
     * @return string
     */
    public function getStreet()
    {
        return $this->street;
    }

    /**
     * Set number
     *
     * @param string $number
     *
     * @return Address
     */
    public function setNumber($number)
    {
        $this->number = $number;

        return $this;
    }

    /**
     * Get number
     *
     * @return string
     */
    public function getNumber()
    {
        return $this->number;
    }

    /**
     * Set box
     *
     * @param string $box
     *
     * @return Address
     */
    public function setBox($box)
    {
        $this->box = $box;

        return $this;
    }

    /**
     * Get box
     *
     * @return string
     */
    public function getBox()
    {
        return $this->box;
    }

    /**
     * Set zip
     *
     * @param string $zip
     *
     * @throws \Assert\AssertionFailedException
     *
     * @return Address
     */
    public function setZip($zip)
    {
        Assertion::notEmpty($zip);
        $this->zip = $zip;

        return $this;
    }

    /**
     * Get zip
     *
     * @return string
     */
    public function getZip()
    {
        return $this->zip;
    }

    /**
     * Set city
     *
     * @param string $city
     *
     * @throws \Assert\AssertionFailedException
     *
     * @return Address
     */
    public function setCity($city)
    {
        Assertion::notEmpty($city);
        $this->city = $city;

        return $this;
    }

    /**
     * Get city
     *
     * @return string
     */
    public function getCity()
    {
        return $this->city;
    }

    /**
     * Set state
     *
     * @param string $state
     *
     * @return Address
     */
    public function setState($state)
    {
        $this->state = $state;

        return $this;
    }

    /**
     * Get state
     *
     * @return string
     */
    public function getState()
    {
        return $this->state;
    }

    /**
     * Set status
     *
     * @param string $status
     *
     * @return Address
     */
    public function setStatus($status)
    {
        $this->status = $status;

        return $this;
    }

    /**
     * Get status
     *
     * @return string
     */
    public function getStatus()
    {
        return $this->status;
    }

    /**
     * Set comment
     *
     * @param string $comment
     *
     * @return Address
     */
    public function setComment($comment)
    {
        $this->comment = $comment;

        return $this;
    }

    /**
     * Get comment
     *
     * @return string
     */
    public function getComment()
    {
        return $this->comment;
    }

    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set country
     *
     * @param Country $country
     *
     * @return Address
     */
    public function setCountry(Country $country)
    {
        $this->country = $country;

        return $this;
    }

    /**
     * Get country
     *
     * @return Country
     */
    public function getCountry()
    {
        return $this->country;
    }

    /**
     * Get a redeable address
     *
     * @return string
     */
    public function __toString()
    {
        return implode(
            ' ',
            [$this->street, $this->number, $this->box, ',' . $this->zip, $this->city]
        );
    }
}

Donc en gros cela ne fonctionne pas avec le comportement normal des formulaires Symfony.

J 'ai donc trouvé des méthodes comme celle ci : A Data Mapper for Value Objects
J 'ai donc adapter cette solution à mon cas et je trouve au final que ce n'est qu une demi solution car l'héritage de formulaire n 'est plus fonctionnel , du coup j ai duplication de code. Et cela rajoute énormement de code juste pour "réinventer la roue".

Voici mon formType pour un formulaire d ajout:

<?php

namespace BEF\EquidataBundle\Form\Person;

use BEF\Entity\Common\Person;
use BEF\EquiclubBundle\Form\Type\AddressSelectorType;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\DataMapperInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Validator\Constraints\LessThanOrEqual;
use Symfony\Component\Validator\Constraints\NotNull;

class PersonCreateType extends AbstractType implements DataMapperInterface
{
    /**
     * @param FormBuilderInterface $builder
     * @param array                $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {

        /** @var Person $person */
        $person = $builder->getData();
        $domicileDisplay = '';
        $domicileId = null;

        if ($person) {
            $domicile = $person->getDomicile();
            if ($domicile) {
                $domicileDisplay = $domicile;
                $domicileId = $domicile->getId();
            }
        }

        /** @var ObjectManager $em */
        $om = $options['em'];

        $nationality = $om->find('BEFEntityCommon:Country', 24);
        if ($person) {
            $nationality = $person->getNationality();
        }

        $date = new \DateTime();

        $builder
            ->add('lastname', 'text', [
                'required' => true,
                'constraints' => [new NotNull(['message' => 'You need to give a lastname'])]
            ])
            ->add('firstname', 'text', [
                'required' => true,
                'constraints' => [new NotNull(['message' => 'You need to give a firstname'])]
            ])
            ->add('birthdate', 'date', array(
                'widget' => 'single_text',
                'format' => 'dd/MM/yyyy',
                'attr' => [
                    'class' => 'datepicker',
                ],
                'required' => true,
                'invalid_message' => 'Invalid format: please use the dd/MM/yyyy format for dates.',
                'constraints' => [
                    new NotNull(['message' => 'You need to give a date of birth']),
                    new LessThanOrEqual([
                        'value' => $date,
                        'message' => 'Your date of birth can\'t be greater than today'
                    ])
                ]
            ))
            ->add('agecategory', 'choice', [
                'choices' => [
                    'SCHOOL' => 'School',
                    'JUNIOR' => 'Junior',
                    'SENIOR' => 'Senior',
                    'VETERAN' => 'Veteran',
                ],
                'required' => false,
                'empty_value' => 'Choose an option',
            ])
            ->add('gender', 'choice', [
                'choices' => [
                    'M' => 'Male',
                    'F' => 'Female'
                ],
                'expanded' => true,
                'multiple' => false,
                'required' => true,
                'constraints' => [new NotNull(['message' => 'You need to give a gender'])],
            ])
            ->add('language', 'choice', [
                'choices' => [
                    'EN' => 'English',
                    'NL' => 'Dutch',
                    'FR' => 'French',
                    'DE' => 'German',
                ],
                'required' => true,
                'empty_value' => 'Select language',
                'constraints' => [new NotNull(['message' => 'You need to choose a language'])],
            ])
            ->add('comment')
            ->add('membersince', 'date', array(
                'widget' => 'single_text',
                'format' => 'dd/MM/yyyy',
                'attr' => [
                    'class' => 'datepicker',
                ],
                'required' => false,
                'invalid_message' => 'Invalid format: please use the dd/MM/yyyy format for dates.',
            ))
            ->add('nationality', 'entity', [
                'class' => 'BEFEntityCommon:Country',
                'property' => 'name',
                'data' => $nationality,
                'required' => true,
                'constraints' => [new NotNull(['message' => 'You need to select a nationality'])],
            ])
            ->add('domicile', new AddressSelectorType($om), array(
                'attr' => array(
                    'placeholder' => $domicileDisplay,
                ),
                'data' => $domicileId,
                'required' => true,
                'constraints' => [new NotNull(['message' => 'You need to select a domicile'])],
            ))
            ->setDataMapper($this);
    }

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => Person::class,
            'empty_data' => null
        ));
        $resolver->setRequired(array(
            'em'
        ));
        $resolver->setAllowedTypes(array(
            'em' => ObjectManager::class,
        ));
    }

    public function mapDataToForms($data, $forms)
    {
        $forms = iterator_to_array($forms);
        $forms['lastname']->setData($data ? $data->getLastname() : '');
        $forms['firstname']->setData($data ? $data->getFirstname() : '');
        if (isset($data) && $data->getBirthdate() !== null) {
            $forms['birthdate']->setData($data->getBirthdate());
        }
        $forms['agecategory']->setData($data ? $data->getAgecategory() : '');
        $forms['gender']->setData($data ? $data->getGender() : '');
        $forms['language']->setData($data ? $data->getLanguage() : '');
        $forms['comment']->setData($data ? $data->getComment() : '');
        if (isset($data) && $data->getMembersince() !== null) {
            $forms['membersince']->setData($data->getMembersince());
        }
        $forms['nationality']->setData($data ? $data->getNationality() : '');
        $forms['domicile']->setData($data ? $data->getDomicile() : '');
    }

    public function mapFormsToData($forms, &$data)
    {
        $forms = iterator_to_array($forms);
        try {
            $data = (new Person(
                $forms['lastname']->getData(),
                $forms['firstname']->getData(),
                $forms['birthdate']->getData(),
                $forms['gender']->getData(),
                $forms['language']->getData(),
                $forms['nationality']->getData()
            ));
            if ($forms['agecategory']->getData() !== null) {
                $data->setAgecategory($forms['agecategory']->getData());
            }
            $data->setComment($forms['comment']->getData());
            if ($forms['membersince']->getData() !== null) {
                $data->setMembersince($forms['membersince']->getData());
            }
            $data->setDomicile($forms['domicile']->getData());
        } catch (\InvalidArgumentException $e) {
            $data = null;
        }
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'bef_common_person';
    }
}

Et donc imaginez le formulaire d 'edition qui est le meme mais encore plus surchargé avec des champs supplémentaire.

Donc je cherche qq1 qui aurait déjà été confronté un tel problème et qui aurait trouvé une autre solution (meilleur).
(J'ai regardé un peu auprès des DTO mais j 'ai peur que cela apporte son lot de problème et de surcharge de code aussi)

Merci d'avance.

Aucune réponse