Send default value to form from controller - forms

I have a loop in which a create a form for each "Joueur" I have :
foreach ($joueurs as $j)
{
$sUniqueFormName = 'Form' . $j->getId();
$oForm = $this->get('form.factory')->createNamed($sUniqueFormName, PlayedType::class, $played);
$aForms[$sUniqueFormName] = $oForm;
}
I want to send to my form this Entity Joueur and set it as the default value.
Form :
class PlayedType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('joueur')
->add('max')
->add('score')
->add('points')
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Played::class,
]);
}
}
Here, the 'joueur' attribute is a choice type and and want to set this value with the 'joueur' I get in the loop as default.
Is it possible ?

Pass an array as 4th arg with the $j value:
foreach ($joueurs as $j)
{
$sUniqueFormName = 'Form' . $j->getId();
$oForm = $this->get('form.factory')->createNamed($sUniqueFormName, PlayedType::class, $played, array('joueur' => $j);
$aForms[$sUniqueFormName] = $oForm;
}
Check the constructor for more info: https://api.symfony.com/3.3/Symfony/Component/Form/FormFactory.html
And recover it in PlayedType by $options and set it as data property
class PlayedType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$form = $event->getForm();
$form->add('joueur', null, array(
'data' => $event->getData() ?: options['joueur']
))
->add('max')
->add('score')
->add('points')
;
});
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Played::class,
'joueur' => null
]);
}
}

Try to set the joueur directly on the played entity like this for example:
foreach ($joueurs as $j) {
$sUniqueFormName = 'Form' . $j->getId();
$played->setJoueur($j);
$oForm = $this->get('form.factory')->createNamed($sUniqueFormName, PlayedType::class, $played);
$aForms[$sUniqueFormName] = $oForm;
}

Related

How to structure Symfony to check for `onChange` dropdown fields?

In my example, I have four entities that I want to use for a blog platform: Owner Post User Location
An Owner can have multiple Posts
A Post can have multiple Users and Locations
I am trying to create an admin form where I can select the Owner from a dropdown menu, that will refresh the form onChange to populate the dropdown menu of Posts.
When a Post is then selected, the form is again refreshed with form fields Users and Locations associated to that post. I can then either:
Update the existing entities with more information (eg User's date of birth or Location's GPS coordinates)
Create a new instance of either entity to attach to the Post
I've not included the Location entity and not included the namespaces/include statements as they would detract from my main question of how such an admin page should be coded in the controller/Formtypes (my attempts are as follows):
Controller:
/**
* #Route("/adminposts", name="admin_posts")
*/
public function updatePostsAction(Request $request)
{
$user = new User();
$form = $this->createForm(new UserType(), $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($owner);
$em->persist($post);
$em->persist($user);
$em->persist($location);
$em->flush();
return $this->redirectToRoute('homepage');
}
return $this->render('AppBundle:Default:adminupdate.post.html.twig', array(
'form' => $form->createView(),
));
}
User Formtype:
class UserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('owner','entity',array(
'class'=>'AppBundle:Owner',
'choice_label'=>'username',
'query_builder'=>function(EntityRepository $er) {
return $er->createQueryBuilder('d')
->orderBy('d.username','ASC');
}))
->add('post','entity',array(
'class'=>'AppBundle:Post',
'choice_label'=>'posttext',
'query_builder'=>function(EntityRepository $er) {
return $er->createQueryBuilder('d')
->orderBy('d.postdate','ASC');
}))
->add('Firstname')
->add('Surname')
->add('DOB')
->getForm();
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Users',
));
}
public function getName()
{
return 'user';
}
}
Ok, maybe you can take a look here : Symfony2: Change choices with ajax and validation or follow my method :
In your UserType :
class UserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('owner','entity',array(
'class'=>'AppBundle:Owner',
'choice_label'=>'username',
'query_builder'=>function(EntityRepository $er) {
return $er->createQueryBuilder('o')
->orderBy('o.username','ASC');
}))
->add('Firstname')
->add('Surname')
->add('DOB');
// Add listeners for Post field
$builder->addEventListener(FormEvents::PRE_SET_DATA, array($this, 'onPreSetData'));
$builder->addEventListener(FormEvents::PRE_SUBMIT, array($this, 'onPreSubmit'));
}
protected function addElements(FormInterface $form, $owner = null)
{
if($owner){
$form->add('post','entity',array(
'class'=>'AppBundle:Post',
'choice_label'=>'posttext',
'query_builder'=>function(EntityRepository $er, $owner) {
return $er->createQueryBuilder('p')
->join('p.owner', 'o')
->where('o.id = :ownerID')
->setParameter('ownerID', $owner->getID() )
->orderBy('d.postdate','ASC');
}));
}
else{
$form->add('post','choice',array(
'choice_label'=>'posttext',
'empty_value' => '-- Choose --',
'choices' => array())
);
}
}
public function onPreSubmit(FormEvent $event)
{
$form = $event->getForm();
$data = $event->getData();
$this->addElements($form, $data->getOwner());
}
public function onPreSetData(FormEvent $event)
{
/** #var User user */
$user = $event->getData();
$form = $event->getForm();
$this->addElements($form, $user->getOwner());
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Users',
));
}
public function getName()
{
return 'user';
}
}
I assume you know how to create an onChange Event in jQuery (I use to use it) and an ajax call.
Just for remind, in your view :
{{ form_row(
form.owner,
{
'attr': {
'data-owner-id': ""~form.owner.vars.id,
'class': "change-posts-per-owner",
}
}
) }}
{{ form_row(form.post) }}
{{ form_row(form.firstname) }}
{{ form_row(form.surname) }}
{{ form_row(form.DOB) }}
And your Ajax Script :
$(document).on('change', 'select .change-posts-per-owner', function(){
var ownerID = $(this).data("owner-id");
$.ajax({
url: your_url,
type: "GET", //or POST
data: 'ownerID='+ownerID,
dataType: 'JSON', //or html or whatever you want
success:function(data) {
//Replace <option element in your select element for post list considering your dataType (type of response)
}
});
}
You also can use $.post() or $.get() instead of explicit method $.ajax();
I sugget you to use FOSJSRoutingBundle for indicating your url with Routing.generate() method.

Unit Test Form WIth Repository Method

I am attempting to unit test one of my forms that I have which includes an entity form type on it. I would like to test the full form, but I keep on running into the error message - Expected argument of type "Doctrine\ORM\QueryBuilder", "NULL" given
Which is obvious, I need to somehow mock Doctrine\ORM\QueryBuilder as the return type for the entity form type. I am not quiet sure how I go about doing that though.
Here is the code of the Form -
<?php
namespace ICS\BackEnd\BoardBundle\Form;
use Doctrine\ORM\EntityRepository;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class BoardCollectionType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', 'text', array(
'disabled' => TRUE
))
->add('member', 'entity', array(
'class' => 'MemberBundle:Members',
'property' => 'fullName',
'query_builder' => function(EntityRepository $er) {
return $er->findAllActiveMembers();
},
))
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'ICS\BackEnd\BoardBundle\Entity\Board'
));
}
/**
* #return string
*/
public function getName()
{
return 'ics_boardbundle_board';
}
}
This is the test I am running on it -
<?php
namespace ICS\BackEnd\BoardBundle\Tests\Form;
use Doctrine\ORM\QueryBuilder;
use ICS\BackEnd\BoardBundle\Entity\Board;
use ICS\BackEnd\BoardBundle\Form\BoardCollectionType;
use Symfony\Component\Form\Forms;
use Symfony\Component\Form\PreloadedExtension;
use Symfony\Component\Form\Test\TypeTestCase;
class BoardCollectionTypeTest extends TypeTestCase {
protected $repository;
protected function setUp()
{
parent::setUp();
$this->factory = Forms::createFormFactoryBuilder()
->addExtensions($this->getExtensions())
->getFormFactory();
}
public function testSubmittedValueData()
{
$formData = array(
'member' => NULL,
);
$type = new BoardCollectionType();
$form = $this->factory->create($type);
$object = new Board();
$object->createFromArray($formData);
// submit the data to the form directly
$form->submit($formData);
$this->assertTrue($form->isSynchronized());
$this->assertEquals($object, $form->getData());
$view = $form->createView();
$children = $view->children;
foreach (array_keys($formData) as $key) {
$this->assertArrayHasKey($key, $children);
}
}
protected function getExtensions()
{
$this->repository = $this->getMockBuilder('Doctrine\ORM\EntityRepository')
->disableOriginalConstructor()
->getMock();
$mockEntityManager = $this->getMockBuilder('\Doctrine\ORM\EntityManager')
->disableOriginalConstructor()
->getMock();
$mockEntityManager->expects($this->any())
->method('getRepository')
->will($this->returnValue($this->repository));
$classMetadata = $this->getMockBuilder('\Doctrine\Common\Persistence\Mapping\ClassMetadata')
->disableOriginalConstructor()
->getMock();
$mockEntityManager->expects($this->any())
->method('getClassMetadata')
->will($this->returnValue($classMetadata));
$mockRegistry = $this->getMockBuilder('Doctrine\Bundle\DoctrineBundle\Registry')
->disableOriginalConstructor()
->setMethods(array('getManagerForClass'))
->getMock();
$mockRegistry->expects($this->any())
->method('getManagerForClass')
->will($this->returnValue($mockEntityManager));
$mockEntityType = $this->getMockBuilder('Symfony\Bridge\Doctrine\Form\Type\EntityType')
->setMethods(array('getName'))
->setConstructorArgs(array($mockRegistry))
->getMock();
$mockEntityType->expects($this->any())
->method('getName')
->will($this->returnValue('entity'));
$this->assertQueryBuilderCalled();
return array(new PreloadedExtension(array(
$mockEntityType->getName() => $mockEntityType,
), array()));
}
protected function assertQueryBuilderCalled()
{
$em = $this->getMockBuilder('Doctrine\ORM\EntityManager')
->disableOriginalConstructor()->getMock();
$repo = $this->getMockBuilder('ICS\BackEnd\MemberBundle\Entity\Repository\MembersRepository')
->disableOriginalConstructor()->getMock();
$repo->expects($this->once())->method('findAllActiveMembers')
->will($this->returnValue(new QueryBuilder($em)));
/*$qb = $this->getMockBuilder('Doctrine\ORM\QueryBuilder')
->disableOriginalConstructor()
->getMock();
$query = $this->getMockBuilder('Doctrine\ORM\AbstractQuery')
->disableOriginalConstructor()
->setMethods(array('execute'))
->getMockForAbstractClass();
$query->expects($this->any())
->method('execute')
->will($this->returnValue(array()));
$qb->expects($this->any())
->method('getQuery')
->will($this->returnValue($query));
$this->repository->expects($this->any())
->method('findAllActiveMembers')
->will($this->returnValue($query));
$this->repository->expects($this->any())
->method('createQueryBuilder')
->will($this->returnValue($qb));*/
}
}
Thanks for any help!
I resolved the issue by changing the entity form type to choice. It made the test much easier to read and do. I injected the "choices" into the options of the form type.

How to add data transformer inside a event listener

So, here's my problem: I have to add a field to a form based on it's underlying data but i've to add a data transformer to the field.
I thought the solution will be simple, just add a PRE_SET_DATA event listener to the form (just to access to the underlying data) and add the field and the transformer inside the listener. But i can't add the transformer inside the listener because the form is already locked.
I´ve tried many workarounds but i couldn't solved it. Her's my code:
$builder->...
->add(
$builder->create('date', 'choice', array(
'label' => 'form.game.date',
'empty_value' => 'form.game.date',
'required' => false,
'choices' => array(
'2014-04-10' => '10/Apr', // just to test
'2014-04-11' => '11/Apr',
)
))
->addModelTransformer(new DateToStringTransformer())
);
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($builder) {
$game = $event->getData();
$form = $event->getForm();
$period = new \DatePeriod(
$game->getTournament()->getBeginDate(),
new \DateInterval('P1D'),
$game->getTournament()->getEndDate()->add(new \DateInterval('P1D'))
);
$dates = array();
foreach($period as $date){
$dates[$date->format("Y-m-d")] = $date->format("j/M");
}
$form->add('date', 'choice', array(
'label' => 'form.game.date',
'choices' => $dates,
));
});
When i add the date field to the form inside event listener, the previously added data field is replaced so it's data transformer...
Is there a way to do it?
I wrote some test and updated your code a bit. Check if i understand your question correctly.
SomeTypeTest.php:
<?php
class SomeTypeTest extends TypeTestCase
{
/**
* #test
*/
public function testSubmitValidData()
{
$begin = new \DateTime();
$formData = array(
'date' => '2014-01-15'
);
$type = new SomeType();
$form = $this->factory->create($type);
$form->submit($formData);
$this->assertTrue($form->isSynchronized());
$this->assertEquals(['date' => \DateTime::createFromFormat('Y-m-d', '2014-01-15')], $form->getData());
$view = $form->createView();
$children = $view->children;
foreach (array_keys($formData) as $key) {
$this->assertArrayHasKey($key, $children);
}
}
}
SomeType.php:
<?php
class SomeType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($builder) {
//$game = $event->getData();
$form = $event->getForm();
$period = new \DatePeriod(
\DateTime::createFromFormat('Y-m-d', '2014-01-01'), // for test
new \DateInterval('P1D'),
\DateTime::createFromFormat('Y-m-d', '2014-01-30') // for test
);
$dates = array();
foreach ($period as $date) {
$dates[$date->format("Y-m-d")] = $date->format("j/M");
}
$form->add($builder->create('date', 'choice', array(
'label' => 'form.game.date',
'empty_value' => 'form.game.date',
'auto_initialize' => false,
'required' => false,
'choices' => $dates
))
->addModelTransformer(new DateToStringTransformer())->getForm()
);
});
}
public function getName()
{
return 'st';
}
}
DateToStringTransformer.php:
<?php
class DateToStringTransformer implements DataTransformerInterface
{
/**
* #param mixed $value
* #return mixed|void
*/
public function transform($value)
{
if (!$value) {
return null;
}
return $value->format('Y-m-d');
}
/**
* #param mixed $value
* #return mixed|void
*/
public function reverseTransform($value)
{
return \DateTime::createFromFormat('Y-m-d', $value);
}
}
https://gist.github.com/ChubV/11348928
I've managed to get it work by creating a custom type that always add the data transformer. Then i can call "form->add('date', 'my_type',..)" from any event listener without loosing the data transformer.
MyType.php
class MyType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('field1')
->add('field2')
...;
$builder->addEventSubscriber(new AddDateSubscriber());
}
}
CustomType.php
class DateChoiceType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addModelTransformer(new DateToStringTransformer());
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'invalid_message' => 'The selected date does not exist',
));
}
public function getParent()
{
return 'choice';
}
public function getName()
{
return 'date_choice';
}
}
Every time i add a date_choice type to a form the data transformer will be added too.
class AddDateSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return array(FormEvents::PRE_SET_DATA => 'preSetData');
}
public function preSetData(FormEvent $event)
{
$game = $event->getData();
$form = $event->getForm();
$endDate = \DateTime::createFromFormat('Y-m-d', $game->getTournament()->getEndDate()->format('Y-m-d'));
$period = new \DatePeriod(
$game->getTournament()->getBeginDate(),
new \DateInterval('P1D'),
$endDate
);
$dates = array();
foreach($period as $date){
$dates[$date->format("Y-m-d")] = $date->format("j/M");
}
$form->add('date', 'date_choice', array(
'label' => 'form.game.date.label',
'empty_value' => 'form.game.date.none',
'required' => false,
'choices' => $dates,
));
}
}
DateToStringTransformer.php
class DateToStringTransformer implements DataTransformerInterface
{
public function transform($date)
{
if (null === $date) {
return "";
}
return $date->format("Y-m-d");
}
public function reverseTransform($stringDate)
{
if (!$stringDate) {
return null;
}
$date = \DateTime::createFromFormat('Y-m-d', $stringDate);
if (false === $date) {
throw new TransformationFailedException('Sting to date transformation failed!');
}
return $date;
}
}
Hope that this will help someone.

Symfony2 - Set a selected value for the entity field

I'm trying to set a selected value inside an entity field. In accordance with many discussions I've seen about this topic, I tried to set the data option but this doesn't select any of the values by default:
class EventType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('place', 'entity', array(
'class' => 'RoyalMovePhotoBundle:Place',
'property' => 'name',
'empty_value' => "Choisissez un club",
'mapped' => false,
'property_path' => false,
'data' => 2
))
->add('begin')
->add('end')
->add('title')
->add('description')
;
}
// ...
}
By looking for more I've found that some people had to deactivate the form mapping to the entity. That seems logical so I tried to add 'mapped' => false to the options, without success...
If it can help, here's my controller:
class EventController extends Controller
{
// ...
public function addAction()
{
$request = $this->getRequest();
$em = $this->getDoctrine()->getManager();
$event = new Event();
$form = $this->createForm(new EventType(), $event);
$formHandler = new EventHandler($form, $request, $em);
if($formHandler->process()) {
$this->get('session')->getFlashBag()->add('success', "L'évènement a bien été ajouté.");
return $this->redirect($this->generateUrl('photo_event_list'));
}
return $this->render('RoyalMovePhotoBundle:Event:add.html.twig', array(
'form' => $form->createView()
));
}
}
And the EventHandler class:
class EventHandler extends AbstractHandler
{
public function process()
{
$form = $this->form;
$request = $this->request;
if($request->isMethod('POST')) {
$form->bind($request);
if($form->isValid()) {
$this->onSuccess($form->getData());
return true;
}
}
return false;
}
public function onSuccess($entity)
{
$em = $this->em;
$em->persist($entity);
$em->flush();
}
}
I'm a bit stuck right now, is there anyone who got an idea?
You only need set the data of your field:
class EventController extends Controller
{
// ...
public function addAction()
{
$request = $this->getRequest();
$em = $this->getDoctrine()->getManager();
$event = new Event();
$form = $this->createForm(new EventType(), $event);
// -------------------------------------------
// Suppose you have a place entity..
$form->get('place')->setData($place);
// That's all..
// -------------------------------------------
$formHandler = new EventHandler($form, $request, $em);
if($formHandler->process()) {
$this->get('session')->getFlashBag()->add('success', "L'évènement a bien été ajouté.");
return $this->redirect($this->generateUrl('photo_event_list'));
}
return $this->render('RoyalMovePhotoBundle:Event:add.html.twig', array(
'form' => $form->createView()
));
}
}
In order to option appear selected in the form, you should set corresponding value to entity itself.
$place = $repository->find(2);
$entity->setPlace($place);
$form = $this->createForm(new SomeFormType(), $entity);
....
For non-mapped entity choice fields, the method I found easiest was using the choice_attr option with a callable. This will iterate over the collection of choices and allow you to add custom attributes based on your conditions and works with expanded, multiple, and custom attribute options.
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('place', 'entity', array(
//...
'choice_attr' => function($place) {
$attr = [];
if ($place->getId() === 2) {
$attr['selected'] = 'selected';
//for expanded use $attr['checked'] = 'checked';
}
return $attr;
}
))
//...
;
}
When you use the query_builder option, and the data option expects an collection instance, and you don't want to touch your controller by adding setDatas for only certain fields, and you already have your querybuilder and the ids of the repopulating options in your form type class, you can repopulate a selection as following:
// Querybuilder instance with filtered selectable options
$entities = $qb_all;
// Querybuilder instance filtered by repopulating options (those that must be marked as selected)
$entities_selected = $qb_filtered;
Then in your add() Method
'data' => $entities_selected->getQuery()->getResult(), // Repopulation
'query_builder' => $entities,
EDIT: Real use case example
You want to repopulate a checkbox group rendered with following elements:
Label: What is your favourite meal?
4 Checkboxes: Pasta, Pizza, Spaghetti, Steak
And you want to repopulate 2 Checkboxes:
Pizza, Steak
$qb_all would be a QueryBuilder instance with the all 4 selectable Checkboxes
$qb_filtered would be a new additional QueryBuilder instance with the repopulating Checkboxes Pizza, Steak. So a "filtered" version of the previous one.

Model populated with unposted data

I have two models, Lesson and Evaluation. Each lesson can have multiple evaluations.
I am trying to set up an embedded form which will allow users to enter all of this data at the same time.
It works fine for adding and editing data, however I have a problem if I try to remove an evaluation.
For example, I have a lesson with three evaluations attached. I then submit with form again but with one of those removed.
In the controller, I first get the lesson being edited, then get its evaluations and loop through them, printing the ids. Three ids are printed as expected.
Next, I bind the request to the form and check if it is valid. I then get the evaluations again and loop through them once more to check that they've been removed, however all three ids were still there!
If I print the raw POST data, there are only two.
Can anyone see what I have done wrong?
Here is my controller code:
public function editAction($id = NULL)
{
$lesson = new Lesson;
if ( ! empty($id))
{
$lesson = $this->getDoctrine()
->getRepository('LessonBundle:Lesson')
->find($id);
}
foreach ($lesson->getEvaluations() as $evaluation)
{
print_r($evaluation->getId());
print_r('<br />');
}
$form = $this->createForm(new LessonType(), $lesson);
$request = $this->getRequest();
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
if ($form->isValid()) {
foreach ($lesson->getEvaluations() as $evaluation)
{
print_r($evaluation->getId());
print_r('<br />');
}
die();
$em = $this->getDoctrine()->getEntityManager();
$em->persist($lesson);
$em->flush();
}
}
}
Here is my lesson form:
class LessonType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('evaluations', 'collection', array(
'type' => new EvaluationType(),
'allow_add' => true,
'by_reference' => false,
'allow_delete' => true,
));
}
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'LessonBundle\Entity\Lesson',
);
}
public function getName()
{
return 'Lesson';
}
}
And finally, my Evaluation form:
class EvaluationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('report');
}
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'LessonBundle\Entity\Evaluation',
);
}
public function getName()
{
return 'Evaluation';
}
}
Any advice appreciated.
Thanks.
I think your form is not binded properly with the Class.
have a look at here http://symfony.com/doc/2.0/cookbook/form/form_collections.html
Form should look like this
$builder
->add('name lesson')
->add('evaluation', 'collection', array('type'=>new EvaluationsType()))
YOu need to create a new form class with other forms embedded.
The other way is to manually check the posted data and remove the evalauation manually in the controller and then persist the Lesson again
I got around in by using:
$lesson = $form->getData();