Query Builder Error in doctrine symfony using where in - symfony

I have a raw query which I would like to convert into doctrine ORM. It's basically a query which contains sub query to calculate total count.
SELECT Count(*) AS total_count
FROM (SELECT *
FROM content_item_languages
WHERE default_content_item_id IN (SELECT id AS default_content_item_id
FROM content_item
WHERE content_type = 1
AND is_translated = 0
AND modified_on >=
'$timePeriodStart'
AND is_active = 1)
AND language_id = '$language') AS t
I have written below doctrine ORM but still I am getting error
$em = $this->getEntityManager()->createQueryBuilder();
$totalPostSubselect = $em->addSelect('c.id AS defaultContentItemId')
->from('AppBundle\Entity\ContentItem\ContentItem', 'c')
->andWhere('c.contentType = 1')
->andWhere('c.isTranslated = 0')
->andWhere('c.modifiedOn >= :timeperiod')
->andWhere('c.isActive = :status')
->setParameter('status', 1)
->setParameter('timeperiod', $timePeriodStart)->getDQL();
$em = $this->getEntityManager()->createQueryBuilder();
$defaultSubSelect = $em->addSelect(['*'])
->from('AppBundle\Entity\ContentItem\ContentItemLanguages', 'cl')
->andWhere("cl.defaultContentItemId IN ($totalPostSubselect)")
->andWhere('cl.languageId = :language')
->setParameter('subSelect', $totalPostSubselect)
->setParameter('language', $language)->getDQL();
$em = $this->getEntityManager()->createQueryBuilder();
$mainQuerySelect = $em->addSelect(["count(*) as total_count"])
->from("(".$defaultSubSelect.")", 'AS t')->getQuery();
return $mainQuerySelect->getResult();
Here is the error I got
[Doctrine\ORM\Query\QueryException] [Syntax Error] line 0, col 13: Error: Expected Literal, got '*'
[Doctrine\ORM\Query\QueryException]
SELECT count(*) as total_count FROM (SELECT * FROM
AppBundle\Entity\ContentItem\ContentItemLanguages cl
WHERE (
cl.defaultContentItemId IN (SELECT c.id AS defaultContentItemId
FROM AppBundle\Entity\ContentItem\ContentItem c WHERE
c.contentType = 1 AND
c.isTranslated = 0 AND
c.modifiedOn >= :timeperiod AND c.isActive = :status))
AND cl.languageId = :language) AS t
can anyone suggest, in exactly where I am doing wrong ?

In doctrine query language you can't SELECT *, instead you have to deal with objects. For your example something like:
$mainQuerySelect = $em->addSelect("count(t.id) as total_count")
->from("(".$defaultSubSelect.")", 'AS t')->getQuery();

Related

Doing a subquery inside a where with Doctrine 2 querybuilder

I am trying (without success) to translate this SQL query inside a Doctrine2 querybuilder. How should I do to include the subselect inside a Where with Querybuilder ?
SQL query I am trying to implement with querybuilder :
SELECT * FROM `message` A
WHERE A.id =
(SELECT B.id FROM `message` B
WHERE (A.user_id = B.user_id AND A.receiver_id = B.receiver_id) OR (A.user_id = B.receiver_id AND A.receiver_id = B.user_id)
ORDER BY creationdate DESC
LIMIT 1)
So far, I tried something like this in Message repository but I guess I am far away from the good way to do it :
public function getConversations()
{
$qb = $this
->createQueryBuilder('A')
->Where('A.id IN
(SELECT B.id FROM Message B
WHERE (A.user_id = B.user_id AND A.receiver_id = B.receiver_id) OR (A.user_id = B.receiver_id AND A.receiver_id = B.user_id)
ORDER BY creationdate DESC
LIMIT 1')
;
return $qb
->getQuery()
->getResult()
;
}
}
This trigger error message:
Error: Class 'Message' is not defined.
For people interested I finally found a solution. I did the query like this (if someone has another solution I am very interested):
public function getConversations()
{
$rawSql = "SELECT * FROM `message` A
WHERE A.id =
(SELECT B.id FROM `message` B
WHERE (A.user_id = B.user_id AND A.receiver_id = B.receiver_id) OR (A.user_id = B.receiver_id AND A.receiver_id = B.user_id)
ORDER BY creationdate DESC
LIMIT 1)
";
$stmt = $this->getEntityManager()->getConnection()->prepare($rawSql);
$stmt->execute([]);
return $stmt->fetchAll();
}

DQL access id from object property with left join

I realized this sql which works without problems
SELECT meeting.name, meeting.date, community.name, participation.isPresent, participation.user_id
FROM meeting
INNER JOIN community
ON meeting.community_id = community.id
AND community.is_active = 1
LEFT join participation
ON meeting.id = participation.meeting_id
AND participation.user_id = 1078
WHERE meeting.date >= CURRENT_DATE()
ORDER BY meeting.date DESC
I'm trying to reproduce it with the doctrine query builder but I never got the right result. The user id part doesn't seem to be part of the leftJoin function but is applied to the request globally, which is not what I want.
public function getNextMeetings()
{
$qb = $this->createQueryBuilder('m')
->select('m.name AS meeting, m.date, c.name AS community, p.isPresent', 'IDENTITY(p.user) AS user')
->innerJoin('m.community', 'c')
->where('c.isActive = true')
->leftJoin('m.participations', 'p')
//->leftJoin('p.user', 'u')
//->where('u.id = 1078 OR u.id IS NULL')
//->where('IDENTITY(p.user) = 1078')
->andWhere('m.date >= CURRENT_DATE()')
->orderBy('m.date', 'DESC');
return $qb->getQuery()->execute();
}
My comments are what I tried to fix this issue.
Check Working with QueryBuilder: High level API methods
More precisely, the definition od leftJoin() function:
public function leftJoin($join, $alias, $conditionType = null, $condition = null, $indexBy = null);
You can place a condition on the joined Entity by:
use Doctrine\ORM\Query\Expr;
->leftJoin('m.participations', 'p', Expr\Join::WITH, 'p.user = :userId')
->setParameter('userId', 1078)
Note you do not need a condition for "meeting.id = participation.meeting_id", as this is autoapplied by the relation m.participations to the join constructed.

Semantical Error, Symfony DQL

I have a query that perform normally with MySQL :
SELECT *
FROM td_user u
JOIN td_ranking ranking ON ranking.user_id = u.id
JOIN (
SELECT x.user_id,
MAX(x.id) AS default_id
FROM td_ranking x
GROUP BY x.user_id
) y
ON y.user_id = ranking.user_id
AND y.default_id = ranking.id
I try to transform it in DQL for run it in Symfony :
$query = $this->_em->createQuery('
SELECT u.*,ranking.*
FROM UserBundle:User u
JOIN UserBundle:Ranking ranking
WITH ranking.user_id = u.id
JOIN (
SELECT x.user_id, MAX(x.id) AS default_id
FROM UserBundle:Ranking x
GROUP BY x.user_id
) y
ON y.user_id = ranking.user_id
AND y.default_id = ranking.id'
);
$results = $query->getResult();
I have this error :
[Semantical Error] line 0, col 113 near '(SELECT x.user_id,': Error: Class '(' is not defined.
Do you have any idea please ? Thanks!
Use native query
$rsm = new ResultSetMapping();
$sql = "
SELECT *
FROM td_user u
JOIN td_ranking ranking ON ranking.user_id = u.id
JOIN (
SELECT x.user_id,
MAX(x.id) AS default_id
FROM td_ranking x
GROUP BY x.user_id
) y
ON y.user_id = ranking.user_id
AND y.default_id = ranking.id
";
$result = $this->getEntityManager()->createNativeQuery($sql, $rsm)->getResult();

Doctrine left join where joined table is null shows results

the goal of this query is to show records from table orders that don't have any shipments created yet. Here is how it should be done in SQL:
SELECT *
FROM orders
LEFT JOIN orders_shipments shipments ON orders.trx_id = shipments.trx_id
WHERE shipments.shipment_id IS NULL
AND orders.purchase_date IS NOT NULL
AND orders.fulfillment_channel = 'MFN';
The following query shows 0 results. Vs the following:
$qb = $this->createQueryBuilder('orders');
$qb->select('orders, shipments')
->leftjoin('orders.shipments', 'shipments')
->Where('shipments.id IS NULL')
->ANDWhere('orders.purchaseDate IS NOT NULL')
->ANDWhere('orders.fulfillmentChannel = :a')->setParameter('a', 'MFN');;
$results = $qb->getQuery()
->getResult();
return $results;
Does show results. Why is that and how to fix it?
Not sure why but I had to use GROUP and HAVING to get it to work:
$qb = $this->createQueryBuilder('orders');
$qb->select('orders, shipments')
->leftjoin('orders.shipments', 'shipments')
->Where('shipments.id IS NULL')
->ANDWhere('orders.purchaseDate IS NOT NULL')
->ANDWhere('orders.fulfillmentChannel = :a')->setParameter('a', 'MFN')
->GroupBy('orders.id')
->having('count(shipments) = 0');
$results = $qb->getQuery()->getResult();

doctrine dql exception: Illegal offset type in /var/www/Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/SqlWalker.php line 601

I want to produce a DQL for following MySQL query:
SELECT * FROM `folders` AS `t` WHERE `t`.`Library` = #myLib AND AND `t`.`Id` NOT IN (
SELECT DISTINCT(`f`.`Id`) FROM `folders` AS `f` JOIN `folders` AS `ff` ON (`f`.`Position` LIKE CONCAT(`ff`.`Position`, '%')) WHERE `ff`.`Active` = 1 AND `ff`.`Library` = #myLib AND `f`.`Library` = #myLib
)
ORDER BY `t`.`Position` ASC
The query works fine in mySQL and returns correct records.
To generate DQL I've tried both below options:
1.
$query = $em->createQuery("SELECT F FROM MyBundle:Folders T WHERE T.Library = :libid AND T.id NOT IN (
SELECT DISTINCT(F.id) FROM MyBundle:Folders F JOIN MyBundle:Folders FF WITH F.Position LIKE CONCAT(FF.Position, '%') AND F.Library = :libid AND FF.Library = :libid AND FF.Active = true
) ORDER BY T.Position ASC")
->setParameter('libid', $library);
$result = $query->getResult();
2.
$q1 = $this->createQueryBuilder('F')
->select('DISTINCT(F.id)');
$q1->join('\MyBundle\Entity\Folders', 'FF', 'WITH', $q1->expr()->like('F.Position', $q1->expr()->literal('CONCAT(FF.Position, \'%\')')))
->where('FF.Active = true')
->andWhere("FF.Library = '$library'")
->andWhere("F.Library = '$library'");
$q2 = $this->createQueryBuilder('T');
$q2->where('T.Library = :libid')
->andWhere($q2->expr()->notIn('T.id', $q1->getDQL()))
->setParameter('libid', $library)
->orderBy('T.Position', 'ASC');
$result = $q2->getQuery()->getResult();
In my perspective it seems OK but I don't know why in both ways it produce following exception:
ContextErrorException: Warning: Illegal offset type in
/var/www/Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/SqlWalker.php line 601
Any help will be appreciated.
It seems no one has an answer for this. I found a temporary solution as below (I call it temporary because I'm changing my unique query to two separate queries and it seems the issue is in core of doctrine).
$qb = $this->createQueryBuilder('F')
->select('DISTINCT(F.id)');
$qb->join('\MyBundle\Entity\Folders', 'FF', 'WITH', 'F.Position LIKE CONCAT(FF.Position, \'%\')')
->where('FF.Active = true')
->andWhere("FF.Library = :library")
->andWhere("F.Library = :library")
->setParameter('library', $library);
$included_folders = $qb->getQuery()->getArrayResult();
$query = $this->createQueryBuilder('F')
->where('F.Active = false')
->andWhere('F.Library = :library')
->setParameter('library', $library)
->orderBy('F.Position', 'ASC');
if (!empty($included_folders)) {
if (count($included_folders) > 1)
{
foreach ($included_folders as $index => $value)
{
if (is_array($value))
{
$included_folders[$index] = !empty($value['id']) ? $value['id'] : $value[1];
}
}
$query->andWhere($query->expr()->notIn('F.id', $included_folders));
}
else {
$query->andWhere('F.id != :folder ')
->setParameter('folder', $included_folders[0]);
}
}
$result = $query->getQuery()->getResult();
As you see instead of getting the dql from my first query and putting it inside my second dql in notIn section which will lead to the warning message, I execute the first query and get the results then put the results inside notIn if amount of returned values are more than one, otherwise it should be in regular !=. This solved my problem for now, but as you see amount of transactions are now increased
If anyone has a better solution or any fix for the warning I will be thankful.
I've encountered the same error and it seems that this has been fixed in latest trunk of Doctrine/ORM.
Using "2.5.*#dev" as version in your composer.json for doctrine/orm should fix this bug and will let you do what you want in a single query.

Resources