Why Sonata Admin doesn't save my custom doctrine field? - symfony

I writed the simpliest Money class ever:
class Money
{
private $amount;
private $currency;
// getters and setters here
public function toArray() {
return ['amount' => $this->amount, 'currency' => $this->currency];
}
}
Then I created Doctrine custom type which extend Sonata's JsonType:
class MoneyType extends JsonType
{
/**
* #param Money $value
* #param AbstractPlatform $platform
* #return mixed|null|string
*/
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
return parent::convertToDatabaseValue($value->toArray(), $platform);
}
public function convertToPHPValue($value, AbstractPlatform $platform)
{
return new Money(parent::convertToPHPValue($value, $platform));
}
public function getName()
{
return 'money';
}
}
Then I added it in my config.yml:
doctrine:
dbal:
types:
json: Sonata\Doctrine\Types\JsonType
money: Enl\CurrencyBundle\Doctrine\Type\MoneyType
Then I added form type for this data piece:
class MoneyType extends AbstractType
{
// Some trivial getters and setters for dependencies here
/**
* Returns the name of this type.
*
* #return string The name of this type
*/
public function getName()
{
return 'enl_money';
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults([
'currencies' => $this->getPossibleCurrencies(),
'data_class' => 'Enl\CurrencyBundle\Model\Money'
]);
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('currency', 'choice', ['choices' => $options['currencies'], 'required' => true])
->add('amount', 'number', ['required' => true]);
}
public function getParent()
{
return 'form';
}
}
And then I added the field to my model:
/**
* #var Money
* #ORM\Column(type="money", nullable=true)
*/
protected $price;
And finally my sonata admin form:
$form
->with('editor.dish', ['class' => 'col-md-8'])
->add('price', 'enl_money')
// blah-blah-blah
The problem is that Sonata Admin just doesn't save the form value!
I added var_dump($object); to Admin::update() method - the new value is there in object.
After that I created the simple test:
$dish = new Dish();
$dish->setPrice(new Money(7000, "BYR"));
$em = $this->getContainer()->get('doctrine.orm.entity_manager');
$em->persist($dish);
$em->flush();
It works! What should I change in my Admin class to get this working?

Related

Symfony Form with ManyToMany Mapping

Symfony 3.4 Doctrine 1.9
I have found a lot of articles about this. But nothing could resolve my
problem.
I have two Entities User and Company which are mapped as Many2Many.
Both Entities should be filled with a form submit. Therefor I have the following FormTypes:
CustomerRegistrationType
This includes the CollectionType with entry_type of CompanyFormType, which returns the Company:class
class CustomerRegistrationType extends AbstractType
{
private $translator;
private $session;
public function __construct(TranslatorInterface $translator,Session $session)
{
$this->session = $session;
$this->translator = $translator;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('mandant',HiddenType::class,array('data'=>
->add('newsletter',CheckboxType::class,array('label' => false,'required' => false))
->add('company', CollectionType::class, array('entry_type' => CompanyFormType::class, 'entry_options' => array('label' => false)));
}
CompanyFormType
class CompanyFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
$builder->add('telephone', TextType::class,array('required' => false))
->add('company_name', TextType::class,array('label' => false,'required' => false))
->add('company_supplement', TextType::class,array('label' =>
->add('send_info', CheckboxType::class,array('label' => false,'required' => false))
->add('send_invoice', CheckboxType::class,array('label' => false,'required' => false))
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Company'));
}
}
Many2Many mapping
class User extends BaseUser
{
public function __construct()
{
parent::__construct();
$this->company = new ArrayCollection();
}
/**
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Company",inversedBy="users")
* #ORM\JoinTable(name="user_comp_comp_user",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="company_id", referencedColumnName="id")}
* )
*/
protected $company;
public function getCompany()
{
return $this->company;
}
public function setCompany($company)
{
$this->company = $company;
return $this;
}
public function addCompany(Company $company)
{
if ($this->company->contains($company)) {
return;
}
$this->company[] = $company;
return $this;
}
public function removeCompany(Company $company)
{
if (!$this->company->contains($company)) {
return;
}
$this->company->removeElement($company);
return $this;
}
class Company
{
public function __construct()
{
$this->users = new ArrayCollection();
}
/**
* #var \Doctrine\Common\Collections\Collection|Company[]
* #ORM\ManyToMany(targetEntity="User",mappedBy="company")
*/
protected $users;
}
In the Controller I want to save all Data to the different Entities.
Therefor I do:
public function registerAction(Request $request)
{
$user = $this->userManager->createUser();
$form = $this->createForm(CustomerRegistrationType::class,$user);
$form->handleRequest($request);
$company = $user->getCompany();
$company->setSendInvoice(true);
$company->setSendInfo(true);
if ($form->isSubmitted()){
$user->addCompany($company);
$this->userManager->updateUser($user);
....
}
return $this->render('Registration/register.html.twig',[
'form' => $form->createView()
]);
}
I does not matter, which way I try, eachtime I get an error. In this example, the company data is empty. Other ways are in conflict with the ArrayCollection() of $this->company in User()
User {#907 ▼
#id: null
#company: ArrayCollection {#926 ▼
-elements: []
}
#groups: null
#mandant: null
#salutation: null
#first_name: null
#last_name: null
#fullname: null
#created: DateTime #1544539763 {#901 ▶}
#telephone: null
Update:
In Twig form I have no access to
{{ form_widget(form.company.company_name, {'attr': {'class': 'form-control'}})}}
Neither the property "company_name" nor one of the methods "company_name()", "getcompany_name()"/"iscompany_name()"/"hascompany_name()" or "__call()" exist and have public access in class "Symfony\Component\Form\FormView".
This comes up before form submit.
I found the solution here:
https://groups.google.com/forum/#!topic/symfony2/DjwwzOfUIuQ
So I used an array based form in the controller
$form = $this->createFormBuilder()
->add('user', CustomerRegistrationType::class, array(
'data_class' => 'AppBundle\Entity\User'
))
->add('company', CompanyFormType::class, array(
'data_class' => 'AppBundle\Entity\Company'
))
->getForm();
The different Objects can catched like this:
$form->handleRequest($request);
$user = $form->get('user')->getData();
$company = $form->get('company')->getData();
and then
if ($form->isSubmitted()){
...
$user->addCompany($company);
$this->userManager->updateUser($user);
}
That's it

Symfony2 forms and many to many relation

(Symfony version 2.7)
Hi, I have a problem with form in field with many to many relation.
Class Notification {
public function __construct()
{
$this->assigneduser = new \Doctrine\Common\Collections\ArrayCollection();
$this->flags = new ArrayCollection();
}
/**
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Flag", inversedBy="notificationflags", cascade={"persist"})
* #ORM\JoinTable(name="sla_notificationflags",
* joinColumns={#ORM\JoinColumn(name="notification_id", referencedColumnName="notificationId")},
* inverseJoinColumns={#ORM\JoinColumn(name="flag_id", referencedColumnName="flagId")}
* )
*
*/
private $flags;
/**
* Add flag
*
* #param \AppBundle\Entity\Flag $flag
* #return Notification
*/
public function addFlag(Flag $flag)
{
$flag->addNotificationflag($this);
$this->flags[] = $flag;
return $this;
}
}
Class Flag {
public function __construct()
{
$this->notificationflags = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Notification", mappedBy="flags")
*/
protected $notificationflags;
/**
* Add notificationflags
*
* #param \AppBundle\Entity\Notification $notificationflag
* #return Flag
*/
public function addNotificationflag(Notification $notificationflag)
{
if(!$this->notificationflags->contains($notificationflag)) {
$this->notificationflags->add($notificationflag);
}
return $this;
}
}
My Form Class
class NotificationSingleFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('flags','entity',array(
'label' => false,
'attr' => array(
'class' => 'select'
),
'class' => 'AppBundle\Entity\Flag',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('p')
->addOrderBy('p.name','ASC');
},
'property' => 'name',
'required' => false
)
);
}
}
When i send the form i see error:
Neither the property "flags" nor one of the methods
"addFlag()"/"removeFlag()", "setFlags()", "flags()", "__set()" or
"__call()" exist and have public access in class
"AppBundle\Entity\Notification".
You have to genrate getters/setters and add/remove methods of flag attribute.
use php app/console doctrine:generate:entities to generate them automatically

Extending EntityType to allow extra choices set with AJAX calls

I try to create a Symfony Custom type extending the core "entity" type.
But I want to use it with Select2 version 4.0.0 (ajax now works with "select" html element and not with hidden "input" like before).
This type should create an empty select instead of the full list of entities by the extended "entity" type.
This works by setting the option (see configureOption):
'choices'=>array()
By editing the object attached to the form it should populate the select with the current data of the object. I solved this problem but just for the view with the following buildView method ...
Select2 recognize the content of the html "select", and does its work with ajax.
But when the form is posted back, Symfony doesn't recognize the selected choices, (because there were not allowed ?)
Symfony\Component\Form\Exception\TransformationFailedException
Unable to reverse value for property path "user": The choice "28" does not exist or is not unique
I tried several methods using EventListeners or Subscribers but I can't find a working configuration.
With Select2 3.5.* I solved the problem with form events and overriding the hidden formtype, but here extending the entitytype is much more difficult.
How can I build my type to let it manage the reverse transformation of my entites ?
Custom type :
<?php
namespace AppBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
class AjaxEntityType extends AbstractType
{
protected $router;
public function __construct($router)
{
$this->router = $router;
}
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->setAttribute('attr',array_merge($options['attr'],array('class'=>'select2','data-ajax--url'=>$this->router->generate($options['route']))));
}
/**
* {#inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['attr'] = $form->getConfig()->getAttribute('attr');
$choices = array();
$data=$form->getData();
if($data instanceOf \Doctrine\ORM\PersistentCollection){$data = $data->toArray();}
$values='';
if($data != null){
if(is_array($data)){
foreach($data as $entity){
$choices[] = new ChoiceView($entity->getAjaxName(),$entity->getId(),$entity,array('selected'=>true));
}
}
else{
$choices[] = new ChoiceView($data->getAjaxName(),$data->getId(),$data,array('selected'=>true));
}
}
$view->vars['choices']=$choices;
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setRequired(array('route'));
$resolver->setDefaults(array('choices'=>array(),'choices_as_value'=>true));
}
public function getParent() {
return 'entity';
}
public function getName() {
return 'ajax_entity';
}
}
Parent form
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class AlarmsType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name','text',array('required'=>false))
->add('user','ajax_entity',array("class"=>"AppBundle:Users","route"=>"ajax_users"))
->add('submit','submit');
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array('data_class' => 'AppBundle\Entity\Alarms','validation_groups'=>array('Default','form_user')));
}
/**
* #return string
*/
public function getName()
{
return 'alarms';
}
}
Problem solved.
The solution is to recreate the form field with 'choices'=>$selectedChoices in both PRE_SET_DATA and PRE_SUBMIT FormEvents.
Selected choices can be retrived from the event with $event->getData()
Have a look on the bundle I created, it implements this method :
Alsatian/FormBundle - ExtensibleSubscriber
Here is my working code which adds to users (EntityType) related to tag (TagType) ability to fill with options from AJAX calls (jQuery Select2).
class TagType extends AbstractType
{
//...
public function buildForm(FormBuilderInterface $builder, array $options)
{
$modifyForm = function ($form, $users) {
$form->add('users', EntityType::class, [
'class' => User::class,
'multiple' => true,
'expanded' => false,
'choices' => $users,
]);
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($modifyForm) {
$modifyForm($event->getForm(), $event->getData()->getUsers());
}
);
$userRepo = $this->userRepo; // constructor injection
$builder->addEventListener(
FormEvents::PRE_SUBMIT,
function (FormEvent $event) use ($modifyForm, $userRepo) {
$userIds = $event->getData()['users'] ?? null;
$users = $userIds ? $userRepo->createQueryBuilder('user')
->where('user.id IN (:userIds)')->setParameter('userIds', $userIds)
->getQuery()->getResult() : [];
$modifyForm($event->getForm(), $users);
}
);
}
//...
}
here's my approach based on Your bundle just for entity type in one formtype.
Usage is
MyType extends ExtensibleEntityType
(dont forget parent calls on build form and configure options)
and the class itself
abstract class ExtensibleEntityType extends AbstractType
{
/**
* #var EntityManagerInterface
*/
private EntityManagerInterface $entityManager;
/**
* ExtensibleEntityType constructor.
* #param EntityManagerInterface $entityManager
*/
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
public function getParent()
{
return EntityType::class;
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
$builder->addEventListener(FormEvents::PRE_SET_DATA, [$this, 'preSetData']);
$builder->addEventListener(FormEvents::PRE_SUBMIT, [$this, 'preSubmit'], 50);
}
/**
* #param FormEvent $event
*/
public function preSetData(FormEvent $event)
{
$form = $event->getForm();
$parent = $event->getForm()->getParent();
$options = $form->getConfig()->getOptions();
if (!$options['pre_set_called']) {
$options['pre_set_called'] = true;
$options['choices'] = $this->getChoices($options, $event->getData());
$parent->add($form->getName(), get_class($this), $options);
}
}
/**
* #param FormEvent $event
*/
public function preSubmit(FormEvent $event)
{
$form = $event->getForm();
$parent = $event->getForm()->getParent();
$options = $form->getConfig()->getOptions();
if (!$options['pre_submit_called']) {
$options['pre_submit_called'] = true;
$options['choices'] = $this->getChoices($options, $event->getData());
$parent->add($form->getName(), get_class($this), $options);
$newForm = $parent->get($form->getName());
$newForm->submit($event->getData());
}
}
public function configureOptions(OptionsResolver $resolver)
{
parent::configureOptions($resolver);
$resolver->setDefaults([
'multiple' => true,
'expanded' => true,
'choices' => [],
'required' => false,
'pre_set_called' => false,
'pre_submit_called' => false,
'validation_groups' => false,
]);
}
/**
* #param array $options
* #param $data
* #return mixed
*/
public function getChoices(array $options, $data)
{
if ($data instanceof PersistentCollection) {
return $data->toArray();
}
return $this->entityManager->getRepository($options['class'])->findBy(['id' => $data]);
}
}

Model transformer and expected form view data mismatch

I have a Symfony 2 application, with a form that needs to store a reference to another entity (project) in a hidden field. The project entity is passed in via the form options, my plan was to have a field of the type 'hidden' that simply contains the entity id, this should then be transformed into a project entity on when the form is submitted.
I'm going about this by using a model transformer to transform between the entity to a string (it's ID). However when I try to view the form, I get the following error:
The form's view data is expected to be an instance of class Foo\BarBundle\Entity\Project, but is a(n) string. You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms a(n) string to an instance of Foo\BarBundle\Entity\Project.
Here is my form class:
<?php
namespace Foo\BarBundle\Form\SED\Waste;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Foo\BarBundle\Form\DataTransformer\EntityToEntityIdTransformer;
/**
* Class WasteContractorEntryType
* #package Foo\BarBundle\Form\CommunityInvestment\Base
*/
class WasteContractorEntryType extends AbstractType
{
protected $name;
protected $type;
protected $phase;
protected $wasteComponent;
public function __construct($formName, $type, $phase, $wasteComponent)
{
$this->name = $formName;
$this->type = $type;
$this->phase = $phase;
$this->wasteComponent = $wasteComponent;
}
/**
* #return mixed
*/
public function getType()
{
return $this->type;
}
/**
* #return mixed
*/
public function getPhase()
{
return $this->phase;
}
/**
* #return mixed
*/
public function getProject()
{
return $this->project;
}
/**
* #return mixed
*/
public function getWasteComponent()
{
return $this->wasteComponent;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$em = $options['em'];
$wasteComponentTransformer = new EntityToEntityIdTransformer($em,
'Foo\BarBundle\Entity\SED\Waste\WasteComponent');
$projectTransformer = new EntityToEntityIdTransformer($em, 'Foo\BarBundle\Entity\Project');
$builder->add('id', 'hidden');
$builder->add(
$builder->create('project', 'hidden', array(
'data' => $options['project'],
'by_reference' => false
))
->addModelTransformer($projectTransformer)
);
$builder->add(
$builder->create('wasteComponent', 'hidden', array(
'data' => $this->getWasteComponent()
))
->addModelTransformer($wasteComponentTransformer)
);
$builder->add('phase', 'hidden', array(
'data' => $this->getPhase()
));
$builder->add('type', 'hidden', array(
'data' => $this->getType()
));
$builder->add('percentDivertedFromLandfill', 'text', array());
$builder->add('wasteContractor', 'entity', array(
'class' => 'Foo\BazBundle\Entity\Contractor',
'property' => 'name',
'attr' => array(
'class' => 'js-select2'
)
));
}
public function getName()
{
return $this->name;
}
/**
* {#inheritDoc}
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'csrf_protection' => true,
'data_class' => 'Foo\BarBundle\Entity\SED\Waste\WasteContractorEntry'
))
->setRequired(array(
'em',
'project'
))
->setAllowedTypes(array(
'em' => 'Doctrine\Common\Persistence\ObjectManager',
'project' => 'Foo\BarBundle\Entity\Project'
));
}
}
And my model transformer class:
<?php
namespace Foo\BarBundle\Form\DataTransformer;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
use Doctrine\Common\Persistence\ObjectManager;
class EntityToEntityIdTransformer implements DataTransformerInterface
{
/**
* #var ObjectManager
*/
private $om;
/**
* #var Entity class
*/
protected $entityClass;
/**
* #param ObjectManager $om
*/
public function __construct(ObjectManager $om, $className)
{
$this->om = $om;
$this->entityClass = $className;
}
protected function getEntityClass()
{
return $this->entityClass;
}
/**
* Transforms an object (project) to a string (id).
*
* #param Project|null $issue
* #return string
*/
public function transform($entity)
{
if (null === $entity) {
return "";
}
return $entity->getId();
}
/**
* Transforms a string (id) to an object (project).
*
* #param string $id
*
* #return Issue|null
*
* #throws TransformationFailedException if object (project) is not found.
*/
public function reverseTransform($id)
{
if (!$id) {
return null;
}
$entity = $this->om
->getRepository($this->getEntityClass())
->find($id);
if (null === $entity) {
throw new TransformationFailedException(sprintf(
'An entity of class %s with id "%s" does not exist!',
$this->getEntityClass(),
$id
));
}
return $entity;
}
}
I've tried using a adding the transformer as a view transformer instead of a model transformer, however then I just get a slightly different error:
The form's view data is expected to be an instance of class
Foo\BarBundle\Entity\Project, but is a(n) integer. You can avoid this
error by setting the "data_class" option to null or by adding a view
transformer that transforms a(n) integer to an instance of
Foo\BarBundle\Entity\Project.
It seems that setting 'data_class' to null as suggested by the exception message above is the solution. I had previously rejected this as it seems counter-intuitive when we know that the purpose of the field is to reference a project entity.
With the 'data_class' option set to null, the hidden project field contains the project id, and upon submission, calling getProject() on the created entity returns the correct project object.

Cannot generate one web form by attaching two entities to it

I have a 1 to n relationship so one Brand has many Cars. What I want to do is to create only one web form where all the fields from both of the entities get displayed. To do that I created a form type but I think I'm doing something wrong because I' getting error below when trying to print the form fields in twig. Could anyone tell me where am I doing wrong?
Error:
Method "brand" for object "Symfony\Component\Form\FormView" does not exist in CarBrandBundle:Default:both.html.twig at line 1
Entities:
class BrandEntity
{
protected $name;
protected $origin;
//Followed by getters and setters
/**
* #ORM\ManyToOne(targetEntity="BrandEntity", inversedBy="car")
* #ORM\JoinColumn(name="brand_id", referencedColumnName="id", nullable=false)
* #var object $brand
*/
protected $brand;
}
class CarEntity
{
protected $model;
protected $price;
//Followed by getters and setters
/**
* #ORM\OneToMany(targetEntity = "CarEntity", mappedBy = "brand")
* #var object $car
*/
protected $car;
public function __construct()
{
$this->car = new ArrayCollection();
}
public function addCar(\Car\BrandBundle\Entity\CarEntity $car)
{
$this->car[] = $car;
return $this;
}
public function removeCar(\Car\BrandBundle\Entity\CarEntity $car)
{
$this->car->removeElement($car);
}
}
Form Type:
namespace Car\BrandBundle\Form\Type;
use Car\BrandBundle\Entity\BrandEntity;
use Car\BrandBundle\Entity\CarEntity;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Test\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class BothType extends AbstractType
{
public function builder(FormBuilderInterface $builder, array $options)
{
$builder
->setAction($options['action'])
->setMethod('POST')
->add('brand', new BrandEntity())
->add('car', new CarEntity())
->add('button', 'submit', array('label' => 'Add'))
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
//'data_class' => 'Car\BrandBundle\Entity\CarEntity',
'cascade_validation' => true
));
}
public function getName()
{
return 'both';
}
}
Controller:
namespace Car\BrandBundle\Controller;
use Car\BrandBundle\Form\Type\BothType;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class BothController extends Controller
{
public function indexAction()
{
$form = $this->getFrom();
return $this->render('CarBrandBundle:Default:both.html.twig',
array('page' => 'Both', 'form' => $form->createView()));
}
private function getFrom()
{
return $this->createForm(new BothType(), null,
array('action' => $this->generateUrl('bothCreate')));
}
}
Twig:
{{ form_row(form.brand.name) }}
{{ form_row(form.brand.origin) }}
{{ form_row(form.car.model) }}
{{ form_row(form.car.price) }}
If you want a "car form" in which you need to choose a brand, then the other answer will be ok.
If what you want is a "brand form" in which you can add /edit/delete several cars, then you need to embed a Collection of Forms.
The cookbook answer is here: http://symfony.com/doc/current/cookbook/form/form_collections.html
To render a brand form containing a collection of car forms (1-n relationship):
The form types will look like this:
The brand type
// src/Acme/TaskBundle/Form/Type/BrandType.php
//...
class BrandType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('description');
$builder->add('cars', 'collection', array('type' => new CarType()));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\BrandBundle\Entity\Brand',
));
}
public function getName()
{
return 'brand';
}
}
The car type:
namespace Acme\CarBundle\Form\Car;
//...
class TagType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\CarBundle\Entity\Car',
));
}
public function getName()
{
return 'car';
}
}
Then the controller and the views just like in the cookbook. It's very powerful and easy in the end.
To add entities to a form you must use the entity field type: from the docs
$builder->add('users', 'entity', array(
'class' => 'AcmeHelloBundle:User',
'property' => 'username',
));
In this case, all User objects will be loaded from the database and rendered as either a select tag, a set or radio buttons or a series of checkboxes (this depends on the multiple and expanded values). If the entity object does not have a __toString() method the property option is needed.
Also please post the relationships.

Resources