How to write DQL query innner join to avoid lazy loading? - symfony

My code:
$entityManager = $this->getDoctrine()->getEntityManager();
$result = $entityManager->createQueryBuilder()
->select('c')
->from('BlogHomepageBundle:Comment', 'c')
->innerJoin('BlogHomepageBundle:Post', 'po', 'WITH', 'c.postFk = po.postId')
->getQuery()->getResult();
foreach ($result as $c) {
//additional sql query
echo $c->getPostFk()->getName();
}
It works just fine, but when Im trying to get postFk ( post relate to comment one-to-many relation) I'm getting additional query to db ( lazy loading). Can I avoid this situtation to get all data in one DQL query ? Simple to performe sql query
select c.*, p.* from comment as c inner join post as p on c.post_fk = p.post_id
I want to use DQL ( not raw sql ).
EDIT
I would like to have Objects and access to them like in foreach loop / not scalar data.

You need to specifically select a property or a join to avoid lazy loading :
->select('c', 'po')
http://www.doctrine-project.org/blog/doctrine-lazy-loading.html

I think I found solution #Rpg600 thanks for help.
This is code:
$entityManager = $this->getDoctrine()->getEntityManager();
$result = $entityManager->createQueryBuilder()
->select('c', 'po')
->from('BlogHomepageBundle:Comment', 'c')
->innerJoin('c.postFk', 'po', 'WITH', 'c.postFk = po.postId')
->getQuery()
->getResult();
foreach ($result as $c) {
echo $c->getContent();
echo $c->getPostFk()->getName();
}

Related

DQL query ManyToMany IN

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.

doctrine query onetonmany / notIn with objects / symfony forms querybuilder

I am using symfony 2 and doctrine to prefilter a form field type 'entity' with the help of a querybuilder.
My querybuilder should return all products which the user has not already added to a list.
All relations are bidirectionnal.
I have products linked to userIngredients (oneToMany) each linked to one user (manyToOne)
I have come with this so far but it's not working, I get products not added by other users.
return $this
->createQueryBuilder('p')
->leftJoin('p.userIngredients', 'i')
->where('i.user <> ?1')
->setParameter(1,$user);
1; Any clue on how to correct this ?
Alternatively, I could select the products I don't want and then reselect those who don't match but using an expression and NotIn seems to only work for strings
$products = $this
->createQueryBuilder('p')
->leftJoin('p.userIngredients', 'i')
->where('i.user = ?1')
->setParameter(1,$user)
->getQuery()
->getResult();
return $this
->createQueryBuilder('p')
->where($this->createQueryBuilder('p')->expr()->notIn('p', $products));
2; how could we correct this to make it work with objects ?
3; alternatively : is there a way to pass not a querybuilder but an array of results to symfony form builders ?
I got thinks thanks to Javad:
(slight modification, I'm using an array result, not dql):
$qb = $this->_em->createQueryBuilder();
$ids = $qb
->select('p.id')
->from('AppBundle:MarketPlace\Product','p','p.id')
->leftJoin('p.userIngredients', 'i')
->where('i.user = ?1')
->setParameter(1,$user)
->getQuery()
->getResult();
//I don't know why I couldn't directly get an array of ids otherwise... if you know how to do better directly from the query, I'm interested (getScalarResult does not make it)
$ids=array_keys($ids);
$result = $this
->createQueryBuilder('p')
->where($this->createQueryBuilder('p')->expr()->notIn('p.id', $ids));
return $result;

Running the following query in Symfony2

I am trying to run a query as follows in Symfony:
SELECT * FROM company
WHERE name LIKE '%$search%'
ORDER BY CASE WHEN name LIKE '$search%' THEN 1
WHEN name LIKE '%$search' THEN 2
WHEN name LIKE '%$search%' THEN 3
END
LIMIT 0,10
There seems to be a lot of the limitations with createQuery() and findBy() I was wondering if there was a way to query the DB in such a way with Symfony2?
Note, the company table is also set up as an entity.
This is what I tried which doesn't accomplish my whole query:
$this->getDoctrine()
->getRepository('testMyBundle:Company')
->findBy(array(),array(),10,($current-1)*$numItemsPerPage);
I appreciate any suggestions, thanks in advance!
I don't like solutions like that, but should working:
// CompanyRepository.php
public function getSth() {
$query = 'your sql query here';
$em = $this->getEntityManager();
$connection = $em->getConnection();
$stmt = $connection->prepare($query);
$stmt->execute();
return $stmt->fetchAll();
}
And in your controller:
$this->getDoctrine()
->getRepository('testMyBundle:Company')->getSth();
This DQL should work:
$query = $this->getDoctrine()
->createQuery('
SELECT c
FROM testMyBundle:Company c
WHERE c.name LIKE :search
ORDER BY CASE WHEN c.name LIKE :search THEN 1
WHEN c.name LIKE :search THEN 2
WHEN c.name LIKE :search THEN 3
END
')
->setParameter('search', '%search%')
->setMaxResults(10)
->setFirstResult(0)
->execute()
;

Doctrine2 findOneBy argument equivalent to BETWEEN in SQL

I need to be able to use the following WHERE clause in Doctrine:
WHERE AL.UserID = 41 AND (TheDate BETWEEN DATE_SUB(CURDATE(), INTERVAL 2 WEEK) AND CURDATE())
and what I'm currently doing is:
$results = $em->getRepository('MyBundle:MyTable')->findOneBy(array('userId' => $userId));
However, I haven't been able to filter results by the last 2 weeks without writing SQL or DQL.
Is there any way I can achieve this through Doctrine's methods?
You can use QueryBuilder. Assuming you are using MySQL BETWEEN, something like:
<?php
// $em instanceof EntityManager
$qb = $em->createQueryBuilder();
$now = new DateTime();
$qb->select('c')
->from('MyClass', 'c')
->where($qb->expr()->andX(
$qb->expr()->eq('c.UserID', '?1'),
$qb->expr()->gte('c.TheDate', '?2'),
$qb->expr()->lte('c.TheDate', '?3')
))
->setParameter(1, 41)
->setParameter(2, $now.sub(new DateInterval('P2W')))
->setParameter(3, $now);
$query = $qb->getQuery();
$c = $query->getSingleResult();
This is cleaner code and should work across the different database platforms supported by Doctrine2 ORM.

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();

Resources