Symfony - using orWhere() in doctrine query builder - php

I want to return query result for the words I am searching in a message but just where userOne or userTwo is currently logged in user.
I think I have trouble with defining my query builder right because when testing otherwise logged in user is returned correctly.
I am trying with orWhere() clause but it always returns all results of that word not just for logged in user.
My code:
public function search($word, $user)
{
return $this->getMessageRepository()
->createQueryBuilder('a')
->where('a.message LIKE :message')
->andWhere("a.toUser = $user OR fromUser = $user")
->setParameter('message', '%' . $word. '%')
->setParameter('toUser', $user)
->setParameter('fromUser', $user)
->getQuery()
->getResult();
}

The logic of the where statement should work as expected.
But it seems like you are using incorrect parameter binding.
toUser and fromUser are columns and therefore no need to bind them.
$user is the target user that we want to filter on, thus it should be bound to the query.
An example:
{
return $this->getMessageRepository()
->createQueryBuilder('a')
->where('a.message LIKE :message')
->andWhere("a.toUser = :user OR a.fromUser = :user")
->setParameter('message', '%' . $word. '%')
->setParameter('user', $user)
->getQuery()
->getResult();
}

You need to specify all fields with a prefix a because you create this prefix in createQueryBuilder('a');
If you have more 1 params use setParameters.
And you can OR write in QueryBuilder type -> $builder->expr()->orX.
Your query example:
public function search($word, $user)
{
$builder = $this->createQueryBuilder('a');
return $builder
->where('a.message LIKE :message')
->andWhere($builder->expr()->orX(
$builder->expr()->eq('a.toUser', ':user'),
$builder->expr()->eq('a.fromUser', ':user'),
))
->setParameters([
'message' => '%' . $word . '%',
'user' => $user,
])
->getQuery()
->getResult();
}

Related

Laravel - how to surround all previous clauses with where clause on builder ?

In database table I have one row :
users
id|email|is_deleted
1|test#test.com|1
I have this code :
User::where('email', 'test#test.com')
->orWhere('email', 'test2#test2.com')
->get();
and this query is generated :
select * from users where email = 'admin#myzone.com' or email = 'asdasdas'
with one result. Now I want apply where is_deleted = 0
If I do like this :
User::where('email', 'test#test.com')
->orWhere('email', 'test2#test2.com')
->where('is_deleted', 0)
->get();
Generated query is :
select * from "users" where "email" = ? or "email" = ? and "users"."deleted_at" is null
So far everything works as expected, this query returns one result, but I want only not deleted users, I can do following :
User::where(function($query){
$query->where('email', 'test#test.com')
->orWhere('email', 'test2#test2.com')
})->where('is_deleted', 0)
->get();
and this will work, but in my code I already have returned builder :
function applyNotDeleted(Builder $builder){
//here I want to filter only not deleted users,
//but this is already triggered on builder $query->where('email', 'test#test.com')->orWhere('email', 'test2#test2.com')
//currently generated query on builder is select * from users where email = 'admin#myzone.com' or email = 'asdasdas'
//but at this stage I want to create query which will look like select * from "users" where "email" = ? or "email" = ? and "users"."deleted_at" is null
//something like this
$builderNew = $builderNew->where(function($query){
$query->applyAllLogicFromCurrentBuilder($builder)
})
->where('is_deleted', 0)
->get();
}
any idea?
Personally I would use query scope to just obtain non deleted records
public function scopeNotDeleted(Builder $query): Builder
{
return $query->where('is_deleted', 0);
}
and then use it when fetching records
User::notDeleted()->where(function(Builder $query) {
$query->where('email', 'test#test.com')->orWhere('email', 'test2#test2.com');
})->get();
If you are using applyAllLogicFromCurrentBuilder method, you can also extract it to the query scope and just chain it with your call like so:
User::allLogicFromCurrentBuilder()->notDeleted()->where(function(Builder $query) {
$query->where('email', 'test#test.com')->orWhere('email', 'test2#test2.com');
})->get();
You can also keep your applyNotDeleted method as is, but without the call to get() method - this way you can append any further statements to it if need to. I would probably convert it to a public static method so you can call it without instantiating model:
User::applyNotDeleted(User::where(function(Builder $query) use ($email) {
$query->where('email', 'test#test.com')->orWhere('email', 'test2#test2.com');
}))->get();
Personally I would prefer the scope approach as it seems a bit cleaner.

How to get related items in controller (Symfony2.8)

For this question I have 3 entities in my DB :
Case to Line : 1 Case to Many Lines (1 case have n lines)
Line to Loan : 1 Line to Many Loans (1 line have n loans)
I want in my controller to get a Case(Dosier) by ID, then to foreach lines, and then to foreach every loan.
So, with every loan object I want to perform some calculations and collect all this data.
How can I access the loan object, to make next things like ($loan->getCapital(), $loan->getDuration() for my calculations?
I tried in this way :
/**
* #Route("/", name="homepage")
*/
public function indexAction(Request $request)
{
$user = $this->getUser();
$dosiers = $this->getDoctrine()
->getRepository('AppBundle:Dosier')
->createQueryBuilder('e')
->select('e')
->where('e.userId = :id')
->andwhere('e.isActive = 1')
->orderBy('e.id', 'DESC')
->setParameters(array('id'=> $user))
->getQuery()
->getResult();
foreach ($line as $dosiers->getLines()) {
foreach ($loan as $line->getLoans()) {
echo $loan->getName();
}
}
return $this->render('AppBundle:default:index.html.twig', array(
'dosiers' => $dosiers
));
}//indexAction
But it gives me error :
Compile Error: Can't use method return value in write context
Ah, I find a solution :
This code :
$dosiers = $this->getDoctrine()
->getRepository('AppBundle:Dosier')
->createQueryBuilder('e')
->select('e')
->where('e.userId = :id')
->andwhere('e.isActive = 1')
->orderBy('e.id', 'DESC')
->setParameters(array('id'=> $user))
->getQuery()
->getResult();
returns an array of objects that match that conditions, instead returning one object.
So, I changed the query for test in :
$dosiers = $em->getRepository('AppBundle:Dosier')->findOneBy(array('id' => 15));
and the loop to :
foreach ($dosiers->getLines() as $line) {
foreach ($line->getLoans() as $loan) {
echo $loan->getName();
}
}
and now it works. Next, need just to add a new parameter to the action, $id, and instead of constant '15' in query to put $id.

Multiple filtering in Symfony

I added a filter to my project that works with symfony.
I have the ID (numbers to be searched) and the client name.
When I constructed my query with one parameter, it works, just like that
public function findFilter($filter)
{
return $this->createQueryBuilder("a")
->andWhere('a.id like :id')
->setParameter('id', '%' . $filter . '%')
->getQuery()
;
}
and when I add one more parameter, the search doesn't happen.
public function findFilter($filter)
{
return $this->createQueryBuilder("a")
->andWhere('a.id like :id')
->setParameter('id', '%' . $filter . '%')
->andWhere('a.client like :client')
->setParameter('client', '%' . $filter . '%')
->getQuery()
;
}
and here is my view where the filter can be entered
<form action="" method="get">
<input name="filter" type="text">
<button type="submit" class="btn btn-default">Filtrer</button>
</form>
So maybe I'm not sticking them right?
Anyone got an idea on how to add more parameters for the filter bar?
try this:
return $this->createQueryBuilder("a")
->andWhere('a.id like :id' OR 'a.client like :client')
->setParameters([
'id' => '%' . $filter . '%',
'client' => '%' . $filter . '%'
]),
->getQuery();
If you want to filter on multiple columns with an unique value, you've to use an array of OR filters.
use Doctrine\ORM\Query\Expr;
[...]
$orX = new Expr\Orx();
$orX->add($qb->expr()->orx($qb->expr()->like('a.id', ':filter'));
$orX->add($qb->expr()->orx($qb->expr()->like('a.client', ':filter'));
$qb
->andWhere($orx)
->setParameter('filter', '%'.$filter.'%')
;
You should use orWhere instead of andWhere
public function findFilter($filter)
{
return $this->createQueryBuilder("a")
->where('a.id like :filter')
->orWhere('a.client like :filter')
->setParameter('filter', '%' . $filter . '%')
->getQuery()
;
}
Moreover you might have missed a getResult after getQuery (but don't know if it is a typo or something else)

Doctrine where if empty

$repository = $this->getEntityManager()->getRepository('App\Entity\HolidayPackages');
$holiday_packages = $repository
->createQueryBuilder('hp')
->addSelect('hpt')
->innerJoin('hp.holiday_packages_translation', 'hpt')
->where('hpt.code = :code')
->setParameter('code', $language_code)
->andWhere('hpt.title LIKE :title')
->setParameter('title', $title . '%');
if (!empty($starting_date)) {
$repository
->andWhere('hp.starting_date = :starting_date')
->setParameter('starting_date', $starting_date);
}
$repository
->setFirstResult($offset)
->setMaxResults($limit)
->getQuery()
->getResult();
I am trying to filter search. How can i check if parameter is empty, don' t add to where query ?
I followed this link : doctrine2 - querybuilder, empty parameters
But i doesn't works for me.
When i try to like that, i got an error :
Undefined method 'setFirstResult'. The method name must start with either findBy or findOneBy!
Thanks in advice..
Update
if i add to command line setFirstResult error change :
Undefined method 'getQuery'. The method name must start with either findBy or findOneBy!
When i used to use pdo, i can like this using bind parameters. But i don't know how to do in Doctrine.
You should keep using $holiday_packages instead of $repository.
$repository = $this->getEntityManager()->getRepository('App\Entity\HolidayPackages');
$holiday_packages = $repository
->createQueryBuilder('hp')
->addSelect('hpt')
->innerJoin('hp.holiday_packages_translation', 'hpt')
->where('hpt.code = :code')
->setParameter('code', $language_code)
->andWhere('hpt.title LIKE :title')
->setParameter('title', $title . '%');
if (!empty($starting_date)) {
$holiday_packages->andWhere('hp.starting_date = :starting_date')
->setParameter('starting_date', $starting_date);
}
$holiday_packages->setFirstResult($offset)
->setMaxResults($limit)
->getQuery()
->getResult();

Prioritize MySQL SELECT/LIKE result in Repository

I want to create a query that values more precise search terms, e.g. search for "Essen" should return Essen currently it returns Evessen as this is a valid value as well.
My current function:
public function findCities($city){
$qb = $this->createQueryBuilder('z');
$qb
->select('z')
->where($qb->expr()->like('z.city', ':city'))
->orderBy('z.code')
->setParameter('city', '%'.$city . '%');
return $qb->getQuery()->getResult();
}
Based on THIS advice I created a repository function:
public function findCities($city){
$qb = $this->createQueryBuilder('z');
$qb
->select('z')
->where($qb->expr()->like('z.city', ':city'))
->orderBy('INSTR(z.city, '.$city.'), z.city')
->setParameter('city', '%'.$city . '%');
return $qb->getQuery()->getResult();
}
Unfortunately it returns [Syntax Error] line 0, col 70: Error: Expected known function, got 'INSTR'
Any other approach (that does NOT return an array, as there is a function that needs heavy altering if the output is an array, I'd like to avoid that) maybe?
There is no INSTR function in DQL, that's why you get this error see docs
instead you can make NativeQuery see docs
something like this
$rsm = new \Doctrine\ORM\Query\ResultSetMapping();
$rsm->addEntityResult('City', 'c');
// for every selected field you should do this
$rsm->addFieldResult('c', 'id', 'id');
$rsm->addFieldResult('c', 'name', 'name');
$em = $this->getEntityManager()
->createNativeQuery('
SELECT
id, name
FROM cities WHERE city LIKE '%:city%'
ORDER BY INSTR(city, ':city'), city',
$rsm
)->setParameter('city', $city);
return $em->getResult();

Categories