Symfony submit button doesn't flush/update the entity properly - forms

My entity "corporation" has two ManyToMany relationships with
entity "User" and
entity "Agency"
The related data, I'd like to display as a table with a EntityType-dropdown to (un-)select data.
Therefor I have the following form:
$builder
->add('usercorporations', EntityType::class, array(
'class' => 'UserBundle:User',
'query_builder' => function (EntityRepository $er) use ($corporationMarket) {
return $er->createQueryBuilder('e')
->andWhere(':marketIds MEMBER OF e.markets')
->setParameter('marketIds',$corporationMarket)
->orderBy('e.lastName', 'ASC');
},
'choice_label' => function($user) {
return $user->getFirstName() . ' ' . $user->getLastName() ;
},
'expanded' => false, 'multiple' => true,
'required'=>false,
'by_reference' => false,
'empty_value' => "label.select_user",
'translation_domain' => 'Agency'))
->add('agencies', EntityType::class, array(
'class' => 'AppBundle:Agency',
'query_builder' => function (EntityRepository $er){
return $er->createQueryBuilder('a')
->addOrderBy('a.account', 'ASC');
},
'label' => 'label.agencies',
'choice_label' => function($agency) {
return $agency->getId() . ' - ' . $agency->getAccount() . ' - ' . $agency->getCityName() . ', ' . $agency->getState();
},
'expanded' => false, 'multiple' => true,
'required' => false,
'translation_domain' => 'Agency',
));
my twig template includes the two dropdowns as well as two tables for each of the entities.
{{ form_start(form) }}
{# This renders a red banner if the form contains errors.
If the form variable is not called "form", pass it explicitly. #}
{% include 'Form/form_errors_banner.html.twig' %}
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-body">
<legend>{{ 'label.assignedUsers'|trans }}</legend>
{{ form_widget(form.usercorporations) }}
<br>
<br>
{% include 'UserBundle:User:AssignedUsers.html.twig' %}
</div>
</div>
</div>
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-body">
<legend>{{ 'label.assignedAgencies'|trans }}</legend>
{{ form_widget(form.agencies) }}
<br>
<br>
{% include 'AppBundle:Agency:AssignedAgencies.html.twig' with {'entity': corporation} %}
</div>
</div>
</div>
<div>
<input type="submit" class="btn-primary btn" value="{{ 'label.apply'|trans }}"/>
</div>
{{ form_end(form) }}
</div>
I'm using the tables (AssignedUsers and AssignedAgencies) on other pages too, that's all working fine.
So now my problem:
I'd like to have the possibility to simply add and remove users or agencies. By just deselecting e.g. a user from the dropdown and then submitting, it's working, the user isn't assigned to the corporation anymore. Somehow, the same procedure is not working for the agencies. I don't know why though, I dumped the data prior to and after the flush and it's dumping the correct data, but when I return to the corporation, nothing changed.
My controller action:
/**
* #Route("/corporation/{id}/{page}", name="appBundle_corporation", requirements={"id" = "\d+", "page" = "\d+"}, defaults={"page" = 1}))
*/
public function corporationAction($id, Request $request, $page)
{
$repository = $this->getDoctrine()
->getRepository('AppBundle:Corporation');
$em = $this->getDoctrine ()->getManager ();
$corporation = $repository->findOneById($id);
/*
* CREATE PAGINATION FOR TABLES
*/
//assigned Users
$assignedUsers = $corporation->getUsercorporations();
$assignedAgencies = $corporation->getAgencies();
dump($assignedAgencies);
$form = $this->createForm(CorporationAssignmentType::class,$corporation, array(
'corporationMarket' => $corporationMarket,
));
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em->persist($corporation);
$em->flush();
dump($assignedAgencies);
$this->addFlash(
'success',
'Your changes were saved!'
);
return $this->redirectToRoute('appBundle_corporation', array('id' => $corporation->getId()));
}
return $this->render('AppBundle::corporation.html.twig', array(
'item' => $corporation,
'corporation'=>$corporation,
'assignedUsers'=>$userTable,
'assignedAgencies' => $agencyTable,
'form' => $form->createView(),
));
}
any ideas why it's flushing the users but not the agencies?

I solved my problem that way, but it might be that #ASOlivieri 's answer could've helped es well.
What I did initially is:
in Entity Agency
/**
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Corporation", inversedBy="agencies", cascade={"persist"})
* #ORM\JoinTable(name="app_agency_corporations",
* joinColumns={#ORM\JoinColumn(name="agency_id", referencedColumnName="iata8")},
* inverseJoinColumns={#ORM\JoinColumn(name="corporation_id", referencedColumnName="ucid")})
* #var \AppBundle\Entity\Corporation
**/
private $corporations;
in Entity Corporation
/**
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Agency", mappedBy="corporations")
**/
private $agencies;
when switching it --> the shorter code to the Agency's property corporations and the longer code about the JoinTable etc. to the Corporation's property agencies it worked.
If anybody could explain to me why this is the solution, I'd be happy!

If your entities work in other places (other controllers, etc.) then I suspect you have to by_reference to false in your agencies form options.
->add('agencies', EntityType::class, array(
'class' => 'AppBundle:Agency',
'query_builder' => function (EntityRepository $er){
return $er->createQueryBuilder('a')
->addOrderBy('a.account', 'ASC');
},
'label' => 'label.agencies',
'choice_label' => function($agency) {
return $agency->getId() . ' - ' . $agency->getAccount() . ' - ' . $agency->getCityName() . ', ' . $agency->getState();
},
'expanded' => false, 'multiple' => true,
'required' => false,
'by_reference' => false,
'translation_domain' => 'Agency',
));
It looks as though it's set that way in your user form options.

Related

Symfony4 Form not submitted

I have a problem with my Form in symfony4, when I click on the submit button it is not submitted (It doesn't pass the isSubmitted condition)
Here is my Form
<?php
namespace App\Form\Backend\Team;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
/**
* Class AddTeamForm
* #package App\Form\Backend\Team
*/
class TeamForm extends AbstractType
{
const NAME = 'name';
const WEBSITE = 'website';
const IRC = 'irc';
const DISCORD = 'discord';
const TWITTER = 'twitter';
const FACEBOOK = 'facebook';
const HIDDEN = 'hidden';
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('id', HiddenType::class)
->add(self::NAME, TextType::class, [
'required' => true,
'label' => 'admin.team.form.name'
])
->add(self::WEBSITE, TextType::class, [
'required' => false,
'label' => 'admin.team.form.website'
])
->add(self::IRC, TextType::class, [
'required' => false,
'label' => 'admin.team.form.irc'
])
->add(self::DISCORD, TextType::class, [
'required' => false,
'label' => 'admin.team.form.discord'
])
->add(self::TWITTER, TextType::class, [
'required' => false,
'label' => 'admin.team.form.twitter'
])
->add(self::FACEBOOK, TextType::class, [
'required' => false,
'label' => 'admin.team.form.facebook'
])
->add(self::HIDDEN, CheckboxType::class, [
'required' => false,
'label' => 'admin.team.form.hidden'
]);
}
}
and Here is my action
/**
* #Route("/add", name="add")
*/
public function add(Request $request)
{
$form = $this->createForm(TeamForm::class);
$form->handleRequest($request);
if ($form->isSubmitted()) {
var_dump('submitted');
if($form->isValid())
{
} else {
var_dump('non vlide');exit;
}
$team = $form->getData();
}
return $this->render('backend/team/add.html.twig', [
'form' => $form->createView(),
]);
}
and my view
{{ form_start(form, {attr: {class: 'ui form inverted', novalidate:'novalidate', 'action': url('admin_team_add')} }) }}
{{ form_errors(form) }}
<div class="ui grid two column">
<div class="row">
<div class="twelve wide column">
{{ form_row(form.name) }}
{{ form_row(form.website) }}
{{ form_row(form.irc) }}
{{ form_row(form.discord) }}
{{ form_row(form.twitter) }}
{{ form_row(form.facebook) }}
<div class="field">
<div class="ui checkbox">
{{ form_widget(form.hidden) }}
{{ form_label(form.hidden) }}
{{ form_errors(form.hidden) }}
</div>
</div>
<input type="submit" class="ui button green" value="{{ 'admin.team.form.btn-create' }}"/>
</div>
</div>
</div>
{{ form_end(form) }}
Like I said, When I click my submit button, the var_dump 'submitted' is not shown. The page refreshes but nothing happen, like a normal page refresh.
I must miss something but can't figure what ...
you can check if your route name exist:
php bin/console debug:router admin_team_add
if it's not exist , change your view action to :
{{ form_start(form, {attr: {class: 'ui form inverted', novalidate:'novalidate', 'action': url('add')} }) }}
or change your controller route name to :
/**
* #Route("/add", name="admin_team_add")
*/
public function add(Request $request)
{

I can not display the password field input (with 'repeat' option) with twig (Symfony2)

I have the following form and Twig template:
FormType
class UserType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name','text',array('label' => 'Name', 'max_length' => 30))
->add('surname','text',array('label' => 'Sjurname', 'max_length' => 30))
....
->add('password', 'repeated', array('error_bubbling' => true,'required' => false, 'first_options' => array('label' => 'New Password'),'second_options' => array('label' => 'Repeat Password'),'type' => 'password' ,'invalid_message'=> 'Passwords must be the same.'));
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Bundle\Entity\User',
));
}
/**
* #return string
*/
public function getName()
{
return 'user';
}
}
Twig
....
{{form_start(form, {'method':'Put','attr':{'data-toggle':"validator", 'role':"form" ,'novalidate':'novalidate', 'autocomplete':'off'}})}}
{{ form_errors(form) }}
<div class="form-group has-feedback">
{{ form_label(form.password, 'New Password:',{'label_attr':{'class': 'col-md-5'}}) }}
<div class="col-md-7">
{{ form_widget(form.password,{'attr':{'class': 'form-control', 'type': 'password','data-error': 'You must enter a minimum of 6 characters', 'placeholder': 'Min 6 characters', 'data-minlength':"6", 'required':'true' }}) }}
<span class="glyphicon form-control-feedback" aria-hidden="true"></span>
<div class="help-block with-errors"></div>
</div>
</div>
{{ form_row(form.submit,{'attr':{'class': 'btn btn-primary pull-right' }}) }}
<div class="hidden">
{{ form_rest(form) }}
</div>
{{ form_end(form) }}
...
The problem I have is that the input is not created. The label is displayed. I have tried using form.password.first and form.password.second but neither is the input (only the labels). With the other fields I do not have that problem, the only thing in this case all the others are hidden in a div. What could be the problem?
I appreciate your help.
Take a look at this. it is for symfony 2.8/3+ but you can adapt it to your needs.
FormType
->add('plainPassword', RepeatedType::class, [
'type' => PasswordType::class,
'first_options' => [
'label' => 'registration.password',
],
'second_options' => [
'label' => 'registration.retype.password',
],
]) ...
twig
<div>
{{ form_label(form.plainPassword.first) }}
{{ form_widget(form.plainPassword.first) }}
{{ form_errors(form.plainPassword.first) }}
</div>
<div>
{{ form_label(form.plainPassword.second) }}
{{ form_widget(form.plainPassword.second) }}
{{ form_errors(form.plainPassword.second) }}
</div>
Do you have a version of xDebug installed? You could place a breakpoint on the return section of the Controller and have a look inside the children element of the form. This could tell you what the names of the elements are.
**PS, I would have commented this but I don't have enough rep.

Double textarea? Symfony 2 with FOSU

i have this weird problem, and i really dont know why this happens.
The text areas are doubled and their position is bad.
Look at the image.
So, the builder looks like:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('imie', 'text', array('label' => false, 'translation_domain' => 'FOSUserBundle'))
->add('nazwisko', 'text', array('label' => false, 'translation_domain' => 'FOSUserBundle'))
->add('username', null, array('label' => false, 'translation_domain' => 'FOSUserBundle'))
->add('email', 'email', array('label' => false, 'translation_domain' => 'FOSUserBundle'))
->add('telefon', 'number', array('label' => false, 'translation_domain' => 'FOSUserBundle'))
->add('plainPassword', 'repeated', array(
'type' => 'password',
'options' => array('translation_domain' => 'FOSUserBundle'),
'first_options' => array('label' => false),
'second_options' => array('label' => false),
'invalid_message' => 'fos_user.password.mismatch',
))
->add('captcha', 'captcha', array(
'label' => ' ',
'width' => 200,
'height' => 50,
'length' => 6,
'invalid_message' => 'The captcha code is invalid.'
))
;
}
and the html.twig
http://pastebin.com/2pbHqNyH
Note that im using symfony with twig for 2 weeks and im begginer. And im also new to the FOSU. I just want to change the default look of register form from FOSU to suitable for my site.
That is because your repeated password contains 2 fields, so the plainPassword field rendering contains invalid css structure.
Replace:
<div class="form-group">
{{ form_label(form.plainPassword, 'Hasło:', {'label_attr': {'class': 'col-sm-3 control-label'}}) }}
<div class="col-sm-5">
{{ form_widget(form.plainPassword, {'attr': {'class':'form-control' }}) }}
{{ form_errors(form.plainPassword) }}
</div>
</div>
By:
<div class="form-group">
{{ form_label(form.plainPassword.first, 'Hasło:', {'label_attr': {'class': 'col-sm-3 control-label'}}) }}
<div class="col-sm-5">
{{ form_widget(form.plainPassword.first, {'attr': {'class':'form-control' }}) }}
{{ form_errors(form.plainPassword.first) }}
</div>
</div>
<div class="form-group">
{{ form_label(form.plainPassword.second, 'Hasło:', {'label_attr': {'class': 'col-sm-3 control-label'}}) }}
<div class="col-sm-5">
{{ form_widget(form.plainPassword.second, {'attr': {'class':'form-control' }}) }}
{{ form_errors(form.plainPassword.second) }}
</div>
</div>
More details: http://symfony.com/doc/current/reference/forms/types/repeated.html

Symfony2 interaction between forms, problems if validation fails

I have 2 forms which display the following:
They are created dynamically, not from entities.
My controller is the following:
<?php
...create the relevant array $rolesListForForm
$form = $this->createFormBuilder()->getForm(); //create empty form
$HRsInThisProject = $em->getRepository('AppBundle:User')->findUsersByProject($prj);
foreach ($HRsInThisProject as $key => $HR)
{
$form->add('roleOf_'.$key, 'choice', array('choices' => $rolesListForForm, 'required' => true, 'data' => $HR['role'], 'label' => false, ));
$form->add('isActive_'.$key, 'choice', array('choices' => [0 => 'Inactive', 1 => 'Active'] , 'required' => true, 'data' => $HR['is_active'], 'label' => false, ));
}
...create the relevant array $HRsInMyDomainForForm
$form->add('showinactive', 'checkbox', array('label' => 'Show inactive users', 'required' => false, 'data' => true, ));
$form->add('HRid', 'choice', array('choices' => $HRsInMyDomainForForm,'required' => false, 'placeholder' => 'Choose a resource', 'label' => false, ));
$form->add('role', 'choice', array('choices' => $rolesListForForm,'required' => false, 'placeholder' => 'Choose a role', 'label' => false, ));
$form->add('save', 'submit', array('label' => 'Save'));
$form->handleRequest($request);
// If form is valid
if ($form->isValid())
{
...lots of logic here to understand if persisting or not stuff on DB, then I simply refresh the current page
return $this->redirect($this->generateUrl('hr_manage', array('projectID' => $prj->getId())));
}
//creation of the second form
$formGlobalSearch=$this->createFormBuilder()
->add('username', 'text', array('constraints' => new UsernameExists()))
->add('role', 'choice', array('choices' => $rolesListForForm,'required' => false, 'placeholder' => 'Choose a role', 'label' => false, ))
->add('submitUsername', 'submit', array('label' => 'Search username globally'))
->getForm();
$formGlobalSearch->handleRequest($request);
if ($formGlobalSearch->isValid())
{
//persist stuff on DB and refresh current page
return $this->redirect($this->generateUrl('hr_manage', array('projectID' => $prj->getId())));
}
return $this->render('HR/show.html.twig', array('projectID' => $prj->getId(), 'hrlist' => $HRsInMyDomain, 'form' => $form->createView(), 'HRs' => $HRsInThisProject, 'formGlobalSearch' => $formGlobalSearch->createView(),));
It all works smoothly, the only problem occurs when the second form throws a validation error. When it does the top form is not properly rendered anymore, I see stuff like this:
Here is the relevant part of the twig:
{{ form_start(form) }}
{{ form_row(form.showinactive) }}
<table>
<tr>
<td>User ID</td>
<td>Name</td>
<td>Role</td>
<td>Started</td>
<td>Status</td>
</tr>
{% for key, HR in HRs %}
<tr>
<td>{{ key }}</td>
<td>{{ HR.name }}</td>
<td>{{ form_row(form['roleOf_' ~ key]) }}</td>
<td>{{ HR.started_at|date('Y-m-d H:i:s') }}</td>
<td>{{ form_row(form['isActive_' ~ key]) }}</td>
</tr>
{% endfor %}
</table>
<br>
Add new resource:
{{ form_row(form.HRid) }}{{ form_row(form.role) }}
{{ form_row(form.save) }}
{{ form_end(form) }}
<br>
Or you can search for a user of ProJacked at global level
{{ form_start(formGlobalSearch) }}
{{ form_errors(formGlobalSearch) }}
{{ form_widget(formGlobalSearch) }}
{{ form_end(formGlobalSearch) }}
Any idea?

Overriding forms template Symfony2, twig elements?

i'm trying to override a template for some forms.
This one being one of them
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('nombreBD','text', array( 'required' => true, 'label' => 'Nombre Base de Datos: '))
->add('Servidor','choice', array(
'choices' => array('1' => 'Si', '0' => 'No'),
'required' => true,
'multiple' => false,
'expanded' => true,
'label' => 'Servidor Existente?',
))
->add('ServidorBD','entity',
array ('class' => 'MonseWebBundle:ServidoresBD',
'multiple' => true,
'required' => true,
'label' => 'Servidor de Base de Datos: ',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('u')
->orderBy('u.url', 'ASC');
},
))
;
}
And this being the template
{% block text_widget %}
<div class="round full-width-input" id="full-width-input">
<input type="text" {{ block('attributes') }} value="{{ value }}" >
</div>
{% endblock %}
I think i succeded in the text inputs but i've got no idea how to set up the ones for the entity and the ones for the radio buttons (choice) because i don't know where the information is stored. For example, i don't quite know what block ('attributes') nor {{value}] return. Same as i don't know how to make of the radiobuttons selected.
I wanted to use this:
<label for="dropdown-actions">Dropdown</label>
<select id="dropdown-actions">
<option value="option1">Select your action here</option>
</select>
for the entity "ServidoresBD" and this:
<label for="selected-radio" class="alt-label"><input type="radio" id="selected-radio" checked="checked" />A selected radio</label>
<label for="unselected-radio" class="alt-label"><input type="radio" id="unselected-radio" />An uselected radio</label>
for the radio buttons.
Also, for a weird reason, all the labels in ALL the project appear as upper-case, no matter what style i put them. ALWAYS and this is really annoying.
Any help would be greatly appreciated.
The default form theming is stored under the Twig bridge. Here, you can find all blocks which are defined in the form theme.
Just take a look to this file & IMO, you will understand what you need to do. :)
Hope that helps.