Symfony Forms - dynamic number of items - symfony

I'm trying to build a product page that will contain a form with a dynamic number of "options" (either select boxes or input fields) depending on the product. After reading the documentation, I can't see how to create a form entity that would work when building this form. I feel like I'm missing something obvious.

What you need to do is basically create form field of collection type, which will be your collection of select boxes, input fields, whatever.
Check documentation and read about embeding forms, it is described pretty well ther
Your parent form:
class ParentType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('id', 'hidden')
->add('name')
->add('yourCollection', 'collection', array(
'type' => new ChildType(),
'label' => 'Label for your child form',
));
}
}
Your child form:
class ChildType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('id', 'hidden')
->add('category', 'choice')
;
}
}

Related

add object if only it doesn't already exists (Embedded Forms) Symfony 2

I need some help. I have a form that adds a medical record, which is linked to the entity patient by a manyToOne relationship.
MedicalRecordType.php
class MedicalRecordType extends AbstractType {
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('service','text');
$builder->add('patient','collection', array('type' => new PatientType()));
$builder->add('piece','collection', array('type' => new PieceType()));
}
}
PatientType.php
class PatientType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('Firstname', 'text')
->add('Secondname', 'text')
->add('DateOfBirth', 'date', array(
'widget' => 'single_text',
'format' => 'yyyy-MM-dd',
))
;
}
when adding a new medical record, I do not want to add Patient data along with it if a patient already exists in the database. Thanks for any suggestions.
i'm aware that i can do this with a simple condition in the controller, but it's gonna take a lot of code, i was wondering if there is an easier way with symfony.
You will need a oneToMany relationship in your entities:
One MedicalReport holds many Patient entities.
Than you can do something like this in your form-builder:
$builder->add('patients','entity', array(
'class' => 'YourBundle:Patient',
));
and if your entity mapping is correct doctrine will automatically insert or update the needed rows

how to remove a form field in embedded forms from symfony 2 controller

I have a form as below:
class AdminEmployerForm extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('firstName', 'text')
->add('user', new AdminUserForm());
}
}
class AdminUserForm extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('username', 'text')
->add('email', 'text');
}
}
I am calling AdminEmployerForm in controller and I want to remove email field of AdminUserForm from AdminEmployerForm:
$form = $this->createForm(new AdminEmployerForm, $employer);
//i want to do something like $form->remove('email')
how can i do use $form->remove() to remove field in embedded form? Is it possible to remove a field of embedded form from controller?
You'll have to get the embedded form type to remove a field from it.
$form = $this->createForm(new AdminEmployerForm, $employer);
// Get the embedded form...
$adminUserForm = $form->get('user');
// ... remove its email field.
$adminUserForm->remove('email');
Not sure of your exact use-case, but you may consider leveraging form events as it may be more ideal than handling this in the controller.

Symfony 2 not validating entities in a collection form type?

My form uses the uploads collection type. Each element of the collection is of UploadType:
class MultiUploadType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('uploads', 'collection', array(
'type' => new UploadType(), // This should be validated
'allow_add' => true,
));
$builder->add('Save', 'submit');
}
}
Using javascript I'm able to add new uploads, but validation doesn't work. I've read many questions here (here, here or here) but I can't find a solution yet.
This is how the upload type looks like, while validation is defined using YAML, as the form has a corresponding entity of type Upload (file can't be blank):
class UploadType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('file', 'file');
$builder->add('description', 'textarea');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'required' => false,
'data_class' => 'App\Entity\Upload'
));
}
}
Validation code:
App\Entity\Upload:
properties:
file:
- NotBlank:
message: Occorre selezionare un file.
- File: ~
From comments disscusion:
Yes, basically each form should have a data class. It has not to be a entity, a simple model class is enough. So you can apply validation to it. To validate embed forms the Valid assert is required and for collections the same but with the option traverse: true.

Symfony2 + Doctrine2 / building a form from 2 joined entity objects

Is it possible to build a form from 2 joined entity objects?
I have two entities property & propertylanguage which are joined on onetomany relation.
(One property can have many languages)
Language has a title and description colomns.
So one property can have a english, french, german title.
I am trying to build a form out of that.
See below.
Controller: addProperty.php
class AddPropertyController extends Controller
{
// ....
public function indexAction(Request $request)
{
$property = new property;
$language = new propertyLanguage;
$property ->addpropertylanguage($language);
$form = $this->createForm(new propertyType($this->getDoctrine()),$property);
// .....
}
Form type: propertType.php
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('title', 'text');
// other ->add() below.
}
It returns the following error:
Neither property "title" nor method "getTitle()" nor method
"isTitle()" exists in class "\defaultBundle\Entity\property"
Of course there is no property Title in property, but there is one in propertylanguage..
Even if I try:
->add('title', 'entity', array('class'=>defaultBundle:propertylanguage));
it doesn't work.
Thanks if you have time to help me.
Best,
Pierre.
What you will want to do is make a PropertyLanguageType class as well as a PropertyType.
Then, in your PropertyType you will embed the PropertyLanguageType:
public function buildForm(FormBuilder $builder, array $options)
{
// $builder->add('propertyLanguage', new PropertyLanguageType());
// Since we have a 1 to many relation, then a collection is needed
$builder->add('propertyLanguage', 'collection', array('type' => new PropertyLanguageType()));
The PropertyLanguageType is where you add the title.
It's all in the forms section in the manual but it might take several readings.
A second approach is to add a getTitle to your Property entity which would return the title from the PropertyLanguage entity. By doing this, your original form will work. But it can be a bit of a mess when you start to have multiple associations with multiple attributes. Best to just define a type for each entity.
You could use a query_builder when defining the form. Here's how your form class might look like. Of course it will certainly not be exactly as so but that will give you a good start ;)
public function __construct($id)
{
$this->propertylanguageId = $id;
}
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('propertylanguage', 'entity', array(
'label' => 'Property Language',
'class' => 'YourAdressToBundle:Propertylanguage',
'query_builder' => function(EntityRepository $er) use ($propertylanguageId) {
return $er->createQueryBuilder('p')
->join('p.property', 'prop', Expr\Join::WITH, 'prop.id = :propertylanguageId')
->setParameter('propertylanguageId', $propertylanguageId);
},
));
}
Hope that'll be helpful

Display ManyToOne field in Symfony2 forms?

I am having two entity files one as user.php and another as usertype.php. now i want to display a login form with 3 fields viz username, password and usertype. the usertype will be a selection that will fetch data from usertype table. here is the code that i wrote inside user.php to create a manytoone field for usertype_id
/**
* #ORM\ManyToOne(targetEntity="Usertype")
*/
protected $usertype;
Below is my Form generation Code
class LoginForm extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('login', 'text', array('label' => 'Username',));
$builder->add('password');
}
}
Now I need to add one more field to my form builder that will be a selection of usertype table.
...
use Acme\YourBundle\Entity\Usertype;
class LoginForm extends AbstractType {
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('usertype', 'entity',
array(
'class' => 'AcmeYourBundle:Usertype'
'label' => 'User Type',
)
);
}
}
You can read more informations about the entity field type wich will give you the options available for this type of field.
Don't forget to add a __toString() method to your model to tell the form builder what to display.
namespace Acme\YourBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
class Usertype
{
public function __toString()
{
return $this->getName();
}
}
There are other ways to do it, but you can try this:
$builder->add('usertype', 'entity',
array(
'class' => 'YourBundle:UserType
'required' => true, // Choose if it's required or not
'empty_value' => 'User type', // Remove this line if you don't want empty values
'label' => 'Type', // You can put a label here or remove this line
)
);
I hope it helped!
http://symfony.com/doc/2.0/reference/forms/types/entity.html
property¶
type: string
This is the property that should be used for displaying the entities as text in the HTML element. If left blank, the entity object will be cast into a string and so must have a __toString() method.

Resources