Hi i am tying pass array collection (method getProjects() returns it) to form (select input) and fail. This code returns exception - A "__toString()" method was not found on the objects of type "Tasker\WebBundle\Entity\Project" passed to the choice field.
Can anybody help? Is needed transformer? Or what is right way?
Controller:
/**
* #Route("/pridaj", name="web.task.add")
* #Template()
*/
public function addAction(Request $request)
{
$task = new Task;
/** #var User $loggedUser */
$loggedUser = $this->get('security.token_storage')->getToken()->getUser();
$form = $this->createForm(new AddTaskType(), $task, ['user' => $loggedUser]);
if ($form->handleRequest($request) && $form->isValid()) {
// some stuff
}
return [
'form' => $form->createView()
];
}
Form:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('project', 'entity', [
'label' => 'Projekt:',
'class' => 'TaskerWebBundle:Project',
'choices' => $options['user']->getProjects(),
'placeholder' => 'Označte projekt',
])
// ....
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setRequired(array(
'user',
));
$resolver->setDefaults(array(
'user' => null,
));
}
just add __ToString() to your Project class
Tasker\WebBundle\Entity\Project
class Project
{
....
function __toString() {
return $this->getName(); //or whatever string you have
}
}
I wanted to add another answer, because you do not have to add __toString() to your Project class. The Symfony entity field type allows you to specify which property/field to use for displaying. So instead of __toString() you could specify the property in the form configuration like so:
$builder
->add('project', 'entity', [
'label' => 'Projekt:',
'class' => 'TaskerWebBundle:Project',
'choices' => $options['user']->getProjects(),
'placeholder' => 'Označte projekt',
'property' => 'name'
])
If you check this part of the Symfony documentation you will see that __toString() is automatically called only if you do not specify the property.
Related
I am trying to pass a parameter from a FORM to a twig, that is different from the one where I make my data input. If this explanation is messy - here's more simplified version... I have just started to study php+symfony so please don't hurt me too hard...
I have two empty fields on a "CREATE" page,
I fill them with say AAA and BBB each,
I want AAA and BBB to appear on another "FORMZ" page.
I am NOT using any database, so no need to use ObjectManager etc, it's only to understand how everything's working...
I have created a ArticleFormType.php file
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', TextType::class, [
'attr' => [
'placeholder' => "title from ArticleFormType",
'class' => 'form-control'
]
])
->add('content')
->add('save', SubmitType::class, [
'label' => 'SAVE'
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => MyClassArticle::class,
]);
}
and that is my Controller:
/**
* #Route("/formz", name="formz")
*/
public function index()
{
$title = 'Created by DT';
return $this->render('formz/index.html.twig', [
'title' => $title
]);
}
/**
* #Route("/formz/create", name="create")
*/
public function create (Request $request, ObjectManager $manager ) {
$article = new MyClassArticle();
$task = new ArticleFormType();
$form = $this->createForm(ArticleFormType::class, $article, [
'action' => $this->generateUrl('create'),
]);
$form->handleRequest($request);
dump($article);
if($form->isSubmitted() && $form->isValid()) {
dump($article);
return $this->redirectToRoute('formz');
}
return $this->render('formz/create.html.twig', [
'formTest' => $form->createView()
]);
}
I don't get how can I transfer my $article to a public function index() - I heard it can be done somehow (in the case above) by passing parameters from public function create() to public function index().
Can anybody help me with that please?
I am thanking you in advance!
you need to store the article somewhere, ideally through doctrine (entity save)
then you need to update your index route to be something like this
#Route("/formz/{article}", name="formz")
function index(Artile $article = null)
Then you can use the following with redirectToRoute
$this->redirectToRoute("formz", array("article" => $article))
That should solve your issue.
I faced up with some non-ordinary situation for me.
1) I have a dependent list that rendering by Symfony FormType like this:
2) Location and Instruction fields are depend from Company field.
3) When I change Company field (onchange event js) then goes ajax request that retrieves data from the database and build a dropdown list.
4) But when form is submitted I have an error:
Please help me to resolve this. Thanks in advance.
My formType:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('hours')
->add('messageText', null, ['required' => false])
->add('company', null, [
'choice_label' => 'name',
'placeholder' => 'Please select company',
'required' => true
])
->add('procedure', TextType::class, ['attr' => ['placeholder' => 'Please type code or description'] ])
->add('instruction', ChoiceType::class, ['mapped' => false])
->add('location', ChoiceType::class, ['mapped' => false])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => InstructionNotification::class
));
}
Action from controller:
/**
* #Route("/admin/api/instructions", name="admin_api_instructions")
* #param Request $request
* #return JsonResponse
*/
public function getInstructionsByCompanyId(Request $request)
{
$id = $request->get('id');
if (!$id) {
return new JsonResponse('No data', 404);
}
$instructions = $this->getDoctrine()->getRepository('OctaneBundle:Instruction')->findInstructionsByCompanyId($id);
return new JsonResponse($instructions);
}
findInstructionsByCompanyId($id):
public function findInstructionsByCompanyId($id)
{
$qb = $this->createQueryBuilder('i');
if ($id) {
$qb
->where('i.company = :id')
->setParameter('id', $id);
}
return $qb->getQuery()->getResult();
}
response from api (i.e.: admin/api/instructions?id=1):
[{"id":2,"label":"First instruction"},{"id":3,"label":"First instruction"}]
If you need any additional information please leave comments below. Thanks
Symfony's Validator expects that your submitted form will have a submitted instruction and location value that exists in the list you provided when creating your form in form type class. Since you are not providing any options for instructions and locations, you are getting a validation error.
In order to bypass this error you should use Symfony's Form Events in your buildForm function in your form type like this:
$builder->get('company')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) {
$company = $event->getForm()->getData();
$form = $event->getForm()->getParent();
$form->add('location', EntityType::class, array(
'class' => Location::class,
'query_builder' => function (EntityRepository $repo) use ($company) {
return $repo->createQueryBuilder('location')
->where('location.company = :company')
->setParameter('company', $company->getId());
}
));
$form->add('instruction', EntityType::class, array(
'class' => Instruction::class,
'query_builder' => function (EntityRepository $repo) use ($company) {
return $repo->createQueryBuilder('instruction')
->where('instruction.company = :company')
->setParameter('company', $company->getId());
}
));
}
);
Thanks for the answer but I found out more elegant solution for my case. So,
my formType now:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
...
->add('instruction', FormattedSelectType::class, ['class' => Instruction::class])
->add('location', FormattedSelectType::class, ['class' => Location::class])
;
}
FormattedSelectType:
class FormattedSelectType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'choice_label' => function (FormattedLabelInterface $entity) {
return $entity->getFormattedLabel();
}
));
}
/**
* {#inheritdoc}
*/
public function getParent()
{
return EntityType::class;
}
}
Etities Location and Instruction entities implement JsonSerializable and custom FormattedLabelInterface interface and have the next methods:
/**
* #return string
*/
public function getFormattedLabel()
{
return sprintf(self::LABEL_FORMATTED, $this->zip, $this->city, $this->name, $this->address, $this->phone);
}
/**
* #return array|mixed
*/
public function jsonSerialize()
{
return [
'id' => $this->id,
'label' => $this->getFormattedLabel()
];
}
I am trying to set parameter to query builder in Form type. I want to set impact variable to form field query builder. I get impact from form options
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('title');
$parentPage = $options["parentPage"];
$impact = $options["impact"];
if($parentPage != null){
$builder->add('parent', 'entity', array(
'class' => "CoreBundle:Page",
'choices' => array($parentPage)
));
}else{
$builder->add('parent', 'entity', array(
'class' => "CoreBundle:Page",
'query_builder' => function(PageRepository $pr){
$qb = $pr->createQueryBuilder('p');
$qb->where("p.fullPath NOT LIKE '/deleted%'");
$qb->andWhere('p.impact = :impact')
->setParameter('impact', $impact); <-'Undefined variable $impact'
return $qb;
},
));
}
Why this code is shown to be wrong, it says that $impact is undefined variable. Isn't it global variable that can be accessed from anywhere in the buildForm function?
The problem is that you need to explicitly specify variables passed to a closure (aka the query_builder function):
$builder->add('parent', 'entity', array(
'class' => "CoreBundle:Page",
'query_builder' => function(PageRepository $pr) use ($impact) { // ADD
$qb = $pr->createQueryBuilder('p');
$qb->where("p.fullPath NOT LIKE '/deleted%'");
$qb->andWhere('p.impact = :impact')
->setParameter('impact', $impact); <-'Undefined variable $impact'
return $qb;
},
));
Most languages don't need this but php does.
See example 3 : http://php.net/manual/en/functions.anonymous.php
It sounds like you arent't passing the parameters into your form builder.
If you dump($options) in your buildForm function do you see them passed?
To add a custom value into the options your form type should be like;
<?php
// src/AppBundle/Form/Enitiy/PageType.php
namespace AppBundle\Form\Entity;
use Symfony\Component\Form\AbstractType,
Symfony\Component\Form\FormBuilderInterface,
Symfony\Component\OptionsResolver\OptionsResolver;
class PageType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('title');
// ...
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Page',
'parentPage' => false,
'impact' => false
));
}
/**
* #return string
*/
public function getName()
{
return 'appbundle_page;
}
}
Then your controller action would be something like;
$form = $this->createForm(new PageType(), $page, [
'parentPage' => 'foo',
'impact' => 'bar'
]);
I am trying to implement a one to one relation. Each User can be affected at a building (Etablissement for me). A building can have many people but each people can be affected at one building at most.
I have this error :
ContextErrorException: Catchable Fatal Error: Argument 1 passed to Intranet\UserBundle\Entity\User::setUserEtab() must be an instance of Intranet\RhBundle\Entity\Etablissement, array given, called in C:\wamp\www\projet\vendor\symfony\symfony\src\Symfony\Component\PropertyAccess\PropertyAccessor.php on line 360 and defined in C:\wamp\www\projet\src\Intranet\UserBundle\Entity\User.php line 322
The line 322 of User.php is :
public function setEtablissement(\Intranet\RhBundle\Entity\Etablissement $etablissement = null)
It occurs at the line $form->handleRequest($request); of my controller. This is my controller :
public function editerAction(Request $request, User $user){
$form = $this->createForm(new EditerFormType, $user);
if ($request->getMethod() == 'POST') {
$form->handleRequest($request);
die("ici");
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$this->get('session')->getFlashBag()->add('success', "L'utilisateur ". $user->getNom() ." ". $user->getPrenom() . " a été édité avec succès !");
$em->flush();
return $this->redirect($this->generateUrl('intranet_rh_homepage'));
}else
$this->get('session')->getFlashBag()->add('danger', "Erreur de formulaire !");
}
return $this->render('IntranetRhBundle:User:editer.html.twig',array('user' => $user, 'form' => $form->createView()));
}
The die doesn't work. Before adding the form, it was working.
This is the EditForm :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('email', 'email', array('label' => 'form.email', 'translation_domain' => 'FOSUserBundle'))
->add('nom', 'text')
->add('prenom', 'text')
->add('naissance','date',array(
'widget' => 'single_text',
'format' => 'dd/MM/yyyy',
'attr' => array('class' => 'date', 'readonly' => 'readonly')
))
->add('sexe', 'choice', array(
'choices' => array('Homme' => 'Homme', 'Femme' => 'Femme'),
'multiple' => false
))
->add('etablissement', new UserEtabType())
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array('data_class' => 'Intranet\Userbundle\Entity\User'));
}
This is my UserEtab form :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('etablissement', 'entity', array('class' => 'IntranetRhBundle:Etablissement', 'property' => 'nom', 'empty_value' => 'Aucun', 'empty_data' => -1, 'required' => false))
;
}
And my relation on User entity :
/**
* #ORM\OneToOne(targetEntity="Intranet\RhBundle\Entity\Etablissement", cascade={"persist", "remove"})
**/
private $etablissement;
The form's view is okay, there is a select list with all the building and an empty value. But when I post, I have this error I can't understand and solve.
I have the setter and getter if User entity :
/**
* Set Etablissement
*
* #param \Intranet\RhBundle\EntityEtablissement $etablissement
* #return User
*/
public function setEtablissement(\Intranet\RhBundle\Entity\Etablissement $etablissement = null)
{
$this->etablissement = $etablissement;
return $this;
}
/**
* Get Etablissement
*
* #return \Intranet\RhBundle\Entity\Etablissement
*/
public function getEtablissement()
{
return $this->etablissement;
}
But when I var_dump $request->get('user')->get('etablissement') it doesn't work :
Error: Call to undefined method Intranet\UserBundle\Entity\User::get() in C:\wamp\www\projet\src\Intranet\RhBundle\Controller\UserController.php line 69
And the building doesn't appear in var_dump of $request->get('user').
EDIT :
I don't have a setDefaultOptions method for my UserEtabType because I don't know what I have to do. I tried to implements it but I have this kind of error :
The form's view data is expected to be an instance of class Intranet\UserBundle\Entity\User, but is an instance of class Proxies__CG__\Intranet\RhBundle\Entity\Etablissement. You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms an instance of class Proxies__CG__\Intranet\RhBundle\Entity\Etablissement to an instance of Intranet\UserBundle\Entity\User.
For the new UserEtabType :
namespace Intranet\UserBundle\Form\Type;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class UserEtabType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('etablissement', 'entity', array('class' => 'IntranetRhBundle:Etablissement', 'property' => 'nom', 'empty_value' => 'Aucun', 'empty_data' => -1, 'required' => false))
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array('data_class' => 'Intranet\UserBundle\Entity\User'));
}
public function getName()
{
return 'intranet_userbundle_useretablissementtype';
}
}
Can you show the new UserEtabType() class ?
EDIT 1 : Try putting this line :
->add('etablissement', 'entity', array('class' => 'IntranetRhBundle:Etablissement', 'property' => 'nom', 'empty_value' => 'Aucun', 'empty_data' => -1, 'required' => false));
in the main EditForm
EDIT 2:
plus be careful :
$resolver->setDefaults(array('data_class' => 'Intranet\UserBundle\Entity\User'));
must be
$resolver->setDefaults(array('data_class' => 'Intranet\UserBundle\Entity\Etablissement'));
in your UserEtabType() class
Are you getting this error when you try to insert a record ? Or before that. For your information, setUserEtab() in the User entity expects an object of Etablissement, because of the one-to-one relationship. Passing the value of an array is not sufficient. Try passing the object of Etablissement it self (the selected object after performing dql).
Hope this helps someone.
Cheers!
I'm using entity choice list in my form. I want to use only specific entities (in example: only groups that user belongs to)
So, in controller, I'm getting these groups, and trying to pass them into formBuider.
Controller:
/.../
$groups = $em->getRepository('VendorMyBundle:Group')->getUserGroups($user);
$form = $this->createForm(new Message($groups), $message);
/.../
so, what now? how to use it in formBuilder?
how to change this line to use passed array of groups?
->add('group','entity',array('class' => 'Vendor\MyBundle\Entity\Group', 'label'=>'Group:'))
or in the other way:
class MessageType
{
/.../
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('group','entity',
array(
'class' => 'Vendor\MyBundle\Entity\Group',
'property' => 'name',
'query_builder' => function ($repository) {
$qb = $repository->createQueryBuilder('group');
$qb->add('where', 'group.administrator = :user');
$qb->setParameter('user', $user->getId());
return $qb;
},
'label' => 'Group'
)
)
// Continue adding fields
;
}
/.../
}
so how can i get object $user to use in form builder? ($user represent current logged user)
You can give the object you want to use in the __construct() method.
Eg :
$form = $this
->get('form.factory')
->create(new ApplyStepOneFormType($this->company, $this->ad), $applicant);
In your form type :
function __construct(\Your\Bundle\Entity\Company $company, \DYB\ConnectBundle\Entity\Ad $ad) {
$this->company = $company;
$this->ad = $ad;
}
And then in your form type in buildForm method :
$company = $this->company;
$builder->add('ad', 'entity', array(
'class' => '\Your\Bundle\Entity\Ad',
'query_builder' => function(\Your\Bundle\Repository\AdRepository $er) use ($company) {
return $er->getActiveAdsQueryBuilder($company);
},
));
//In controller pass the value which you want to use in builder form in array like
$object = new Question();
$form->create(new QuestionType() , $object , array('sqtname'=>2,'question_type'=>2));
//In Form type class
public function buildForm(FormBuilderInterface $builder , array $options)
{
//for setting data field dynamically
if (array_key_exists('question_type', $options) && $options['question_type'] != '') {
$data = $em->getReference("RecrutOnlineStandardBundle:StdQuestionType",$options['question_type']->getId());
} else {
$data = "";
}
$builder->add('StdQuestionType', 'entity', array(
'class' => 'TestStandardBundle:StdQuestionType',
'property' => 'name',
'empty_value' => 'Sélectionner un question type',
'required' => true,
'data' => $data,
'query_builder' => function(EntityRepository $er ) use ( $options ) {
if (isset($options['sqtname']) && $options['sqtname'] != '') {
return $er->createQueryBuilder('sqt')
->where("sqt.name!= ".$options['sqtname']);
} else{
return $er->createQueryBuilder('sqt');
}
}
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Test\QuestionBundle\Entity\Question',
'required' => false,
'sqtname' => '',
'question_type' =>''
));
}
Bacteries' solution IS NOT a good one. For example, if you declare your type as service, it is impossible to pass an object to constructor.
A perfect solution is options - just pass data as option to form builder.
If you want to use custom query, you have to set query_builder option as follows:
use Doctrine\ORM\EntityRepository;
...
$message = new Message();
$form = $this->createFormBuilder($message)
->add('group', 'entity', array(
'class' => 'Vendor\MyBundle\Entity\Group',
'label'=>'Group:',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('g')
->... // whatever you want to do
}
))
->getForm();
You can find more info about query builder in Doctrine manual and about options for entity in Symfony2 manual.
Bacteries' solution is a real good one. Just a note to save headache to other guy like me :)
In this part may I point out the use ($company) part.
It was hidden by the frame and of course nothing works properly without it.
$builder->add('ad', 'entity', array(
'class' =>
'\Your\Bundle\Entity\Ad',
'query_builder' =>
function(\Your\Bundle\Repository\AdRepository $er) use ($company) {
return $er->getActiveAdsQueryBuilder($company);
},
)
);
Best way (my opinion) is give to your form entityManager and select all you need in it. But don't forget to declare empty key in setDefaults() otherwise data won't pass to your builder.
Something like this one
public function buildForm(FormBuilderInterface $builder, array $options)
{
$options['em']->getRepository(''); // select all you need
$builder->add('title', 'text')
->add('content', 'textarea');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Main\BlogBundle\Entity\Post',
'validation_groups' => array('post'),
'required' => false,
'em' => null // this var is for your entityManager
));
}
Apply EM as simple option...