I have an API and I am sending a reference of an entity, I'm using a DataTransformer to get my entity but the DataTransformer is always called before the $form->handleRequest($request) the value is always null and it could't works
My Controller
public function newAction(Request $request)
{
$orderNewFormType = $this->get('competitive_bo.api_bundle.form.type.order_new');
$card = new Card();
try {
$form = $this->createForm($orderNewFormType, $card);
$form->handleRequest($request);
} catch (TransformationFailedException $e) {
return $this->notFoundErrorResponse(
'Business not found'
);
}
if ($form->isValid()) {
return $this->okResponse(array());
}
$validatorErrorFormatter = $this->get('competitive_bo.api_bundle.formatter.validator_error');
$errors = $validatorErrorFormatter->formatFromFormError($form->getErrors(true));
return $this->badRequestErrorResponse(
'Invalid data',
$errors
);
}
The form type
class OrderNewFormType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('customer', 'entity', array(
'class' => 'CompetitiveBOBusinessBundle:Customer',
'property' => 'id'
))
->add('business', 'business', array(
'mapped' => false,
))
;
}
/**
* {#inheritdoc}
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'csrf_protection' => false,
'data_class' => Card::class
));
}
public function getName()
{
return null;
}
}
The Business form type
class BusinessReferenceFormType extends AbstractType
{
/**
* #var ReferenceToBusinessTransformer
*/
private $referenceToBusinessTransformer;
public function __construct(ReferenceToBusinessTransformer $referenceToBusinessTransformer)
{
$this->referenceToBusinessTransformer = $referenceToBusinessTransformer;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addViewTransformer($this->referenceToBusinessTransformer);
}
public function getName()
{
return 'business';
}
public function getParent()
{
return 'text';
}
}
And the DataTransformer
/**
* Class ReferenceToBusinessTransformer
*/
class ReferenceToBusinessTransformer implements DataTransformerInterface
{
/**
* #var BusinessRepository
*/
private $businessRepository;
public function __construct(BusinessRepository $businessRepository)
{
$this->businessRepository = $businessRepository;
}
/**
* {#inheritdoc}
*/
public function transform($reference)
{
var_dump($reference);
$business = $this->businessRepository->findOneBy(array(
'reference' => $reference
));
if (null === $business) {
throw new TransformationFailedException;
}
return $business;
}
/**
* {#inheritdoc}
*/
public function reverseTransform($value)
{
if (!($value instanceof Business)) {
throw new TransformationFailedException;
}
return $value->getReference();
}
}
The var_dump($reference) is always null
And I have my test
public function testNewAction($getParams, $postParam, $responseCode)
{
$client = static::createClient();
$router = $client->getContainer()->get('router');
$route = $router->generate('competitivebo_api_order_new',$getParams);
$client->request('POST', $route, $postParam);
$response = $client->getResponse();
$this->assertJsonResponse($response, $responseCode);
}
With the post params
'customer' => 1,
'business' => LoadBusinessData::REFERENCE_1,
'name' => 'Test',
The exception TransformationFailedException is always thrown during the $this->createForm(...) so the request is not handled
According with the documentation,
When null is passed to the transform() method, your transformer should return an equivalent value of the type it is transforming to (e.g. an empty string, 0 for integers or 0.0 for floats).
Related
I'm working on a Symfony project where an I have two types of User Client and EmployeSpie, both have their own entity.
When you create/edit a user you can link EmployeSpie to a CLient.
That's where is my problem, When I edit or create a user I can create a user but nothing is store inside my table which make the link between my table Client and EmployeSpie.
Here is what I've done:
my entity Client having this:
class Client extends User
{
/**
* #ORM\ManyToMany(targetEntity=EmployeSpie::class, mappedBy="clients", cascade={"persist"})
*/
private $employeSpies;
/**
* #return Collection|EmployeSpie[]
*/
public function getEmployeSpies(): Collection
{
return $this->employeSpies;
}
public function addEmployeSpy(EmployeSpie $employeSpy): self
{
if (!$this->employeSpies->contains($employeSpy)) {
$this->employeSpies[] = $employeSpy;
$employeSpy->addClientEmploye($this);
}
return $this;
}
public function removeEmployeSpy(EmployeSpie $employeSpy): self
{
if ($this->employeSpies->contains($employeSpy)) {
$this->employeSpies->removeElement($employeSpy);
$employeSpy->removeClientEmploye($this);
}
return $this;
}
}
and my table EmployeSpie:
class EmployeSpie extends User
{
/**
* #ORM\ManyToMany(targetEntity=Client::class, inversedBy="employeSpies")
*/
private $clients;
/**
* #return Collection|Client[]
*/
public function getClients(): Collection
{
return $this->clients;
}
public function addClient(Client $client): self
{
if (!$this->clients->contains($client)) {
$this->clients[] = $client;
}
return $this;
}
public function removeClient(Client $client): self
{
if ($this->clients->contains($client)) {
$this->clients->removeElement($client);
}
return $this;
}
public function __toString()
{
return $this->getPrenom()." ".$this->getNom();
}
My forms are made with a Symfony form:
class ClientType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('email')
->add('password')
->add('nom')
->add('prenom')
->add('telephone')
->add('fax')
->add('is_active')
->add('client_fonction')
->add('site')
->add('employeSpies', EntityType::class, array(
'class' => EmployeSpie::class ,
'label' => 'Sélectionnez les emloyés rattachés à ce client',
'expanded' => false,
'multiple' => true,
))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Client::class,
]);
}
}
and in my Controller I've made the following thing:
/**
* #Route("/admin/clients/create", name="admin.client.new")
* #param Request $request
* #return RedirectResponse|Response
*/
public function new(Request $request, UserPasswordEncoderInterface $passwordEncoder)
{
$client = new Client();
$form = $this->createForm(ClientType::class, $client);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
$client->setRoles(array('ROLE_CUSTOMER'));
$client->setPassword(
$passwordEncoder->encodePassword(
$client,
$form->get('password')->getData()
)
);
$this->em->persist($client);
$this->em->flush();
$this->addFlash('success', 'Nouveau client crée avec succès');
$this->redirectToRoute('admin.clients.index');
}
return $this->render("admin/clients/create.html.twig", [
'client' => $client,
'form' => $form->createView()
]);
}
/**
* #Route("/admin/clients/{id}", name="admin.client.edit", methods="GET|POST")
* #param Client $client
* #return Response
*/
public function edit(Client $client,Request $request, UserPasswordEncoderInterface $passwordEncoder)
{
$form = $this->createForm(ClientType::class, $client);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
$clientEmploye = $request->request->get('client');
$clientEmploye = $clientEmploye['employeSpies'];
$client->setPassword(
$passwordEncoder->encodePassword(
$client,
$form->get('password')->getData()
)
);
foreach ($form->get('employeSpies')->getData() as $employe){
$client->addEmployeSpy($employe);
}
$client->setRoles(array('ROLE_CUSTOMER'));
$this->em->flush();
$this->addFlash('success', 'Nouveau client modifié avec succès');
$this->redirectToRoute('admin.clients.index');
}
return $this->render("admin/clients/edit.html.twig", [
'client' => $client,
'form' => $form->createView()
]);
}
Si my user is created or edited normally but I did not store the link for employeSpies in my form. Do you have any idea why?
I found the answer to my problem.
#Jakumi was right but few other cha ges were needed.
In my client Entity I has to change :
public function addEmployeSpy(EmployeSpie $employeSpy): self
{
if (!$this->employeSpies->contains($employeSpy)) {
$this->employeSpies[] = $employeSpy;
$employeSpy->addClientEmploye($this);
}
return $this;
}
to :
public function addEmployeSpy(EmployeSpie $employeSpy): self
{
if (!$this->employeSpies->contains($employeSpy)) {
$this->employeSpies[] = $employeSpy;
$employeSpy->addClient($this);
}
return $this;
}
Same thing for the remove.
public function removeEmployeSpy(EmployeSpie $employeSpy): self
{
if ($this->employeSpies->contains($employeSpy)) {
$this->employeSpies->removeElement($employeSpy);
$employeSpy->removeClientEmploye($this);
}
return $this;
}
to :
public function removeEmployeSpy(EmployeSpie $employeSpy): self
{
if ($this->employeSpies->contains($employeSpy)) {
$this->employeSpies->removeElement($employeSpy);
$employeSpy->removeClient($this);
}
return $this;
}
But after the other change in my ClientType :
->add('employeSpies', EntityType::class, array(
'class' => EmployeSpie::class ,
'by_reference' => false,
'label' => 'Sélectionnez les employés rattachés à ce client',
'expanded' => false,
'multiple' => true,
))
I need to add the 'by_reference' => false,to make it works.
Because of this Symfony will not try to find the "setClient" method but to find addClient method
Hope it could help later some other persons :)
I am trying to validate a form in Symfony 2.3. I need to get the current User id and submit in my database.
My controller :
public function giftcardAction(Request $request)
{
$giftcard = new Giftcard();
$giftcard->setDate(new \DateTime());
$user = $this->container->get('security.context')->getToken()->getUser();
$userId = $user->getId();
var_dump($userId);
$form = $this->createFormBuilder($giftcard)
->add('amount', 'integer')
->add('onBehalfOf')
->add('towards')
->add('message', 'text')
// ->add($userId)
->add('submit', 'submit')
->getForm();
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($giftcard);
$em->flush();
}else{
throw new NotFoundHttpException("Page not found");
}
}
return $this->render('FrontBundle:Forms:giftcard.html.twig', array(
'form' => $form->createView(),
));
}
My FormType
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class GiftCardType extends AbstractType
{
private $userId;
public function __construct(array $userId)
{
$this->userId = $userId;
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('date')
->add('onBehalfOf')
->add('towards')
->add('message')
// ->add('UserId')
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Front\Bundle\Entity\GiftCard',
));
}
/**
* #return string
*/
public function getName()
{
return 'front_bundle_giftcard';
}
}
At the moment i can get the user id in var_dump in the controller. But how I can pass the variable in the form. Has anyone may help me. Thank you.
i have a form definition which uses the so-far great field type entity. With the option query_builder I select my values and the are displayed.
The sad part is, I am required to display a null default value, like all (it's a filter form). I don't like the choices option of entity because I have database values and a FormType shouldn't query the database.
My approach so far was to implement a custom field type which extends entity and adds a null entry to the top of the list. The field type is loaded and used but unfortunately the dummy value is not displayed.
The field definition:
$builder->add('machine', 'first_null_entity', [
'label' => 'label.machine',
'class' => Machine::ident(),
'query_builder' => function (EntityRepository $repo)
{
return $repo->createQueryBuilder('m')
->where('m.mandator = :mandator')
->setParameter('mandator', $this->mandator)
->orderBy('m.name', 'ASC');
}
]);
The form type definition:
class FirstNullEntityType extends AbstractType
{
/**
* #var unknown
*/
private $doctrine;
public function __construct(ContainerInterface $container)
{
$this->doctrine = $container->get('doctrine');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setRequired('query_builder');
$resolver->setRequired('class');
}
public function buildView(FormView $view, FormInterface $form, array $options)
{
$class = $options['class'];
$repo = $this->doctrine->getRepository($class);
$builder = $options['query_builder']($repo);
$entities = $builder->getQuery()->execute();
// add dummy entry to start of array
if($entities) {
$dummy = new \stdClass();
$dummy->__toString = function() {
return '';
};
array_unshift($entities, $dummy);
}
$options['choices'] = $entities;
}
public function getName()
{
return 'first_null_entity';
}
public function getParent()
{
return 'entity';
}
}
Here is what works in Symfony 3.0.3
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
$builder->add('example' EntityType::class, array(
'label' => 'Example',
'class' => 'AppBundle:Example',
'placeholder' => 'Please choose',
'empty_data' => null,
'required' => false
));
You can use placeholder from 2.6
An alternative approach would be to use a ChoiceList with choices that are generated from the database and then use that in a custom choice form type that will allow for an empty_value.
Choice List
namespace Acme\YourBundle\Form\ChoiceList;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Form\Extension\Core\ChoiceList\LazyChoiceList;
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList;
class MachineChoiceList extends LazyChoiceList
{
protected $repository;
protected $mandator;
public function __construct(ObjectManager $manager, $class)
{
$this->repository = $manager->getRepository($class);
}
/**
* Set mandator
*
* #param $mandator
* #return $this
*/
public function setMandator($mandator)
{
$this->mandator = $mandator;
return $this;
}
/**
* Get machine choices from DB and convert to an array
*
* #return array
*/
private function getMachineChoices()
{
$criteria = array();
if (null !== $this->mandator) {
$criteria['mandator'] = $this->mandator;
}
$items = $this->repository->findBy($criteria, array('name', 'ASC'));
$choices = array();
foreach ($items as $item) {
$choices[** db value **] = ** select value **;
}
return $choices;
}
/**
* {#inheritdoc}
*/
protected function loadChoiceList()
{
return new SimpleChoiceList($this->getMachineChoices());
}
}
Choice List Service (YAML)
acme.form.choice_list.machine:
class: Acme\YourBundle\Form\ChoiceList\MachineChoiceList
arguments:
- #doctrine.orm.default_entity_manager
- %acme.model.machine.class%
Custom Form Type
namespace Acme\YourBundle\Form\Type;
use Acme\YourBundle\Form\ChoiceList\MachineChoiceList;
..
class FirstNullEntityType extends AbstractType
{
/**
* #var ChoiceListInterface
*/
private $choiceList;
public function __construct(MachineChoiceList $choiceList)
{
$this->choiceList = $choiceList;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$choiceList = $this->choiceList;
$resolver->setDefault('mandator', null);
$resolver->setDefault('choice_list', function(Options $options) use ($choiceList) {
if (null !== $options['mandator']) {
$choiceList->setMandator($options['mandator']);
}
return $choiceList;
});
}
public function getName()
{
return 'first_null_entity';
}
public function getParent()
{
return 'choice';
}
}
Custom Form Type Service (YAML)
acme.form.type.machine:
class: Acme\YourBundle\Form\Type\FirstNullEntityType
arguments:
- #acme.form.choice_list.machine
tags:
- { name: form.type, alias: first_null_entity }
In Your Form
$builder
->add('machine', 'first_null_entity', [
'empty_value' => 'None Selected',
'label' => 'label.machine',
'required' => false,
])
;
I'm working on a form that handle N:M relationship with an extra parameter (extra field/column). This is what I've done until now:
In OrdersType.php form:
class OrdersType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
// $builder fields
// $builder fields only need on edit form not in create
if ($options['curr_action'] !== NULL)
{
$builder
// other $builder fields
->add("orderProducts", "collection", array(
'type' => new OrdersHasProductType(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false
));
}
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Tanane\FrontendBundle\Entity\Orders',
'render_fieldset' => FALSE,
'show_legend' => FALSE,
'intention' => 'orders_form',
'curr_action' => NULL
));
}
public function getName()
{
return 'orders';
}
}
In OrderHasProductType.php:
class OrdersHasProductType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('product', 'text', array(
'required' => FALSE,
'label' => FALSE
))
->add('amount', 'text', array(
'required' => TRUE,
'label' => FALSE
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Tanane\FrontendBundle\Entity\OrderHasProduct',
'intention' => 'order_has_product'
));
}
public function getName()
{
return 'order_has_product';
}
}
And finally this is Orders.php and OrdersHasProduct.php entities:
class Orders {
use IdentifiedAutogeneratedEntityTrait;
// rest of fields for the entity
/**
* #ORM\OneToMany(targetEntity="OrderHasProduct", mappedBy="order", cascade={"all"})
*/
protected $orderProducts;
protected $products;
/**
* #ORM\Column(name="deletedAt", type="datetime", nullable=true)
*/
protected $deletedAt;
public function __construct()
{
$this->orderProducts = new ArrayCollection();
$this->products = new ArrayCollection();
}
public function getOrderProducts()
{
return $this->orderProducts;
}
public function getDeletedAt()
{
return $this->deletedAt;
}
public function setDeletedAt($deletedAt)
{
$this->deletedAt = $deletedAt;
}
public function getProduct()
{
$products = new ArrayCollection();
foreach ($this->orderProducts as $op)
{
$products[] = $op->getProduct();
}
return $products;
}
public function setProduct($products)
{
foreach ($products as $p)
{
$ohp = new OrderHasProduct();
$ohp->setOrder($this);
$ohp->setProduct($p);
$this->addPo($ohp);
}
}
public function getOrder()
{
return $this;
}
public function addPo($ProductOrder)
{
$this->orderProducts[] = $ProductOrder;
}
public function removePo($ProductOrder)
{
return $this->orderProducts->removeElement($ProductOrder);
}
}
/**
* #ORM\Entity
* #ORM\Table(name="order_has_product")
* #Gedmo\SoftDeleteable(fieldName="deletedAt")
* #UniqueEntity(fields={"order", "product"})
*/
class OrderHasProduct {
use IdentifiedAutogeneratedEntityTrait;
/**
* Hook timestampable behavior
* updates createdAt, updatedAt fields
*/
use TimestampableEntity;
/**
* #ORM\ManyToOne(targetEntity="\Tanane\FrontendBundle\Entity\Orders", inversedBy="orderProducts")
* #ORM\JoinColumn(name="general_orders_id", referencedColumnName="id")
*/
protected $order;
/**
* #ORM\ManyToOne(targetEntity="\Tanane\ProductBundle\Entity\Product", inversedBy="orderProducts")
* #ORM\JoinColumn(name="product_id", referencedColumnName="id")
*/
protected $product;
/**
* #ORM\Column(type="integer", nullable=false)
*/
protected $amount;
/**
* #ORM\Column(name="deletedAt", type="datetime", nullable=true)
*/
protected $deletedAt;
public function setOrder(\Tanane\FrontendBundle\Entity\Orders $order)
{
$this->order = $order;
}
public function getOrder()
{
return $this->order;
}
public function setProduct(\Tanane\ProductBundle\Entity\Product $product)
{
$this->product = $product;
}
public function getProduct()
{
return $this->product;
}
public function setAmount($amount)
{
$this->amount = $amount;
}
public function getAmount()
{
return $this->amount;
}
public function getDeletedAt()
{
return $this->deletedAt;
}
public function setDeletedAt($deletedAt)
{
$this->deletedAt = $deletedAt;
}
}
But when I try to edit a order with this code in my controller:
public function editAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$order = $em->getRepository('FrontendBundle:Orders')->find($id);
$type = $order->getPerson()->getPersonType() === 1 ? "natural" : "legal";
$params = explode('::', $request->attributes->get('_controller'));
$actionName = substr($params[1], 0, -6);
$orderForm = $this->createForm(new OrdersType(), $order, array('action' => '#', 'method' => 'POST', 'register_type' => $type, 'curr_action' => $actionName));
return array(
"form" => $orderForm->createView(),
'id' => $id,
'entity' => $order
);
}
I get this error:
The form's view data is expected to be of type scalar, array or an
instance of \ArrayAccess, but is an instance of class
Proxies__CG__\Tanane\ProductBundle\Entity\Product. You can avoid this
error by setting the "data_class" option to
"Proxies__CG__\Tanane\ProductBundle\Entity\Product" or by adding a
view transformer that transforms an instance of class
Proxies__CG__\Tanane\ProductBundle\Entity\Product to scalar, array or
an instance of \ArrayAccess.
And I don't find or know how to fix it, can any give me some help?
I think this is happening because this code
class OrdersHasProductType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('product', 'text', array(
'required' => FALSE,
'label' => FALSE
))
));
}
//...
}
means that Symfony is expecting "product" to be a field of type "text", but when it calls getProduct() on the OrderHasProduct it gets a Product object (or a Doctrine Proxy to a Product, since it's not been loaded at that point). Symfony Fields inherit from Form/AbstractType, so they're essentially Forms in their own right, with just one field, hence the error message.
The solution is either to make that field of type "entity", or to create a different method which only gives the name of the Product, e.g. getProductName() on OrderHasProduct, and then use that as the data behind the field.
I want to add a collection of entities in Symfony 2.1.0-dev bug I got:
Neither property "sitterDegrees" nor method "getSitterDegrees()" nor method "isSitterDegrees()" exists in class "xxx\Entity\Degrees"
It happen because I have an entity in DegreesFormType.php and at this line
$this->form->bindRequest($request); in my handler.
I want to add multiple "degrees" on "sitter" entity (but degrees are a choice not like http://symfony.com/doc/master/cookbook/form/form_collections.html)
Did I forget something?
Entities
A simple ManyToMany between Sitter and Degrees
Sitter
class Sitter
{
//some properties
/**
* #var xxx\Entity\Degrees
* #ORM\ManyToMany(targetEntity="xxx\Entity\Degrees", orphanRemoval=true, inversedBy="sitters",cascade={"persist"})
* #ORM\JoinTable(name="sitter_degrees_relationships",
* joinColumns={
* #ORM\JoinColumn(name="sitter_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="degrees_id", referencedColumnName="id")
* }
* )
*/
private $sitterDegrees;
public function getSitterDegrees()
{
return $this->sitterDegrees;
}
public function setSitterDegrees(ArrayCollection $sitterDegrees)
{
foreach ($sitterDegrees as $sitterDegree) {
$sitterDegree->addSitter($this);
}
$this->sitterDegrees = $sitterDegrees;
}
public function addSitterDegree(xxx\Entity\Degrees $sitterDegrees)
{
$this->sitterDegrees[] = $sitterDegrees;
return $this;
}
public function removeSitterDegree(xxx\Entity\Degrees $sitterDegrees)
{
$this->sitterDegrees->removeElement($sitterDegrees);
}
}
Degrees
class Degrees
{
public function __toString(){return $this->name;}
private $id;
private $name;
/**
* #var xxx\Entity\Sitter
* #ORM\ManyToMany(targetEntity="xxx\Entity\Sitter", mappedBy="sitterDegrees")
*/
private $sitters;
public function __construct()
{
$this->sitters = new \Doctrine\Common\Collections\ArrayCollection();
}
public function getId()
{
return $this->id;
}
public function setName($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
public function getSitters()
{
return $this->sitters;
}
public function addSitter(xxx\Entity\Sitter $sitter)
{
if (!$this->sitters->contains($sitter)) {
$this->sitters->add($sitter);
}
}
public function removeSitter(xxx\Entity\Sitter $sitters)
{
$this->sitters->removeElement($sitters);
}
}
FormType
VerifFormType.php is my main form, it embed DegreesFormType.
VerifFormType.php
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
//->add('some_properties')
->add('sitterDegrees', 'collection', array(
'type' => new DegreesFormType(),
'by_reference' => false,
'allow_add' => true,
'allow_delete' => true,
)
);
}
DegreesFormType.php
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('sitterDegrees', 'entity', array(
'class' => 'xxx:Degrees'
));
}
Controller
public function indexAction()
{
$user = $this->get('security.context')->getToken()->getUser();
$sitter = $user->sitter;
$formHandler = $this->get('xxx.form.handler');
$form = $formHandler->getForm();
$form->setData($sitter);
if ($formHandler->process()) {
//ok
}
//fail
}
Handler
public function process()
{
$request = $this->container->get('request');
if ('POST' == $request->getMethod()) {
$this->form->bindRequest($request);//Fail at this line
if ($this->form->isValid()) {
return $this->onSuccess();
}
}
return false;
}
public function onSuccess()
{
$sitter = $this->form->getData();
$this->form->bindRequest($this->container->get('request'));
$sitter->setContainer($this->container);
$this->container->get('xxx.manager')->persistSitter($sitter);
return true;
}
index.html.twig
With some javascript like in the cookbook http://symfony.com/doc/master/cookbook/form/form_collections.html
<ul class="degrees" data-prototype="{{ form_widget(form.sitterDegrees.getVar('prototype')) | e }}">
{% for sitterDegree in form.sitterDegrees %}
<li>{{ form_row(sitterDegree) }}</li>
{% endfor %}
</ul>
The error comes from DegreesFormType: The sitterDegrees field maps to a setterDegrees property in your Degrees class. However, this class doesn't have such property.
There is a similar problem in VerifFormType: The sitterDegrees field maps to a setterDegrees property in your Sitter class. However, this class doesn't have such property.