Symfony FormEvent. Entities passed to the choice field must be managed - symfony

I try to use EventListener but i have error:
Entities passed to the choice field must be managed. Maybe persist them in the entity manager?
ExampleType.php
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) {
$form = $event->getForm();
// this would be your entity, i.e. SportMeetup
$data = $event->getData();
$category = $data->getCategory();
$tagi = null === $category ? array() : $category->getTags();
$form->add('tags', 'entity', array(
'class' => 'MyAppBundle:Tag',
'placeholder' => '',
'choices' => $tagi,
));
}
);
//Category.php (entity)
/**
* Get tags
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getTags()
{
return $this->tags;
}

Related

Symfony Edit and persist multiple entities on one form

I have an entity called Objective and its property called 'weight' and I can edit one objective at a time.. and now i want to edit all weights in a single form and persist them in DB using Doctrine..
This issue helped me in bringing all objective weights on a single form..
Edit multiple entities in one form
Now I am trickling around on how to save all weight values from the form in DB with a single click of save button..
Below is my code so far..
This is the controller action:-
/**
* #Route("/mou/objectives/manage", name="objective_manage")
*/
public function manageAction(Request $request){
$objs = $this->getDoctrine()
->getRepository('AppBundle:Objective')
->findAll();
$form = $this->createFormBuilder()
->add('weight', 'collection', array(
'type' => new WeightType() ,
'allow_add' => false,
'allow_delete' => false,
'label' => false))
->add('save', 'submit')
->getForm();
$form->setData(array('weight' => $objs));
/* Till here things are fine */
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()){
/* **Here I need help how to persist all weight values.. maybe inside a loop.. hence This is the missing piece** */
foreach($objs as $obj){
$obj =new Objective();
$obj = $em->getRepository('AppBundle:Objective')->find($obj);
$obj->setWeight($obj);
$em->persist($obj);
}
$em->flush();
return $this->redirectToRoute('objective_manage');
}
return $this->render('keyobjective/manage.html.twig', array(
'objs' => $objs,
'form' => $form->createView()
));
}
This is the FormType:-
class WeightType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('weight','text', array('label' => false));
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Objective'
//'data_class' => null
));
}
/**
* #return string
*/
public function getName()
{
return 'appbundle_objective';
}
}
and this is twig template:-
{% extends 'base.html.twig' %}
{% block body %}
{{form_start(form)}}
{{form_label(form.weight,'Enter Weight')}}
{{form_widget(form.weight)}}
{{form_end(form)}}
{% endblock %}
Any suggested approach..!!
Somehow I figured this out.. after form handle request I created a loop to iterate through the number of objectives being edited and then inside of it another foreach loop which transforms the weight values received from the Form to the setWeight() method one by one:-
/**
* #Route("/mou/objectives/manage", name="objective_manage")
*/
public function manageAction(Request $request){
$objs = $this->getDoctrine()
->getRepository('AppBundle:Objective')
->findAll();
$count = count($objs);
for($i =0; $i < $count; $i++){
$objsarray = new Objective();
}
$form = $this->createFormBuilder()
->add('weight', 'collection', array(
'type' => new WeightType() ,
'allow_add' => false,
'allow_delete' => false,
'options' => array('label' => false),
))
->add('save', 'submit')
->getForm();
$form->setData(array('weight' => $objs));
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()){
$em = $this->getDoctrine()->getManager();
for($i=0; $i < count($objs); $i++){
$obj = new Objective();
$obj = $em->getRepository('AppBundle:Objective')->find($objs[$i]);
$weight = $form->get('weight')->get($i)->getData();
foreach($weight as $val){
$obj->setWeight($val);
$em->persist($obj);
}
}
$em->flush();
$this->addFlash(
'notice',
'Objective weight updated'
);
return $this->redirectToRoute('objective_manage');
}
return $this->render('keyobjective/manage.html.twig', array(
'objs' => $objs,
'form' => $form->createView()
));
}

symfony2 + EntityType + queryBuilder and default top value/entry

I have an entity (Category) where the user can choice a parent (always Category) for the new/edit action where the link is the vocabolaryId field.
This is my CategoryType.
class CategoryType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$vocId = $options['data']->getVocabularyId();
$builder
->add('name')
->add('vocabularyId',HiddenType::class,[
'data' => $vocId,
])
->add('description')
->add('weight',null,[
'label' => 'Posizione'
])
;
$builder->add('parent',EntityType::class,array(
'class' => 'AppBundle:Category',
'query_builder' => function (EntityRepository $er) use ($vocId) {
return $er->createQueryBuilder('c')
->where('c.vocabularyId = ?1')
->orderBy('c.name')
->setParameter(1,$vocId);
}
));
}
To get the list of all category that have the same vocabularyId I use the "query_builder" parameter.
When I submit the form to symfony without choice a parent (or with an empty table) it replies me with : " This value is not valid." (for the parent field).
How can I set a "null" parent ? I mean a category that have no parent.
EDIT:I have added "'required' => false," like say by Stephan Vierkant, but now I have another error: "Warning: spl_object_hash() expects parameter 1 to be object, string given"
this is my controller's newAction function:
/**
* Creates a new Category entity.
*
* #Route("/new", name="admin_category_new")
* #Method({"GET", "POST"})
*/
public function newAction(Request $request, $vocId)
{
$category = new Category($vocId);
$form = $this->createForm('AppBundle\Form\CategoryType', $category);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
dump($category);
exit();
$em->persist($category);
$em->flush();
return $this->redirectToRoute('admin_category_show', array('vocId' => $vocId, 'id' => $category->getId()));
}
return $this->render('category/new.html.twig', array(
'category' => $category,
'form' => $form->createView(),
'vocId' => $vocId
));
}
Set required (docs) to false:
$builder->add('parent',EntityType::class,array(
'class' => 'AppBundle:Category',
'required' => false,
'query_builder' => function (EntityRepository $er) use ($vocId) {
return $er->createQueryBuilder('c')
->where('c.vocabularyId = ?1')
->orderBy('c.name')
->setParameter(1,$vocId);
}
));
You can set a placeholder (docs) if you don't want an empty option.

Symfony2 Dynamic Form Modification not saving generated data

I'm going crazy because if I choose a client from an entity field, it correctly populate the second entity field called proposals. Then I choose the proposal dynamically generated, but when I save the form it saves the form correctly but without filling the proposal field. I followed the Symfony Tutorial about the Dynamic Forms which can be found here
This is my FormType code:
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('client', 'entity', array(
'class' => 'AppBundle\Entity\Client',
'property' => 'name',
'label' => 'Client:',
'empty_value' => '',
'required' => false,
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('u')
->orderBy('u.name', 'ASC');
},
));
$formModifier = function (FormInterface $form, Client $client = null) {
$proposals = null === $client ? array() : $this->em->getRepository('AppBundle:Proposals')->findBy(
array('client'=>$client->getId()),
array('id' => 'DESC'));
$form->add('proposal', 'entity', array(
'class' => 'AppBundle\Entity\Proposal',
'choice_label' => 'subject',
'placeholder' => '',
'choices' => $proposals,
'label' => 'Proposal',
'required' => false
));
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier) {
$client = null;
$data = $event->getData();
if(!empty($data)) {
$client = $data->getClient();
}
$formModifier($event->getForm(), $client );
}
);
$builder->get('client')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
$client = $event->getForm()->getData();
$formModifier($event->getForm()->getParent(), $client);
}
);
This is the Prenotazione Entity, the one who belong the form.
class Prenotazione {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Client", inversedBy="prenotazioni")
* #ORM\JoinColumn(name="client_id", referencedColumnName="id")
*/
private $client;
/**
* #ORM\OneToOne(targetEntity="Proposal", inversedBy="prenotazione")
* #ORM\JoinColumn(name="proposal_id", referencedColumnName="id")
*/
private $proposal;
public function getId() {
return $this->id;
}
public function setProposal(\AppBundle\Entity\Proposal $proposal = null)
{
$this->proposal = $proposal;
return $this;
}
public function getProposal() {
return $this->proposal;
}
public function setClient(\AppBundle\Entity\Client $client = null)
{
$this->client = $client;
return $this;
}
public function getClient()
{
return $this->client;
}
}
Where am I wrong ?
Are you sure your proposals query is correct?
$proposals = null === $client ? array() : $this->em->getRepository('AppBundle:Proposals')->findBy(
array('client'=>$client->getId()),
array('id' => 'DESC'));
Shouldn't this be either array('client_id' => $client->getId()), or array('client' => $client),?
Try checking the actual content of $proposals by adding a dump($proposals) just below and looking up the result in the symfony profiler.

Symfony: use of query builder in a Form

I have a form that I am building using the FormBuilder:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('rosters', 'entity', array(
'class' => 'ReliefAppsPlatformBundle:Roster',
'property' => 'display',
'query_builder' => function(RosterRepository $r) use ($user) {
return $r->createQueryBuilder('r')
->leftJoin('r.members', 'm')
->addSelect('m')
->where('(m.rights = :adminRight or m.rights = :managerRight) and m.user = :user')
->setParameter('adminRight', RosterMember::ADMIN_LEVEL)
->setParameter('managerRight', RosterMember::MANAGER_LEVEL)
->setParameter('user', $user);
},
'required' => true,
'expanded' => true,
'multiple' => true
))
->add('save', 'submit')
;
}
As you can see I my QueryBuilder I use $user (the current user) as a parameter.
My controler looks like that:
public function createAction(Request $request, Event $event)
{
$alert = new RosterEvent;
$alert->setEvent($event);
$user = $this->getUser();
$form = $this->createForm(new RosterEventType(), $alert, $user);
$form->handleRequest($request);
if ($form->isValid()) { ....
My issue is that I need to pass the $user to the formbiulder. But I get "Catchable Fatal Error: Argument 3 passed to Symfony\Bundle\FrameworkBundle\Controller\Controller::createForm() must be of the type array, object given,..."
I know the problem is how I pass $user from the controller to the formbuilder. But I have no clue how to do that.
Any ideas?
As mentioned in the documentation, the third parameter ($options = array()) of method createForm need an array and not a object.
This line is wrong
$form = $this->createForm(new RosterEventType(), $alert, $user);
The $options parameter can be used for example like this
$form = $this->createForm(new TaskType(), $task, array(
'action' => $this->generateUrl('target_route'),
'method' => 'GET',
));
If you want pass a parameter to the form, you can try something like this
Controller
$form = $this->createForm(new RosterEventType($user), $alert);
Form
protected $user;
public function __construct (User $user)
{
$this->user = $user;
}
Hope it will help.
The third parameter of createForm is expecting an array of options so use this when creating the form:
$form = $this->createForm(new RosterEventType(), $alert, array('user'=>$user));
Then you will need to get your RosterEventType to allow the 'user' option to be provided. You can do this by overriding the setDefaultOptions function of your AbstractType and provided a default value for the option. For example you can add the following to your RosterEventType class:
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'user' => false,
));
}
If you do this then you can access the user object in your buildForm function using $options['user'].

Controller - No access in class - Entity

I got this error message, but I don't really understand why.
Neither the property "categories" nor one of the methods "addCategory()"/"removeCategory()", "setCategories()", "categories()", "__set()" or "__call()" exist and have public access in class "Checkout\Bundle\ItemBundle\Entity\Item".
The thing is, in my entity "Item" I really have all of this stuff:
/**
* #ORM\ManyToMany(targetEntity="Checkout\Bundle\ItemBundle\Entity\Category", mappedBy="items")
**/
private $categories;
and
/**
* Add categories
*
* #param Category $categories
* #return Item
*/
public function addCategory(Category $categories)
{
$this->categories[] = $categories;
return $this;
}
/**
* Remove categories
*
* #param Category $categories
*/
public function removeCategory(Category $categories)
{
$this->categories->removeElement($categories);
}
/**
* Get categories
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getCategories()
{
return $this->categories;
}
Okay, okay - and what is in my Controller?
/**
* Creates a new Item entity.
*
* #Route("/create", name="item_create")
* #param Request $request
* #return \Symfony\Component\HttpFoundation\Response
*/
public function createAction(Request $request)
{
$entity = new Item();
$currentUser = $this->getUser();
$form = $this->createFormBuilder($entity)
->add('name', null, array(
'label' => 'Item Name',
'required' => true,
))
->add('categories', 'entity', array(
'label' => 'Select a Category',
'required' => false,
'class' => 'CheckoutItemBundle:Category',
'property' => 'name',
'query_builder' => function (EntityRepository $er) use ($currentUser) {
return $er->createQueryBuilder('c')
->where('c.user = :user')
->setParameter('user', $currentUser);
},
))
->add('submit', 'submit', array('label' => 'Speichern'))
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
}
return $this->render(
'CheckoutItemBundle:Item:create.html.twig',
array(
'entity' => 'entity',
'form' => $form->createView()
)
);
}
So, the big question is, why he say that he didn't find it, when it is obviously there. Any idea? Thank you in advance!
->add('categories', 'entity', array(
'label' => 'Select a Category',
'required' => false,
'class' => 'CheckoutItemBundle:Category',
'property' => 'name',
'multiple' => true,
'query_builder' => function (EntityRepository $er) use ($currentUser) {
return $er->createQueryBuilder('c')
->where('c.user = :user')
->setParameter('user', $currentUser);
},
))
You have a Many-To-Many relation, but your form expects a Many-To-One. To fix this behavior need to set multiple to true.

Resources