symfony 4/5 collection type ne fonctionne pas après migration (symfony2)

Petit nouveau ! | 1 Messages

05 janv. 2020, 19:29

Bonjour à tous,
J'ai développé une appli symfony 2 pour un ex Client qui est revenu vers moi en vue d'adapter l'appli pour php 7...
J'ai donc essayé de refondre l'appli sur symfony 4.3 et 5 mais je me heurte à un problème qui hante mes jours et mes nuits...
Je vous explique le principe de l'appli pour que ce soit plus parlant. Il s'agit de créer des fiches de réparations pour des vélos, chaque fiche contient une liste d'opérations qui elles même contiennent une liste de fournitures... ça fonctionnait très bien sur symfony 2, voici une capture de ce qui est encore en production actuellement:
Image

version symfony 2:
fichesrep
namespace FicherepBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * Fichesrep
 *
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="FicherepBundle\Entity\FichesrepRepository")
 * @ORM\HasLifecycleCallbacks()
 */
class Fichesrep
{
    public function __construct()
    {
        $this->created         = new \Datetime();
        $this->modified        = new \Datetime();
        $this->operationsrep   = new ArrayCollection();
    }
    
   
        
    /**
     * @var array
     *
     * @ORM\OneToMany(targetEntity="Operationsrep", cascade={"persist","remove"},orphanRemoval=true, mappedBy="fichesrep")
     * @ORM\OrderBy({"id" = "ASC"}) 

    * @ORM\JoinColumn(nullable=false)
     */
    protected $operationsrep;
    
       
    /**
   * @ORM\ManyToOne(targetEntity="ClientBundle\Entity\Clients",inversedBy="fichesrep")
   * @ORM\JoinColumn(name="client_id", referencedColumnName="id")
   */
    private $client;
    
   /**
     * Get operationsrep
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getOperationsrep()
    {
        return $this->operationsrep;
    }

    /**
     * Add operationsrep
     *
     * @param \FicherepBundle\Entity\Operationsrep $operationsrep
     * @return Fichesrep
     */
    public function addOperationsrep(\FicherepBundle\Entity\Operationsrep $operationsrep)
    {
        $this->operationsrep[] = $operationsrep;
        $operationsrep->setFichesrep($this);

        return $this;
    }
    
    
    /**
     * Remove operationsrep
     *
     * @param \FicherepBundle\Entity\Operationsrep $operationsrep
     */
    public function removeOperationsrep(\FicherepBundle\Entity\Operationsrep $operationsrep)
    {
        $this->operationsrep->removeElement($operationsrep);
    }
version symfony 2:
Operationsrep
namespace FicherepBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * Operationsrep
 *
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="FicherepBundle\Entity\OperationsrepRepository")
 * @ORM\HasLifecycleCallbacks()
 */
class Operationsrep
{
    /**
     * @var integer
     * 
     * @ORM\ManyToOne(targetEntity="Fichesrep", inversedBy="operationsrep")
     * @ORM\JoinColumn(name="fichesrep_id", referencedColumnName="id")
     * 
     * @ORM\JoinColumn(nullable=false)
     */
    protected $fichesrep;
    
    /**
     * @var array
     *
     * @ORM\OneToMany(targetEntity="Fournituresrep", cascade={"persist","remove"},orphanRemoval=true, mappedBy="operationrep")
     * @ORM\OrderBy({"id" = "ASC"}) 

    * @ORM\JoinColumn(nullable=false)
     */
    protected $fournituresrep;
    
    
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;
    
version symfony 2:
voici le formulaire fichesrepType:
namespace FicherepBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Doctrine\ORM\EntityRepository;

class FichesrepType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('modele','textarea',array('required' => false))
            ->add('nota','textarea',array('required' => false))
            ->add('signatureclient', 'choice', array(
                    'choices' => array('1'=>'Visible sur la fiche','2'=>'Pas visible'),
                    'empty_value' => 'Choix'
                ))
            ->add('acompte','text',array('required'=>false))
            ->add('delai','date',array(
                                                'widget' => 'single_text',
                                                'input' => 'datetime',
                                                'format' => 'dd/MM/yyyy',
                                                'read_only'=>true
                                                ))
            ->add('rv','date',array(
                                                'widget' => 'single_text',
                                                'input' => 'datetime',
                                                'format' => 'dd/MM/yyyy',
                                                'read_only'=>true
                                                ))
            ->add('operationsrep', 'collection', array(
                    'type'         => new OperationsrepType(),
                    'allow_add'    => true,
                    'allow_delete' => true,
                    'cascade_validation'  => true,
                    'by_reference' => false,
                    ))   
            ->add('enregistrer','submit',array('attr'=>array('class'=>'btn btn-primary btn-sm')))
        ;
    }
    
version symfony 2:
voici le controleur "ajouter une fiche" en version simplifiée:
 /**
   * @Security("has_role('ROLE_ADMIN')")
   */
    public function addAction(Request $request, $idclient){
       
        $ficherep = new Fichesrep();
        $form = $this->get('form.factory')->create(new FichesrepType, $ficherep);
        $form->handleRequest($request);
        
        $client = $this->getDoctrine()
                    ->getManager()
                    ->getRepository('ClientBundle:Clients')
                    ->find($idclient)
    ;
        
        if ($form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->persist($ficherep
                    ->setClient($client)
                    );
            $em->flush();
        
            $request->getSession()->getFlashBag()->add('notice', 'La fiche réparation a bien été ajoutée.');

            return $this->redirect($this->generateUrl('ficherep_admin_home'));
        }        
        
        return $this->render('FicherepBundle:Admin:add.html.twig', array(
            'form' => $form->createView(),
            'client'=> $client
        ));
    }
Et ça fonctionne très bien sur symfony 2, quand je valide le formulaire après avoir ajouté des opérations et des fournitures, toutes les tables de la base de données sont bien remplies avec toutes les opérations, toutes les fournitures et les données propre à la fiche, le tout en un seul "submit".... maintenant que j'ai adapté le code sur symfony 4.3 ( testé également sur symfony 5) , j'ai le message suivant lors de la validation :

Expected argument of type "App\Entity\Operationsrep", "array" given at property path "operationsrep".
le submit du formulaire ne renvoie donc plus des objets automatiquement(liste des opérations) comme sur symfony 2 mais des tableaux...

Avatar du membre
Mammouth du PHP | 1253 Messages

07 janv. 2020, 12:26

Salut, il n'y a pas d'option type sur les champs CollectionType.
https://symfony.com/doc/4.4/reference/f ... ction.html

Il faut que tu corriges le code pour qu'il fonctionne avec Symfony 4+
J'édite souvent mon message après avoir répondu pour le corriger où y apporter des informations complémentaires alors n'hésitez pas à y jeter un nouveau coup d'oeil ^^