symfony2 doctrine select IFNULL - symfony

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

Related

Doctrine 2 : Select specific columns from Entity and its Join entities

I have this scenario where I have to select specific columns of Entity and join entities.
This statement works and fetches all columns of all Entities.
$this->createQueryBuilder('e')
->select('e','bs','t')
->leftJoin('e.bits', 'bs')
->leftJoin('bs.tests', 't')
->getQuery()
->getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY)
Question 1
I want something like this
Try 1
$this->createQueryBuilder('e')
->select('e.title','bs.name','bs.content','t.id','t.date')
->leftJoin('e.bits', 'bs')
->leftJoin('bs.tests', 't')
->getQuery()
->getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY)
But this throws errors like
[Semantical Error] line 0, col -1 near 'SELECT e.title,': Error: Cannot select entity through identification variables without choosing at least one root entity alias.
Try 2
$this->createQueryBuilder()
->select('e.title','bs.name','bs.content','t.id','t.date')
->from($this->_entityName, "e")
->leftJoin('e.bits', 'bs')
->leftJoin('bs.tests', 't')
->getQuery()
->getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY)
This throws error
Warning: Missing argument 1 for Doctrine\ORM\EntityRepository::createQueryBuilder(),
Try 3
This works but only if I select from just 1 Entity
$this->createQueryBuilder('e')
->select('e.title')
->leftJoin('e.bits', 'bs')
->leftJoin('bs.tests', 't')
->getQuery()
->getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY)
Question 2
Is there a smart way to remove specific columns from select query instead of writing all columns. I have around 30 columns in an Entity and its really messy to write 27 of them which I want in a query
Thanks
Try to use partial like this
$this->createQueryBuilder()
->select(['partial e.{title}','partial bs.{name, content}','partial t.{id, date}'])
->from($this->_entityName, "e")
->leftJoin('e.bits', 'bs')
->leftJoin('bs.tests', 't')
->getQuery()
->getArrayResult

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

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.

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

Doctrine - select last 4 rows from table

I'm using Symfony/Doctrine.
I'm trying to select last 4 rows from table, but im getting error.
$em = $this->getDoctrine()->getEntityManager();
$query = $em->createQuery(
'SELECT c FROM DprocMainBundle:Courses c ORDER BY id DESC LIMIT 4'
);
$course = $query->getResult();
This is my query but it shows error.
Expected end of string, got 'LIMIT'
How should i use limit, and get the LAST 4 rows?
thanks!
Use setMaxResults() to limit the number of results.
$course = $query->setMaxResults(4)->getResult();
If you want to use this for pagination you can add a setFirstResult() call.
$course = $query->setMaxResults(4)->setFirstResult(10)->getResult();

doctrine2 findby two columns OR condition

My action:
$matches_request = $em->getRepository('Bundle:ChanceMatch')->findByRequestUser(1);
$matches_reply = $em->getRepository('Bundle:ChanceMatch')->findByReplyUser(1);
Is it possible to join the querys with an or condition with getRepository, eg.
$matches_reply = $em->getRepository('FrontendChancesBundle:ChanceMatch')->findBy(array('requestUser' => 1, 'replyUser' => 1);
//this of course gives me the a result when `requestUser` and `replyUser` is `1`.
My table
id | requestUser | replyUser
....
12 | 1 | 2
13 | 5 | 1
My query should return the id 12 & 13.
Thanks for help!
You can use QueryBuilder or create a custom repository for that entity and create a function that internally use QueryBuilder.
$qb = $em->getRepository('FrontendChancesBundle:ChanceMatch')->createQueryBuilder('cm');
$qb
->select('cm')
->where($qb->expr()->orX(
$qb->expr()->eq('cm.requestUser', ':requestUser'),
$qb->expr()->eq('cm.replyUser', ':replyUser')
))
->setParameter('requestUser', $requestUserId)
->setParameter('replyUser', $replyUserId)
;
$matches_reply = $qb->getQuery()->getSingleResult();
// $matches_reply = $qb->getQuery()->getResult(); // use this if there can be more than one result
For more information on custom Repository see official documentation:
http://symfony.com/doc/2.0/book/doctrine.html#custom-repository-classes
It's possible to use Criteria for the complex queries with getRepository():
$criteria = new \Doctrine\Common\Collections\Criteria();
$criteria
->orWhere($criteria->expr()->contains('domains', 'a'))
->orWhere($criteria->expr()->contains('domains', 'b'));
$domain->ages = $em
->getRepository('Group')
->matching($criteria);

Resources