symfony doctrine complex querybuilder - php

Maybe something simple but my query builder doesn't return what I want. I would something like ... where ... AND (.... OR ....)
I try to read the doctrine doc but, I'm not fluent english so I don't really understand the doctrine doc (maybe a translation in french is available ?).
<?php
// $qb instanceof QueryBuilder
$qb->select(array('u')) // string 'u' is converted to array internally
->from('User', 'u')
->where($qb->expr()->orX(
$qb->expr()->eq('u.id', '?1'),
$qb->expr()->like('u.nickname', '?2')
))
->orderBy('u.surname', 'ASC'));
Here is my MySQL test code that work
select count(distinct(u.username)) from fos_user u join users_accounts ua ON u.id=ua.user_id join account acc ON acc.id = ua.account_id where u.id=48 and (acc.id=2 OR acc.id=5)
Here is the query builder :
I use a service because I had to use this functionality more than once.
/**
* Check if User exists in one of the connected user (Admin or SupAdmin) accounts
* argument : userID
*
*/
public function userExists($userID)
{
// Return accounts (array)
$accounts = $this->accountManager->listAccountsByConnectedUser();
$repository = $this->em->getRepository('CMiNewsBundle:User');
$qb = $repository->createQueryBuilder('u');
$query = $qb
->select('count(u)')
->join ('u.accounts', 'acc')
->where('u.id = :userID')
->andwhere('acc.id = :accountID')
->setParameters(array(
'userID' => $userID,
'accountID' => $accounts[0]->getId(),
));
if (count($accounts) > 1) {
$accountMax = count($accounts);
for($acc=1; $acc<$accountMax; $acc++)
{
$query->orWhere('acc.id = :accountID_'.$acc.'')->setParameter('accountID_'.$acc.'', $accounts[$acc]->getId());
}
};
$query = $query->getQuery();
$result = $query->getResult();
return $result;
}
Thank you for your advices

You can rewrite your query as using IN() in mysql like below
SELECT
COUNT(DISTINCT (u.username))
FROM
fos_user u
JOIN users_accounts ua
ON u.id = ua.user_id
JOIN account acc
ON acc.id = ua.account_id
WHERE u.id = 48
AND acc.id IN(2,5) /* this is equivalent to acc.id = 2 or acc.id = 5 */
The current query for doctrine you are running is ignoring your and condition like if you have 2 accounts ids query will be
WHERE u.id = 48 AND acc.id = 2 OR acc.id = 5
So it will give records for acc.id = 5 and u.id can be any other id
For doctrine query you can rewrite your code as below,You have to build an array of account ids and pass this array in your IN() clause
public function userExists($userID)
{
// Return accounts (array)
$accounts = $this->accountManager->listAccountsByConnectedUser();
$repository = $this->em->getRepository('CMiNewsBundle:User');
$qb = $repository->createQueryBuilder('u');
$accounts=array();
$accounts[]=$accounts[0]->getId();
if (count($accounts) > 1) {
$accountMax = count($accounts);
for ($acc = 1; $acc < $accountMax; $acc++) {
$accounts[]=$accounts[$acc]->getId();
}
}
$query = $qb
->select('count(u) as your_count')
->join('u.accounts', 'acc')
->where('u.id = :userID')
->andwhere('acc.id IN(:accountID)')
->setParameters(array(
'userID' => $userID,
'accountID' => $accounts,
));
$query = $query->getQuery();
$result = $query->getResult();
return $result;
}

Related

How can i resolve this PDOException for this update query? [duplicate]

Using Doctrine 2 I want to get some users that are contacts of another user. The table user contains the mapping between those users. The query in the function will return the following error:
Invalid parameter number: number of bound variables does not match number of tokens.
However to my best understanding $stris set to "b" and $ownerId is set to "2" and both are assigned by the setParameters function.
protected function getContactBySubstring($str, $ownerId) {
echo $str;
echo $ownerId;
$em = $this->getDoctrine()->getEntityManager();
$qb = $em->createQueryBuilder();
$qb->add('select', 'u')
->add('from', '\Paston\VerBundle\Entity\User u, \Paston\VerBundle\Entity\Contact c')
->add('where', "c.owner = ?1 AND c.contact = u.id AND u.username LIKE '?2'")
->add('orderBy', 'u.firstname ASC, u.lastname ASC')
->setParameters(array (1=> $ownerId, 2=> '%'.$str.'%'));
echo $qb->getDql();
$query = $qb->getQuery();
$users = $query->getResult();
foreach($users as $user)
echo $user->getUsername();
exit;
//return $contacts;
}
Don't surround any of the parameters in your query text with quotes!
->add('where', "c.owner = ?1 AND c.contact = u.id AND u.username LIKE '?2'")
should be
->add('where', "c.owner = ?1 AND c.contact = u.id AND u.username LIKE ?2")

symfony2 : Sql Syntax Error

I want to display the list of papers with more That a reporter , but I think I have a problem in my sql query syntax .. here is the whole function in my controller :
`public function nonattribuéAction()
{
$em=$this->getDoctrine()->getManager();
$repository = $em->getRepository('administrationadministrationBundle:Papier');
$repository = $em->getRepository('administrationadministrationBundle:CorrectionPap');
$query = $em->createQuery('SELECT * FROM administaration\administrationBundle\Entity\Papier WHERE pNum IN (SELECT DISTINCT pNum FROM administaration\administrationBundle\Entity\CorrectionPapier GROUP BY pNum HAVING COUNT(rNum)=>0)');
$papier = $query->getResult();
return $this->render('administrationadministrationBundle:Default:papier.html.twig', array('papier' => $papier, 'name' => 'Papiers Non Attribués'));
}`
This is the answer :D
public function nonattribuéAction()
{
$em = $this->getDoctrine()->getEntityManager();
$query = $em->createQuery('SELECT u FROM administrationadministrationBundle:Papier u WHERE u.pNum IN (SELECT DISTINCT v.pNum FROM administrationadministrationBundle:CorrectionPap v GROUP BY v.pNum HAVING COUNT(v.rNum)= 2)');
$results = $query->getResult();
return $this->render('administrationadministrationBundle:Default:papier.html.twig', array('papier' => $results, 'name' => 'Papiers Non Attribués'));
}

Symfony - how to use an array as an parameter by using a querybuilder?

I'm about to output a list that includes several documents(called waiver). However not every user should be allowed to see all documents and therefore I've implemented an filter to check if the user has the same "airline" and "market" assigned. So every user should only see the documents that are assigned to his "airline" and "market".
This is f.e. the getter for the airline of the user entity:
/**
* Get airlines
*
* #return array
*/
public function getAirlines()
{
if($this->airlines != null)
{
$airlines = explode(",", $this->airlines);
return $airlines;
}
return Array();
}
This is the controller logic:
//Get User:
$user = $this->container->get('security.context')->getToken()->getUser();
// Gets an Array of User markets
$user_markets = $user->getMarkets();
// Gets an Array of User carriers
$user_airlines = $user->getAirlines();
if(!$this->ROLE_IS(Array( 'ROLE_XY'))){
$query = $em->createQuery(
'SELECT w
FROM WaiverBundle:Waiver w
WHERE w.carrier = :carrier
AND w.market = :market
ORDER BY w.id DESC'
)
->setFirstResult($page*10-10)
->setMaxResults(10)
// I wan't to get the whole array and not just one position here:
->setParameters(array(':carrier'=>$user_airlines[0],
':market'=>$user_markets[0],
));
}else{
$query = $em->createQuery(
'SELECT u
FROM WaiverBundle:Waiver u
ORDER BY u.id DESC'
)
->setFirstResult($page*10-10)
->setMaxResults(10);
}
Question: How do I manage to compare the DQL attributes with an array and not just a string as a parameter?
I think you want to use "IN" syntax, not "=" syntax:
'SELECT w
FROM WaiverBundle:Waiver w
WHERE w.carrier IN (:carrier)
AND w.market = :market
ORDER BY w.id DESC'
Your query is not complicated. I think you should consider QueryBuilder instead of DQL in this case. Something like this would do the trick:
$qb = $em->createQueryBuilder();
$qb->select('w')
->from('WaiverBundle:Waiver', 'w')
->where($qb->expr()->in('w.carrier', ':carrier'))
->andWhere($qb->expr()->eq('w.market', ':market'))
->orderBy('w.id', 'DESC')
->setParameters(
array(
'carrier'=>$user_airlines[0],
'market'=>$user_markets[0)
);

Restriction the results for relation

I have simple tables Post and Comment and I am doing query:
$repository = $this->getDoctrine()
->getRepository('AppBundle:Post');
$query = $repository->createQueryBuilder('p')
->where('p.made = :made')
->setParameter('made', 1)
->leftJoin('p.comments', 'c')
->andWhere('c.isAdmin = :isAdmin')
->setParameter('isAdmin', 1)
->getQuery();
$results = $query->getResult();
foreach($results as $post) {
echo $post->getId(); // this clause where (->where('p.made = :made')) working ok
foreach($post->getComments() as $comments) {
echo $comment->getId(); //this clause where (->andWhere('c.isAdmin = :isAdmin')) not working. This return all results
}
}
So how can I use clause where in query with relations?
SQL:
SELECT
i0_.id AS id0,
i0_.made AS made1,
i0_.name AS name2,
FROM
post i0_
LEFT JOIN comment i1_ ON i0_.id = i1_.comment_id
WHERE
i0_.made = ?
AND i1_.isAdmin = ?
Let's add a select method in your request:
$query = $repository->createQueryBuilder('p')
->select(["c", "p"])
->where('p.made = :made')
->setParameter('made', 1)
->leftJoin('p.comments', 'c')
->andWhere('c.isAdmin = :isAdmin')
->setParameter('isAdmin', 1)
->getQuery();
Is it better ?
This works better because you specify to hydrate the whole objects rather than just Ids.

Invalid parameter number: number of bound variables does not match number of tokens in Doctrine

Using Doctrine 2 I want to get some users that are contacts of another user. The table user contains the mapping between those users. The query in the function will return the following error:
Invalid parameter number: number of bound variables does not match number of tokens.
However to my best understanding $stris set to "b" and $ownerId is set to "2" and both are assigned by the setParameters function.
protected function getContactBySubstring($str, $ownerId) {
echo $str;
echo $ownerId;
$em = $this->getDoctrine()->getEntityManager();
$qb = $em->createQueryBuilder();
$qb->add('select', 'u')
->add('from', '\Paston\VerBundle\Entity\User u, \Paston\VerBundle\Entity\Contact c')
->add('where', "c.owner = ?1 AND c.contact = u.id AND u.username LIKE '?2'")
->add('orderBy', 'u.firstname ASC, u.lastname ASC')
->setParameters(array (1=> $ownerId, 2=> '%'.$str.'%'));
echo $qb->getDql();
$query = $qb->getQuery();
$users = $query->getResult();
foreach($users as $user)
echo $user->getUsername();
exit;
//return $contacts;
}
Don't surround any of the parameters in your query text with quotes!
->add('where', "c.owner = ?1 AND c.contact = u.id AND u.username LIKE '?2'")
should be
->add('where', "c.owner = ?1 AND c.contact = u.id AND u.username LIKE ?2")

Categories