Problem/Motivation
It is possible to add a chain of entity references to a query access condition, e.g.:
$conditions->addCondition('field_mammals.entity:mammal.field_primates.entity:primate.field_title.value', 'Gorilla')
This works with everywhere Entity Queries are used, like in JSONAPI.
Views however builds queries in it's own way, and chained conditions will actually break the view.
Steps to reproduce
Create a query_access handler with a chained condition and a view to implement it.
Proposed resolution
Fix ViewsQueryAlter::mapConditions to also map the conditions when there is a chained entity reference.
Remaining tasks
Write a test to prove this works with:
- Base fields with cardinality 1
- Base fields with cardinality -1
- Config fields
- Multiple levels of chaining.
User interface changes
API changes
Data model changes
Issue fork entity-3315432
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #3
nuezI know this needs tests, but marking this as needs-review anyway just to get some feedback.
I'll see if I can get some time to add the tests for this.
Comment #4
nuezComment #5
nuezComment #6
jonmcl commentedYes, please!
Works well for us to chain through two entity reference fields.
Comment #7
meickol+1 RTBC works perfect!
Comment #8
sander wemagine commented+1 RTBC works!
Comment #10
benstallings commented@meickol @sander wemagine Could you please review and test again now that I've rebased?
Comment #11
jonmcl commentedI have a question about the join type in the new ::addJoin method:
Why 'INNER' and not 'LEFT'?
The problem we are running into with 'INNER' is that if there are two event subscribers altering the query, and one of them is using a field that is only available on some bundles, then the INNER JOIN causes no results from the other bundles because they don't have that field.
Our use case is that we have a custom entity type, called 'survey', and two bundles: one, two. If a user has permissions to access bundle one, an event subscriber puts an additional condition on the query to reduce the results based on some business logic. If a user has permissions to access bundle two, another event subscriber adds another additional condition with some different business logic. Both conditions go through a chained entity reference field.
The problem is that bundle one has field_entity_reference_one and bundle two has field_entity_reference_two. Since both conditions are being added with INNER JOIN, there ends up being 0 results because the inner table joins remove the results. LEFT JOIN would solve this by instead having a null value return from the joined table when a field doesn't exist in a bundle.
Or at least that's how I think the join types work?
It should be noted that our use case also runs into trouble with the use of the 'OR' condition group in EventOnlyQueryAccessHandler::getConditions. However, it's trivial to replace that function with an extend. Not so easy to replace ViewsQueryAlter::addJoin because ViewsQueryAlter is being called directly from \entity_views_query_alter().