How to use doctrine QueryBuilder in a nested loop - doctrine-orm

I’m using QueryBuilder in the in the following way:
$qb = $entityManager->createQueryBuilder();
$qb->select('m')
->from('MyEntity', 'm');
$query = $qb->getQuery();
$collection = $query->getResult();
foreach ($collection as $item) {
$qb = $entityManager->createQueryBuilder();
$qb->update('MyEntity ', 'm')
->set('m.myItem', '?1');
$query = $qb->getQuery();
$result = $query->execute();
}
(I've remove a lot of details in order to focus on the gist of the question)
How should this script be written?
Is it appropriate to reuse $qb or should I use $qb1, $qb2,
etc.?
In this particular script, the results of the first instance of
QueryBuilder get passed into an array $collection before the next
steps, so I assume that I’m done with the first instance of
QueryBuilder at that time. Does there need to be something like
$qb->close before moving on?
Is it necessary to say $qb = $entityManager->createQueryBuilder();
more than once?

Related

DQL getResult return array

I'm playing with Doctrine, and I think I probably miss something.
So I have a table for some relations, and here is the columns:
id | user_id | workshop_id
Basically, I use this table to know that a user is register for a workshop.
I want to count how many users subscribe for a workshop.
So in my Repository, I use a DQL request:
/** #var EntityManager $entityManager */
$entityManager = $this->getEntityManager();
$query = $entityManager->createQuery("
SELECT COUNT('uw.id')
FROM App\Entity\UserWorkshops AS uw
LEFT JOIN App\Entity\User AS u WITH u.userId = uw.user
WHERE uw.workshop = :workshop_id");
$count = $query
->setParameters(['workshop_id' => $workshopId])
->getResult();
And here, and example of the result:
I just need to retrieve 3, as an integer.
How can I return something different ?
thanks
You can use getSingleScalarResult, from the doc:
Query#getSingleScalarResult(): Retrieves a single scalar value from
the result returned by the dbms. If the result contains more than a
single scalar value, an exception is thrown. The pure/mixed
distinction does not apply.
As example:
$count = $query
->setParameters(['workshop_id' => $workshopId])
->getSingleScalarResult();

Left Join with NOT IN clause and QueryBuilder

i'm trying to convert a query to DQL or build ir with query builder.
I can retrive with success the results from database with the following query:
SELECT * FROM flag
left join countries
on flag.id = countries.flag
where countries.flag IS NULL
Now, i need to conver this to DQL or build it with queryBuilder.
My entities are Country and Flag. The entity Country as a field flag as a external id.
So far, i got the following code:
$qb = $em->createQueryBuilder();
$available =
$qb
->select('f')
->from('Flag', 'f')
->leftJoin('Countries', 'c', 'ON', 'c.flag = f.id')
->where('f.id IS NULL');
My dump of $available doesnt return anything.
What's whong with this QueryBuilder?
Thanks.
you also need to actually execute the query:
$result = $qb->getQuery()->execute();
that should give you the results.
where('f.id IS NULL');
is wrong.
It should be
where('c.flag IS NULL');
Thanks for the help.
Both answers are correct. Heres the final code, in case someone else search.
Also, i had to replace the 'ON' with 'WITH'.
$available =
$qb
->select('f')
->from('Flag', 'f')
->leftJoin('Countries', 'c', 'WITH', 'c.flag = f.id')
->where('c.flag IS NULL');
$flags = $qb->getQuery()->execute();

Symfony One-To-Many, unidirectional with Join Table query

I have some One-To-Many, unidirectional with Join Table relationships in a Symfony App which I need to query and I can't figure out how to do that in DQL or Query Builder.
The Like entity doesn't have a comments property itself because it can be owned by a lot of different types of entities.
Basically I would need to translate something like this:
SELECT likes
FROM AppBundle:Standard\Like likes
INNER JOIN comment_like ON comment_like.like_id = likes.id
INNER JOIN comments ON comment_like.comment_id = comments.id
WHERE likes.created_by = :user_id
AND likes.active = 1
AND comments.id = :comment_id
I've already tried this but the join output is incorrect, it selects any active Like regardless of its association with the given comment
$this->createQueryBuilder('l')
->select('l')
->innerJoin('AppBundle:Standard\Comment', 'c')
->where('l.owner = :user')
->andWhere('c = :comment')
->andWhere('l.active = 1')
->setParameter('user', $user)
->setParameter('comment', $comment)
I see 2 options to resolve this:
Make relation bi-directional
Use SQL (native query) + ResultSetMapping.
For the last option, here is example of repository method (just checked that it works):
public function getLikes(Comment $comment, $user)
{
$sql = '
SELECT l.id, l.active, l.owner
FROM `like` l
INNER JOIN comment_like ON l.id = comment_like.like_id
WHERE comment_like.comment_id = :comment_id
AND l.active = 1
AND l.owner = :user_id
';
$rsm = new \Doctrine\ORM\Query\ResultSetMappingBuilder($this->_em);
$rsm->addRootEntityFromClassMetadata(Like::class, 'l');
return $this->_em->createNativeQuery($sql, $rsm)
->setParameter('comment_id', $comment->getId())
->setParameter('user_id', $user)
->getResult();
}
PS: In case of Mysql, 'like' is reserved word. So, if one wants to have table with name 'like' - just surround name with backticks on definition:
* #ORM\Table(name="`like`")
I find the Symfony documentation very poor about unidirectional queries.
Anyway I got it working by using DQL and sub-select on the owning entity, which is certainly not as fast. Any suggestion on how to improve that is more than welcomed!
$em = $this->getEntityManager();
$query = $em->createQuery('
SELECT l
FROM AppBundle:Standard\Like l
WHERE l.id IN (
SELECT l2.id
FROM AppBundle:Standard\Comment c
JOIN c.likes l2
WHERE c = :comment
AND l2.owner = :user
AND l2.active = 1
)'
)
->setParameter('user', $user)
->setParameter('comment', $comment)
;

Doctrine DQL query rewrite to Query Builder

I have query
$Select = 'SELECT COUNT(o.Id) FROM Entities\Order o';
How to rewrite this query for query builder?
$qb = $this->entityManager->createQueryBuilder();
$qb->select(.....
Thanks
It is very straight forward as you can see in the documentation.
$qb = $this->entityManager->createQueryBuilder();
$result = $qb->select('COUNT(o.Id)')
->from('Entities\Order', 'o')
->getQuery()
->getResult();
If you just want to have the number in $result you can use
$qb = $this->entityManager->createQueryBuilder();
$result = $qb->select('COUNT(o.Id)')
->from('Entities\Order', 'o')
->getQuery()
->getSingleScalarResult();

Is this the proper way to handle an ordered array with Doctrine2's WHERE IN expression?

Using Zend Lucene Search, I am returning a list of relevance-ordered IDs that map to blog records that I will fetch from the database.
Is this the proper way of handling an array with Doctrine2's WHERE IN expression:
$dql = "SELECT b FROM BlogPost WHERE b.id IN (" . implode(', ', $ids) . ")";
$query = $em->createQuery($dql);
...
Or is there a better way of maybe passing in the actual $ids array as a parameter to the query?
Also, the Zend Search returns the array of IDs based on relevance. Will using the above technique preserve the order of relevance in retrieving the blog posts?
If it makes you feel better, you can use the ExpressionBuilder.
$ex = $em->getExpressionBuilder();
$dql = 'SELECT b FROM BlogPost b WHERE ' . $ex->in('b.id', $ids));
$query = $em->createQuery($dql);
function cmp($a, $b) {
global $ids;
return (array_search($a->getId(), $ids) < array_search($b->getId(), $ids)) ? -1 : 1;
}
usort($res, 'cmp');
It's a bit cleaner, but does the same as you behind the screens.
You should pas the $ids array through setParameter() function as this is a best practice in doctrine:
$query = $this->_em->createQuery('SELECT b FROM BlogPost WHERE b.id IN (?1)');
$query->setParameter(1, implode(',', $ids));
I think the IN statement will not preserve the order of the passed ID's as IN will match the first found $id not depending on the order.