Starting with Symfony is quite a learning curve. Even after reading for hours, I cannot get across this presumably simple problem. I want to load a choices-form with values from an entity.
Controller:
namespace AppBundle\Controller
class ItemController extends Controller
{
public function itemAction (Request $request)
{
$myItems = new Itemlist();
//some statements to fill $myItems
$form = $this->createForm (AllitemsType::class, $myItems);
// some more stuff
return $this->render (...);
}
}
Entity:
namespace AppBundle\Entity;
class Itemlist
{
protected $choices;
protected $defaultvalue;
public function __construct ()
{
$choices = array();
}
// all the get and set-methods to fill/read the $choices array and $defaultvalue
}
Form:
namespace AppBundle\Form
class AllitemsType extends AbstractType
{
public function buildForm (FormBuilderInterface $builder, array $options)
{
// and here is my problem: how can I fill next two lines with values from the Itemlist-Entity?
// The Itemlist instance has been build in the controller and is unknown here
$items = ??? // should be 'AppBundle\Entity\Itemlist->$choices
$defaultitem = ??? // should be 'AppBundle\Entity\Itemlist->$defaultvalue
$choices_of_items = array (
'choices' => $items,
'expanded' => true,
'multiple' => false,
'data' => $defaultitem,
);
$builder->add ('radio1', ChoiceType::class, $choices_of_items);
}
}
Any help appreciated,
Wolfram
$builder->add('choices', ChoiceType::class);
should be sufficient as you're binding an entity to the form, the process of getting values and setting them back is automatic. Of course you need to have setter and getter for choices field in AllitemsType
To give a complete answer - part above is the so called "best practice one" - you can also choose one of the following
$items = $options['data'];
or
$builder->addEventListener(
FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$allItems = $event->getData();
$form = $event->getForm();
$form->add('radio1', ChoiceType::class, [
'choices' => $allItems
]);
});
Second one should be preferred as, in options['data'], entity could change during form event's lifetime.
Pass variables with createForm object.
Controller:
namespace AppBundle\Controller
class ItemController extends Controller
{
public function itemAction (Request $request)
{
$myItems = new Itemlist();
$formVars = array("items" => array(1,2,3,4,6), "defaultItems" => 2); // Store variables
^^
//some statements to fill $myItems
$form = $this->createForm (new AllitemsType($formVars), $myItems);
^^
// some more stuff
return $this->render (...);
}
}
Now create constructor in form and set class variables items and defaultitem in form.
Form:
namespace AppBundle\Form
class AllitemsType extends AbstractType
{
$this->items = array();
$this->defaultitem = 0;
public function __construct($itemArr)
{
$this->items = $itemArr['items'];
$this->defaultitem = $itemArr['defaultItems'];
}
public function buildForm (FormBuilderInterface $builder, array $options)
{
$choices_of_items = array (
'choices' => $this->items, // User class variable
'expanded' => true,
'multiple' => false,
'data' => $this->defaultitem, // User class variable
);
$builder->add ('radio1', ChoiceType::class, $choices_of_items);
}
}
It should solve your problem.
Related
I want to create a reusable AJAX-based select (select2) using Symfony form types and I've spent quite some time on it but can't get it to work like I want.
As far as I know you cannot override options of form fields after they have been added, so you have to re-add them with the new config. The Symfony docs also provide some examples on how to dynamically add or modify forms using events. https://symfony.com/doc/current/form/dynamic_form_modification.html
I've managed to create my AJAX based elements in the form and it's working but not completely reusable yet:
Form field extends Doctrine EntityType to have full support of data mappers etc
Form field is initialized with 'choices' => [], so Doctrine does not load any entities from db
Existing choices on edit is added during FormEvents::PRE_SET_DATA
Posted choices are added during FormEvents::PRE_SUBMIT
The current setup works but only in the parent form. I want to have my AjaxNodeType completely reusable so the parent form does not need to care about data handling and events.
Following the 2 examples, parent and child form. Here with event listeners in both, but of course they should only be in one.
Is it simply not possible in single element types to replace "yourself" in the parent form or am I doing something wrong? Is there any other way to dynamically change the choices?
Parent form
This works!
class MyResultElementType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'fixedNode',
AjaxNodeType::class,
[
'label' => 'Fixed node',
'required' => false,
]
);
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (PreSetDataEvent $event) {
if ($event->getData()) {
$fixedNode = $event->getData()->getFixedNode();
//this works here but not in child???
if ($fixedNode) {
$name = 'fixedNode';
$parentForm = $event->getForm();
$options = $parentForm->get($name)->getConfig()->getOptions();
$options['choices'] = [$fixedNode];
$parentForm->add($name, AjaxNodeType::class, $options);
}
}
},
1000
);
$builder->addEventListener(
FormEvents::PRE_SUBMIT,
function (PreSubmitEvent $event) {
$data = $event->getData()['fixedNode'];
if ($data) {
$name = 'fixedNode';
$parentForm = $event->getForm();
// we have to add the POST-ed data/node here to the choice list
// otherwise the submitted value is not valid
$node = $this->entityManager->find(Node::class, $data);
$options = $parentForm->get($name)->getConfig()->getOptions();
$options['choices'] = [$node];
$parentForm->add($name, AjaxNodeType::class, $options);
}
}
);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
[
'data_class' => MyResultElement::class,
'method' => 'POST',
]
);
}
}
Child form / single select This does NOT work. On POST the fixedNode field is not set to the form data-entity.
class AjaxNodeType extends AbstractType
{
/** #var EntityManager */
private $entityManager;
public function __construct(
EntityManager $entityManager
) {
$this->entityManager = $entityManager;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
//this does not work here but in parent???
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (PreSetDataEvent $event) {
if ($event->getData()) {
$fixedNode = $event->getData();
$name = $event->getForm()->getName();
$parentForm = $event->getForm()->getParent();
$options = $parentForm->get($name)->getConfig()->getOptions();
$newChoices = [$fixedNode];
// check if the choices already match, otherwise we'll end up in an endless loop ???
if ($options['choices'] !== $newChoices) {
$options['choices'] = $newChoices;
$parentForm->add($name, AjaxNodeType::class, $options);
}
}
},
1000
);
$builder->addEventListener(
FormEvents::PRE_SUBMIT,
function (PreSubmitEvent $event) {
if ($event->getData()) {
$name = $event->getForm()->getName();
$data = $event->getData();
$parentForm = $event->getForm()->getParent();
// we have to add the POST-ed data/node here to the choice list
// otherwise the submitted value is not valid
$node = $this->entityManager->find(Node::class, $data);
$options = $parentForm->get($name)->getConfig()->getOptions();
$options['choices'] = [$node];
$parentForm->add($name, self::class, $options);
}
},
1000
);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
[
'class' => Node::class,
// prevent doctrine from loading ALL nodes
'choices' => [],
]
);
}
public function getParent(): string
{
return EntityType::class;
}
}
Again, answering my own Questions :)
After spending some more time on it I got a working solution. And maybe it will be helpful for someone.
I've switched from EntityType to ChoiceType as it only made things more complicated and is not actually needed
multiple and single selects need different settings/workarrounds (like by_reference), see the line comments below
re-adding yourself to the parent form works, I don't know why it did not before...
beware of endless-loops when re-adding / re-submitting values
The main re-usable AjaxEntityType that does all the logic without reference to any specific entity:
<?php
namespace Tool\Form\SingleInputs;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\EntityManager;
use Symfony\Bridge\Doctrine\Form\DataTransformer\CollectionToArrayTransformer;
use Symfony\Bridge\Doctrine\Form\EventListener\MergeDoctrineCollectionListener;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Event\PreSetDataEvent;
use Symfony\Component\Form\Event\PreSubmitEvent;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;
class AjaxEntityType extends AbstractType
{
/** #var EntityManager */
private $entityManager;
public function __construct(
EntityManager $entityManager
) {
$this->entityManager = $entityManager;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
// shamelessly copied from DoctrineType - this is needed to support Doctrine Collections in multi-selects
if ($options['multiple'] && interface_exists(Collection::class)) {
$builder
->addEventSubscriber(new MergeDoctrineCollectionListener())
->addViewTransformer(new CollectionToArrayTransformer(), true);
}
// PRE_SET_DATA is the entrypoint on form creation where we need to populate existing choices
// we process current data and set it as choices so it will be rendered correctly
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (PreSetDataEvent $event) use($options) {
$data = $event->getData();
$hasData = ($options['multiple'] && count($data) > 0) || (!$options['multiple'] && $data !== null);
if ($hasData) {
$entityOrList = $event->getData();
$name = $event->getForm()->getName();
$parentForm = $event->getForm()->getParent();
$options = $parentForm->get($name)->getConfig()->getOptions();
// ONLY do this if the choices are empty, otherwise readding PRE_SUBMIT will not work because this is called again!
if(empty($options['choices'])) {
if($options['multiple']) {
$newChoices = [];
foreach ($entityOrList as $item) {
$newChoices[$item->getId()] = $item;
}
} else {
$newChoices = [$entityOrList->getId() => $entityOrList];
}
$options['choices'] = $newChoices;
$parentForm->add($name, self::class, $options);
}
}
},
1000
);
// PRE_SUBMIT is the entrypoint where we need to process the submitted values
// we have to add the POST-ed choices, otherwise this field won't be valid
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (PreSubmitEvent $event) use($options) {
$entityIdOrList = $event->getData();
$entityClass = $options['class'];
// new choices constructed from POST
$newChoices = [];
if ($options['multiple']) {
foreach ($entityIdOrList as $id) {
if ($id) {
$newChoices[$id] = $this->entityManager->find($entityClass, $id);
}
}
} elseif ($entityIdOrList) {
$newChoices = [$entityIdOrList => $this->entityManager->find($entityClass, $entityIdOrList)];
}
$name = $event->getForm()->getName();
$parentform = $event->getForm()->getParent();
$currentChoices = $event->getForm()->getConfig()->getOptions()['choices'];
// if the user selected/posted new choices that have not been in the existing list, add them all
if ($newChoices && count(array_diff($newChoices, $currentChoices)) > 0) {
$options = $event->getForm()->getParent()->get($name)->getConfig()->getOptions();
$options['choices'] = $newChoices;
// re-add ourselves to the parent form with updated / POST-ed options
$parentform->add($name, self::class, $options);
if(!$parentform->get($name)->isSubmitted()) {
// after re-adding we also need to re-submit ourselves
$parentform->get($name)->submit($entityIdOrList);
}
}
}, 1000);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
[
'mapped' => true,
'choice_value' => 'id',
'choice_label' => 'selectLabel',
'choices' => [],
'attr' => [
'class' => 'select2-ajax',
],
'ajax_url' => null,
]
);
// AJAX endpoint that is select2 compatible
// https://select2.org/data-sources/ajax
$resolver->setRequired('ajax_url');
$resolver->setAllowedTypes('ajax_url', ['string']);
// entity class to process
$resolver->setRequired('class');
// by_reference needs to be true for single-selects, otherwise our entities will be cloned!
// by_reference needs to be false for multi-selects, otherwise the setters wont be called for doctrine collections!
$resolver->setDefault('by_reference', function (Options $options) {
return !$options['multiple'];
});
// adds the ajax_url as attribute
$resolver->setNormalizer('attr', function (Options $options, $value) {
$value['data-custom-ajax-url'] = $options['ajax_url'];
return $value;
});
}
public function getParent(): string
{
return ChoiceType::class;
}
}
Actual usage with specific entity and ajax endpoint:
<?php
namespace Tool\Form\SingleInputs;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Tool\Entities\User\Node;
class AjaxNodeType extends AbstractType
{
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
[
'class' => Node::class,
'ajax_url' => 's/ajax-select/nodes',
]
);
}
public function getParent(): string
{
return AjaxEntityType::class;
}
}
I have a class RegisterType for my form:
<?php
class RegisterType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name');
$builder->add('price');
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Register'
));
}
public function getName()
{
return 'register';
}
}
?>
The Register Entity has a relation with an Entity called Product
I would like to add this condition to the buildForm function:
<?php
if ($product->getTitle() == 'SuperProduct') {
$builder->add('amount', 'money', [
'required' => FALSE,
]);
}
?>
If the product title has the value 'SuperProduct' then I add a field in the the form.
But I have no idea about the syntax I have to use to call another Entity value in a FormType.
Thanks in advance for your help.
Ah good you've implemented your FormType as an independent class rather than in a controller, so what I'd do is pass in your product entity as an option to a private variable within your FormType class. I'm not sure what class your product is or the name space it resides in, so you'll have to fill that in.
I've also written this in the expectation that you could have more than one option to pass through in the future, so it'll be useful to other FormType classes you write. Each variable you define in the class scope can be set when you create an instance of the FormType class. Be sure to initialise these variables as false instead of null, or the code in the constructor function won't see them.
<?php
class RegisterType extends AbstractType
{
private $product = false;
public function __construct(array $options = [])
{
foreach ($options as $name => $value) {
if (isset($this->$name)) {
$this->$name => $value;
}
}
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('price')
;
if ($this->product && is_a("\Namespace\To\Your\Entity\Called\Product", $this->product)) {
if ($this->product->getTitle() == 'SuperProduct') {
$builder
->add('amount', 'money', [
'required' => FALSE,
])
;
}
}
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Register'
));
}
public function getName()
{
return 'register';
}
}
?>
That "is_a()" function checks that the product variable passed in through the form type class constructor really is an instance of your product entity, so you can be sure that the getTitle() function exists.
Now when you create a new instance of your RegisterType class, you need to pass through an options array including your product. Two conceptual variable names for you to rename here.
<?php
$form = $this->createForm(new RegisterType([
"product" => $instanceOfProductEntityOrNull,
]), $theEntityTheFormWillBeHandling);
?>
Try something like this:
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$product = $event->getData();
$form = $event->getForm();
if ($product->getTitle() == 'SuperProduct') {
$form->add('name', 'text');
}
});
And do not forget the specific use
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
I have 3 Entities: User , Report and ReportCategory.
A User can put Reports in ONE ReportCategory. In the User-Entity there is a list, which ReportCategories are allowed for the user. This works all fine - I made it with a connectionTable which has the userID and the reportCategoryId.
Now I make an Array in Controller to get all ReportCategories of the current logged in User:
public function newAction()
{
$entity = new Report();
$form = $this->createCreateForm($entity);
$userId = $this->get('security.context')->getToken()->getUser()->getId();
$user = $this->getDoctrine()->getRepository('MyBundle:User')->find($userId);
$userReportCategories = array();
foreach($user->getReportCategories() as $reportCategory)
{
$userReportCategories[] = $reportCategory->getId();
}
return array(
'entity' => $entity,
'form' => $form->createView(),
'userReportCategories' => $userReportCategories
);
}
How can I set only these Values to my twig template field? When I make an own field it is not managed form Doctrine!
{{ form_row(form.reportCategory, {'attr': {'class': 'form-control'}, 'label': 'Category'}) }}
THANKS FOR ANY HELP!!!
UPDATE:
My ReportType looks like this:
class ReportType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('reportCategory')
->add('creationDate', 'date', array(
'data' => new \DateTime()
))
->add('headline')
->add('text')
->add('user')
;
}
....
Create a form class and add an event listener so that the form is aware of the user. The following is an adaptation of How to dynamically Generate Forms Based on user Data in the Symfony docs. [It is not guaranteed to accurately capture your needs].
form class
use Symfony\Component\Security\Core\SecurityContext;
use Doctrine\ORM\EntityRepository;
// ...
class ReportFormType extends AbstractType
{
private $securityContext;
public function __construct(SecurityContext $securityContext)
{
$this->securityContext = $securityContext;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
// grab the user, do a quick sanity check that one exists
$user = $this->securityContext->getToken()->getUser();
if (!$user) {
throw new \LogicException(
'The ReportFormType cannot be used without an authenticated user!'
);
}
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($user) {
$form = $event->getForm();
$formOptions = array(
'class' => 'Acme\DemoBundle\Entity\ReportCategory',
'property' => 'category',
'query_builder' => function (EntityRepository $er) use ($user) {
// build a custom query
// return $er->createQueryBuilder('c')
->select('category')
->where('user = $user);
},
);
// create the field, this is similar the $builder->add()
// field name, field type, data, options
$form->add('userReportCategories', 'entity', $formOptions);
}
);
}
// ...
}
new action
public function newAction()
{
$entity = new Report();
$form = $this->createForm(new ReportFormType(), $entity);
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
I'm trying to implement an answer from the topic as covered here, but I'm having issues!
Q
I am getting the following error when loading the registration form
Notice: Undefined index: roles
with reference to
in src/Ampisoft/Bundle/etrackBundle/Form/Type/RegistrationFormType.php at line 21
RegistrationFormType::RegisterAction
Ive tested the output of $roles on the 2nd line of this snippet and I have a full array as expected.
//.......
$roles = $this->container->getParameter('security.role_hierarchy.roles');
var_dump($roles);
return $this->container->get('templating')->renderResponse('FOSUserBundle:Registration:register.html.'.$this->getEngine(), array(
'form' => $form->createView(
array('roles' => $roles,
)),
));
// .......
The problem seems to be the way Im passing (or retrieving from) the $roles array to the Type class.
RegistrationFormType
class RegistrationFormType extends AbstractType
{
protected $roles;
public function __construct($options = array())
{
$this->roles = $options['roles']; // <--------------- THIS IS line 21
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
// custom form fields
$builder->add('firstname');
$builder->add('lastname');
$builder->add('roles', 'choice', array(
'required' => true,
'multiple' => true,
'choices' => $this->refactorRoles($this->roles)
));
}
public function getDefaultOptions()
{
return array(
'roles' => null
);
}
private function refactorRoles($originRoles)
{
$roles = array();
$rolesAdded = array();
// Add herited roles
foreach ($originRoles as $roleParent => $rolesHerit) {
$tmpRoles = array_values($rolesHerit);
$rolesAdded = array_merge($rolesAdded, $tmpRoles);
$roles[$roleParent] = array_combine($tmpRoles, $tmpRoles);
}
// Add missing superparent roles
$rolesParent = array_keys($originRoles);
foreach ($rolesParent as $roleParent) {
if (!in_array($roleParent, $rolesAdded)) {
$roles['-----'][$roleParent] = $roleParent;
}
}
return $roles;
}
public function getParent()
{
return 'fos_user_registration';
}
public function getName()
{
return 'etrack_user_registration';
}
}
I've tried various ways of passing the contents of the security.hierarchy.roles array through to the Type class but to no avail.
What I want to do :
I'm trying to access a field from an embedded formType in a collection.
I can easily access the first level (so getting the collection) with $form->get('childType') but I struggle to access the field embedded in childType.
I tried $form->get('childType')->get('anotherAttr') with no success. IMHO the problem comes from the fact that a Collection is not just a field, and getting('anotherAttr') can't be done without Symfony knowing on what item of the collection I want to do this get. Anyways after a lot of search I haven't find how to tell him I want the first item from the collection.
Here is the code :
The parent class type :
<?php
namespace my\myBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class ParentType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('attribute1','text',array("label" => 'attribute 1 :'))
->add('childType','collection',array('type' => new ChildType($options['attrForChild'])));
}
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'my\myBundle\Entity\Parent',
'attrForChild' => null
);
}
public function getName()
{
return 'my_mybundle_childtype';
}
}
The childClassType :
<?php
namespace my\myBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class ChildType extends AbstractType
{
private $childAttr;
public function __construct($childAttr=null){
$this->childAttr=$childAttr;
}
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('childAttr','text',array("label" => 'childAttr : ','property_path' => false));
if(isset($this->childAttr)){
$childAttr = $this->childAttr;
$builder->add('childAttrDependantEntity','entity',array("label" => 'RandomStuff : ',
'class' => 'mymyBundle:randomEntity',
'property' => 'randProperty',
'multiple' => false,
'query_builder' => function(\my\myBundle\Entity\randomEntityRepository $r) use ($childAttr) {
return $r->findByChildAttr($childAttr);
}
));
}
$builder->add('anotherAttr','text',array("label" => 'Other attr : '))
}
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'crri\suapsBundle\Entity\Adresse',
'childAttr' => null
);
}
public function getName()
{
return 'my_mybundle_childtype';
}
}
Also, does the childAttr solution I use is ok? (it is working, but it feels a bit as a hack, is there a cleaner way to do the same thing?). What it is used for = the user gives me a text field, I verify if it exists in database, if it does exist, I add an entityType to the form which is related to this attribute. The goal is that the user will select from a restrain list of elements, instead of all the elements from the database.
EDIT : the controller's corresponding code :
public function parentTypeAddAction(Request $request){
$parentEntity = new ParentEntity();
$parentEntity->addChildEntity(new ChildEntity());
$form = $this->createForm(new ParentType,$parentEntity);
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
// Testing (everything I tried)
$test=$form->get('childType')->getAttribute('childAttr');
/**
$test=$form['childAttr'];
$test=$form->get('childAttr'); **/
return $this->container->get('templating')->renderResponse('myMyBundle:Default:test.html.twig',
array('test' => $test));
if($test!=null ){
$anEntity = $em->getRepository('crrisuapsBundle:AnEntity')->find($test);
if($anEntity==null){
$form->get('childType')->get('childAttr')->addError(new FormError("Invalid attribute."));
} else {
$form = $this->createForm(new ParentType,$parentType,array('childAttr' => $test));
$individu->getAdresses()->first()->setAnEntity($anEntity);
}
}
$form->bindRequest($request);
if($request->request->get('CHILDATTRPOST')!='Search attribute'){
if ($form->isValid()) {
$em->persist($parentType);
$em->persist($individu->getChildEntity()->first());
$em->flush();
return $this->redirect($this->generateUrl('myMyBundle_homepage'), 301);
}
}
}
return $this->container->get('templating')->renderResponse('myMyBundle:Default:parentTypeAdd.html.twig',
array('form' => $form->createView()));
}
Thanks to cheesemacfly's suggestions I could figure out how to get it. Here is the solution :
//Getting the childEntities forms as an array
$childArray=$form->get('childType')->getChildren();
//Getting the childEntity form you want
$firstChild=$childArray[0];
//Getting your attribute like any form
$childAttrForm=$childArray[0]->get('childAttr');
$childAttr=$childAttrForm->getData();