doctrine queryBuilder where IN collection - symfony

On my entity I have an array collection of users
/**
* #ORM\ManyToMany(targetEntity="\UserBundle\Entity\User", mappedBy="acr_groups")
*/
protected $users;
public function __construct() {
$this->users = new \Doctrine\Common\Collections\ArrayCollection();
}
In my FormType I want to filter out those groups wherein current user is a member:
$builder
->add('acr_group', EntityType::class, array(
'label' => 'ATS',
'class' => 'HazardlogBundle:ACRGroup',
'query_builder' => function (EntityRepository $er) use ($user) { // 3. use the user variable in the querybilder
$qb = $er->createQueryBuilder('g');
$qb->where(':user IN (g.users)');
$qb->setParameters( array('user' => $user) );
$qb->orderBy('g.name', 'ASC');
return $qb;
},
'choice_label' => 'name'
))
My problem is obviously on this line:
$qb->where(':user IN (g.users)');
How can I use my collection of users as the argument for the IN()?

Try below code
$user = array(12,211,612,84,63,23); // Assuming User Ids whose groups you want to retrive
$builder
->add('acr_group', EntityType::class, array(
'label' => 'ATS',
'class' => 'HazardlogBundle:ACRGroup',
'query_builder' => function (EntityRepository $er) use ($user) {
$qb = $er->createQueryBuilder('g');
$qb->innerJoin('g.users', 'u'); // Inner Join with users
$qb->where('u.id IN (:user)');
$qb->setParameters( array('user' => $user) );
$qb->orderBy('g.name', 'ASC');
return $qb;
},
'choice_label' => 'name'
))
I have tried it in symfony 2.3 with doctrine2. You can use select function with createQueryBuilder() to get specific columns.

$q = $this->createQueryBuilder('v')
->select('v')
->andWhere('v.workingHours IN (:workingHours)')
->setParameter('workingHours', $workingHours);
From : Doctrine 2 WHERE IN clause using a collection of entities
Or according to doctrine documentation : http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/query-builder.html#the-expr-class
To insert IN condition in query builder with doctrine you can use expr()
$qb->add('select', new Expr\Select(array('u')))
->add('from', new Expr\From('User', 'u'))
->add('where', $qb->expr()->orX(
$qb->expr()->eq('u.id', '?1'),
$qb->expr()->like('u.nickname', '?2')
))
->add('orderBy', new Expr\OrderBy('u.name', 'ASC'));
Syntaxe of IN :
$qb->expr()->in('u.id', array(1, 2, 3))
Also, Make sure that you do NOT use something similar to $qb->expr()->in('value', array('stringvalue')) as this will cause Doctrine to throw an Exception. Instead, use $qb->expr()->in('value', array('?1')) and bind your parameter to ?1

I ended up turning thing around a bit after unsuccessfully attempting some of your solutions. I manually created an array of the IDs I wanted.
There is probably a native way of doing this, seems like a pretty standard thing... this works however.
// 1. to inject user entity into this builder first make a construct function (remember to inject it from controller!)
function __construct($user)
{
$this->user = $user;
}
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$user = $this->user; // 2. instantiate the variable we created in our construct above
//create group list array
$groupList = $this->user->getACRGroups();
$gla = array();
foreach ($groupList as $g) {
$gla[] = $g->getId();
};
$builder
->add('acr_group', EntityType::class, array(
'label' => 'ATS',
'class' => 'HazardlogBundle:ACRGroup',
'query_builder' => function (EntityRepository $er) use ($gla) { // 3. use the user variable in the querybilder
$qb = $er->createQueryBuilder('g');
$qb->where('g.id IN (:gla)');
$qb->setParameters( array('gla' => $gla) );
$qb->orderBy('g.name', 'ASC');
return $qb;
},
'choice_label' => 'name'
))

Related

Symfony 3: How to use two choices/dropdowns from two tables in one form

Symfony version 3.1.3
I have created a dropdown using the entity called Classes and you can see the Controller below,
public function studentAddClassAction( $id, Request $request )
{
// get the student from the student table
$em = $this->getDoctrine()->getManager();
$user = $em->getRepository('PIE10Bundle:Users')->find($id);
// new class object and create the form
$classes= $em->getRepository('PIE10Bundle:Classes')->findAll();
$form = $this->createForm(ClassType::class, $classes);
$form->handleRequest($request);
if( $form->isSubmitted() && $form->isValid() )
{
// form submit operations
}
return $this->render(
'PIE10Bundle:student:layout_student_addclass.html.twig',
array(
'user' => $user,
'title' => 'Add Class',
'tables'=> 1,
'form' => $form->createView()
)
);
}
and the ClassType is below
class ClassType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('classes',
EntityType::class,
array('class' => 'PIE10Bundle:Classes',
'expanded' => false,
'multiple' => false,));
$builder->add('Add Class',
SubmitType::class,
array('attr' => array('class' => 'btn btn-primary',
'style' => 'margin:15px 0;')) );
}
}
And this works fine and it gives all the classes from the database. Also I have another entity called Users and it has a column called roles (DC2Type:array) and it has a role called ROLE_PARENT and I can retrieve all the parents using the following query
$query = $this->getDoctrine()->getEntityManager()
->createQuery('SELECT u FROM PIE10Bundle:Users u WHERE u.roles LIKE :role')
->setParameter('role', '%"ROLE_PARENT"%' );
$users = $query->getResult();
My Question is how to add these parents list as a choice list into same above form in the studentAddClassAction Controller.
Please let me know in any other information is needed for this.
To have a custom set of entities as a choice list you need to use a query_builder option
So it will look like
$builder->add('parent',
EntityType::class,
array('class' => 'PIE10Bundle:Users',
'expanded' => false,
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('u')
->where('u.roles LIKE :role')
->setParameter('role', '%"ROLE_PARENT"%');
},
'multiple' => false
));

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 Form query_builder - allow null

In Symfony2 forms, when trying to get entities, Symfony expects to receive QueryBuilder object, but sometimes there are no entities returned. In that case, an error message appears:
Expected argument of type "Doctrine\ORM\QueryBuilder", "NULL" given
How to make query_builder to allow option that there are no entities available.
$builder
->add('client', 'entity', array(
'class' => 'Faktura\FakturaBundle\Entity\Client',
'query_builder' => function(\Web\MyBundle\Repository\ClientRepository $er) use ($company){
return $er->getClients($company);
))
;
ClientRepository.php
public function getClients($company)
{
$qb = $this->createQueryBuilder('c')
->select('c')
->where('c.company = :company')
->setParameter('company', $company)
->getQuery();
return $qb->getResult();
}
Actually, it's just basic $er->findBy(array('company' => $company)) method
but I use custom getClients() method
Your Closure should return QueryBuilder object, not results of it.
Your ClientRepository should look like:
public function getClients($company)
{
$qb = $this->getClientsQueryBuilder($company);
return $qb->getQuery()->getResult();
}
public function getClientsQueryBuilder($company)
{
return $this->createQueryBuilder('c')
->select('c')
->where('c.company = :company')
->setParameter('company', $company);
}
And then you need to use getClientQueryBuilder in your Closure.
$builder
->add('client', 'entity', array(
'class' => 'Faktura\FakturaBundle\Entity\Client',
'query_builder' => function(\Web\MyBundle\Repository\ClientRepository $er) use ($company){
return $er->getClientsQueryBuilder($company);
))
;

Symfony2 : Form View - add another field on entity field type

I have the following code in my buildForm method of my FormType
$builder->add('privileges', 'entity', array(
'label' => 'Privileges',
'expanded' => true,
'multiple' => true,
'class' => 'AcmeStoreBundle:AdminPrivilege',
'property'=> 'description',
'query_builder' => function(EntityRepository $er) use ($category)
{
return $er->createQueryBuilder('p')
->where('p.categoryid = :categoryID')
->andWhere('p.parentid = -1')
->setParameter('categoryID', $category->getId())
->orderBy('p.position', 'ASC');
}
));
Here if the parentid is greater than -1, then i'd like to show further form components after the checkbox where parentid is greater than -1 is created.
I've searched over Google and have been unable to find a way to do this, can anybody help?
Mat.
If I understand correctly, you can inject parentid and entity manager to form type construct from controller.
So you can run query before add field to builder, and use if-else. For example:
public function __construct($parentId, $em)
{
$this->parentId = $parentId;
$this->em = $em;
}
public function buildForm(FormBuilder $builder, array $options)
{
$choices = $this->em->getRepository()->callNeededMethod();
if($this->parentId){
$builder->add([someFieldParams]);
}else{
$builder->add([anoutherFieldParams]);
}
}

passing data from controller to Type symfony2

if i show a field of type "entity" in my form, and i want to filter this entity type based on a argument I pass from the controller, how do i do that.. ?
//PlumeOptionsType.php
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('framePlume', 'entity', array(
'class' => 'DessinPlumeBundle:PhysicalPlume',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('pp')
->where("pp.profile = :profile")
->orderBy('pp.index', 'ASC')
->setParameter('profile', ????)
;
},
));
}
public function getName()
{
return 'plumeOptions';
}
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'Dessin\PlumeBundle\Entity\PlumeOptions',
'csrf_protection' => true,
'csrf_field_name' => '_token',
// a unique key to help generate the secret token
'intention' => 'plumeOptions_item',
);
}
}
and inside the controller, i create the form :
i have that argument that i need to pass in my action code:
$profile_id = $this->getRequest()->getSession()->get('profile_id');
...
and then i create my form like this
$form = $this->createForm(new PlumeOptionsType(), $plumeOptions);
the $plumeOptions is just a class to persist. But it has a one-to-one relationship with another class called PhysicalPlume. Now, when i want to display the 'framePlume' in my code, i want to show a filtered PhysicalPlume entity.
You can pass parameters to the form class as follows:
//PlumeOptionsType.php
protected $profile;
public function __construct (Profile $profile)
{
$this->profile = $profile;
}
Then use it in the query_builder of your buildForm:
$profile = $this->profile;
$builder->add('framePlume', 'entity', array(
'class' => 'DessinPlumeBundle:PhysicalPlume',
'query_builder' => function(EntityRepository $er) use ($profile) {
return $er->createQueryBuilder('pp')
->where("pp.profile = :profile")
->orderBy('pp.index', 'ASC')
->setParameter('profile', $profile)
;
},
));
And finally in your controller:
// fetch $profile from DB
$form = $this->createForm(new PlumeOptionsType($profile), $plumeOptions);
You can use $plumeOptions to pass everything your argument, but you'll need to add a getDefaultOptions() in PlumeOptionsType to specify the default value for your option.
See for instance https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Form/Extension/Core/Type/CheckboxType.php to see what this method should look like.

Resources