How to select distinct query using symfony2 doctrine query builder? - php

I have this symfony code where it retrieves all the categories related to a blog section on my project:
$category = $catrep->createQueryBuilder('cc')
->Where('cc.contenttype = :type')
->setParameter('type', 'blogarticle')
->getQuery();
$categories = $category->getResult();
This works, but the query includes duplicates:
Test Content
Business
Test Content
I want to use the DISTINCT command in my query. The only examples I have seen require me to write raw SQL. I want to avoid this as much as possible as I am trying to keep all of my code the same so they all use the QueryBuilder feature supplied by Symfony2/Doctrine.
I tried adding distinct() to my query like this:
$category = $catrep->createQueryBuilder('cc')
->Where('cc.contenttype = :type')
->setParameter('type', 'blogarticle')
->distinct('cc.categoryid')
->getQuery();
$categories = $category->getResult();
But it results in the following error:
Fatal error: Call to undefined method Doctrine\ORM\QueryBuilder::distinct()
How do I tell symfony to select distinct?

This works:
$category = $catrep->createQueryBuilder('cc')
->select('cc.categoryid')
->where('cc.contenttype = :type')
->setParameter('type', 'blogarticle')
->distinct()
->getQuery();
$categories = $category->getResult();
Edit for Symfony 3 & 4.
You should use ->groupBy('cc.categoryid') instead of ->distinct()

If you use the "select()" statement, you can do this:
$category = $catrep->createQueryBuilder('cc')
->select('DISTINCT cc.contenttype')
->Where('cc.contenttype = :type')
->setParameter('type', 'blogarticle')
->getQuery();
$categories = $category->getResult();

you could write
select DISTINCT f from t;
as
select f from t group by f;
thing is, I am just currently myself getting into Doctrine, so I cannot give you a real answer. but you could as shown above, simulate a distinct with group by and transform that into Doctrine. if you want add further filtering then use HAVING after group by.

Just open your repository file and add this new function, then call it inside your controller:
public function distinctCategories(){
return $this->createQueryBuilder('cc')
->where('cc.contenttype = :type')
->setParameter('type', 'blogarticle')
->groupBy('cc.blogarticle')
->getQuery()
->getResult()
;
}
Then within your controller:
public function index(YourRepository $repo)
{
$distinctCategories = $repo->distinctCategories();
return $this->render('your_twig_file.html.twig', [
'distinctCategories' => $distinctCategories
]);
}
Good luck!

Related

Symfony Doctrine disable cache

In my symfony project I have two entities that are related via one to many.
I need to find the first and last child, so I use repository functions that look like this:
public function getFirstPost(Topic $topic)
{
$query = $this->createQueryBuilder('t')
->addSelect('p')
->join('t.posts', 'p')
->where('t.id = :topic_id')
->setParameter('topic_id' => $topic->getId())
->orderBy('p.id', 'ASC')
->setMaxResults(1)
->getQuery();
return $query->getOneOrNullResult();
}
public function getLastPost(Topic $topic)
{
$query = $this->createQueryBuilder('t')
->addSelect('p')
->join('t.posts', 'p')
->where('t.id = :topic_id')
->setParameter('topic_id' => $topic->getId())
->orderBy('p.id', 'DESC')
->setMaxResults(1)
->getQuery();
return $query->getOneOrNullResult();
}
So the only difference is in in ->orderBy(), for the first Post I use ASC and for the last I use DESC.
Now If I use one of those functions from my controller, the return the expected result and work just fine. But If I run them both at the same time from my controller, they return the same result, which they shouldn't.
My guess is that Doctrine caches these queries and the results somehow and that's why the return the same so I tried using $query->useResultCache(false) but that didn't do anything.
So my question is, why is this happening and how can I fix it?
Well, it is cache issue indeed, but mostly it is query issue. Instead of returning a post in these function you return the whole topic with joined posts.
What you can do is to rewrite these queries to select Post entity directly and join Topic entity to it which will be filtered by.
If you really(dont do this) need these queries to work you can detach first topic returned by one of those methods and then call the other method:
$this->getDoctrine()->getManager()->detach($firstTopic);

How convert SQL query to Doctrine2?

I want to convert this in Doctrine2.
Similar to these questions:
Symfony2 / Doctrine2 - How to convert this SQL request with QueryBuilder?
How to convert a complex MySQL Query to Doctrine2
Convert SQL to Doctrine 2 Query Builder or DQL by using NOT IN?
Is it possible?
SELECT
SUM(q.amount)
FROM(
SELECT amount
FROM expense_report e0_
WHERE
(e0_.is_account_transfer = 0)
AND (e0_.remove_date IS NULL)
LIMIT 0, 2) q
Thanks
you can archive your problem with this custom repository method:
public function getAmount()
{
$qb = $this->createQueryBuilder("q");
return
$qb
->select("sum(q.amount)")
->where($qb->expr()->isNull('q.remove_date'))
->andWhere('q.is_account_transfer = 0')
->setFirstResult(0)
->setMaxResults(2)
->getQuery()
->getSingleScalarResult();
}
And simply use it, as example, in a controller method as:
public function testAction()
{
....
$totalAmount = $this->getDoctrine()
->getRepository("AcmeDemoBundle:ExpenseReport")
->getAmount();
...
}
Hope this help

Symfony2 Query Builder Not Returning Many To One Value

I have an entity that has a column "inventoryLcoation_id" that has a many to one relationship. For some reason when I use createQueryBuilder() it is not returning that value in my ajax call, but it returns everything else: id, name, etc etc.. This is not an issue with Symfony2, its an issue with my lack of knowledge :)
Here is my query builder code:
$qb = $this
->createQueryBuilder('p')
->select('p.id', 'p.name')
->where('p.inventoryLocation = :inventoryId')
->andWhere('p.account = :account_id')
->setParameter('inventoryId', $value)
->setParameter('account_id', $account_id)
->orderBy('p.id', 'DESC');
if($qb->getQuery()->getArrayResult()){
return $qb->getQuery()->getArrayResult();
}else{
return false;
}
What do I need to code to have it also include the value from the inventoryLocation table which is mapped to the column value "inventoryLocation_id"?
Thanks so much for your help in enlightening my understanding to the awesome world of Symfony2!
try a join:
$qb->join('p.inventoryLocation','i')
and in the select especify both entities
$qb->select('p','i')
it should look like this:
$qb = $this
->createQueryBuilder('p')
->select('p','i')
->join('p.inventoryLocation','i')
->where('p.inventoryLocation = :inventoryId') // or ->where('i = :inventoryId')
->andWhere('p.account = :account_id')
->setParameter('inventoryId', $value)
->setParameter('account_id', $account_id)
->orderBy('p.id', 'DESC');

How to fetch class instead of array in Doctrine 2

I am able to fetch my data from database by using this structure:
$user = $this->getDoctrine()
->getRepository('AcmeDemoBundle:Emails')
->find(8081);
When I do that, I am able to get my data like this:
$user->getColumnNameHere();
Basically I am able to use Entity Class.
But if I want to use QueryBuilder instead of find I am only getting associative arrays.
$product->createQueryBuilder('p')
->setMaxResults(1)
->where('p.idx = :idx')
->select('p.columnNameHere')
->setParameter('idx', 8081)
->orderBy('p.idx', 'DESC')
->getQuery();
$product = $query->getResult();
$product returnds as array. Is it possible to fetch it withj Entity Managaer Class? If yes, how?
I digg the documentation but it seems not possible or not exist in the doc or I'm just blind :)
Yes you can, usually using:
$repository
->createQueryBuilder('p')
->getQuery()
->execute()
;
This should return you an array of entities.
If you want to get a single entity result, use either getSingleResult or getOneOrNullResult:
$repository
->createQueryBuilder('p')
->getQuery()
->getOneOrNullResult()
;
Warning: These method can potentially throw NonUniqueResultException.
Edit: Ok, so the question was about partial objects: http://docs.doctrine-project.org/en/latest/reference/partial-objects.html
you can get an object instead of array by using "Partial Objects".
here is a tested example with DoctrineORM 2.2.2:
// create query builder
// $em is the EntityManager
$qb = $em->createQueryBuilder();
// specify the fields to fetch (unselected fields will have a null value)
$qb->select ('partial p.{id,pubDate,title,summary}')
->from ('Project\Entity\Post', 'p')
->where ('p.isActive = 1')
->orderBy ('p.pubDate', 'desc');
$q = $qb->getQuery();
$result = $q->getResult();
var_dump($result); // => object
If you wish to return an object from your original query:
$product->createQueryBuilder('p')
->setMaxResults(1)
->where('p.idx = :idx')
->select('p.columnNameHere')
->setParameter('idx', 8081)
->orderBy('p.idx', 'DESC')
->getQuery();
$product = $query->getResult();
Remove this line
->select('p.columnNameHere')
As soon as you use select, it will return an array...
getResult() method returns a collection (an array) of entities. Use getSingleResult() if you're going to fetch only one object.
EDIT:
Oh, I just noticed that you want to fetch a single field of a single object. Use getSingleScalarResult() as #Florian suggests.

Symfony2 & Doctrine - Get number of rows returned from datasource

I have the following code in my Symfony2 Repository Class...
$query = $this->createQueryBuilder('foo')
->where('foo.bar = :id')
->setParameter('id', $myID)
->getQuery();
How do I get the number of rows found by the database?
Thanks in advance
You need to execute DQL to do something you want.
$query = $this->createQueryBuilder()
->from('foo', 'f')
->where('foo.bar = :id')
->setParameter('id', $myID)
->getQuery();
$total = $query->select('COUNT(f)')
->getQuery()
->getSingleScalarResult();
I think you can do something like that:
$query = $this->createQueryBuilder()
->select('COUNT(f.id)')
->from('foo', 'f')
->where('foo.bar = :id')
->setParameter('id', $myID)
->getQuery();
$total = $query->getSingleScalarResult();
You execute the query then get the results. When you have the results, you get the number of record by doing a count on the results:
$results = $query->getResult();
$resultCount = count($results);
If you are concerned with paging, like getting 25 records out of the total. Then, you have two choices.
You perform the query twice, one time to get total results, another time to retrieve only 25 results using the method setFirstResult and setMaxResults. This method setFirstResult enable you to set the offset and the second, setMaxResults, number of records. The following code will give you results ranging from 25 to 50, it's the second page if you use 25 records by page.
$query->setFirstResult(25);
$query->setMaxResults(25);
You can check doctrine-extensions for Doctrine2 which have paginator support. These extensions have been made by one of the developer of Doctrine2. You can review these here.
Hope this help.
Regards,
Matt
I think this is as concise as it gets:
$qb = $repo->createQueryBuilder('entity');
$qb->select('COUNT(entity)');
$count = $qb->getQuery()->getSingleScalarResult();
Where $repo is of type Doctrine\ORM\EntityRepository

Categories