Symfony embed form ManyToOne relation - forms

I'm trying to improve a personal application but I'm getting into trouble with an embed form. In fact, I have an advertType form in which I want to add a field in order to choose the skill and the level attached to the advert.
In that way, I have an advert entity, a skill entity, an advertSkill entity which is referencing advert and skill entities thanks to a OneToMany relation. The level attribute is from the advertSkill entity.
I don't know how to proceed to add a skill field in my advert form so as to the advert will be correctly stored with the corresponding skill and level.
There is no attribute in my advert entity which is referencing skill.
Below, a sample of my advertType class :
$builder
->add('date', DateTimeType::class, array(
'view_timezone' => 'Europe/Paris',
'with_seconds' => true
))
->add('title', TextType::class)
->add('content', TextareaType::class)
->add('author', TextType::class)
->add('email', TextType::class)
->add('image', ImageType::class)
->add('categories', EntityType::class, array(
'class' => 'OCPlatformBundle:Category',
'choice_label' => 'name',
'multiple' => true
))
->add('save', SubmitType::class);
Thanks for help, I can give more details about my code but it's just ugly when I put some code with the .

I tried to go ahead reading some advices on the same problem as me on a french forum but I have got a mistake yet because I don't suceed in displaying my skills name and my levels name.
My AdvertType form class :
enter code here $builder
->add('date', DateTimeType::class, array(
'view_timezone' => 'Europe/Paris', // On affiche l'horaire avec le fuseau horaire de Paris
'with_seconds' => true // On ajoute les secondes àl'affichage de l'horaire
))
->add('title', TextType::class)
->add('content', TextareaType::class)
->add('author', TextType::class)
->add('email', TextType::class)
->add('image', ImageType::class)
->add('categories', EntityType::class, array(
'class' => 'OCPlatformBundle:Category',
'choice_label' => 'name',
'multiple' => true
))
->add('advertSkill', CollectionType::class, array(
'entry_type' => AdvertSkillType::class
))
->add('save', SubmitType::class);
My new AdvertType form class :
enter code here public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('advertSkill', EntityType::class, array(
'class' => 'OCPlatformBundle:Skill',
'choice_label' => 'name'
))
->add('level', EntityType::class, array(
'class' => 'OCPlatformBundle:AdvertSkill',
'choices' => array('Débutant', 'Intermédiaire', 'Expert')
));
}
Moreover, I added a OneToMany attribute "advertSkill" in the two classes referenced by the advertSkill class.
I don't understand how to make it works !

Related

Symfony4 - Can't get error_mapping to work

In my Symfony4 project, I have an entity called 'Customer'. This entity has an extra validation method to do some extra validation for the field 'zip code'. When a zip code is invalid i receive a general error.
/**
#Assert\IsTrue(message = "invalid.zipcode")
*/
public function isZipCodeValid()
{
...
return false;
}
I would like to map this specific error to the 'zip code' field so i can show users which field is causing the issue.
I have tried the following code in the CustomerForm, as mentioned in the Symfony documentation: https://symfony.com/doc/current/reference/forms/types/form.html#error-mapping
....
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Customer::class,
'error_mapping' => [
'isZipCodeValid' => 'zip_code',
],
]);
}
Unfortunately this keeps sending a global error after posting my form. Not sure why.. Does anyone knows how to fix this? Thanks!
buildForm:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class, array('label' => 'Name', 'attr' => array('size' => '50')))
->add('address_line', TextType::class, array('label' => 'Addressline', 'attr' => array('size' => '50')))
->add('zip_code', TextType::class, array('label' => 'Zipcode', 'attr' => array('size' => '20')))
->add('city', TextType::class, array('label' => 'City', 'attr' => array('size' => '50')));
}

Symfony 3 : Build forms for entities based on Traits

I'm having a hard time building forms for my entities that are themselves built with traits.
For example my "Article" entity only contains the link to the category and 2 pics, the rest of its properties is in the SeoTrait (title, meta_title, meta_desc, content, etc...), ValidTrait (isValid true/false)... which I want to use for other entities.
It all works fine for doctrine, that generates my schema with all the fields from the Traits in each entity that use them. The problem is for the forms :
I've created the SeoTraitType for the "SEO" properties :
class SeoTraitType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class, array(
'label' => 'Nom'
))
->add('metaTitle', TextType::class, array(
'label' => 'Meta Title'
))
->add('metaDescription', TextareaType::class, array(
'label' => 'Meta Description'
))
->add('metaKeywords', TextType::class, array(
'label' => 'Keywords'
))
->add('content', TextareaType::class, array(
'label' => 'Content'
))
;
}
}
And then I'm using it in my ArticleType :
class ArticleType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('seo', SeoTraitType::class, array(
'label' => 'Seo',
'mapped' => false
))
->add('isValid', ValidTraitType::class, array(
'label' => 'Valid',
'mapped' => false
))
->add('save', SubmitType::class, array(
'label' => 'form_save',
'translation_domain' => 'back_default'
));
;
}
}
The two problems I have here is that I must set mapped => false for the 2 TraitTypes when I want to embed them in my main entity's form
And then in my form I get article[seo][name] for the SeoTrait's fields, so I can't really use the $form->handleRequest() methods and all... to handle the submission of my form
I was wondering if there is a special way to do this within the provided methods of the form component, or if I just have to handle the request myself and parse the trait arrays myself to build my entity before saving it ? I couldn't really find anything on the internet :(
One way to solve your problem is to transform your class SeoTraitType into a Trait.
like:
trait SeoTraitType
{
public function buildSEOForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class, array(
'label' => 'Nom'
))
->add('metaTitle', TextType::class, array(
'label' => 'Meta Title'
))
->add('metaDescription', TextareaType::class, array(
'label' => 'Meta Description'
))
->add('metaKeywords', TextType::class, array(
'label' => 'Keywords'
))
->add('content', TextareaType::class, array(
'label' => 'Content'
))
;
}
}
Then:
class ArticleType extends AbstractType
{
use SeoTraitType;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$this->buildSEOForm($builder, $options);
$builder
->add('isValid', ValidTraitType::class, array(
'label' => 'Valid',
'mapped' => false
))
->add('save', SubmitType::class, array(
'label' => 'form_save',
'translation_domain' => 'back_default'
));
;
}
}
You can also do this with static method. Not a big fan of Trait.
Ok so the Trait solution works fine, but I chose to go for this method here :
https://symfony.com/doc/current/form/inherit_data_option.html
Thanks so much guys, I was pretty sure that the solution would be somewhere in the documentation but couldn't find it !

How can I get the id and the name of the pupils in the table "eleve" in a FormType?

You can see here my FormType.
And I would like to let appear a drop down menu with the pupils name as a value and the id as the key.
Something like this :
->add('eleve', 'choice', array(
'choices' => array(id of the pupil => name of the pupil),
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('eleve', 'entity', array(
'class' => 'WCSCantineBundle:Eleve'
))
->add('status', 'choice', array(
'choices' => array('0' => 'Non-Inscrit'),
'label' => false
))
->add('date', 'text', array(
'label' => false
))
->add('Ajouter', 'submit');
}
Thank you for your help.
->add('eleve', 'entity', array(
'class' => 'WCSCantineBundle:Eleve'
'choice_label' => 'pupilname',
))
here pupil name would be the name of the field in your Eleve entity
this would create a drop down menu with all the Eleve records loaded from the database, on submission the id of the selection would be submitted through the form
Read more here

remove entity from entity form field if custom condition is matched

I have an unsubscribe form, where the first field is a entity field, fetching my UnsubscribeType entities :
$builder
->add('type', 'entity', array(
'class' => 'Evo\SubscriptionBundle\Entity\UnsubscribeType',
'property' => 'name',
'label' => 'Choose process type',
'empty_value' => 'Choose an option',
'empty_data' => null,
'label_attr' => array(
'class' => 'control-label',
),
'attr' => array(
'class' => 'form-control',
),
))
this collection contains 2 entities, #1 and #2. I would like to remove entity #2 from the select field if a custom test about the authed user fails.
Let's say I'd to test $this->getUser()->getCustomField(). If it is false, then i would like to remove entity #2 from the select field containing my UnsubscribeType entities.
Any idea how to do that ?
Perhaps you could pass to the form builder the result of the test from you controller and then, either use 'property' => 'name' or 'choices => // fetch entity #1 here.
So, something like this
public function buildForm(FormBuilderInterface $builder, array $options)
{
if($options['customField'] === TRUE)
{
$builder
->add('type', 'entity', array(
'class' => 'Evo\SubscriptionBundle\Entity\UnsubscribeType',
'property' => 'name',
// ..
;
}
else
{
$builder
->add('type', 'entity', array(
'class' => 'Evo\SubscriptionBundle\Entity\UnsubscribeType',
'choices' => $options['customField'],
// ..
;
}
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
// ..
$resolver->setRequired(array(
'customField'
));
}
And in your controller:
$form = $this->get('form.factory')->create(new EntryType(), $entry, array(
'customField' => $this->getUser()->getCustomField()
));
with getCustomField() returning either true or the entity (or collection of entities) that you want populating your select field. My solution would involve changing the getCustomField method though, don't know if that would suit.

Symfony2 form populating entitiy based on other entity

I'm using Symfony2 form component to create and modify forms. I'm currently loading all model entities as choices, but I need to get only the Models related to the selected (posted) value from manufacturer.
How can I achieve this?
class VehicleType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('manufacturer', 'entity', array(
'label' => 'Brand',
'attr' => array('class' => 'input-block-level'),
'class' => 'BalslevCarBundle:Manufacturers',
'property' => 'short_name',
'empty_value' => 'All',
'required' => false
));
$builder->add('model', 'entity', array(
'label' => 'Model',
'class' => 'BalslevCarBundle:Models',
'property' => 'model',
'empty_value' => 'All',
'required' => false
));
}
public function getName()
{
return 'search';
}
}
First of all, you have to create "dynamically" your choices based onto user selection.
There are two ways, strictly coupled with your application behaviour, that leads (in both cases) at the same "core" code; the difference is only the way you call it.
So, let's explain the two possibilities:
Select manufacturer "statically" and don't change it over the time of request: use data retrieved from your business logic
Select manufacturer "dinamically" and can change them over the time of request: replace your form at every request; new form will be provided by business logic
So, the HEART of your question is: how can I retrieve only associated entities?
Answer
Into your VehicleType.php (where entity, in this case, is VehicleType ?)
private $manufacturerId;
public function __construct($manufacturerId)
{
$this->manufacturerId = $manufacturerId;
}
public function BuildForm(FormBuilderInterface $builder)
{
$manufacturerId = $this->manufacturerId;
$manufacturerQuery = function(EntityRepository $repo) use ($manufacturerId ){
return $repo->createQueryBuilder('m')
->where('m.id = :id')
->setParameter('id',$manufacturerId );};
$builder->add('manufacturer', 'entity', array(
'label' => 'Brand',
'attr' => array('class' => 'input-block-level'),
'class' => 'BalslevCarBundle:Manufacturers',
'property' => 'short_name',
'empty_value' => 'All',
'required' => false,
'query_builder' => $manufacturerQuery;
));
$builder->add('model', 'entity', array(
'label' => 'Brand',
'attr' => array('class' => 'input-block-level'),
'class' => 'BalslevCarBundle:Manufacturers',
'property' => 'short_name',
'empty_value' => 'All',
'required' => false,
'query_builder' => $modelQuery;
));
}
As you can see, in this way we use a custom repository to get only entities that are suitable for our needs. Obviously I am writing my DQL query without knowing your DB structure: it's your task and responsibility to adapt it to your real situation.
Moreover, you have to create another query for model (called $modelQuery in my answer) to retrieve correct models based on selected $id