Accessing Fields of a has_one relation Silvestripe - silverstripe

I have a DataObject Team that has a has_one relation to Member. I would like to use the ORM to search Team but be able to filter records by the value of one field of the related Member table. Just to be more clear, I can achieve the same result with SQL:
SELECT * FROM Member
LEFT JOIN Team ON Team.MemberID=Member.ID
WHERE Member.CityID=142
AND Team.Target='Boy'
AND Team.GenreID=51
AND Team.Fyr <= 9
AND Team.Tyr >= 9
Okay, I got it. The answer is:
$teams= Team::get()->filter(array('Member.CityID:ExactMatch' => $var));
and later simply filter $teams

Related

Doctrine2 QueryBuilder select entity and count of associated entities

I'm having a huge problem with ORM QueryBuilder. What I need to do is:
I need to fetch order with count of its products and plenty of associated entities (associated with order), but I assume they're not relevant here. I also need to order result by that count.
Could anyone give me an example of how this can be achieved? I would like to avoid "inline" DQLs if possible.
You can get data via Doctrine Query Builder.
You are supposed to left join products from Order and then group by order id. You can have COUNT(product.id) in your select statement and use the alias in order by clause to make your orders sorted. Below is a small code snippet from Repository.
/**
* #return \Doctrine\ORM\Query
*/
public function getHotelAndRoomType()
{
$qb = $this->createQueryBuilder('order')
->select('partial order.{id, orderId} as order, count(product.id) as total_products_in_order')
->leftJoin('AppBundle:Product', 'product', 'WITH', 'product.order = order.id')
->groupBy('order.id')
->orderBy('total_products_in_order', 'DESC')
;
return $qb->getQuery()->execute();
}
Note : Code not tested.

pagerfanta - DoctrineORMAdapter Sorting

Although I know this is trivial I'm stuck trying to implement the pagerfanta Paginator using the DoctrineORMAdapter, I want to paginate all entities sorted by id in descending order, the final SQL I want is this:
SELECT id, name FROM User ORDER BY id DESC LIMIT 0, 5;
Suppose I had users from A to Z and I want to limit them by 5 each page, what DoctrineORMAdapter is paginating results in User E to A listed in the first page, while what I actually expect is to see User Z to user V in the first page, U to Q in the second page and so on. The DQL I'm passing to DoctrineORMAdapter is as follow:
SELECT u FROM My\FluffyBundle\Entity\User u ORDER BY u.id DESC
On execution this is the final DQL for the first page:
SELECT DISTINCT id0 FROM (SELECT u0_.id AS id0, u0_.name AS name1 FROM User u0_
ORDER BY u0_.id DESC) dctrn_result LIMIT 5 OFFSET 0
Please note that when using the ArrayAdapter instead of DoctrineORM's it works as expected, but it's not a good idea to rely on ArrayAdapter when you have thousands of complex Doctrine Entities, not even with extra lazy loading :D.
This is the only relevant code:
$queryBuilder = $repo->createQueryBuilder('u')->orderBy('u.id', 'DESC');
$adapter = new DoctrineORMAdapter($queryBuilder);
$pager = new Pagerfanta($adapter);
$pager->setMaxPerPage(5);
Thanks.
This will help you:
$adapter = new DoctrineORMAdapter($queryBuilder, false);
Had the same problem this morning.
By default Pagerfanta is treating your query as one with joins. Setting second argument to false makes it use simple query handling.
In Kunstmaan Bundle, in AdminListConfiguration class, you have to overide function that is creating Pagerfanta, if you want to sort simple entity.

QueryBuilder OneToMany filter entity without relations

I have a model
House #OneToMany(People)
People #ManyToOne(House)
i need a QueryBuilder for filter all Houses without People
Current not working code
$houseRepository
->createQueryBuilder('h')
->join('h.people', 'p')
->where('p is NULL');
always return me nothing, i have 3 house in the database only one have people
You need to use left join for such queries. something like:
$houseRepository
->createQueryBuilder('h')
->leftJoin('h.people', 'p')
->where('p is NULL');

Symfony2 QueryBuilder join ON and WITH difference

I'm new with Symfony2 and I built successfully my first join through QueryBuilder and Doctrine 2.
Probably this is a stupid question but both on-line and in the Symfony2's methods I was unable to find anything for understanding the difference between the join clauses "WITH" and "ON".
For example this is my join code:
->leftJoin('EcommerceProductBundle:ProductData', 'pdata', 'WITH', 'prod.id = IDENTITY(pdata.product)')
It works good but if I put ON instead of WITH I get the following error:
[Syntax Error] line 0, col 200: Error: Expected
Doctrine\ORM\Query\Lexer::T_WITH, got 'ON'
Why? I've seen among the objects that there are both the T_ON and T_WITH like join clauses, but which is their usage difference? What is their uses like?
#florian gave you the correct answer but let me try to explain it on example:
In sql, joins are done like this:
SELECT * FROM category
LEFT JOIN product ON product.category_id = category.id
(or something like this)
Now in Doctrine, you don't need to use ON clause because doctrine knows that from relations annotations in your entities. So above example would be:
// CategoryRepository.php
public function getCategoriesAndJoinProducts()
{
return $this->createQueryBuilder("o")
->leftJoin("o.products", "p")->addSelect("p")
->getQuery()->getResult() ;
}
Both would fetch all categories and join products associated with them.
Now comes the WITH clause. If you want to join only products with price bigger than 50, you would do this in SQL:
SELECT * FROM category
LEFT JOIN product ON product.category_id = category.id AND product.price>50
In Doctrine:
// CategoryRepository.php
public function getCategoriesAndJoinProductsWithPriceBiggerThan($price)
{
return $this->createQueryBuilder("o")
->leftJoin("o.products", "p", "WITH", "p.price>:price")
->setParameter("price", price)->addSelect("p")
->getQuery()->getResult() ;
}
So, in reality you should never, ever use ON if you are using Doctrine. If you have a need for something like that, you can be almost sure that you screwed something else.
In theory, ON permits you to give the full join criterias, while WITH permits to add additional criterias to the default ones (IMHO).
But, what DQL permits is to avoid giving the JOIN criterias:
You just have to say: $qb->leftJoin('prod.pdata', 'pdata');
And doctrine2 will handle the join correctly.
Here is a related question about that: Can I use "ON" keyword in DQL or do I need to use Native Query?

Automatically add a Join statement in findBy magic method

I'm using Symfony2 / Doctrine2.
I'm trying to override the BaseEntityRepository Class so the magic findBy method automatically adds a JOIN on a "translations" relation. It was easy to do in Symfony 1.4/Doctrine 1, because it was manipulating a Doctrine_Query object, so I simply had to $query->addJoin() and it did the trick.
Unfortunately, in Doctrine 2 you only receive an array of criteria as parameter, and that's where I'm stucked.
I got many entities which have a one-to-many relationship with a translation entity.
For exemple : Section as a one-to-many relationship with SectionTranslation
The goal is to retrieve only the "active" sections (active is in SectionTranslation) when using SectionRepository->findAll(); (or even findBy).
The wanted DQL result is : Select * from Section INNER JOIN SectionTranslation ON Section.id = SectionTranslation.translatable_id WHERE SectionTranslation.locale = $locale AND SectionTranslation.active = 1;
Any idea?
The solution could be adding event listener for particular entity and particular method.

Resources