DQL query ManyToMany IN - symfony

This query in not working. What could be wrong? Post has author(User entity). User has Following(ManyToMany self-directing)
I'm trying to get all Posts of the Users which I'm following
$userId = $this->getUser()->getId();
$qb = $em->createQueryBuilder();
$qb2 = $qb;
$qb2 = $em->createQueryBuilder()
->select('u.following')
->from('AppBundle\Entity\User', 'u')
->where('u.id = :userId');
$qb->select('p')
->from('AppBundle\Entity\Post', 'p')
->where($qb->expr()->In('p.author', $qb2->getDQL()));
$qb->setParameter('userId', $userId);
$dql = $qb->getDQL();

I will assume that your code is in repository as it should be...
src/AppBundle/Controller/PostController.php
$em=$this->getDoctrine()->getManager();
$myResultCollection=$em->getRepository(Post::class)->myCustomQuery($this->getUser());
src/AppBundle/Repository/PostRepository.php
public function myCustomQuery(User $user) {
$em=$this->getEntityManager();
$qb=$em->createQueryBuilder();
return $qb->select("p")
->from(Post::class, "p")
->where($qb->expr()->in("p.author",
$qb->select("u.following")
->from(User::class, "u")
->where("u.id=:USERID")
->getDQL()))
->setParameters(array('USERID'=>$user->getId()))
->getQuery()
->execute();
}
As side note, you should be careful with quotes.
Make sure to use double quotes when using DQL (it's true for SQL too).
The reason is because you need simple quote for strings in queries.

Related

Symfony QueryBuilder andWhere for User-Relation not Working

I want to load items for a given User. Between Item and User lives a One-To-Many relationship.
If I use the following, everything is working well:
$result = $em→getRepository(Item::class)→findBy(['user' => $user]);
The $result has 3 entries.
Now I have to give additional conditions to the query. So I want to use the queryBuilder insight the repository:
$result = $this->createQueryBuilder('i')
->andWhere('i.user = :user')
->setParameter('user', $user)
->getQuery()
->getResult();
The result is empty but the query runs without any errors.
Can someone tell me what I'm doing wrong?
In both cases the $user is the related App\Entity\User entity.
I found the solution. It didn't work because of the Uuid. This works:
$result = $this->createQueryBuilder('i')
->andWhere('i.user = :user')
->setParameter('user', $user->getId()->toBinary())
->getQuery()
->getResult();

Doctrine2 empty parameter on queryBuilder

I am trying to check whether an user email is set or not. I am able to get the ones that are set to NULL but I am missing on the ones that have an empty string as the value. Here is my attempt:
$user = $this->createQueryBuilder('u')
->where('(u.email IS NULL OR u.email = :empty)')
->setParameter('empty', "''")
->getQuery()->getResult()
;
I have no problem getting the NULL emails but I fail to get the empty string emails. Is there any way to accomplish this or is it not supported in DQL?
How about this (EDIT #2):
$user = $this->createQueryBuilder('u')
->where('u.email = NULL')
->orWhere('u.email = \'\'')
->getQuery()->getResult()
;
Does that work?
Worths mention that the Expr Helper from QueryBuilder provides a function for that:
// Example - $qb->expr()->isNull('u.id') => u.id IS NULL
public function isNull($x); // Returns string
So for your case you can do something like:
$qb = $this->createQueryBuilder('u');
$qb
->where(
$qb->expr()->orX(
$qb->expr()->isNull('u.email'),
$qb->expr()->eq('u.email', ':empty'),
)
)
->setParameter('empty', '""');
$users = $qb->getQuery()->getResult();

Symfony Query Builder: remove results from a request from another requests

I have a first request (I used QueryBuilder but it is a simple findAll()):
public function findAllRosters(){
$qb = $this->createQueryBuilder('r')
;
return $qb->getQuery()
->getResult();
}
I want to remove from the results of this first query all results from another query:
public function findOtherRosters($user){
$qb = $this->createQueryBuilder('r')
->leftJoin('r.members', 'm')
->addSelect('m')
->where('m.user = :user')
->setParameter('user', $user)
;
return $qb->getQuery()
->getResult();
}
Is there a simple way? It seems that using a where NOT IN might be the way forward..
EDIT
I have tried to follow this exemple: https://stackoverflow.com/a/22616937/4228086 see my answer
Have a look at this stackoverflow solution
Here q2 is your second query, the sub result you want to reduce the first result with.
Hope that helps.
After much googling; I finally found the right Query:
public function findOtherRosters($user){
$q2 = $this->createQueryBuilder('r')
->leftJoin('r.members', 'm')
->addSelect('m')
->where('m.user = :user')
->setParameter('user', $user);
$qb = $this->createQueryBuilder('ro');
$qb
->where('ro not IN (:rosters)')
->setParameter('rosters', $q2->getQuery()->getResult())
;
return $qb->getQuery()
->getResult();
}
Hope it can help others with the same issue

Use Limit and Offset in Doctrine2 query

I'm trying to do the pagination, but there is an error:
[Syntax Error] line 0, col 57: Error: Expected end of string, got 'limit'
I'm not quite sure if this is the right syntax (and logic) to make my query:
public function getFriendsFromTo ($user, $limit, $offset)
{
return $this->getEntityManager()
->createQuery('SELECT f FROM EMMyFriendsBundle:Friend f WHERE f.user='.$user.' limit '.$limit. 'offset' .$offset)
->getResult();
}
Friends and users are related manyToOne and oneToMany, so in the friends table there is a field - user_id.
This is in my controller:
$user = $this->get('security.context')->getToken()->getUser();
$id = $user->getId();
$friends = $user->getFriends();
$result = count($friends)
$FR_PER_PAGE = 7;
$pages = $result/$FR_PER_PAGE;
$em = $this->getDoctrine()->getEntityManager();
$friends = $em->getRepository('EMMyFriendsBundle:Friend')
->getFriendsFromTo($id, $FR_PER_PAGE, $page*$FR_PER_PAGE);
I know that it's stupid and even wrong (especially the third parameter to be $page*$FR_PER_PAGE), but I just wanted to try if the query works, and it didn't.
Nope. Use:
return $this->getEntityManager()
->createQuery('...')
->setMaxResults(5)
->setFirstResult(10)
->getResult();
$towary = $this->getDoctrine()
->getRepository('AcmeStoreBundle:Towar')
->findBy(array(),array(),10,($current-1)*$numItemsPerPage);
You can use findBy 3rd and 4th parameters of method of doctrine repository, which are limit and offset.
Here is the method definition:
findBy(
array $criteria,
array $orderBy = null,
integer|null $limit = null,
integer|null $offset = null
)
Source: http://www.doctrine-project.org/api/orm/2.2/class-Doctrine.ORM.EntityRepository.html
you can also use
$query->getSingleResult();
Doctrine2.6, stumbled upon this old post and tried the DQL way but it did not fit for purpose. So if you want to avoid using DQL because you already have Entities mapped and joined together, you can do paging using matching & Criteria
$criteria = Criteria::create()
->setMaxResults($limit ? $limit : null)
->setFirstResult($offset ? $offset : null)
$result = $em->getRepository('EMMyFriendsBundle:Friend')
->matching($criteria)->toArray();

Count Rows in Doctrine QueryBuilder

I'm using Doctrine's QueryBuilder to build a query, and I want to get the total count of results from the query.
$repository = $em->getRepository('FooBundle:Foo');
$qb = $repository->createQueryBuilder('n')
->where('n.bar = :bar')
->setParameter('bar', $bar);
$query = $qb->getQuery();
//this doesn't work
$totalrows = $query->getResult()->count();
I just want to run a count on this query to get the total rows, but not return the actual results. (After this count query, I'm going to further modify the query with maxResults for pagination.)
Something like:
$qb = $entityManager->createQueryBuilder();
$qb->select('count(account.id)');
$qb->from('ZaysoCoreBundle:Account','account');
$count = $qb->getQuery()->getSingleScalarResult();
Some folks feel that expressions are somehow better than just using straight DQL. One even went so far as to edit a four year old answer. I rolled his edit back. Go figure.
Here is another way to format the query:
return $repository->createQueryBuilder('u')
->select('count(u.id)')
->getQuery()
->getSingleScalarResult();
It's better to move all logic of working with database to repositores.
So in controller you write
/* you can also inject "FooRepository $repository" using autowire */
$repository = $this->getDoctrine()->getRepository(Foo::class);
$count = $repository->count();
And in Repository/FooRepository.php
public function count()
{
$qb = $repository->createQueryBuilder('t');
return $qb
->select('count(t.id)')
->getQuery()
->getSingleScalarResult();
}
It's better to move $qb = ... to separate row in case you want to make complex expressions like
public function count()
{
$qb = $repository->createQueryBuilder('t');
return $qb
->select('count(t.id)')
->where($qb->expr()->isNotNull('t.fieldName'))
->andWhere($qb->expr()->orX(
$qb->expr()->in('t.fieldName2', 0),
$qb->expr()->isNull('t.fieldName2')
))
->getQuery()
->getSingleScalarResult();
}
Also think about caching your query result - http://symfony.com/doc/current/reference/configuration/doctrine.html#caching-drivers
public function count()
{
$qb = $repository->createQueryBuilder('t');
return $qb
->select('count(t.id)')
->getQuery()
->useQueryCache(true)
->useResultCache(true, 3600)
->getSingleScalarResult();
}
In some simple cases using EXTRA_LAZY entity relations is good
http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/tutorials/extra-lazy-associations.html
If you need to count a more complex query, with groupBy, having etc... You can borrow from Doctrine\ORM\Tools\Pagination\Paginator:
$paginator = new \Doctrine\ORM\Tools\Pagination\Paginator($query);
$totalRows = count($paginator);
Since Doctrine 2.6 it is possible to use count() method directly from EntityRepository. For details see the link.
https://github.com/doctrine/doctrine2/blob/77e3e5c96c1beec7b28443c5b59145eeadbc0baf/lib/Doctrine/ORM/EntityRepository.php#L161
Example working with grouping, union and stuff.
Problem:
$qb = $em->createQueryBuilder()
->select('m.id', 'rm.id')
->from('Model', 'm')
->join('m.relatedModels', 'rm')
->groupBy('m.id');
For this to work possible solution is to use custom hydrator and this weird thing
called 'CUSTOM OUTPUT WALKER HINT':
class CountHydrator extends AbstractHydrator
{
const NAME = 'count_hydrator';
const FIELD = 'count';
/**
* {#inheritDoc}
*/
protected function hydrateAllData()
{
return (int)$this->_stmt->fetchColumn(0);
}
}
class CountSqlWalker extends SqlWalker
{
/**
* {#inheritDoc}
*/
public function walkSelectStatement(AST\SelectStatement $AST)
{
return sprintf("SELECT COUNT(*) AS %s FROM (%s) AS t", CountHydrator::FIELD, parent::walkSelectStatement($AST));
}
}
$doctrineConfig->addCustomHydrationMode(CountHydrator::NAME, CountHydrator::class);
// $qb from example above
$countQuery = clone $qb->getQuery();
// Doctrine bug ? Doesn't make a deep copy... (as of "doctrine/orm": "2.4.6")
$countQuery->setParameters($this->getQuery()->getParameters());
// set custom 'hint' stuff
$countQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, CountSqlWalker::class);
$count = $countQuery->getResult(CountHydrator::NAME);
For people who are using only Doctrine DBAL and not the Doctrine ORM, they will not be able to access the getQuery() method because it doesn't exists. They need to do something like the following.
$qb = new QueryBuilder($conn);
$count = $qb->select("count(id)")->from($tableName)->execute()->fetchColumn(0);
To count items after some number of items (offset), $qb->setFirstResults() cannot be applied in this case, as it works not as a condition of query, but as an offset of query result for a range of items selected (i. e. setFirstResult cannot be used togather with COUNT at all). So to count items, which are left I simply did the following:
//in repository class:
$count = $qb->select('count(p.id)')
->from('Products', 'p')
->getQuery()
->getSingleScalarResult();
return $count;
//in controller class:
$count = $this->em->getRepository('RepositoryBundle')->...
return $count-$offset;
Anybody knows more clean way to do it?
Adding the following method to your repository should allow you to call $repo->getCourseCount() from your Controller.
/**
* #return array
*/
public function getCourseCount()
{
$qb = $this->getEntityManager()->createQueryBuilder();
$qb
->select('count(course.id)')
->from('CRMPicco\Component\Course\Model\Course', 'course')
;
$query = $qb->getQuery();
return $query->getSingleScalarResult();
}
You can also get the number of data by using the count function.
$query = $this->dm->createQueryBuilder('AppBundle:Items')
->field('isDeleted')->equals(false)
->getQuery()->count();

Resources