[DDC-1007] Add ability to filter a association Created: 31/Jan/11  Updated: 01/Mar/13  Resolved: 31/Jan/11

Status: Resolved
Project: Doctrine 2 - ORM
Component/s: ORM
Affects Version/s: Git Master
Fix Version/s: None
Security Level: All

Type: New Feature Priority: Critical
Reporter: Jáchym Toušek Assignee: Benjamin Eberlei
Resolution: Duplicate Votes: 0
Labels: None
Environment:

any


Attachments: File example_entities.php    
Issue Links:
Duplicate
duplicates DDC-551 Consider adding ability to specify ad... Resolved

 Description   

Note: I used critical priority for this issue because this is one of the most criticised things about Doctrine 2 worldwide.


The worst thing about Doctrine 2 is, that you can do almost nothing through methods like Category::getArticles();.
For example, you have the Category and want to output all the articles. Fine, nothing easier:

foreach ($category->getArticles() as $article) {
echo $article->name;
}

OK. And now I need only "visible" articles (others are hidden for now). And here it is. You need DQL even for this easy task. Without DQL you can't do nothing, but using DQL (or QueryBuilder) everywhere is very very bad. Simply there is no way to write method like getVisibleArticles(). (Except selecting all and using some filter, but that's nonsense.)

The solution would be some kind of smart collections (but i don't mind if you come up with something different):

public function getArticles($visibility = 0, $limit = NULL) {
return $this->articles->filter('visibility', $visibility)->limit($limit);
}

Of course when you need any AND, OR, XOR, IN, LIKE and so DQL is needed. This should be for some simple things only.



 Comments   
Comment by Benjamin Eberlei [ 31/Jan/11 ]
Note: I used critical priority for this issue because this is one of the most criticised things about Doctrine 2 worldwide. 

By which standard are you making this assumption?

Comment by Jáchym Toušek [ 02/Feb/11 ]

Just some examples:

http://www.doctrine-project.org/docs/orm/2.0/en/reference/limitations-and-known-issues.html#restricing-associations
http://groups.google.com/group/doctrine-user/browse_thread/thread/d013705a109d7e44
http://stackoverflow.com/questions/4214286/doctrine-2-association

You need to use DQL even for the most easiest tasks. There is no way to implement methods like "getVisibleArticles", everything must be done through repositories and DQL. Therefor the associations are almost useless as they are now.

There is almost always need for some filter and this logic should be in entities themselves. I mean I of course can make new repository class for every entity, but then why are we using ORM which makes every task even more difficult then it is without the ORM?

I've been looking for some way to manually modify the SQL query used to load the collection, but found none.

//EDIT:
This is also related. There would be no need for such crutches if this issue is solved.
http://www.doctrine-project.org/blog/doctrine2-large-collections

Comment by Marc Hodgins [ 03/Feb/11 ]

No need for this. This is exactly what custom repositories are for. http://www.doctrine-project.org/docs/orm/2.0/en/reference/working-with-objects.html#custom-repositories

If you don't like writing raw DQL, use the QueryBuilder class instead to build up your query.

<?php
class ArticleRepository extends EntityRepository
{
    public function getVisibleArticles()
    {
        // use Query or QueryBuilder object to build up your query here and return the results.
    }
}
Comment by Benjamin Eberlei [ 04/Feb/11 ]

I do think its very necessary to have this, but we are still evaluating how this can be done generically.

Comment by Parl Johnson [ 27/Mar/11 ]

I tend to agree. I have just spent an unfortunate amount of time trying to figure out how to filter an association without loading the whole thing. I figured i could easily use a custom repository and was headed down that path until it dawned on me that I'm breaking the whole point of doctrine to use an Entity Manager inside of an existing entity... which is the only way I can call a custom repository from inside of an entity. In order to keep my code clean I need a way to get an association and filter it without loading the whole thing. Tell me how else I would do that without breaking clean coding rules? Even if you could just use custom Collection loaders from a custom repository that would be great but it doesn't appear that when you load a collection you're not even calling a Repository to do it, if you were, I would have found a way to override that function and add some filtering devices to it. This seems to make complete sense to me? What am I missing here about Jachyms request?

Comment by Benjamin Eberlei [ 27/Mar/11 ]

There is currently no way to "just override" some function, as I said its really complicated to implement and we are evaluating the best way to do it. If you want to filter associations use DQL for now.

Comment by Parl Johnson [ 27/Mar/11 ]

Awesome, thanks for the quick response. Just leaves me with 2 questions then that would help me a ton:
1. How does DQL filter the association now as it is and why couldn't that be overriden in the hydration process of an association?
2. Knowing the answer to 1 is difficult for now and that I should just use DQL, how do you suggest I do that? I have an entity that cannot have its association pre-populated by a DQL, should I just get an EM from inside the entity and go from there? Just wondering what the optimal way to this is?

To clarify, I have an entity with an association that is NULL for a specific filter and I need it to stay null, but I can't because it autoloads all the other records that don't match that filter when I ask for it. I have no way to "redo" the filter I originally used in the DQL.

Thanks again for the quick response.

Comment by Benjamin Eberlei [ 27/Mar/11 ]

1. Assocations are not loaded through DQL but through the Persisters.
2. In DQL you can do SELECT a FROM Article a JOIN a.comments c WITH c.status = 'active' ...
3 . With Doctrine 2.1-DEV you can mark an association as EXTRA_LAZY and use Article::$comments->slice($count, $offset) to fetch only parts of the association.

Comment by Parl Johnson [ 27/Mar/11 ]

So based on my clarification above, how do you suggest I call a DQL from inside of an entity? Call it inline in one my methods through an entity manager? or through an entity manager to a custom repository? I don't see any other ways, am I missing anything? My problem is the reverse of what you are solving with Extra Lazy Loading, I need a collection to stay empty based on a my DQL, but it won't! It keeps calling all associations.

Comment by Jáchym Toušek [ 20/Dec/11 ]

Hi, is there a way to implement this in current Doctrine? I'm talking about this method (it should be a method of CategoryEntity):

public function getArticles($visibility = 0, $limit = NULL)

{ return /* what should be here? */ }
Comment by Koby Soto [ 27/Sep/12 ]

A year later this is still highly required feature.

Comment by Alexandre Salomé [ 01/Mar/13 ]

Found this in documentation, related to this ticket:

http://docs.doctrine-project.org/en/latest/reference/working-with-associations.html#filtering-collections

Generated at Wed Sep 03 07:13:21 UTC 2014 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.