how to search array words with Doctrine DQL using bucle - symfony

i'm trying to search words stored in array in this way:
$dql_cat =' SELECT c
FROM FrontendBundle:Categoria c
WHERE';
foreach ($palabras as $palabra){
if ($palabra === reset($palabras)){
$dql_cat .= ' c.nombre LIKE %'.$palabra.'%';
}
else{
$dql_cat .= ' OR c.nombre LIKE %'.$palabra.'%';
}
}
$dql_cat .= ' ORDER BY c.nombre';
$query = $em->createQuery($dql_cat);
$resultados['categorias'] = $query->getResult();
But i get an exception with the query.
Query result:
SELECT c
FROM FrontendBundle:Categoria c
WHERE c.nombre LIKE %carpinteria% OR c.nombre LIKE %aluminio% ORDER BY c.nombre
Query exception:
QueryException: [Syntax Error] line 0, col 98: Error: Expected StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression, got '%'
I think that is more proper to use queryBuilder to avoid mistakes but i don't know how to use it with a parameters array.
I need a solution with or without queryBuilder.
Thanks.

queryBuilder would be as follows:
$qb = $em->createQueryBuilder();
$qb->select('c')
->from('FrontendBundle:Categoria', 'c');
foreach ($palabras as $palabra){
if ($palabra === reset($palabras)){
$qb->where($qb->expr()->like('c.nombre', $qb->expr()->literal('%' . $palabra . '%')));
}
$qb->orWhere($qb->expr()->like('c.nombre', $qb->expr()->literal('%' . $palabra . '%')));
}
$query = $qb->orderBy('c.nombre', 'ASC')
->getQuery();
$resultados['categorias'] = $query->getResult();

To begin with %$palabra% should be quoted, right?:
foreach ($palabras as $palabra){
if ($palabra === reset($palabras)){
$dql_cat .= " c.nombre LIKE '%".$palabra."%'";
}
else{
$dql_cat .= " OR c.nombre LIKE '%".$palabra."%'";
}
}

Related

Query builder - adding methods depending on if statement

I have a problem with query builder notation. I would like to add additional methods depending on if statement. I'm writhing like below but it is not working
$repository->createQueryBuilder('k')
->where('k.autor LIKE :autor OR k.tytul LIKE :tytul ');
if($tag!==''){
$repository->createQueryBuilder('k')->andWhere('k.cena=:jezyk');
$repository->createQueryBuilder('k') ->setParameter('jezyk',$tag);
}
$repository->createQueryBuilder('k')->setParameter('autor', '%' . $s . '%');
$repository->createQueryBuilder('k')->setParameter('tytul', '%' . $s . '%');
query=$repository->createQueryBuilder('k')->getQuery();
$searched_books = $query->getResult();
I suppose that I made mistakeswith objects. Can somebody h.lp me? Thanks in advance
the problem is that the createQueryBuilder method will create a new query builder at each call. You should try something like that:
$qb = $repository->createQueryBuilder('k');
$qb->where('k.autor LIKE :autor OR k.tytul LIKE :tytul');
if ($tag !== '') {
$qb->andWhere('k.cena = :jezyk');
$qb->setParameter('jezyk', $tag);
}
$qb->setParameter('autor', '%' . $s . '%');
$qb->setParameter('tytul', '%' . $s . '%');
$searched_books = $qb->getQuery()->getResult();

Create a Query using QueryBuilder with two Many-to-Many relation in Symfony2

Good evening everybody!
I have got a problem with the QueryBuilder in Symfony2.
A USER can be part of some GROUPS. Each GROUP can access to CATEGORIES. Here is a little database diagram.
Now, I would like to retrieve Categories for a User with the QueryBuilder in order to put the result in a form thanks to my CategoryRepository. Here is the corresponding SQL Statement (in the example I put 1 for the user_id but it is provided by $user->getId() in the CategoryRepository.
SELECT theCategoryObject
FROM category C, category_group CG, group G, user_group UG, user U
WHERE FU.id = 1
AND U.user_id = UG.user_id
AND UG.group_id = G.group_id
AND CG.group_id = G.group_id
AND CG.category_id = C.category_id
I tried to use EXISTS and MEMBER OF but it does not filter anything.
public function findByUserQueryBuilder(User $user)
{
$qb = $this->createQueryBuilder('c');
$qb->where('c.isSelectionable = true');
foreach ($user->getGroups() as $group)
{
$qb->andWhere('EXISTS (SELECT ' . $group->getId() . ' FROM ISIMA\Bundle\UserBundle\Entity\Group g' . $group->getId() . ' WHERE g' . $group->getId() . ' MEMBER OF c.groups)');
}
return $qb;
}
Thanks for your future answers !
Finally, I found the solution ! I forgot to define the group Id and place an Or condition in case of the User is part of several groups.
public function findByUserQueryBuilder(User $user)
{
$qb = $this->createQueryBuilder('c');
$qb->where('c.isSelectionable = true')
$i = 0;
foreach ($user->getGroups() as $group)
{
$query = 'EXISTS (SELECT 1 FROM ISIMA\Bundle\UserBundle\Entity\Group g' . $group->getId() . ' WHERE g' . $group->getId() . '.id = ' . $group->getId() . ' AND g' . $group->getId() . ' MEMBER OF c.groups)';
if($i == 0)
{
$qb->andWhere($query);
$i = 1;
}
else
{
$qb->orWhere($query);
}
}
return $qb;
}

How can I modify this doctrine query builder?

The profiler shows this query:
SELECT
count(DISTINCT c0_.id) AS sclr0
FROM
customers c0_
LEFT JOIN customers_addresses c1_ ON c0_.id = c1_.customer_id
LEFT JOIN customers_phones c2_ ON c0_.id = c2_.customer_id
WHERE
(
c0_.is_lead = ?
AND c0_.firstname LIKE ?
)
OR c0_.lastname LIKE ?
OR c0_.email LIKE ?
OR c0_.company LIKE ?
OR c1_.street_address1 LIKE ?
OR c1_.street_address2 LIKE ?
OR c1_.city LIKE ?
OR c1_.state = ?
OR c1_.zipcode = ?
OR c2_.phone LIKE ?
And clearly is not what I want, I want it to be like this:
SELECT
count(DISTINCT c0_.id) AS sclr0
FROM
customers c0_
LEFT JOIN customers_addresses c1_ ON c0_.id = c1_.customer_id
LEFT JOIN customers_phones c2_ ON c0_.id = c2_.customer_id
WHERE
(
c0_.is_lead = ?
)
AND
(c0_.firstname LIKE ?
OR c0_.lastname LIKE ?
OR c0_.email LIKE ?
OR c0_.company LIKE ?
OR c1_.street_address1 LIKE ?
OR c1_.street_address2 LIKE ?
OR c1_.city LIKE ?
OR c1_.state = ?
OR c1_.zipcode = ?
OR c2_.phone LIKE ?
)
My query builder looks like this:
public function search($keywords = null, $lead=0){
if ($keywords === null) return $this->findAllOrderedByName($lead);
$qb = $this->createQueryBuilder ('c')
->addSelect('a')
->addSelect('p')
->leftJoin('c.addresses', 'a')
->leftJoin('c.phones', 'p');
$qb->where('c.isLead = :lead');
$qb->andWhere('c.firstname like :firstname');
$qb->orWhere('c.lastname like :lastname');
$qb->orWhere('c.email like :email');
$qb->orWhere('c.company like :company');
$qb->orWhere('a.streetAddress1 like :streetAddress1');
$qb->orWhere('a.streetAddress2 like :streetAddress2');
$qb->orWhere('a.city like :city');
$qb->orWhere('a.state = :state');
$qb->orWhere('a.zipcode = :zipcode');
$qb->orWhere('p.phone like :phone');
$qb->setParameter('lead', $lead);
$qb->setParameter('firstname', '%' . $keywords . '%');
$qb->setParameter('lastname', '%' . $keywords . '%');
$qb->setParameter('email', '%' . $keywords . '%');
$qb->setParameter('company', '%' . $keywords . '%');
$qb->setParameter('streetAddress1', '%' . $keywords . '%');
$qb->setParameter('streetAddress2', '%' . $keywords . '%');
$qb->setParameter('city', '%' . $keywords . '%');
$qb->setParameter('state', $keywords);
$qb->setParameter('zipcode', $keywords);
$qb->setParameter('phone', '%' . $keywords . '%');
$qb->orderBy('c.lastname', 'ASC');
return $qb;
}
The way I currently have my query builder returns results even when the search keywords do not match any records because of the joins, I don't know how I can modify the query builder method, any ideas?
You can write it as
$qb->andWhere('(c.firstname like :firstname
OR c.lastname like :lastname
OR c.email like :email
OR c.company like :company
OR a.streetAddress1 like :streetAddress1
OR a.streetAddress2 like :streetAddress2
OR a.city like :city
OR a.state = :state
OR a.zipcode = :zipcode
OR p.phone like :phone)');
Have you tried to used addAnd(<condition>) instead of andWhere() ?
I think you could make use of the orX and then rewrite it as..
public function search($keywords = null, $lead=0){
if ($keywords === null) return $this->findAllOrderedByName($lead);
$qb = $this->createQueryBuilder ('c')
->addSelect('a')
->addSelect('p')
->leftJoin('c.addresses', 'a')
->leftJoin('c.phones', 'p');
$qb->where(
$qb->expr()->eq('c.isLead', ':lead')
)->andWhere(
$qb->expr()
->orX($qb->expr()->like('c.firstname', ':keywords'))
->add($qb->expr()->like('c.lastname', ':keywords'))
->add($qb->expr()->like('c.email', ':keywords'))
->add($qb->expr()->like('c.company', ':keywords'))
->add($qb->expr()->like('a.streetAddress1', ':keywords'))
->add($qb->expr()->like('a.streetAddress2', ':keywords'))
->add($qb->expr()->like('a.city', ':keywords'))
->add($qb->expr()->eq('a.state', ':keywords'))
->add($qb->expr()->eq('a.zipcode', ':keywords'))
->add($qb->expr()->like('p.phone', 'keywords'))
);
$qb->setParameter('lead', $lead);
$qb->setParameter('keywords', '%' . $keywords . '%');
$qb->orderBy('c.lastname', 'ASC');
return $qb;
}

Order By with DAY(), MONTH() is not working in doctrine2

I am trying to order results of my query by day and month, here is my code
public function getUserBirthday($idList)
{
$queryBuilder = $this->_em->createQueryBuilder();
$queryBuilder->select('fb')
->from('Wishwish\ApplicationBundle\Entity\FbUser', 'fb')
->where(' Week(fb.birthday)<= Week(:now)+2')
->andWhere('Week(fb.birthday)> Week(:now)')
->andWhere('fb.id IN (:idList)')
->orderBy('DAY(fb.birthday)')
->addOrderBy('MONTH(fb.birthday)');
$queryBuilder->setParameter('now', new \DateTime());
$queryBuilder->setParameter('idList',$idList);
return $queryBuilder->getQuery()->getResult();
}
this id the error displayed :
[Syntax Error] line 0, col 170: Error: Expected end of string, got '('
500 Internal Server Error - QueryException
1 linked Exception: QueryException ยป
update =>solution :
the trick was to use createNativeQuery
public function getUserBirthday($idList)
{
$rsm = new ResultSetMapping();
$rsm->addEntityResult('Wishwish\ApplicationBundle\Entity\FbUser', 'fb');
$rsm->addFieldResult('fb', 'birthday', 'birthday');
$rsm->addFieldResult('fb', 'picture', 'picture');
$rsm->addFieldResult('fb', 'name', 'name');
$rsm->addFieldResult('fb', 'id', 'id');
$sql ='select * from fb_user
where (Week(birthday)<= Week(:now)+2) and (Week(birthday)> Week(:now))
and (id IN (:idList)) ORDER By DAY (birthday),MONTH (birthday)';
$query = $this->_em->createNativeQuery($sql, $rsm);
$query->setParameter('now', new \DateTime());
$query->setParameter('idList',$idList);
return $query->getResult();
}
Try to use createNativeQuery() method for more complex query:
use Doctrine\ORM\Query\ResultSetMapping;
$rsm = new ResultSetMapping();
$query = $this->_em->createNativeQuery('
SELECT fb
FROM WishwishApplicationBundle:FbUser fb
WHERE Week(fb.birthday) <= Week(:now)+2
AND Week(fb.birthday) > Week(:now)
AND fb.id IN (:idList)
ORDER BY DAY(fb.birthday) ASC, MONTH(fb.birthday) ASC
', $rsm)
->setParameter('now', new \DateTime())
->setParameter('idList',$idList);
$result = $query->getResult();

Doctrine Query Builder LOWER not working

Somehow doctrine is not allowing me to compare two lowerstring values: that of a variable and the first name of a user.
$qb = $this->getEntityManager()->createQueryBuilder();
$qb
->select('d')
->from('MyBundle:User', 'd')
->where('LOWER(d.firstName) LIKE :fName')
->setParameter('fName', strtolower('%'.$fName.'%'));
$result = $qb->getQuery()->execute();
only when $fName has an uppercase string (i.e. 'Rob'), it will return results like 'Robert' and 'Robby'. But what I want is that even when $fName is spelled lowercase ('rob'), these results should come up. It seems that the d.firstNames are not lowered. Why is this the case?
I found the solution:
$qb = $this->getEntityManager()->createQueryBuilder();
$qb
->select('u')
->from('MyBundle:User', 'u')
->where($qb->expr()->andX(
$qb->expr()->like('LOWER(u.firstName)', '?1'),
$qb->expr()->like('LOWER(u.lastName)', '?2')
))
->setParameter('1', '%' . strtolower($firstName) . '%')
->setParameter('2', '%' . strtolower($lastName) . '%');
$result = $qb->getQuery()->execute();
Still curious why the first attempt was not working.
you can use :
mb_strtolower()
http://php.net/manual/en/function.mb-strtolower.php

Resources