I have a entity
Product:
name # string
country # entity
categories #entity many-many
I have a form for that entity
ProductType:
name
categories
now i need filter categories by country but i dont wanna show a country parameter when i build the form I do
//...
$entity = new Entity\Product();
$entity->setCountry($this->getUser()->getProfile()->getCountry());
$form = $this->createForm(new Form\ProductType(), $entity);
return array('form' => $form->createView());
i want filter the categories by country in the ProductType class, how can achieve this?.
How i can pass $country value to query builder?
//...
->add('categories', 'entity', array(
'class' => 'MyBundle:Category',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBulder('c');
}
)
You are looking for the options array you can pass to a form class.
Add this to your FormType:
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'country' => null
));
}
then call the FormType like this:
$this->createForm(new Form\ProductType(), $entity, array(
'country' => $country
));
And access the $country in your buildForm method like this:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$country = $options['country'];
From there on you could build you own queryBuilder to select only the products you need.
Edit:
For accessing the $country variable in the queryBuilder you should use the use statement. It would look like this:
->add('categories', 'entity', array(
'class' => 'MyBundle:Category',
'query_builder' => function (EntityRepository $er) use($country) {
// here you can use the $country variable in your anonymous function.
return $er->createQueryBuilder('c');
}
)
)
Related
My form is on the base of self-referenced entity (category have parent category)
For the parent field, I want to have different query_builder function depending of action name. When action is update, parent field (drop-down list) contains all categories, excepting edited category. This is work good. But, when action is Create new, parent form field contains only null value (in my case Main category).
This is category form class
CategoryType class:
namespace Dimas\CatalogBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Doctrine\ORM\EntityRepository;
class CategoryType extends AbstractType {
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('name')
->add('parent', 'entity', array(
'label' => 'Parent Category ',
'empty_value' => '- Main level -',
'class' => 'DimasCatalogBundle:Category', 'property' => 'getTreeName',
'required' => false,
'query_builder' => function(EntityRepository $er) use ($options) {
$er->createQueryBuilder('u');
//need only if action is 'update'
$er->where('u.id <> :selfId');
$er->setParameter(':selfId', $options['data']->getId());
// end if
return $er;
},
));
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'Dimas\CatalogBundle\Entity\Category'
));
}
/**
* #return string
*/
public function getName() {
return 'dimas_catalogbundle_category';
}
}
Is it a good idea to add if in query_builder? How to get action name?
$options array contains action name, but it is so deep inside.
Pass in an option into the builder from your controller action that can act as a conditional:
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
if ($options['action'] === 'update') {
$callable = function (EntityRepository $er)...
} elseif ($option['action'] === 'Create new') {
$callable = function (EntityRepository $er) ...
}
...
'required' => false,
'query_builder' => $callable,
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver
->setDefaults(array(
'data_class' => 'Dimas\CatalogBundle\Entity\Category'
))
->setRequired(['action'])
;
}
// Your controller
public function createNewAction(Request $request)
{
$form = $this->createForm(new CategoryType(), $category, ['action' => 'Create new']);
}
public function updateAction(Request $request)
{
$form = $this->createForm(new CategoryType(), $category, ['action' => 'update']);
}
I achieve result this way:
I use EventListener to my form class. Learned from cookbook
Now my builForm function in CategoryType class looks like that:
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('name');
$builder->addEventListener(FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($options) {
$category = $event->getData();
$form = $event->getForm();
// check if the Category object is "new"
// If no data is passed to the form, the data is "null".
// This should be considered a new "Category"
if (!$category || null === $category->getId()) {
$form->add('parent', 'entity', array(
'label' => 'Parent Category ',
'empty_value' => '- Main level -',
'class' => 'DimasCatalogBundle:Category', 'property' => 'getTreeName',
'required' => false,
'query_builder' => function(EntityRepository $er) use ($options) {
return $er->createQueryBuilder('u');
},
));
} else {
$form->add('parent', 'entity', array(
'label' => 'Parent Category ',
'empty_value' => '- Main level -',
'class' => 'DimasCatalogBundle:Category', 'property' => 'getTreeName',
'required' => false,
'query_builder' => function(EntityRepository $er) use ($options) {
return $er->createQueryBuilder('u')
->where('u.id <> :selfId')
->setParameter(':selfId', $options['data']->getId());
},
));
}
});
}
I did not get action (but I still wont).
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.
I have form type for build form of category:
class CategoryType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('published', 'checkbox', array(
'required' => FALSE,
))
->add('parent', 'entity', array(
'class' => 'BWBlogBundle:Category',
'property' => 'name',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('c')
->where('c.id != :id')
->setParameter('id', ... /* I need to get category ID here */)
;
},
'required' => FALSE,
'empty_value' => 'Корневая категория',
))
// other my code
How can I get category ID of entity in query_builder closure in buildForm action?
answer for your question into this two questions symfony-2-how-to-pass-data-to-formbuilder and passing-data-from-controller-to-type-symfony2
1) create category variable and __construct() method into CategoryType class:
private category;
public function __construct(yourBundle\Category $category){
$this->category = $category ;
}
2) use category variable in buildForm() method into CategoryType class :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$category = $this->category;
$builder
->add('published', 'checkbox', array(
'required' => FALSE,
))
->add('parent', 'entity', array(
'class' => 'BWBlogBundle:Category',
'property' => 'name',
'query_builder' => function(EntityRepository $er) use ($category){
return $er->createQueryBuilder('c')
->where('c.id != :id')
->setParameter('id', $category->getId())
;
},
'required' => FALSE,
'empty_value' => 'Корневая категория',
))
}
finally when you create form in your controller :
$category = new Category();
$form = $this->createForm(new CategoryType($category),$category);
I don't know if these answers are as valid now. If you have the following code to create a form in your controller:
$fooEntity = $entityManager->find(FooEntity::class, 123);
$form = $this->createForm(MyFormType::class, $fooEntity);
... then the MyFormType::buildForm() method will be passed the $options parameter which will have $options['data'] that contains the entity that you passed to createForm(), i.e., $fooEntity in this case. This is assuming you don't override the 'data' key option with your own value. So you should be able to get the entity's ID from that.
class CategoryType extends AbstractType
{
private $category_id;
public function __construct($category_id=null)
{
$this->category_id = $category_id;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('published', 'checkbox', array(
'required' => FALSE,
))
->add('parent', 'entity', array(
'class' => 'BWBlogBundle:Category',
'property' => 'name',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('c')
->where('c.id != :id')
->setParameter('id', $this->category_id) /* I need to get category ID here */)
;
},
'required' => FALSE,
'empty_value' => 'Корневая категория',
))
// other my code
}
And when you create your form, do something like
public myFooController()
{
//retrieve %category_id here
$form = $this->creteForm(new CategoryType($category_id));
[...]
}
$options['data'] contains the entity for which the type is built.
I have this code
->add('user', 'entity', array(
'class' => 'Acme\Entity\User',
'query_builder' => function(EntityRepository $er) use ($options)
{ return $er->createQueryBuilder('u')
->orderBy('u.name', 'ASC');
},
'data' => $option['id']
))
Its not working
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('description')
->add('user', 'entity', array(
'class' => 'Acme\Entity\User',
'query_builder' => function(EntityRepository $er) use ($options) {
return $er->createQueryBuilder('u');
},
'preferred_choices' => array('2')
))
;
}
You can use the one of the following:
Set a default value in the object
$cl->setUser($this->getDoctrine()->getEntityManager()->getReference('Acme:User',2));
Use a preferred choices option in the form builder:
'preferred_choices' => array('2')
Or set 'property_path' => false and use a 'data' => YourDefaultEnity
The form should map the user->id value automatically to the selected entity select field. For example if your have a Computer entity that has a OnetoOne relationship with a User entity in a join table called 'computer_users':
class Computer{
private $user;
/**
* #ORM\OneToOne(targetEntity="ComputerUser", mappedBy="computer")
*/
private $computerUsers;
public function getUser(){
return $computerUsers->getUser();
}
private function getComputerUser(){
return $this->$computerUsers;
}
}
The field 'user' in the form class should pick up the user->id value from the 'user' attribute object in the Computer class passed to the form.
Alternatively, you can explicitly set the value by explicitly passing the user entity into the form using SetData():
$computerForm = $this->createForm( new ComputerForm(), $computer );
$user = $computer->getComputerUser()->getUser();
$computerForm->get('user')->setData( $user );
return $this->render( 'AcmeBundle:Computer:edit.html.twig'
, array( 'computer' => $computer
, 'computerForm' => $computerForm->createView()
)
);
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...