Page 1 sur 1

Symfony2: Checkboxes non cochées dans un FormType en Edit

Posté : 02 déc. 2013, 15:06
par ouckileou
Hello,

à la suite de ce thread: frameworks-php/form-field-sauver-utilis ... 67851.html dans lequel je cherchais à faire un formulaire de présence à un cours, en ne proposant dans les checkboxes de présence que les étudiants inscrits au cours en question, j'essaie désormais de faire le formlaire de modification de ce compte-rendu.

Je m'attends donc à ce que les checkboxes des étudiants ayant été comptés comme présent à ce cours, soient pré-cochées lors du passage en edit, mais ce n'est pas le cas. Je n'ai le problème que sur les deux champs ajoutés via l'event subscriber (enrolledStudentsField et nonEnrolledStudentsField) , donc j'imagine qu'il y a un soucis de ce côté.

Est-ce que c'est à moi de prendre en charge ce mécanisme ? N'importe quelle piste, même un lien vers la doc qui pourrait m'aider, me serait bien utile :) Un problème du côté de "auto_initialize" peut-être ?

FormType:
<?php

namespace Virgule\Bundle\MainBundle\Form;

use Doctrine\ORM\EntityManager;

use Symfony\Bridge\Doctrine\RegistryInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

use Virgule\Bundle\MainBundle\Entity\Teacher;
use Virgule\Bundle\MainBundle\Form\EventListener\AddClassSessionStudentsFieldSubscriber;

class ClassSessionType extends AbstractType {
        
    private $doctrine;
    
    private $organizationBranchId;
        
    private $currentTeacher;

    private $semesterId;

    public function __construct(RegistryInterface $doctrine, $organizationBranchId = null, Teacher $currentTeacher = null, $semesterId) {
        $this->doctrine = $doctrine;
        $this->organizationBranchId = $organizationBranchId;
        $this->currentTeacher = $currentTeacher;
        $this->semesterId = $semesterId;
    }

    public function buildForm(FormBuilderInterface $builder, array $options) {    
        $now = new \DateTime('now');
        $sNow = $now->format('d/m/Y');
        
        $builder
                ->add('sessionDate', 'date', array(
                    'widget' => 'single_text',
                    'format' => 'dd/MM/yyyy',
                    'attr' => array('class' => 'datepicker', 'data-date-format' => 'dd/mm/yyyy', 'value' => $sNow)))
                ->add('summary')          
                ->add('sessionTeacher', 'entity', array(
                        'class' => 'VirguleMainBundle:Teacher', 
                        'query_builder' => $this->getTeachers($this->organizationBranchId),
                        'multiple' => false,
                        'expanded' => false,
                        'property_path' => 'sessionTeacher',
                        'attr' => array('class' => 'small-select'),
                        'preferred_choices' => array($this->currentTeacher))
                    )                
                ->add('documents', 'entity', array(
                    'class' => 'VirguleMainBundle:Document',
                    'expanded' => false,
                    'multiple' => true,
                    'property' => 'fileName',
                    'property_path' => 'documents',
                    'attr' => array('class' => 'big-select')
                ));
        
        $subscriber = new AddClassSessionStudentsFieldSubscriber($builder->getFormFactory(), $this->semesterId);
        $builder->addEventSubscriber($subscriber);
    }
    
    private function getTeachers($organizationBranchId) {
        $qb = $this->doctrine->getRepository('VirguleMainBundle:Teacher')->getAvailableTeachersQueryBuilder($organizationBranchId);
        return $qb;
    }
    
    private function getStudents($courseId) {
        $qb = $this->doctrine->getRepository('VirguleMainBundle:Student')->getQueryBuilderForStudentEnrolledInCourses(Array($courseId));
        return $qb;
    }
    
    public function setDefaultOptions(OptionsResolverInterface $resolver) {
        $resolver->setDefaults(array(
            'data_class' => 'Virgule\Bundle\MainBundle\Entity\ClassSession',
        ));
        
        
        $resolver->setRequired(array(
            'em',
        ));

        $resolver->setAllowedTypes(array(
            'em' => 'Doctrine\Common\Persistence\ObjectManager',
        ));
    }

    public function getName() {
        return 'virgule_bundle_mainbundle_classsessiontype';
    }

}
EventSubscriber :
<?php

namespace Virgule\Bundle\MainBundle\Form\EventListener;

use \Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class AddClassSessionStudentsFieldSubscriber implements EventSubscriberInterface {

    /**
     * @var FormFactoryInterface
     */
    private $factory;

    private $semesterId;
    
    /**
     * @param factory FormFactoryInterface
     */
    public function __construct(FormFactoryInterface $factory, $semesterId) {
        $this->factory = $factory;
        $this->semesterId = $semesterId;
    }

    public static function getSubscribedEvents() {
        return array(
            FormEvents::PRE_BIND => 'preBind',
            FormEvents::PRE_SET_DATA => 'preSetData',
        );
    }

    /**
     * @param \Symfony\Component\Form\FormEvent $event
     */
    public function preSetData(FormEvent $event) {
        /** @var ClassSession $data */
        $data = $event->getData();
        $form = $event->getForm();

        if (null === $data) {
            return;
        }

        $courseId = null;
        if (null !== $data->getCourse()) {
            $courseId = $data->getCourse()->getId();
        }
        $this->customizeForm($form, $courseId);
    }

    public function preBind(FormEvent $event) {
        $data = $event->getData();
        $course = $data['course'];
        $form = $event->getForm();

        $this->customizeForm($form, $course);
    }

    protected function customizeForm($form, $courseId) {
        if ($courseId) {
            $enrolledStudentsField = $this->factory->createNamed('classSessionStudents', 'entity', new ArrayCollection(), array(
                'class' => 'VirguleMainBundle:Student',
                'query_builder' => function(EntityRepository $er) use ($courseId) {
                    return $er->createQueryBuilder('s')
                                    ->add('orderBy', 's.lastname ASC, s.firstname ASC')
                                    ->innerJoin('s.courses', 'c2', 'WITH', 'c2.id = :courseId')
                                    ->setParameter('courseId', $courseId);
                },
                'expanded'          => true,
                'multiple'          => true,
                'property_path'     => 'classSessionStudents',
                'property'          => 'fullname',
                'cols_number'       => 3,
                'auto_initialize'   => false
            ));
            $form->add($enrolledStudentsField);
                    
            $nonEnrolledStudentsField = $this->factory->createNamed('nonEnrolledStudentsField', 'entity', new ArrayCollection(), array(
                'class'              => 'VirguleMainBundle:Student',
                'query_builder' => function(EntityRepository $er) use ($courseId) {
                    return $er->createQueryBuilder('s')
                                    ->add('orderBy', 's.lastname ASC, s.firstname ASC')
                                    ->leftJoin('s.courses', 'c2', 'WITH', 'c2.id != :courseId')
                                    ->setParameter('courseId', $courseId);
                },
                'expanded'          => false,
                'multiple'          => true,
                'property_path'     => 'nonEnrolledClassSessionStudents',
                'property'          => 'fullname',
                'auto_initialize'   => false,
                'attr'              => array('class' => 'medium-select','required' => false)

            ));
            $form->add($nonEnrolledStudentsField);
                
            $form->add('course', 'hidden', array(
                'data' => $courseId,
                'mapped' => false))
            ;
        } else {
            $semesterId = $this->semesterId;
            
            $field = $this->factory->createNamed('course', 'entity', null, array(
                'class' => 'VirguleMainBundle:Course',
                'query_builder' => function(EntityRepository $er) use ($semesterId) {
                    return $er->createQueryBuilder('c')
                            ->innerJoin('c.semester', 's')
                            ->where('s.id = :semesterId')
                            ->add('orderBy', 'c.dayOfWeek ASC, c.startTime ASC')
                            ->setParameter('semesterId', $semesterId);
                },
                'auto_initialize' => false,
                'expanded' => false,
                'multiple' => false,
                'property_path' => 'course',
                'attr' => array('class' => 'medium-select')
            ));
            $form->add($field);
        }
    }

}
Merci d'avance !

Re: Symfony2: Checkboxes non cochées dans un FormType en Edi

Posté : 03 déc. 2013, 14:45
par ouckileou
A partir de ce sujet http://forum.symfony-project.org/viewto ... es#p143761 j'ai essayé ça :

dans ClassSessionController.editAction
        $enrolledStudents = new ArrayCollection();
        $selectedEnrolledStudents = $entity->getClassSessionStudents();
        foreach($selectedEnrolledStudents as $enrolledStudent) {
            $enrolledStudents->add($enrolledStudent->getId());
        }

        $editForm->get('classSessionStudents')->setData($selectedEnrolledStudents);
Mais ça ne change rien, le champ en edit est vide.

Est-ce que ça viendrait de la mauvaise utilisation d'un événement, ou de ma définitin de colonne ?
    /**
     * @ORM\ManyToMany(targetEntity="Student", inversedBy="classSessions")
     * @ORM\JoinTable(name="classsessions_students")
     * @Assert\NotNull
     */
    protected $classSessionStudents;

Re: Symfony2: Checkboxes non cochées dans un FormType en Edi

Posté : 04 déc. 2013, 11:51
par ouckileou
Bon j'ai fait marcher le truc en modifiant mon FieldSubscriber, dans le preSetData j'ai ajouté la récupération des données sur $data, que j'envoie à la méthode customizeForm et qui sont donc récupérées dans les champs correspondant, que ce soit un ArrayCollection vide ou les données récupérées sur l'objet en edit :
class AddClassSessionStudentsFieldSubscriber implements EventSubscriberInterface {
   /**
     * @param \Symfony\Component\Form\FormEvent $event
     */
    public function preSetData(FormEvent $event) {
        /** @var ClassSession $data */
        $data = $event->getData();
        $form = $event->getForm();

        if (null === $data) {
            return;
        }
        
        $courseId = null;
        if (null !== $data->getCourse()) {
            $courseId = $data->getCourse()->getId();
        }        
        $selectedEnrolledStudents = new ArrayCollection();
        if (null !== $data->getClassSessionStudents()) {
            $selectedEnrolledStudents = $data->getClassSessionStudents();
        }
        $selectedNonEnrolledStudents = new ArrayCollection();
        if (null !== $data->getNonEnrolledClassSessionStudents()) {
            $selectedNonEnrolledStudents = $data->getNonEnrolledClassSessionStudents();
        }
        
        $this->customizeForm($form, $courseId, $selectedEnrolledStudents, $selectedNonEnrolledStudents);
    }

    protected function customizeForm($form, $courseId, $selectedEnrolledStudents, $selectedNonEnrolledStudents) {
        if ($courseId) {
            $enrolledStudentsField = $this->factory->createNamed('classSessionStudents', 'entity', $selectedEnrolledStudents, array(
                'class' => 'VirguleMainBundle:Student',
                'query_builder' => function(EntityRepository $er) use ($courseId) {
                    return $er->createQueryBuilder('s')
                                    ->add('orderBy', 's.lastname ASC, s.firstname ASC')
                                    ->innerJoin('s.courses', 'c2', 'WITH', 'c2.id = :courseId')
                                    ->setParameter('courseId', $courseId);
                },
                'expanded'          => true,
                'multiple'          => true,
                'property_path'     => 'classSessionStudents',
                'property'          => 'fullname',
                'cols_number'       => 3,
                'auto_initialize'   => false
            ));
            $form->add($enrolledStudentsField);
                    
            $nonEnrolledStudentsField = $this->factory->createNamed('nonEnrolledStudentsField', 'entity', $selectedNonEnrolledStudents, array(
                'class'              => 'VirguleMainBundle:Student',
                'query_builder' => function(EntityRepository $er) use ($courseId) {
                    return $er->createQueryBuilder('s')
                                    ->add('orderBy', 's.lastname ASC, s.firstname ASC')
                                    ->leftJoin('s.courses', 'c2', 'WITH', 'c2.id != :courseId')
                                    ->setParameter('courseId', $courseId);
                },
                'expanded'          => false,
                'multiple'          => true,
                'property_path'     => 'nonEnrolledClassSessionStudents',
                'property'          => 'fullname',
                'auto_initialize'   => false,
                'attr'              => array('class' => 'medium-select','required' => false)

            ));
            $form->add($nonEnrolledStudentsField);
// [ ... ]
        }
    }
Si quelqu'un souhaite me donner son avis sur cette méthode je suis preneur, car Symfony fait tellement de trucs tout seul que j'ai parfois du mal à réaliser quand je dois faire le truc moi-même :)