Doctrine Query Builder LOWER not working - symfony

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

Related

Compare a count of subquery with scalar

I'm using Symfony 4.3 and I have a problem in my DQL query.
The purpose of my query is to select email of user how have list of right for this is my DQL query:
$qb = $this->createQueryBuilder('u')
->select('u.email,u.id')
->leftJoin('u.profile', 'profile')
->leftJoin('u.country', 'country')
->leftJoin('profile.privileges', 'pri')
->leftJoin('pri.ressource', 'resource')
$checkRightQuery = $this->em->createQueryBuilder()
->select('count(rc)')
->from(Ressource::class, 'rc')
->leftJoin('rc.privileges', 'privil')
->leftJoin('privil.profile', 'prof')
->leftJoin('prof.user', 'user')
->where( $this->em->getExpressionBuilder()->in('rc.actionFront', ':rights'))
->andWhere('user.id =u.id');
$qb->andWhere(
$this->em->getExpressionBuilder()->eq(count($rights),
$checkRightQuery
)
);
$qb->setParameters(['rights' => $rights]);
The problem is when I take the result of the count it's not a scalar and it can't compare it to scalar.
Any help please?
Try using parenthesis on your condition with the subquery:
$qb->andWhere(
$this->em->getExpressionBuilder()->eq(count($rights),
'(' . $checkRightQuery . ')'
)
);
References
Doctrine return error with “eq”, no with “in”

Convert SQL query into Drupal 7 PHP rules

SELECT address
FROM user_address
WHERE username = '$user->name'
ORDER BY time DESC
LIMIT 1
Here is the SQL query that I can understand. How is it possible to convert it into Drupal's 7 PHP? I'm trying to figure that out for a day, and I tried different approaches, but it seems that I am just bad in that.
You can use db_select :
$results = db_select('user_address', 'ua')
->fields('ua', array('address'))
->condition('ua.username', $user->name, '=')
->orderBy('ua.time', 'DESC')
->range(0,1)
->execute()
->fetchAll();
var_dump($results);
Otherwise you can use db_query if you want to write entire SQL :
$results = db_query("SELECT address
FROM user_address
WHERE username = :username
ORDER BY time DESC
LIMIT 1 ", array(':username' => $user->name))->fetchAll();
var_dump($results);
Finally you can use db_query_range :
$page = 0;
$limit = 1
$results = db_query_range("SELECT address
FROM user_address
WHERE username = :username
ORDER BY time DESC",
$page * $limit,
$limit,
array(':username' => $user->name))
->fetchAll();
var_dump($results);
Try this:
$result = db_select('user_address', 'ua')
->fields('ua', array('address'))
->condition('ua.username', $user->name)
->execute()
->fetchAll();
For that we use db_select() or db_query() - first one preferable.
$query = db_select('user_address', 'u');
// Add condition and fields
$query->condition('u.username', ‘james’)
$query->fields('u’ array('u.address'));
// execute it
$result = $query->execute();
foreach ($result as $record) {
// Do something with each $record
}
For more see
https://www.drupal.org/docs/7/api/database-api/dynamic-queries/introduction-to-dynamic-queries.
update: see condition portion. Also, you can put this in a module or php executable area of your site or via drush command line.
Change the username James to match your need
$result = $result = db_select('usr_address','u')
->fields('u',array('address','uid'))
->range(0,1)
->orderby('time', 'DESC')
->condition('u.uid',$uid,'=')
->execute();
here is how it actually worked.
Thank you for your suggestions, but at the end I made it. By myself. Well, kinda ;D

DQL How to return all records when parameter is empty

I am building a Symfony app where a user can make some search through a search form with many fields. Now my DQL query looks like this:
$users = $repository->createQueryBuilder('u')
->addSelect('u')
->from('AppBundle:User', 'b')
->where('u.Number = :Number **OR u.Number = :blank'**)
->andWhere('u.Code = :Code')
->setParameter('Number', $Number)
->setParameter('blank', $blank)
->setParameter('Code', $code)
->getQuery()
->getResult();
The problem is that I want my request to return ALL records related to the criteria when a user leaves some fields blank. Right now no records are returned because the system thinks I want entries with particular "blank" criteria. I would appreciate any ideas. Thank you
You can use Expr class in DQL to further structure query around 'blank' field submitted by user. Simple if(!empty($field)) will do the trick
$query = $repository->createQueryBuilder('u')
->addSelect('u')
->from('AppBundle:User', 'b')
->where('u.Number = :Number')
->andWhere('u.Code = :Code')
->setParameter('Number', $Number)
->setParameter('Code', $code);
if(!empty($blank)){
$query->andWhere($query->expr()->orX(
$query->expr()->eq('u.Number', ':blank')
));
$query->setParameter('blank', $blank);
}
$users = $query->getQuery()->getResult();
If I understand correctly, you actually have 2 parameters in this case, which are: Number and Code. And if one of them is "blank", then you have the blank variable set ?
If this is the case, I think you should write your request like this:
$query = $repository->createQueryBuilder('u')
->addSelect('u')
->from('AppBundle:User', 'b')
if ($Number != "")
$query->where('u.Number = :Number')
->setParameter('Number', $Number);
if ($code != "") {
if ($Number != "") $query->andWhere('u.Code = :Code');
else $query->where('u.Code = :Code');
$query->setParameter('Code', $code);
}
$users = $query->getQuery()->getResult();

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;
}

'where not in' query with doctrine query builder

Im trying to reproduce this query:
SELECT * FROM `request_lines`
where request_id not in(
select requestLine_id from `asset_request_lines` where asset_id = 1
)
in doctrine query builder,
I am stuck on the where request_id not in(select
I currently have:
$linked = $em->createQueryBuilder()
->select('rl')
->from('MineMyBundle:MineRequestLine', 'rl')
->where()
->getQuery()
->getResult();
You need to use query builder expressions, and this means you need access to the query builder object. Also, the code is easier to write if you generate the subselect list ahead of time:
$qb = $em->createQueryBuilder();
$nots = $qb->select('arl')
->from('$MineMyBundle:MineAssetRequestLine', 'arl')
->where($qb->expr()->eq('arl.asset_id',1))
->getQuery()
->getResult();
$linked = $qb->select('rl')
->from('MineMyBundle:MineRequestLine', 'rl')
->where($qb->expr()->notIn('rl.request_id', $nots))
->getQuery()
->getResult();
It is possible to do this in one Doctrine query:
$qb = $this->_em->createQueryBuilder();
$sub = $qb;
$sub = $qb->select('arl')
->from('$MineMyBundle:MineAssetRequestLine', 'arl')
->where($qb->expr()->eq('arl.asset_id',1));
$linked = $qb->select('rl')
->from('MineMyBundle:MineRequestLine', 'rl')
->where($qb->expr()->notIn('rl.request_id', $sub->getDQL()))
->getQuery()
->getResult();
Check the reference in this answer here
Using Symfony 5, this solution might help those, who are trying to set parameters on a subquery, the notIn() 2nd argument accepts an array or you could pass a DQL instead and that's what we are doing here and keep in mind that the parameters should be added to the main query as below.
$main = $this->em->createQueryBuilder();
$sub = $main;
$sub = $sub->select('arl')
->from('$MineMyBundle:MineAssetRequestLine', 'arl')
->where($sub->expr()->eq('arl.asset_id',':id'));
$linked = $main->select('rl')
->from('MineMyBundle:MineRequestLine', 'rl')
->where($main->expr()->notIn('rl.request_id', $sub->getDQL()))
->setParameter('id', 1)
->getQuery()
->getResult();

Resources