How to save and edit multiple value using checkbox - symfony

I am working in Symfony2 and I have a Form where I show checkboxes which came out of a Database. I want to save the selected checkboxes in the Database (mayby as a array or string like value1, value2). How can I handle this
This is my Code:
Entity:
/**
* #var string
*/
private $relevantewaben;
/**
* #return string
*/
public function getRelevantewaben()
{
return $this->relevantewaben;
}
/**
* #param string $relevantewaben
*/
public function setRelevantewaben($relevantewaben)
{
$this->relevantewaben = $relevantewaben;
}
Controller:
public function newAction()
{
$entity = new ChangeRequest();
$form = $this->createCreateForm($entity);
return $this->render('OtlgCmdbBundle:ChangeRequest:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
public function updateAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('OtlgCmdbBundle:ChangeRequest')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find ChangeRequest entity.');
}
$deleteForm = $this->createDeleteForm($id);
$editForm = $this->createEditForm($entity);
$editForm->handleRequest($request);
if ($editForm->isValid()) {
$em->flush();
return $this->redirect($this->generateUrl('changerequest_edit', array('id' => $id)));
}
return $this->render('OtlgCmdbBundle:ChangeRequest:edit.html.twig', array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
Form:
->add('relevantewaben', 'entity', array(
'class' => 'OtlgCmdbBundle:applicant',
'label' => 'Benötigte, relevante Waben zur Umsetzung',
'property' => 'name',
'expanded' => true,
'required' => false,
'multiple' => true,
'attr' => array('class' => 'css-checkbox')

If you declare the relationship between you entity and OtlgCmdbBundle:applicant, where your entity is the owner side of the relationship, Doctrine will take your changes in account automatically. For example, instead of
/**
* #var string
*/
private $relevantewaben;
you should have sth like
/**
* #var \Doctrine\Common\Collections\ArrayCollection
* #ORM\OneToMany(targetEntity="applicant", mappedBy="changeRequests", cascade={"persist"})
*/
private $relevantewaben;
Take a look at : http://docs.doctrine-project.org/en/2.0.x/reference/association-mapping.html
If what you want to save is not the relationship but, in fact, the checkboxes selected themselves:
In your controller, the variable $entity has all your changes when you enter if ($editForm->isValid()) {, so you could do $entity->getRelevantewaben() to get which ones where selected.
When you have a field that's not mapped, you can access that data with $form->get('relevantewaben')->getData(), and that's the value that you have in the form field. I haven't use it to get values that were already mapped, but that can give you an idea if that's your case.

Related

How to load data in ChoiceType choices options from the database

I want to build a form with ChoiceType and the option values/choices are based on database table (with records already).
When the form displayed, the list of religions will be available at the dropdown list/combo box.
Example :
$builder->add('name', ChoiceType::class, array(
'choices' => $religions //List of religions
));
So far here are my codes:
class Religion
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=50)
*/
protected $name;
/*** getter/setter ... ***/
}
/Form/ReligionType
class ReligionType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', ChoiceType::class, array(
'choices' => ____________
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Religion'
));
}
public function getName()
{
return 'app_bundle_religion_type';
}
}
/Controller
/**
* #Route("/religion/select", name="religion_select")
*
*/
public function selectAction()
{
$em = $this->getDoctrine()->getManager();
$religions = $em->getRepository('AppBundle:Religion')->findAll();
$form = $this->createForm(ReligionType::class, ________);
return $this->render(
'religion/index.html.twig', array(
'form' => $form->createView()
)
);
}
I don't really know what to write so i leave it as __________ and what are the missing codes.
/ReligionRepository
class ReligionRepository extends EntityRepository
{
public function findAll()
{
return $this->getEntityManager()
->createQuery(
'SELECT p FROM AppBundle:Religion p ORDER BY p.name ASC'
)
->getResult();
}
}
/Twig File
{% extends 'base.html.twig' %}
{% block body %}
{{ form_start(form) }}
{{ form_widget(form) }}
<button type="submit">Save</button>
{{ form_end(form) }}
{% endblock %}
as suggested by Rvanlaak, here's the solution.
//ReligionType
$builder->add('religions', EntityType::class, array(
'class' => 'AppBundle\Entity\Religion',
'choice_label' => 'name'
));
//Controller
public function newAction(Request $request)
{
$religion = new Religion();
$form = $this->createForm(ReligionType::class, $religion);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($religion);
$em->flush();
//return $this->redirectToRoute('homepage');
}
return $this->render(
'religion/new.html.twig',
array(
'form' => $form->createView()
)
);
}
I did like this:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('currency', null, [
'expanded' => true,
'multiple' => true,
'label' => 'Currency'
])
In my entity like this:
protected $currency;
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->Currency = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* #param \MyBundle\Entity\Currency $Currency
*
* #return $this
*/
public function addCurrency(\MyBundle\Entity\Currency $Currency)
{
$this->Currency[] = $Currency;
return $this;
}
/**
* Remove Currency
*
* #param \MyBundle\Entity\Currency $Currency
*/
public function removeCurrency(\MyBundle\Entity\Currency $Currency)
{
$this->Currency->removeElement($Currency);
}
/**
* Get Currency
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getCurrency()
{
return $this->Currency;
}
Both posted solutions didn't work for me because the ChoiceType type was removed from it. Here is a solution with the ChoiceType still existing:
I wanted to generate a list with types of absents users can choose from. These types are created by a user in the system settings. I first load them from db, then create one array (for loop) with where the ["name"] will be the name the user sees. The id is the value that the html select field will have and return when selected and saved.
What I added and could not find anywhere was the extra option to pass an option in the createForm function. This enables you to send data to the form basicly.
$systemAbsents = $this->getDoctrine()->getRepository(SystemAbsent::class)->getAllNonDeletedSystemAbsents();
$choices = [];
// Add each choice to the list. The id's have to match correctly so the html choicetype will return the chosen id that then will be saved in the db.
for ($i = 0; $i < count($systemAbsents); $i++) {
$choices += [$systemAbsents[$i]["name"] => $systemAbsents[$i]["id"]];
}
$absent = new Absent();
// Create form and pass the choices to later connect them with the ChoiceType field.
$form = $this->createForm(AbsentType::class, $absent, ['choices' => $choices]);
$form->handleRequest($request);
Then in the form, you can use the data and pass it to the 'choices' option.
public function buildForm(FormBuilderInterface $builder, array $options)
{
$this->choices = $options['choices'];
$builder
->add('choices', ChoiceType::class, [
'choices' => $this->choices,
'label_attr' => [
'class' => 'bold',
],
'attr' => [
'class' => 'input-margin select-field w-100',
],
'mapped' => false,
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'choices' => [],
]);
}
The array I create in the for loop looks like this:
[
"absent-type-1" => 10
"absent-type-2" => 11
"absent-type-3" => 12
"absent-type-4" => 13
"absent-type-5" => 14
"absent-type-6" => 15
"absent-type-7" => 16
"absent-type-8" => 17
]
The ID starts at 10 because I deleted some while testing.
If you by default want to show a selected value in the ChoiceType field you can do setData after you create the form. Like this:
// Create form
$form = $this->createForm(AbsentType::class, $absent, ['choices' => $choices]);
// Add this line to set a default. But make sure you pass the value equal to the html `value` attribute.
$form->get('system_absents')->setData($absent->getSystemAbsentID());
$form->handleRequest($request);
There is a possiblity you get an Array to string conversion error. I dont know how exactly this works but i've once used this solution before.

EntityForm on a ManyToMany bidirectional, for the two sides of the relation

I've 2 entity: User and Strain with a ManyToMany bidirectional relation, the owner of the relation is User.
I want do a form for edit the rights (the User own some Strains), when I do a form for the User where I can select some Strains I want, it works fine (I use an EntityType on Strain). But... Sometimes, I want edit the rights by the other side of the relation: Strain. ie edit the Strain and select the Users I want. But it doesn't work...
I give you my entities User and Strain and the two FormType, and my Uglys Solution...
User.php
/**
* The authorized strains for this user.
*
* #var Strain|ArrayCollection
*
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Strain", inversedBy="authorizedUsers")
*/
private $authorizedStrains;
/**
* User constructor.
*/
public function __construct()
{
$this->authorizedStrains = new ArrayCollection();
}
/**
* Add an authorized strain.
*
* #param Strain $strain
*
* #return $this
*/
public function addAuthorizedStrain(Strain $strain)
{
$this->authorizedStrains[] = $strain;
$strain->addAuthorizedUser($this);
return $this;
}
/**
* Remove an authorized strain.
*
* #param Strain $strain
*/
public function removeAuthorizedStrain(Strain $strain)
{
$this->authorizedStrains->removeElement($strain);
$strain->removeAuthorizedUser($this);
}
/**
* Get authorized strains.
*
* #return Strain|ArrayCollection
*/
public function getAuthorizedStrains()
{
return $this->authorizedStrains;
}
Strain.php
/**
* The authorized user.
* For private strains only.
*
* #var User|ArrayCollection
*
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\User", mappedBy="authorizedStrains")
*/
private $authorizedUsers;
/**
* Strain constructor.
*/
public function __construct()
{
/**
* Add authorized user.
*
* #param User $user
*
* #return $this
*/
public function addAuthorizedUser(User $user)
{
$this->authorizedUsers[] = $user;
return $this;
}
/**
* Remove authorized user.
*
* #param User $user
*/
public function removeAuthorizedUser(User $user)
{
$this->authorizedUsers->removeElement($user);
}
/**
* Get authorized users.
*
* #return User|ArrayCollection
*/
public function getAuthorizedUsers()
{
return $this->authorizedUsers;
}
UserRightsType.php
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('authorizedStrains', EntityType::class, array(
'class' => 'AppBundle\Entity\Strain',
'choice_label' => 'name',
'expanded' => true,
'multiple' => true,
'required' => false,
))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\User',
));
}
StrainRightsType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('authorizedUsers', EntityType::class, array(
'class' => 'AppBundle\Entity\User',
'query_builder' => function(UserRepository $ur) {
return $ur->createQueryBuilder('u')
->orderBy('u.username', 'ASC');
},
'choice_label' => function ($user) {
return $user->getUsername().' ('.$user->getFirstName().' '.$user->getLastName().')';
},
'expanded' => true,
'multiple' => true,
'required' => false,
))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Strain',
));
}
StrainController.php the ugly solution
public function userRightsAction(Request $request, Strain $strain)
{
$form = $this->createForm(StrainRightsType::class, $strain);
$form->add('save', SubmitType::class, [
'label' => 'Valid the rights',
]);
foreach($strain->getAuthorizedUsers() as $authorizedUser) {
$authorizedUser->removeAuthorizedStrain($strain);
}
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
foreach($strain->getAuthorizedUsers() as $authorizedUser)
{
$authorizedUser->addAuthorizedStrain($strain);
$em->persist($authorizedUser);
}
$em->flush();
$request->getSession()->getFlashBag()->add('success', 'The user\'s rights for the strain '.$strain->getName().' were successfully edited.');
return $this->redirectToRoute('strain_list');
}
return $this->render('strain/userRights.html.twig', [
'strain' => $strain,
'form' => $form->createView(),
]);
}
As you can see, I do 2 foreach: the first to remove all the rights on the Strain, and the second to give rights.
I think Symfony have anticipated this problem, but I don't know how to do, and I've found nothing in the documentation...
Thank you in advance for your help,
Sheppard
Finaly, I've found.
On the inversed side (Strain.php):
public function addAuthorizedUser(User $user)
{
$user->addAuthorizedStrain($this);
$this->authorizedUsers[] = $user;
return $this;
}
public function removeAuthorizedUser(User $user)
{
$user->removeAuthorizedStrain($this);
$this->authorizedUsers->removeElement($user);
}
And, on the owner side (User.php)
public function addAuthorizedStrain(Strain $strain)
{
if (!$this->authorizedStrains->contains($strain)) {
$this->authorizedStrains[] = $strain;
}
return $this;
}
public function removeAuthorizedStrain(Strain $strain)
{
if ($this->authorizedStrains->contains($strain)) {
$this->authorizedStrains->removeElement($strain);
}
}
And in the FormType (for the inverse side) (StrainRightsType)), add 'by_reference' => false
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('authorizedUsers', EntityType::class, array(
'class' => 'AppBundle\Entity\User',
'query_builder' => function(UserRepository $ur) {
return $ur->createQueryBuilder('u')
->orderBy('u.username', 'ASC');
},
'choice_label' => function ($user) {
return $user->getUsername().' ('.$user->getFirstName().' '.$user->getLastName().')';
},
'by_reference' => false,
'expanded' => true,
'multiple' => true,
'required' => false,
))
;
}

Automatically set related entity id in one to many relationship Symfony

I have a many to one related entities and everytime I create a new comment which is related to Project, I want to automatically save the realted project_id.
comment
id
comment
manyToOne
project:
targetEntity: Project
cascade: { }
mappedBy: null
inversedBy: comments
joinColumn:
name: project_id
referencedColumnName: id
orphanRemoval: false
project
id
projectName
oneToMany:
comments:
targetEntity: Comment
mappedBy: project
When using Annotation, this can be done easily using the ParamConverter, but in this case I am using Yaml format.I am using the Symfony nice Crud command to automatically generate forms and templates as well as the controllers.
I tried in controller this way
public function createAction(Request $request, Project $project)//Project
{
$entity = new Comment();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
// $entity->setProject($projectName->getProject());
$entity->setProject($project);
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('comment_show', array('id' => $entity->getId())));
}
Then in form,
{{ form(form) }}
The problem with this is it will generate a form with a dropdown with hundreds of project_id in comment project_id field
Then when submitted
Unable to guess how to get a Doctrine instance from the request information.
I am thinking of writing a jquery autocomplete to solve this but if there is more shortcut way of doing this, like the annotation Paramconverter, I am glad to use it
How would you do it so that the related project_id will be automatically saved?
Update
This is exactly the code when running Symfony2 nice crud command in console
<?php
namespace EdgeWeb\Project\EmployeeBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use EdgeWeb\Project\EmployeeBundle\Entity\Comment;
use EdgeWeb\Project\EmployeeBundle\Form\CommentType;
/**
* Comment controller.
*
*/
class CommentController extends Controller
{
/**
* Lists all Comment entities.
*
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('EmployeeBundle:Comment')->findAll();
return $this->render('EmployeeBundle:Comment:index.html.twig', array(
'entities' => $entities,
));
}
/**
* Creates a new Comment entity.
*
*/
public function createAction(Request $request)
{
$entity = new Comment();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('comment_show', array('id' => $entity->getId())));
}
return $this->render('EmployeeBundle:Comment:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
/**
* Creates a form to create a Comment entity.
*
* #param Comment $entity The entity
*
* #return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(Comment $entity)
{
$form = $this->createForm(new CommentType(), $entity, array(
'action' => $this->generateUrl('comment_create'),
'method' => 'POST',
));
$form->add('submit', 'submit', array('label' => 'Create'));
return $form;
}
/**
* Displays a form to create a new Comment entity.
*
*/
public function newAction()
{
$entity = new Comment();
$form = $this->createCreateForm($entity);
return $this->render('EmployeeBundle:Comment:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
/**
* Finds and displays a Comment entity.
*
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('EmployeeBundle:Comment')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Comment entity.');
}
$deleteForm = $this->createDeleteForm($id);
return $this->render('EmployeeBundle:Comment:show.html.twig', array(
'entity' => $entity,
'delete_form' => $deleteForm->createView(),
));
}
/**
* Displays a form to edit an existing Comment entity.
*
*/
public function editAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('EmployeeBundle:Comment')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Comment entity.');
}
$editForm = $this->createEditForm($entity);
$deleteForm = $this->createDeleteForm($id);
return $this->render('EmployeeBundle:Comment:edit.html.twig', array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
/**
* Creates a form to edit a Comment entity.
*
* #param Comment $entity The entity
*
* #return \Symfony\Component\Form\Form The form
*/
private function createEditForm(Comment $entity)
{
$form = $this->createForm(new CommentType(), $entity, array(
'action' => $this->generateUrl('comment_update', array('id' => $entity->getId())),
'method' => 'PUT',
));
$form->add('submit', 'submit', array('label' => 'Update'));
return $form;
}
/**
* Edits an existing Comment entity.
*
*/
public function updateAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('EmployeeBundle:Comment')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Comment entity.');
}
$deleteForm = $this->createDeleteForm($id);
$editForm = $this->createEditForm($entity);
$editForm->handleRequest($request);
if ($editForm->isValid()) {
$em->flush();
return $this->redirect($this->generateUrl('comment_edit', array('id' => $id)));
}
return $this->render('EmployeeBundle:Comment:edit.html.twig', array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
/**
* Deletes a Comment entity.
*
*/
public function deleteAction(Request $request, $id)
{
$form = $this->createDeleteForm($id);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('EmployeeBundle:Comment')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Comment entity.');
}
$em->remove($entity);
$em->flush();
}
return $this->redirect($this->generateUrl('comment'));
}
/**
* Creates a form to delete a Comment entity by id.
*
* #param mixed $id The entity id
*
* #return \Symfony\Component\Form\Form The form
*/
private function createDeleteForm($id)
{
return $this->createFormBuilder()
->setAction($this->generateUrl('comment_delete', array('id' => $id)))
->setMethod('DELETE')
->add('submit', 'submit', array('label' => 'Delete'))
->getForm()
;
}
}
Then in FormType
$builder
->add('comment')
->add('createdby')
->add('updatedby')
->add('datecreated')
->add('dateupdated')
->add('project')//related entity
;
I see at least 3 questions in your question...
For the error :
Unable to guess how to get a Doctrine instance from the request
information,
I don't know why it's happening, but it doesn't seem related directly to the relationship question... Maybe try to suppress fields 'createdby', 'updatedby', 'datecreated', 'dateupdated'from the form builder, as they are not in your mapping yaml file (or maybe you just didn't show them) - whatever, you should probably not display them in the form, but complete these fields in the controller or via prePersist actions, as the user doesn't have to know about them.
Then for the problem that the project field of the form displays a dropdown with project ids : you can specify in the form builder which property of the comment entity you want to display, via the choice_label option, like this :
$builder
->add('comment')
->add('project', 'entity', array(
'class' => 'YourBundle:Project',
'choice_label' => 'projectName',
));
This way, you still will have a dropdown, but with project names displayed instead of ids. The 'entity' file field type has many other options, see the documentation.
For your last question, which is you would like to have a text field with autocomplete instead of a dropdown, you can manage it with a data transformer + a JS autocompleter. See this answer for more information.

Update Data from Collection Form in Symfony2

I can't find how to update data in form collection to database, like in normal Edit action, the EditForm generated and pass to UpdateAction. I can make form for EditForm but can't find how to update data to database.
How to Embed a Collection of Forms is showing how to add and delete it using persist and remove but how to bind it from post data and update it into database? My collection actually just entity without table in database. It's used just for population many fields from my primary entity DftAbsensi into single form.
This is my primary entity DftAbsensi (without getter and setter):
<?php
namespace Sifo\AdminBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
class DftAbsensi
{
private $id;
private $tanggal;
private $status;
This is the collection entity for Absensi :
<?php
namespace Sifo\AdminBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
class CollectionAbsensi
{
private $statusS;
private $tanggal;
public function __construct()
{
$this->tanggalS = new ArrayCollection();
$this->statusS = new ArrayCollection();
}
public function setTanggal($tanggal)
{
$this->tanggal = $tanggal;
return $this;
}
public function getTanggal()
{
return $this->tanggal;
}
public function setStatusS(ArrayCollection $statusS)
{
$this->statusS = $statusS;
return $this;
}
public function getStatusS()
{
return $this->statusS;
}
}
This is DftAbsensiType :
<?php
namespace Sifo\AdminBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class DftAbsensiType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('id', 'text', array('required' => false))
->add('status', 'choice', array(
'choices' => array('H' => 'Hadir', 'A' => 'Tanpa Keterangan', 'S' => 'Sakit', 'I' => 'Izin', 'L' => 'Libur'),
'required' => false,
'empty_value' => '- Pilih -'))
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Sifo\AdminBundle\Entity\DftAbsensi'
));
}
public function getName()
{
return 'sifo_adminbundle_dftabsensi';
}
}
Actually I'm using collection just for populating many fields from databases. Persist database just in my primary entity DftAbsensi above. This is Collection for Absensi Type :
<?php
namespace Sifo\AdminBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class CollectionAbsensiType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('tanggal', 'date', array('label' => false, 'required' => false, 'attr'=>array('style'=>'display:none;'), 'widget' => 'single_text', 'format' => 'yyyy-MM-dd'))
->add('statusS', 'collection', array(
'label' => false,
'options' => array('label' => false, 'required' => false),
'type' => new DftAbsensiType())
);
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Sifo\AdminBundle\Entity\CollectionAbsensi'
));
}
public function getName()
{
return 'sifo_adminbundle_collectionabsensi';
}
}
This is how to population data in my controller. This form used for EditForm :
<?php
namespace Sifo\AdminBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sifo\AdminBundle\Entity\DftAbsensi;
use Sifo\AdminBundle\Entity\CollectionAbsensi;
use Sifo\AdminBundle\Form\CollectionAbsensiType;
use Sifo\AdminBundle\Form\DftAbsensiType;
/**
* DftAbsensi controller.
*
*/
class DftAbsensiController extends Controller
{
public function manageAction(Request $request, $id)
{
$user = $this->getUser();
$emGrupPelajar = $this->getDoctrine()->getManager();
$entityGrupPelajar = $emGrupPelajar->getRepository('SifoAdminBundle:DftGrupPelajar')->findByIdGrup($id);
/* check tanggal and set if exist */
$tanggal = $request->request->get('sifo_adminbundle_collectionabsensi')['tanggal'];
if($tanggal == NULL)
$tanggal = $request->request->get('form')['tanggal'];
$tanggal = new \DateTime($tanggal);
/* Show data */
$emShow = $this->getDoctrine()->getManager();
$collectionAbsensi = new CollectionAbsensi();
foreach ($entityGrupPelajar as $temp) {
$entity = new DftAbsensi();
$entity = $emShow->getRepository('SifoAdminBundle:DftAbsensi')->findOneBy(array('idGrupPelajar' => $temp, 'tanggal' => $tanggal));
if ($entity)
{
$entityPelajar = $emShow->getRepository('SifoAdminBundle:MstPelajar')->find($temp->getIdPelajar());
$dftAbsensi = new DftAbsensi();
$dftAbsensi->setId($entity->getId())
->setIdGrupPelajar($entity->getIdGrupPelajar())
->setStatus($entity->getStatus())
;
$collectionAbsensi->getStatusS()->add($dftAbsensi);
$collectionAbsensi->setTanggal($tanggal);
}
}
$emShow->flush();
$formEdit = $this->createForm(new CollectionAbsensiType(), $collectionAbsensi, array(
'action' => $this->generateUrl('admin_absensi_update', array('id' => $id)),
'method' => 'PUT',
));
$formEdit->add('save', 'submit', array('attr' => array('class' => 'btn btn-info')));
return $this->render('SifoAdminBundle:DftAbsensi:manage.html.twig', array(
'form_refresh' => $formRefresh->createView(),
'form_edit' => $formEdit->createView(),
'user' => $user,
));
}
As mentioned before, my CollectionAbsensi actually just used for population fields from databases. But for updating I'm using DftAbsensi Entity. There is no table for CollectionAbsensi in my databases. This is how I update the data:
public function updateAction(Request $request, $id)
{
$user = $this->getUser();
$emGrupPelajar = $this->getDoctrine()->getManager();
$entityGrupPelajar = $emGrupPelajar->getRepository('SifoAdminBundle:DftGrupPelajar')->findByIdGrup($id);
/* set tanggal */
$tanggal = new \DateTime($request->request->get('sifo_adminbundle_collectionabsensi')['tanggal']);
/* populate data */
$emShow = $this->getDoctrine()->getManager();
$collectionAbsensi = new CollectionAbsensi();
foreach ($entityGrupPelajar as $temp) {
$entity = new DftAbsensi();
$entity = $emShow->getRepository('SifoAdminBundle:DftAbsensi')->findOneBy(array('idGrupPelajar' => $temp, 'tanggal' => $tanggal));
if ($entity)
{
$entityPelajar = $emShow->getRepository('SifoAdminBundle:MstPelajar')->find($temp->getIdPelajar());
$dftAbsensi = new DftAbsensi();
$dftAbsensi->setId($entity->getId())
->setIdGrupPelajar($entity->getIdGrupPelajar())
->setStatus($entity->getStatus())
;
$collectionAbsensi->getStatusS()->add($dftAbsensi);
$collectionAbsensi->setTanggal($tanggal);
}
}
$formEdit = $this->createForm(new CollectionAbsensiType(), $collectionAbsensi);
$formEdit->handleRequest($request);
$emShow->flush();
$response = $this->forward('SifoAdminBundle:DftAbsensi:manage', array(
'id' => $id,
'request' => $request,
));
return $response;
}
There is no error from this code. The problem is the databases not updated when I press Save button. I confused for binding data and how to update them into database in updateAction above. Can a collection form not be used for updating data?
My form is attendance system which look like this :
Actually this is still not really answer my question about "How to update data in form collection?". I do update my data with old way : Get all the data from request manually and bind it to entity then update it into database.
Here my code :
public function updateAction(Request $request, $id)
{
$user = $this->getUser();
/* get request */
$data = $request->request->get('sifo_adminbundle_collectionabsensi')['statusS'];
/* update data */
$total = count($data);
for ($i = 0; $i < ($total / 2); $i++) {
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('SifoAdminBundle:DftAbsensi')->find($data[$i]['id']);
if ($entity){
$entity->setStatus($data[$i]['status'])
->setOperator($user->getNama());
$em->flush();
}
}
$response = $this->forward('SifoAdminBundle:DftAbsensi:manage', array(
'id' => $id,
'request' => $request,
));
return $response;
}
If someone has a better idea, post your answer here.

Many to many relations Symfony2

I am using many to many relations in my symfony2 project, i have successfully made two entities 'Users' and Groups and i have also successfully persisted data which inserts data into users,groups and users_groups table by using
$user = new User();
$user->getGroups()->add($group);
now i want to edit the user which should also edit users_groups record..
I have searched a lot but no luck.Any help would be appreciated ...
CONTROLLER
public function editAction()
{
if($this->getRequest()->query->get("id")){
$id = $this->getRequest()->query->get("id");
$request = $this->getRequest();
$em = $this->getDoctrine()->getEntityManager();
$entity = $em->getRepository('DesignAppBundle:Users')->find($id);
$editForm = $this->createForm(new UserType());
if ($this->getRequest()->getMethod() == 'POST') {
$editForm->bindRequest($request);
if ($editForm->isValid()) {
$postData = $request->request->get('users');
$repository = $this->getDoctrine()
->getRepository('Bundle:groups');
$group = $repository->findOneById($postData['group']);
$entity->addGroups($group );
$em->flush();
return $this->redirect($this->generateUrl('index'));
}
}
return $this->render('User.html.twig',array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
));
}
}
FORM
<?php
use and include .....
class UserType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$request = Request::createFromGlobals();
$builder->add('group', 'entity', array(
'class' => 'Bundle:Groups',
'property' => 'name',
'empty_value' => 'All',
'required' => true,
'multiple'=>true,
'data' => $request->get('group_id')
));
}
public function getDefaultOptions(array $options)
{
return array(
'validation_groups' => array('users'),
'csrf_protection' => false,
);
}
public function getName()
{
return 'users';
}
}
User
/**
* #ORM\ManyToMany(targetEntity="Groups", inversedBy="users")
* #ORM\JoinTable(name="users_groups",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="group_id", referencedColumnName="id")}
* )
**/
protected $group;
public function __construct()
{
$this->group= new ArrayCollection();
}
public function addgroups(\Design\AppBundle\Entity\Categories $group)
{
$this->group[] = $group;
}
Group
/**
* #ORM\ManyToMany(targetEntity="Users", mappedBy="group")
*/
protected $users;
public function __construct()
{
$this->users= new ArrayCollection();
}
/**
* Add users
*
* #param Bundle\Entity\Users $users
*/
public function addUsers(Bundle\Users $users)
{
$this->users[] = $users;
}
/**
* Get users
*
* #return Doctrine\Common\Collections\Collection
*/
public function getUsers()
{
return $this->users;
}
You should not be adding the group_id, you should be adding the groups property
$builder->add('groups');
The group_id column is automatically handled by Doctrine and you should not be handling it yourself directly. Do you have a group_id property? If you do, you should remove it.
The group entity should be:
/**
* #ORM\ManyToMany(targetEntity="Users", mappedBy="group")
*/
protected $users;
public function __construct()
{
$this->users= new ArrayCollection();
}
/**
* Add users
*
* #param Bundle\Entity\User $user
*/
public function addUsers(Bundle\User $users)
{
$this->users[] = $users;
}
/**
* Get users
*
* #return Doctrine\Common\Collections\Collection
*/
public function getUsers()
{
return $this->users;
}
EDIT
This is how your controller should be:
public function editAction($request)
{
$id = $this->getRequest()->query->get("id");
$em = $this->getDoctrine()->getEntityManager();
$entity = $em->getRepository('DesignAppBundle:Users')->find($id);
$editForm = $this->createForm(new UserType(),$entity);
if ($this->getRequest()->getMethod() == 'POST') {
$editForm->bindRequest($request);
if ($editForm->isValid()) {
$em->persits($entity);
$em->flush();
return $this->redirect($this->generateUrl('index'));
}
}
return $this->render('User.html.twig',array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
));
}
and this is how your UserType should be:
class UserType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('group', 'entity', array(
'class' => 'Bundle:Groups',
'property' => 'name',
'empty_value' => 'All',
'required' => true,
'multiple'=>true,
));
}
public function getDefaultOptions(array $options)
{
return array(
'validation_groups' => array('users'),
'csrf_protection' => false,
);
}
public function getName()
{
return 'users';
}
}

Resources