Pass data from entity form to controller Symfony3 - symfony

I have entity type class field (dropdown) which generate data from one of my table. I have form sub-agent where user will select a company for that particular sub-agent.
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('company_id', EntityType::class, array(
'label' => 'Company',
'required' => true,
'class' => 'OnlyBundle\Entity\Company',
'choice_label' => 'name', // The Company Name
'choice_value' => 'id', // The Company ID (unique) to be inserted in DB
'expanded' => false,
'multiple' => false,
'placeholder' => 'Choose a Company',
'constraints' => array(
new NotBlank(array("message" => 'Company name is required.')),
),
));
This entity will generate twig like below.
<select id="sub_agent_company_id" name="sub_agent[company_id]" required="required">
<option value="" selected="selected">Choose a Company</option>
<option value="20">ABC</option>
<option value="21">EFG</option>
<option value="22">HIJ</option>
</select>
I want to pass or set the value of dropdown field (20, 21, 22) into my controller, but the problem is, the drop down returns an object from my company class. How do I pass only the value of dropdown and not the whole controller?
Here's my controller.
public function createAction(Request $request) {
$sub_agent = new Sub_agent;
$form = $this->createForm(SubAgentType::class, $sub_agent, array(
'action'=>$this->generateUrl('swipe_backend_sub_agent_create'),
'method'=>'POST'
));
$form->handleRequest($request);
if ('POST' === $request->getMethod()) {
$data = $form->getData();
$sub_agent_name = $data->getName();
var_dump($data->getCompanyId()); exit;
..../

$data->getCompanyId() returns company object. If you want only get its id instead of whole object just call $data->getCompanyId()->getId()

You can get the company's id in the controller, directly from the form with:
$id = $sub_agent->getId();
...assuming you have a getter in your Sub_agent entity class
public function getId(){
return $this->id;
}
But you're missing the whole point here. When you work with Doctrine, forget about "SQL's way", and instead think the whole problem as objects.
Just drop that if ('POST' === $request->getMethod()) and instead add:
if ($form->isSubmitted() && $form->isValid()) {
...
}
which checks if the form was submitted and if it's valid, according to your constraints, set up in the Sub_agent entity, if any.
And in that check I've told you to add, just dump the $sub_agent variable to see what's inside. Don't forget the first thing: in the template you have the corresponding form, add some data you want, and submit that form, then check the dump from the controller.
//...
if ($form->isSubmitted() && $form->isValid()) {
dump($sub_agent); die;
}
So the whole point is that you don't need to worry, or to try to get each individual field from the form, and then to map them to the entity's properties, to be able to save the form data in the database. Doctrine is already doing that for you. All you need to do is to set up the entity (properties + getters and setters), create the form based on that entity, and then add the code I've told you. That's it! Easy enough?

Related

How do you modify entity references on a form in a custom ajax action in Drupal 8?

I have added a custom button to a form:
$form['actions']['autotag_content'] = [
'#type' => 'button',
'#value' => 'Autotag Content',
'#ajax' => [
'callback' => ['\Drupal\taxonomy_migrate\taggerService', 'tagContent'],
'wrapper' => ['block-adminimal-theme-content'],
'progress' => [
'type' => 'throbber',
'message' => 'Tagging content',
],
],
];
Then in the callback I want to add or remove entities from an entity reference field on the form. This would then get sent back to the browser and rerendered. I don't want the changes to be save, I just want them populated in the form and then the user can accept the changes.
For the sake of this example, I have simplified this to just demonstrate the point. I would like to add two entity references to field_tax_subjects and have the frontend form rerender. Currently, the frontend form rerenders, but doesn't reflect the changes
public static function tagContent(array &$form, FormStateInterface &$form_state) {
$node = $form_state->getFormObject()->getEntity();
$node->field_tax_subjects[] = 12345;
$node->field_tax_subjects[] = 23456;
$form = \Drupal::service('entity.form_builder')->getForm($node);
$form_state->setRebuild();
return $form;
}
my answer is just for in case your ajax is working
because in your question you have'nt full code of form
also its not clear its node form or something else
any way
If your ajax is working you only have to correct how to set value for entity reference field and term reference filed
for entity reference and term reference
public static function tagContent(array &$form, FormStateInterface &$form_state) {
$node = $form_state->getFormObject()->getEntity();
// for entity refrence
$node->field_tax_subjects[]['target_id'] = 12345;
$node->field_tax_subjects[]['target_id'] = 23456;
// for term reference
//$node->field_tax_subjects[]['tid'] = 12345;
//$node->field_tax_subjects[]['tid'] = 23456;
$form = \Drupal::service('entity.form_builder')->getForm($node);
$form_state->setRebuild();
return $form;
}
HOPE THIS HELP YOU
THANKS

How to create two related radiobuttons?

The code below creates 2 radiobuttons, however they are not related to each other. One is rendered with a name description_form[friend] and the other one with the name - description_form[guide]. How can they be rendered with the same name? The documentation is not clear about this subject.
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('friend', RadioType::class, array(
'label' => 'Friend',
'required' => false
))
->add('guide', RadioType::class, array(
'label' => 'Guide',
'required' => false
));
}
Using a list of RadioType is not quite easy, that's why everybody recommends you to use a ChoiceType which dynamically creates a radio list depending on an array of choice data.
When you create a FormTypeInterface, it has to represent (commonly) one field or one sub form in a global form, so each field name has to be unique to be mapped to the corresponding data.
The buildForm method allows to add some sub fields in you FormType, in your case the field holds two sub fields as radio button and each has a specific name, this is intended by default, but you should always keep in mind the global array data you want to deal with.
Here's your example :
class MyCustomFormType extends \Symfony\Component\Form\AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('friend', RadioType::class, array(
'label' => 'Friend',
'required' => false
))
->add('guide', RadioType::class, array(
'label' => 'Guide',
'required' => false
));
}
public function getBlockPrefix
{
return 'my_custom';
}
// ...
}
So this form type data should look like :
$myCustomFormData = array(
'friend' => $friendData,
'guide' => $guideData,
);
And nested in a global form it would be :
$formData = array(
'my_custom' => $myCustomFormData,
);
But you can name the field as you want :
// In a controller extending \Symfony\Bundle\FrameworkBundle\Controller\Controller
$form = $this->createFormBuilder()
->add('custom_field', MyCustomFormType::class)
->getForm();
// Then
$form->setData(array('custom_field' => $myCustomFormData));
Note that currently, since you map "friend" and "guide" data to RadioType they should hold a boolean value as :
$myCustomFormData = array(
'friend' => true, // checked
'guide' => false, // unchecked
);
But how would you unselect a value then ?
You should had a placeholder to do that, and handle it while submission...
Also, changing the name can be done using the finishView method of your type class, it takes the FormView (built view of your type), the form itself and the options as arguments :
public function finishView(FormView $view, FormInterface $form, array $options)
{
$childName = $view->vars['full_name']; // "my_custom" by default
foreach ($view as $childView) {
$childView->vars['full_name'] = $childName;
}
}
But you would also need to add a DataMapperInterface to get back the submitted value to the form type itself instead.
To do all that, you need to know how the Form Component works and it's not easy.
Easy way
So I agree with the other answers, you should use a ChoiceType to get it out-of-the-box.
I assume your custom form type is about choosing either a "friend" or a "guide", so it could look like this :
$builder
->add('fellow', ChoiceType::class, array(
'choices' => array(
'I have a friend' => 'friend',
'I\'d like a guide' => 'guide',
),
'expanded' => true, // use a radio list instead of a select input
// ...
Have a look at the official docs
Then your data will look like :
$form->add('custom_field', MyCustomFormType::class);
$form->setData(array(
'custom_field' => 'friend',
));
When rendered the "friend" choice will be selected and you will be able to change it to "guide".
An array of choices for the choices options takes labels as keys and choice values as values :
<div id="form_custom_field">
<input type="radio" name="form[custom_field]" value="friend" checked="checked">
<label>I have a friend</label>
<input type="radio" name="form[custom_field]" value="guide">
<label>I'd like a guide</label>
...
This is how I do radio buttons in Symfony 2.7 , hope it helps you.
$yes_no = array('1'=>'Yes','0'=>'No');
->add('myfieldname', 'choice',array(
'choices' => $yes_no,
'label'=>'YourLabelGoeshere',
'required'=>true,
'expanded'=>true,
'multiple'=>false,
'placeholder'=>false
))
Perhaps consider using the ChoiceType field.
See here: Documentation
This allows you to output the options as radio buttons if you choose.
RadioType is used internally by ChoiceType. In most use cases you want to use ChoiceType.

formMapper: a field twice in a form

I have a form where I ask the user to select a movie from a list that already exists on the database , and if the film does not exist in he must add another label from input.
When I did this I have an error of course :
$formMapper
->add('movie', 'sonata_type_model', array('label'=>'Select a movie', 'query' => $myData))
->add('movie', 'text', array('label'=>'or grasp one', 'required'=>false));
How do I correct this error?
Add property in your entity and check on add form by your own query like:
/* #var $DM \Doctrine\ORM\EntityManager */
$DM = $this->getDoctrine();
$Result = $DM->getRepository('Traffic\ControlBundle\Entity\Movies')->findBy(array('yourfilters' => $yourfilters));
if(count($Result) == 0){
$formbuilder->add('entityPropertyName','text');
}else{
$formbuilder->add('field','entity', array('class' => 'TrafficControlBundle:Movies'));
}
if movie not exists add text field by that property.
And on submit check if form is valid then set that property value in relational entity.
See this:
$em = $this->getDoctrine()->getManager();
$item->setMovieTitle($this->getRequest()->request->get('movie_name_field'));
$em->persist($item);
$em->flush();
You can map only one field to the form (managed by sonata) and manage the other by your own:
$formMapper
->add('movieList', 'sonata_type_model', array('label'=>'Select a movie', 'query' => $myData, 'mapped' => false))
->add('movie', 'text', array('label'=>'or grasp one', 'required'=>false));
Then In your Controller You can get the user choice:
$movieList = $form->get('movieList');
Then you can do whatever you want (create or update your object as exemple )

Render a Collection of Text Fields which is passed to Doctrine array field

In my entity i have an array field:
/**
* #var array
*
* #ORM\Column(name="work_experience", type="array")
*/
private $workExperience;
now i want to render a collection of text fields which will be passed to this array field.
->add('workExperience', 'collection', array(
'type' => 'text',
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
#'by_reference' => false,
'options' => array(
'required' => false,
'attr' => array('class' => 'line-box')
),
))
but now when i render this field, no input is shown? What is my mistake?
{{ form_row(form.workExperience) }}
Thank you
When prototyping, the collection field(s) is only render if your entity has a value assigned to workExperience inside your controller, Otherwise you would need to use javascript to take the prototype info and create the input field(s), this is also true if you want to add new field(s) with or without your entity having any value.
To get the following to render with values
{{ form_row(form.workExperience) }}
You can do something like the following:
public function controllerAction(Request $request)
{
//By populating your entity with values from your database
//workExperience should receive a value and be rendered in your form.
$em = $this->getDoctrine()->getManager();
$entity = $em
->getRepository('yourBundle:entity')
->findBy(...yourParameters...);
$form = $this->createForm('your_form_type', $entity);
...
Or
...
//If you do not have any data in your database for `workExperience`
//then you would need to set it in your controller.
$arr = array('email' => 'name#company.com', 'phone' => '888-888-8888');
$entity->setWorkExperience($arr);
$form = $this->createForm('your_form_type', $entity);
...
Keep in mind that collection are usually used for one-to-many or many-to-many relationships.
Using it for array can be done but there is not much documented on it. While this link is not a perfect fit, the general ideas presented many be helpful: form_collections

What to do when form choice field depends on value of domain object property

What should I do when a form choice field depends on property of
domain object. I have insurance field that should contain insurances
of specific user.
http://pastie.org/2132730
Thanks in advance
If the insurance choices are a known value of the user, then you can pass them in as options when you create your form:
$form = $this->createForm(new AgentContractFormType(), $agentContract, array(
'insurances' => array(/* insurance choices here */),
));
then in your form class:
public function getDefaultOptions(array $options)
{
return array(
'insurances' => $options['insurances'],
'data_class' => 'NTO\DocumentBundle\Entity\Document\AgentContract',
);
}
You can then use them in buildForm() as you please. Hope that helps.

Resources