Set LIMIT with doctrine 2? - doctrine-orm

I trying to write a query (with subquery) but i don't know how set a limit in my subquery.
My query:
$query_ids = $this->getEntityManager()
->createQuery(
"SELECT e_.id
FROM MuzichCoreBundle:Element e_
WHERE [...]
GROUP BY e_.id")
->setMaxResults(5)
;
$query_select = "SELECT e
FROM MuzichCoreBundle:Element e
WHERE e.id IN (".$query_ids->getDql().")
ORDER BY e.created DESC, e.name DESC"
;
$query = $this->getEntityManager()
->createQuery($query_select)
->setParameters($params)
;
But ->setMaxResults(5) doesn't work. No 'LIMIT' in the SQL query. Can we do simple LIMIT with doctrine 2 ?

$query_ids = $this->getEntityManager()
->createQuery(
"SELECT e_.id
FROM MuzichCoreBundle:Element e_
WHERE [...]
GROUP BY e_.id")
->setMaxResults(5)
->setMaxResults($limit)
;
HERE in the second query the result of the first query should be passed ..
$query_select = "SELECT e
FROM MuzichCoreBundle:Element e
WHERE e.id IN (".$query_ids->getResult().")
ORDER BY e.created DESC, e.name DESC"
;
$query = $this->getEntityManager()
->createQuery($query_select)
->setParameters($params)
->setMaxResults($limit);
;
$resultCollection = $query->getResult();

I use Doctrine\ORM\Tools\Pagination\Paginator for this, and it works perfectly (doctrine 2.2).
$dql = "SELECT p, c FROM BlogPost p JOIN p.comments c";
$query = $entityManager->createQuery($dql)
->setFirstResult(0)
->setMaxResults(10);
$paginator = new Paginator($query, $fetchJoinCollection = true);

Your setMaxResults($limit) needs to be set on the object.
e.g.
$query_ids = $this->getEntityManager()
->createQuery(
"SELECT e_.id
FROM MuzichCoreBundle:Element e_
WHERE [...]
GROUP BY e_.id")
;
$query_ids->setMaxResults($limit);

$limit=5; // for exemple
$query = $this->getDoctrine()->getEntityManager()->createQuery(
'// your request')
->setMaxResults($limit);
$results = $query->getResult();
// Done

$qb = $this->getDoctrine()->getManager()->createQueryBuilder();
$qb->select('p') ->from('Pandora\UserBundle\Entity\PhoneNumber', 'p');
$qb->where('p.number = :number');
$qb->OrWhere('p.validatedNumber=:number');
$qb->setMaxResults(1);
$qb->setParameter('number',$postParams['From'] );
$result = $qb->getQuery()->getResult();
$data=$result[0];

Related

Doctrine2 DQL Syntax error when ordering by count

This is Doctrine Repository function
public function mostReadArticleByUser($userId){
$total = $this->createQueryBuilder('ar')
->select('ar.articleId', 'COUNT(ar)')
->where('ar.authorId = :userId')
->groupBy('ar.articleId')
->orderBy('COUNT(ar)', 'DESC')
->setMaxResults(1)
->setParameter('userId', $userId)
->getQuery()
->getResult();
return $total;
}
which should be equivalent to this query
SELECT article_id, count(id)
FROM profile_article_reads
WHERE author_id = 2
GROUP BY article_id
Order by count(id) DESC
LIMIT 1;
When I execute this code I get error
Error: Expected end of string, got '('
QueryException: SELECT ar.articleId, COUNT(ar) FROM
SciProfileBundle\Entity\ProfileArticleReads ar WHERE ar.authorId =
:userId GROUP BY ar.articleId ORDER BY COUNT(ar) DESC
THe count funtion accept a field, so try with
COUNT(ar.id)
instead of:
COUNT(ar)
Probably for sorting is better using an alias, as example:
public function mostReadArticleByUser($userId){
$total = $this->createQueryBuilder('ar')
->select('ar.articleId', 'COUNT(ar.id) as total')
->where('ar.authorId = :userId')
->groupBy('ar.articleId')
->orderBy('total', 'DESC')
->setMaxResults(1)
->setParameter('userId', $userId)
->getQuery()
->getResult();
return $total;
}
Hope this help

How to use date() function / return hydrated objects?

In my Entity Repository for Doctrine2, I have the following:
$date = new DateTime('NOW');
$date = $date->format('Y-m-d');
if ($region) {
$region_sql = " AND WHERE region LIKE ?3 ";
} else {
$region_sql = "";
}
$sql = "SELECT *, count(month) as count FROM (SELECT *, date(date_from, 'start of month', '+1 month', '-1 day') as month FROM manifestations WHERE date_to >= :date_to " . $region_sql . ") GROUP BY month";
$stmt = $em->getConnection()->prepare($sql);
$stmt->bindValue(':date_to', $date);
if($region) {
$stmt->bindValue(3, sprintf('%%,%s,%%', $region));
}
$stmt->execute();
return $stmt->fetchAll();
But I need to change this so that it returns the objects hydrated instead of an array. I originally wanted to use DQL or queryBuilder but could not find a way to get the date() function to work.
With NativeQuery you can execute native SELECT SQL statements and map the results to Doctrine entities or any other result format supported by Doctrine.
What you want to do can be achieved using the ResultSetMappingBuilder.
ResultSetMappingBuilder is a convenience wrapper. It can generate the mappings for you based on Entities.
This is how I'd do it (I assume your query works, maybe you'll have to adjust it, as I will use a new alias):
Create the ResultSetMapping:
use Doctrine\ORM\Query\ResultSetMapping;// Don't forget this
$rsm = new ResultSetMappingBuilder($entityManager);// $entityManager points to your entity manager.
$rsm->addRootEntityFromClassMetadata('path/to/class/MyClass', 'a');// Notice the a, it's an alias that I'll later on use in the query.
$rsm->addScalarResult("count", "count");// column, alias
Prepare $region_sql part as you do in your code and add the a alias to whatever you want to map. a.* will be mapped to an object (notice the as a I use in the query):
$sql = "SELECT a.*, count(month) as count FROM (SELECT *, date(date_from, 'start of month', '+1 month', '-1 day') as month FROM manifestations WHERE date_to >= :date_to " . $region_sql . ") as a GROUP BY month";
Execute the query:
$query = $entityManager->createNativeQuery($sql, $rsm);
$query->setParameter('date_to', $date);
$result = $query->getResult();
This will give you an array of rows. Each of them will be a mixed array, $result[n][0] will contain the object and $result[n]["count"] the value of the count column of the query (name of the column is the same as the alias we set up in the $rsm) where n is the number of the row.

Doctrine use count() in NativeQuery with ResultSetMapping

i try to use NativeQuery of Doctrine. If i use my SQL ind Phpmyadmin i have the good result. If i use this, my var_dump return an empty array. I don't understand why.
$sql = 'SELECT COUNT(id) as nb FROM app_facture f WHERE SUBSTR(f.datecreate_facture, 1, 4) = 2014 AND SUBSTR(f.numero_facture,1,1) != "E"';
$rsm = new ResultSetMapping;
$rsm->addEntityResult('Acme\MyBundle\Entity\Facture', 'f');
$rsm->addFieldResult('f', 'COUNT(id)', 'nb');
$query = $this->getEntityManager()->createNativeQuery($sql,$rsm);
$results = $query->getResult();
var_dump($results);//return empty array
Thanks
Try
$rsm->addFieldResult('f', 'nb', 'id');
this worked for me.

Doctrine 2: how do you use a subquery column (in the SELECT clause)

I'm trying to do a simple select query with a subquery in the SELECT clause and have simply not found a way to do it. I've tried with both DQL and with the QueryBuilder, neither work. The code follows, please don't say I could just use a join, this is a simplified example just to illustrate the problem, I have legitimate use cases for subqueries.
// With QueryBuilder
$query = $qb->select(array('a',
'(SELECT at.addresstypeName
FROM e:Addresstype at
WHERE at.addresstypeId = a.addresstypeId
) AS addresstypeName'))
->from('e:Address', 'a')
->where('a.addressId = :addressId')
->setParameter('addressId', 1);
// With DQL
$dql = "SELECT a,
(SELECT at.addresstypeName
FROM e:Addresstype at
WHERE at.addresstypeId = a.addresstypeId
) AS addresstypeName
FROM e:Address a
WHERE a.addressId = :addressId";
$query = $em->createQuery($dql)->setParameter(':addressId', 1);
The following relationship is defined on the Address table:
/**
* #ORM\ManyToOne(targetEntity="Addresstype")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="addresstype_id", referencedColumnName="addresstype_id")
* })
*/
protected $addresstype;
In native SQL, the query would look like this:
SELECT
a.*,
(
SELECT at.addresstype_name
FROM addresstype at
WHERE at.addresstype_id = a.addresstype_id
) AS addresstype_name
FROM address a
WHERE a.address_id = 1
Any ideas?
$query = $qb->select('a')
->addSelect('(SELECT at.addresstypeName
FROM e:Addresstype at
WHERE at.addresstypeId = a.addresstypeId) AS addresstypeName'
)
->from('e:Address', 'a')
->where('a.addressId = :addressId')
->setParameter('addressId', 1);
For me subquery with doctrine works with this query :
$qb->select('e.field')
->addSelect('(SELECT count(mv.nm)
FROM Clt\Bundle\MyBundle\Entity\MV mv
LEFT JOIN Clt\Bundle\MyBundle\Entity\M ma WITH mv.nm=ma.nm
WHERE mv.ne=e.ne and ma.nm is null
) AS nm'
)
->from($this->_entityName, 'e')
->leftJoin('e.m', 'm')
->where($qb->expr()->eq('t.id'.$typeModule, $idElementModule));
Note that in the left join you must use WITH instead of ON...
I know this is an old question, but if you want, you could have used another query builder as your subquery:
$qb->select("a")
->addSelect("(" . $qb2->select("at.addresstypeName")
->from("e:Addresstype", "at")
->where("at.addresstypeId = a.addresstypeId")
->getDQL() . ") AS addresstypeName"
)
->from('e:Address', 'a')
->where('a.addressId = :addressId')
->setParameter('addressId', 1);
In my scenario what I needed was to look into a join and find an Id and use it as boolean, found 1 otherwise 0, then applying this to orderBy. DQL expressions worked only when combined with Where clause, which wasn't my case. So, a DQL subselect saved me.
Adapted more or less to your scenario, it would look like this:
// With QueryBuilder
// In AddressRepository
// Where one address may belong to several addressTypes
public function getWithType($addressType){
$qb = $this->createQueryBuilder('a1');
$qb->addSelect('a1.someField', 'a1.otherField')
$qb->addSelect(
'(SELECT at.addressTypeName
FROM App\Entity\Address a2
JOIN a2.addressType at
WHERE at.id = '.$addressType.' AND a2.id = a1.id
) AS addressTypeName')
//The rest part of the query
}

Stop fetching an association

I perform a simple query like this to fetch an association with episodes:
$query = $this->getEntityManager()
->createQuery('
SELECT p,e
FROM AcmeDemoBundle:Place p
LEFT JOIN p.episodes e
WHERE p.id = :id'
)
->setParameter('id',$id);
This is a simple asso:
/**
* #ORM\OneToMany(targetEntity="Episode", mappedBy="place")
*/
protected $episodes;
This works well. Now, I don't want to fetch episodes, but simply the place object (and nothing else):
$query = $this->getEntityManager()
->createQuery('
SELECT p
FROM AcmeDemoBundle:Place p
LEFT JOIN p.episodes e
WHERE p.id = :id'
)
->setParameter('id',$id);
This is still loading episodes by lazy-loading. Is there a way to avoid lazy-loading in that case?
Many thanks.
Like this:
$query = $this->getEntityManager()
->createQuery('
SELECT p
FROM AcmeDemoBundle:Place p
WHERE p.id = :id'
)
->setParameter('id',$id);
$query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);