DQL - leftJoin() error: Expected Literal, got 'JOIN' - symfony

This code:
$builder->select('p')
->from('ProProposalBundle:Proposal', 'p')
->leftJoin('ProProposalBundle:Proposal:Vote', 'v')
->leftJoin('ProUserBundle:User', 'u')
->andWhere('v.proposal = p')
->andWhere('v.user = u')
->andWhere('v.decision = "in_favor" OR v.decision = "against"')
->andWhere('u = :user')
->setParameter('user', $options['user'])
->andWhere('p.community = :community')
->setParameter('community', $community)
->andWhere('p.archived = :archived')
->setParameter('archived', $options['archived'])
->leftJoin('p.convocation', 'c')
->andWhere("p.convocation IS NULL OR c.status = '" . Convocation::STATUS_PENDING . "'");
return $builder->getQuery()->execute();
is returning an error:
[Syntax Error] line 0, col 106: Error: Expected Literal, got 'JOIN'
This is the formed query:
SELECT p FROM ProProposalBundle:Proposal p LEFT JOIN ProProposalBundle:Proposal:Vote v LEFT JOIN ProUserBundle:User u LEFT JOIN p.convocation c WHERE v.proposal = p AND v.user = u AND (v.decision = "in_favor" OR v.decision = "against") AND u = :user AND p.community = :community AND (p.convocation IS NULL OR c.status = 'pending') ORDER BY p.created desc
LEFT JOIN is missing the ON or WITH condition. The question is: what am I doing wrong with DQL query? Am I wrong with leftJoin() method?

Doctrine ORM needs you to tell which relation is joined, not the entity itself (you did it well with p.convocation) :
$builder->select('p')
->from('ProProposalBundle:Proposal', 'p')
->leftJoin('ProProposalBundle:Proposal\Vote', 'v', 'WITH', 'v.proposal = p AND v.user = :user AND (v.decision = :in_favor OR v.decision = :against)')
->setParameter('user', $options['user'])
->setParameter('in_favor', 'in_favor')
->setParameter('against', 'against')
->andWhere('p.community = :community')
->setParameter('community', $community)
->andWhere('p.archived = :archived')
->setParameter('archived', $options['archived'])
->leftJoin('p.convocation', 'c')
->andWhere("p.convocation IS NULL OR c.status = :pending")
->setParameter('pending', Convocation::STATUS_PENDING);
return $builder->getQuery()->execute();
edit: I inversed Vote relation as you commented and removed useless WHERE clauses (Doctrine automatically resolves JOIN ON clause. I also transferred some WHERE clauses about joins in the optional params (WITH in DQL).
edit2: Without relation between Proposal and Vote, not sure it works.
edit3: Best practice is to use setParameter for all values in WHERE clauses.

Related

How can I order by match result in doctrine querybuilder?

I have a custom dql match function and would like to select the match result as 'score' before ordering by that score. How can I adjust the following query to achieve this?
$qb = $this->getEntityManager()->createQueryBuilder();
$qb
->select('i', 'bi')
->from('AdminBundle:Items', 'i')
->where('i.instock=1')
->leftJoin('AdminBundle:MyTable','bi',\Doctrine\ORM\Query\Expr\Join::WITH, 'i.id = bi.productId')
->andWhere('bi.productId IS NULL')
->andWhere('MATCH (i.brand, i.store, i.title, i.description, i.keywords) AGAINST (:search BOOLEAN) > 0')
->andWhere('i.instock = 1')
->setParameter('search', $searchString)
->setMaxResults( $limit )
;
$results = $qb->getQuery()->getArrayResult();
I do not know if I understand your question, do you want to add to your select what you have in your where (match...) and order by it?
You can add not-mapped selects like this:
$qb->addSelect('MY_FUNCTION(my.params) AS HIDDEN mySelectAlias')
In your case, sth like:
$qb->addSelect('(MATCH (i.brand, i.store, i.title, i.description, i.keywords) AGAINST (:search BOOLEAN)) AS HIDDEN mySelectAlias')
And in your order by:
$qb->orderBy('mySelectAlias', 'desc');
Complete example:
https://coderwall.com/p/o5snag

Symfony2 doctrine DQL does not replace wildcards

I'm trying to query the model from my Symfony2 project and I am not able to replace wildcards into my DQL query. Look;
$q2 =
'SELECT
p.codigo,
p.descripcion,
SUM(l.cantidad) as cantidad,
SUM(l.cantidad*l.pvp) as euros
FROM
MGFAppBundle:LineaVenta l
JOIN
MGFAppBundle:Producto p
WITH
l.producto = p.id
JOIN
l.venta v
WITH
l.venta = v.id
WHERE
l.producto IN (:array)
AND
v.farmacia = :farmacia
GROUP BY
p.codigo';
$query2 = $this->em->createQuery($q2)
->setParameter('farmacia', $farmacia)->setParameter('array', $array);
$porFarmacia = $query2->getResult();
// This does not return a single value, when it should return 2 lines.
echo $query2->getSQL();
// Returns:
// SELECT p0_.codigo AS codigo0, p0_.descripcion AS descripcion1, SUM(l1_.cantidad) AS sclr2, SUM(l1_.cantidad * l1_.pvp) AS sclr3 FROM LineaVenta l1_ INNER JOIN Producto p0_ ON (l1_.lineaventas_id = p0_.id) INNER JOIN Venta v2_ ON l1_.venta_id = v2_.id AND (l1_.venta_id = v2_.id) WHERE l1_.lineaventas_id IN (?) AND v2_.farmacia_id = ? GROUP BY p0_.codigo
So, question marks where parameters should be. Any hint? Thanks in advance.

symfony2 doctrine select IFNULL

Ok i have this code:
SELECT
IFNULL(s2.id,s1.id) AS effectiveID,
IFNULL(s2.status, s1.status) AS effectiveStatus,
IFNULL(s2.user_id, s1.user_id) as effectiveUser,
IFNULL(s2.likes_count, s1.likes_count) as effectiveLikesCount
FROM statuses AS s1
LEFT JOIN statuses AS s2 ON s2.id = s1.shared_from_id
WHERE s1.user_id = 4310
ORDER BY effectiveID DESC
LIMIT 15
And i need to rewrite it to querybuilder. Something like that?
$fields = array('IFNULL(s2.id,s1.id) AS effectiveID','IFNULL(s2.status, s1.status) AS effectiveStatus', 'IFNULL(s2.user_id, s1.user_id) as effectiveUser','IFNULL(s2.likes_count, s1.likes_count) as effectiveLikesCount');
$qb=$this->_em->createQueryBuilder()
->select($fields)
->from('WallBundle:Status','s1')
->addSelect('u')
->where('s1.user = :user')
->andWhere('s1.admin_status = false')
->andWhere('s1.typ_statusu != :group')
->setParameter('user', $user)
->setParameter('group', 'group')
->leftJoin('WallBundle:Status','s2', 'WITH', 's2.id=s1.shared_from_id')
->innerJoin('s1.user', 'u')
->orderBy('s1.time', 'DESC')
->setMaxResults(15);
var_dump($query=$qb->getQuery()->getResult());die();
This error is
[Syntax Error] line 0, col 7: Error: Expected known function, got 'IFNULL'
Use COALESCE instead of IFNULL like this
$fields = array('COALESCE(s2.id,s1.id) AS effectiveID','COALESCE(s2.status, s1.status) AS effectiveStatus', 'COALESCE(s2.user_id, s1.user_id) as effectiveUser','COALESCE(s2.likes_count, s1.likes_count) as effectiveLikesCount');
COALESCE return the first value not null in the list, so if A is null and B not null, then COALESCE(A,B) will return B.
There is a Doctrine extension that adds this among others.
This is the DQL file from IFNULL.
https://github.com/beberlei/DoctrineExtensions/blob/master/src/Query/Mysql/IfNull.php
This chapter explains how you use them.
http://symfony.com/doc/2.0/cookbook/doctrine/custom_dql_functions.html

Drupal db_select(), how can I use two db field in condition?

I have a problem with a drupal db_select.
Here is my code :
$query = db_select('node', 'n');
$query->addField('n', 'nid', 'nid');
$query->addField('cfs', 'entity_id', 'feature_support_id');
$query->addField('fpffs', 'entity_id', 'parent_feature_support_id');
$query->addField('cfsfc', 'feature_support_compared_target_id', 'feature_support_compared');
$query->addField('fpffsfc', 'feature_support_compared_target_id', 'parent_feature_support_compared');
//Get feature_support of the feature
$query->join('field_data_feature_support_feature', 'cfs', 'n.nid = cfs.feature_support_feature_target_id');
$query->join('field_data_feature_support_compared', 'cfsfc', 'cfs.entity_id = cfsfc.entity_id');
//Get parent feature_support through feature
$query->join('field_data_feature_parent_feature', 'fp', 'n.nid = fp.entity_id');
$query->join('field_data_feature_support_feature', 'fpffs', 'fp.feature_parent_feature_target_id = fpffs.feature_support_feature_target_id');
$query->join('field_data_feature_support_compared', 'fpffsfc', 'fpffs.entity_id = fpffsfc.entity_id');
$query->condition('n.nid', $node_revision->nid, '=');
$query->condition('cfsfc.feature_support_compared_target_id', 'fpffsfc.feature_support_compared_target_id', '=');
$result = $query->execute();
In DB my request should be
SELECT n.nid AS nid, cfs.entity_id AS feature_support_id, fpffs.entity_id AS parent_feature_support_id, cfsfc.feature_support_compared_target_id AS feature_support_compared, fpffsfc.feature_support_compared_target_id AS parent_feature_support_compared
FROM node n
INNER JOIN field_data_feature_support_feature cfs ON n.nid = cfs.feature_support_feature_target_id
INNER JOIN field_data_feature_support_compared cfsfc ON cfs.entity_id = cfsfc.entity_id
INNER JOIN field_data_feature_parent_feature fp ON n.nid = fp.entity_id
INNER JOIN field_data_feature_support_feature fpffs ON fp.feature_parent_feature_target_id = fpffs.feature_support_feature_target_id
INNER JOIN field_data_feature_support_compared fpffsfc ON fpffs.entity_id = fpffsfc.entity_id
WHERE (n.nid = '9') AND (cfsfc.feature_support_compared_target_id = fpffsfc.feature_support_compared_target_id)
This request work when I try it in phpmyadmin, but instead in mysql log I have
SELECT n.nid AS nid, cfs.entity_id AS feature_support_id, fpffs.entity_id AS parent_feature_support_id, cfsfc.feature_support_compared_target_id AS feature_support_compared, fpffsfc.feature_support_compared_target_id AS parent_feature_support_compared
FROM node n
INNER JOIN field_data_feature_support_feature cfs ON n.nid = cfs.feature_support_feature_target_id
INNER JOIN field_data_feature_support_compared cfsfc ON cfs.entity_id = cfsfc.entity_id
INNER JOIN field_data_feature_parent_feature fp ON n.nid = fp.entity_id
INNER JOIN field_data_feature_support_feature fpffs ON fp.feature_parent_feature_target_id = fpffs.feature_support_feature_target_id
INNER JOIN field_data_feature_support_compared fpffsfc ON fpffs.entity_id = fpffsfc.entity_id
WHERE (n.nid = '9') AND (cfsfc.feature_support_compared_target_id = 'fpffsfc.feature_support_compared_target_id')
See at the end, in the WHERE, there is single quote around 'fpffsfc.feature_support_compared_target_id' which should not be there.
It's obviously because the second argument of ->condition seems only accept variable. Anyone know how I can make a condition with two db fields with db_select?
Thanks for any help you can bring me.
Use $query->where($snippet, $args = array());
$query->where('cfsfc.feature_support_compared_target_id = fpffsfc.feature_support_compared_target_id');

Need some help to translate query from createQuery() to queryBuilder()

I'm used to create query with createQuery() instead of queryBuilder, but I need to translate a query in a queryBuilder one to use in a EntityType to generate a form. Here is my query :
SELECT p FROM D2ECoreBundle:Player p,
D2ECoreBundle:LadderMatch lm,
D2ECoreBundle:PlayerComposition hpc
JOIN hpc.players hp,
D2ECoreBundle:PlayerComposition fpc
JOIN fpc.players fp
WHERE (lm.homePlayerComposition = hpc AND hp = p)
OR (lm.foreignPlayerComposition = fpc AND fp = p)
and here is what i thought it would be in queryBuilder but doesnt work :
$qb->select('p')
->from('D2ECoreBundle:Player', 'p')
->from('D2ECoreBundle:LadderMatch', 'lm')
->from('D2ECoreBundle:PlayerComposition', 'hpc')
->join('hpc.players', 'hp')
->from('D2ECoreBundle:PlayerComposition', 'fpc')
->join('fpc.players', 'fp')
->where('lm.homePlayerComposition = hpc' AND 'hp = p')
->orwhere('lm.foreignPlayerComposition = fpc' AND 'fp = p');
Does anyone know what I should change to have it working? Thanx for the answers!
When you query the DB with:
SELECT * FROM TableA T1, TableB T2 ....
in many implementations is the same as:
SELECT * FROM TableA T1 JOIN TableB T2 ON ... // this is INNER JOIN
So, instead of using from multiple times, do joins:
$qb->select('p')
->from('D2ECoreBundle:Player', 'p')
->join('p.ladderMatches', 'lm')
->join('p.playerComposition', 'hpc')
->join('hpc.players', 'hp')
->join('hp.playerCompossition', 'fpc')
->join('fpc.players', 'fp')
->where('lm.homePlayerComposition = hpc' AND 'hp = p')
->orwhere('lm.foreignPlayerComposition = fpc' AND 'fp = p');
Not sure if I got the relation correct but you get the point...
I eventually managed to do this. Here is my code :
$qb = $this->createQueryBuilder('lm')
->select('p')
->from('D2ECoreBundle:Player', 'p')
->join('lm.homePlayerComposition', 'hpc')
->join('hpc.players', 'hp')
->join('lm.foreignPlayerComposition', 'fpc')
->join('fpc.players', 'fp')
->where('lm.homePlayerComposition = hpc AND hp = p')
->orwhere('lm.foreignPlayerComposition = fpc AND fp = p');
return $qb;
And a very important thing, since I want to select player, but starting by the LadderMatch entity, I need to put this in LadderMatchRepository.php and not PlayerRepository.php like I did, because it affects the generat

Resources