I would like to know if it's possible to check if an array contains any element of another array in doctrine query builder.
In my case, i want to get all the products (items) who have at least one of the category in the array passed in parameter.
Relationship between Item and Category :
/**
* @ORM\ManyToMany(targetEntity="Category")
* @ORM\JoinTable(name="items_categories",
* joinColumns={@ORM\JoinColumn(name="item_id", referencedColumnName="id", nullable=false)},
* inverseJoinColumns={@ORM\JoinColumn(name="category_id", referencedColumnName="id", nullable=false)}
* )
*/
private $categories;
My first try from the Item repository (i know this work if i have only one value to check):
public function getListItemsFromCatList($listCat) {
$qb = $this->createQueryBuilder('i');
$qb->select('i')
->where($qb->expr()->like('i.categories', ':listCat'))
->setParameter('listCat', '%"' . $listCat . '"%');
return $qb->getQuery()->getResult();
}
$listCat is an array of Category Entity :
array (size=5)
0 =>
object(ItemBundle\Entity\Category)[518]
private 'id' => int 22
private 'children' =>
object(Doctrine\ORM\PersistentCollection)[520]
private 'snapshot' =>
array (size=2)
...
private 'owner' =>
&object(ItemBundle\Entity\Category)[518]
private 'association' =>
array (size=15)
...
private 'em' =>
object(Doctrine\ORM\EntityManager)[796]
...
private 'backRefFieldName' => string 'parent' (length=6)
private 'typeClass' =>
object(Doctrine\ORM\Mapping\ClassMetadata)[579]
...
private 'isDirty' => boolean false
protected 'collection' =>
object(Doctrine\Common\Collections\ArrayCollection)[515]
...
protected 'initialized' => boolean true
private 'parent' => null
private 'name' => string 'Luxe' (length=4)
1 =>
object(ItemBundle\Entity\Category)[504]
private 'id' => int 25
private 'children' =>
object(Doctrine\ORM\PersistentCollection)[505]
private 'snapshot' =>
array (size=0)
...
private 'owner' =>
&object(ItemBundle\Entity\Category)[504]
private 'association' =>
array (size=15)
...
private 'em' =>
object(Doctrine\ORM\EntityManager)[796]
...
private 'backRefFieldName' => string 'parent' (length=6)
private 'typeClass' =>
object(Doctrine\ORM\Mapping\ClassMetadata)[579]
...
private 'isDirty' => boolean false
protected 'collection' =>
object(Doctrine\Common\Collections\ArrayCollection)[500]
...
protected 'initialized' => boolean false
private 'parent' =>
object(ItemBundle\Entity\Category)[512]
private 'id' => int 23
private 'children' =>
object(Doctrine\ORM\PersistentCollection)[513]
...
private 'parent' =>
object(ItemBundle\Entity\Category)[518]
...
private 'name' => string 'Bijoux' (length=6)
private 'name' => string 'Bagues' (length=6)
Use the inbuilt ES6 function some() to iterate through each and every element of first array and to test the array. Use the inbuilt function includes() with second array to check if element exist in the first array or not. If element exist then return true else return false.
If you can populate a one column table with the values that you need to test against then you could do this. If the count is equal to the number of values you're testing against then the array forms a subset. Of course this assumes that you're using a SQL variant with intersect. Dems' solution should work everywhere.
The in_array() function is an inbuilt function in PHP that is used to check whether a given value exists in an array or not. It returns TRUE if the given value is found in the given array, and FALSE otherwise.
I would solve it adding a join.
public function getListItemsFromCatList($listCat) {
$em = $this->getDoctrine()->getManager();
$qb = $em->createQueryBuilder();
$qb->select('i')
->from('AppBundle:Item', 'i')
->innerJoin('i.categories','cat')
->where('cat IN (:listCat)')
->setParameter('listCat', $listCat);
return = $qb->getQuery()->getResult();
}
Notice this approach will filter the categories inside items. It means that when you try to get categories from a given item i
, $i->getCategories()
, it will return only the categories from i
which matchs with $listCat
.
If you will need to use all categories from each item, even those doesn't match with $listCat
. I will recommend you to use subqueries to filter, and main query to return the full items. Let a comment if you need any futher help with that.
Try your query builder like this instead:
$em = $this->getDoctrine()->getManager();
$qb = $em->createQueryBuilder();
$qb->select('i')
->from('AppBundle:Item', 'i')
->where('i.categories LIKE :listCat')
->setParameter('listCat', '%"' . $listCat . '"%');
return = $qb->getQuery()->getResult();
I think that should work. I'm presuming the Entity in Doctrine you are using is called Item
.
EDIT #2 - based on comments
You need to loop through the array and get the name (I think), which I think is the category you are looking for. In this code I show looping through to create a $cats
variable, and then use that in a IN
query.
foreach ($listCat as $item){
$cats = $cats . "'" . $item.getName() . "'".',';
}
$cats = substr($cats, -1);
$em = $this->getDoctrine()->getManager();
$qb = $em->createQueryBuilder();
$qb->select('i')
->from('AppBundle:Item', 'i')
->where("i.categories IN (:listCat)")
->setParameter('listCat', $cats);
return = $qb->getQuery()->getResult();
Can you try it? I think you need something like that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With