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")
Related
I'm trying to make a "complex" (for me) querybuilder. Here is the basic SQL request:
SELECT DISTINCT fif.idfichefrais, fif.idvisiteur, fif.date, fif.nbjustificatifs, fif.montantvalide, fif.datemodif, fif.idetat, montantTotalFraisForfait, montantTotalFraisHorsForfait, libelleFraisHorsForfait
FROM FicheFrais fif
INNER JOIN (SELECT lff.idfichefrais, SUM(frf.montantFraisForfait*lff.quantite) as montantTotalFraisForfait
FROM LigneFraisForfait AS lff
INNER JOIN FraisForfait AS frf ON frf.idfraisforfait = lff.idfraisforfait
GROUP BY lff.idfichefrais) a USING (idfichefrais)
INNER JOIN (SELECT e.idetat, e.libelleEtat
FROM Etat AS e) b USING (idetat)
LEFT JOIN (SELECT lfhf.idfichefrais, SUM(lfhf.montant) as montantTotalFraisHorsForfait, lfhf.libelle as libelleFraisHorsForfait
FROM LigneFraisHorsForfait AS lfhf
GROUP BY lfhf.idfichefrais) c USING (idfichefrais)
WHERE fif.idvisiteur = '?'
AND YEAR(fif.date) ='?'
ORDER BY MONTH(fif.date) ASC;
and here is my querybuilder that I'm trying to accomplish
public function findFicheFraisByIdVisiteurAndAnnee($idvisiteur, $annee): array
{
$qb = $this->getEntityManager()->createQueryBuilder();
$a = $this->getEntityManager()->createQueryBuilder();
$b = $this->getEntityManager()->createQueryBuilder();
$c = $this->getEntityManager()->createQueryBuilder();
$selectFraisForfait = $a->select(array('lff.idfichefrais, SUM(frf.montantFraisForfait*lff.quantite)'))
->from('App:Lignefraisforfait', 'lff')
->innerJoin('App:Fraisforfait', 'frf', Join::WITH, 'frf.idfraisforfait = lff.idfraisforfait')
->groupBy('lff.idfichefrais');
$selectEtat = $b->select(array('e.idetat, e.libelleEtat ad libelleFraisHorsForfait'))
->from('App:Etat', 'e');
$selectFraisHorsForfait = $c->select(array('lfhf.idfichefrais, SUM(lfhf.montant) as montantTotalFraisHorsForfait'))
->from('App:Lignefraishorsforfait','lfhf')
->groupBy('lfhf.idfichefrais');
return $FicheFraisByIdVisiteurAndAnnee = $qb
->select(array('fif.idfichefrais, identity(fif.idvisiteur) as idvisiteur, fif.date, fif.nbjustificatifs, fif.montantvalide, fif.datemodif, identity(fif.idetat) as idetat,montantTotalFraisForfait, montantTotalFraisHorsForfait, libelleFraisHorsForfait'))
->from('App:Fichefrais', 'fif')
->innerJoin('App:Lignefraisforfait', sprintf('($s)selectfraisforfait', $selectFraisForfait->getDQL()), Join::WITH, 'fif.idfichefrais = selectfraisforfait.idfichesfrais')
->innerJoin('App:Etat', sprintf('($s)selectetat', $selectEtat->getDQL()), Join::WITH, 'fif.idetat = selectetat.idetat')
->leftJoin('App:Lignefraishorsforfait', sprintf('($s)selectFraisHorsForfait', $selectFraisHorsForfait->getDQL()), Join::WITH, 'fif.idfichefrais = selectfraishorsforfait.idfichefrais')
->where('fif.idvisiteur = :idvisiteur')
->setParameter('idvisiteur' , $idvisiteur)
->andWhere('YEAR(fif.date) = :annee')
->setParameter('annee', $annee)
->groupBy('fif.idfichefrais')
->groupBy('lfhf.idfichefrais')
->orderBy('MONTH(fif.date)', 'ASC')
->setMaxResults(12)
->getQuery()
->getResult()
;
}
I am using Symfony v3.4 branch with Doctrine.
I am having trouble translating SQL query to Doctrine ORM query.
I have 3 tables.
Shop
Firm
User
User --> 1:1 --> Firm --> 1:1 --> Shop
(Symfony developer tool bar reports that associations in tables are made correctly).
I want to get Shop data that corresponds to cretain User in one query.
My SQL, that get a result:
SELECT *
FROM mp2_fos_user as u
LEFT JOIN mp2_firm AS f ON u.id = f.firmUserId
LEFT JOIN mp2_shop AS s ON f.id = s.shopFirmId
WHERE u.id = 1
My Doctrine ORM query
$query = $em->createQueryBuilder()
->select('u, f, s')
->from('App:User', 'u')
->leftJoin('u.userFirm WITH u.id = f.firmUserId', 'f')
->leftJoin('f.firmShop WITH f.id = s.shopFirmId', 's')
->where('u.id = :user_id')
->setParameter('user_id', $user_id)
->getQuery();
at the moment running the code results in an error
[Syntax Error] line 0, col 57: Error: Expected end of string, got 'u'
What would be best practice for my issue?
Help would be much appreciated,
Thank you!
UPDATE
tried:
$query = $em->createQueryBuilder()
->select('s.id')
->from('App:User', 'u')
->leftJoin('u.userFirm WITH f.firmUser = u', 'f')
->leftJoin('f.firmShop WITH s.shopFirm = f', 's')
->where('u.id = :user_id')
->setParameter('user_id', $user_id)
->getQuery();
got [Syntax Error] line 0, col 54: Error: Expected end of string, got 'f'
There is no need to use WITH clause if you have defined mapping in your entities, WITH clause is used when you want to join your entities with additional matching criteria
class User
{
/**
* #ORM\YourRelationShipNature(targetEntity="App\Entity\Firm", mappedBy="user")
*/
private $userFirm;
}
class Firm
{
/**
* #ORM\YourRelationShipNature(targetEntity="App\Entity\Shop", mappedBy="firm")
*/
private $firmShop;
}
class Shop
{
//.....
}
And then your could simple use properties to join your entites
$query = $em->createQueryBuilder()
->select('u, f, s')
->from('App:User', 'u')
->leftJoin('u.userFirm', 'f')
->leftJoin('f.firmShop', 's')
->where('u.id = :user_id')
->setParameter('user_id', $user_id)
->getQuery();
I was thinking of something more along the lines of this (assuming the entity names are correct):
$query = $em->createQueryBuilder()
->select('u, f, s')
->from('App:User', 'u')
->leftJoin('App:UserFirm f WITH f.firmUser = u')
->leftJoin('App:FirmShop s WITH s.shopFirm = f')
->where('u.id = :user_id')
->setParameter('user_id', $user_id)
->getQuery();
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;
}
I want to get the last user profile . But i am not able to do that in DQL.
I have this code
$em = $this->getEntityManager();
$dql = "SELECT p FROM AcmeBundle:UserProfile p
WHERE p.user_id = :user_id
ORDER BY p.createdAt DESC ";
$allProfiles = $em->createQuery($dql)
->setParameter('user_id', $user_id)
->setMaxResults(5)
->getResult();
return $allProfiles;
It returns all the profiles.
If i use getSingleResult() then it says result not unique
The right method is:
$singleProfile = $em->createQuery($dql)
->setParameter('user_id',$user_id)
->getSingleResult();
To prevent error then no results try this:
$singleProfile = $em->createQuery($dql)
->setParameter('user_id',$user_id)
->getOneOrNullResult();
$allProfiles = $em->createQuery($dql)
->setParameter('user_id',$user_id)
->setMaxResults(1)
->getResult();
return $allProfiles[0];
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")