Hopefully the title is clear enough. Essentially when filtering with an or group with two entity relationship fields, if one of the fields is empty, the desired node is excluded from the results.
My example uses "Tournaments" that have a "game" and "teams" relationships. So my filter is if IDs in GAME or IDs in TEAMS return the tournament, however if one of those fields is empty, I don't get that entity.
What's more, this only happens for anonymous users. If a user is logged in as admin and visits the jsonapi page directly, they will see the "desired" result. For now I've found that if I turn on "Bypass Content Access Control" for anonymous users, I see the proper return. This is obviously not an ideal fix.
Visit this URL as admin (admin/admin) and as an anonymous users, and you will see the data count differs.
Edit: the simply test me expired - forgot about that. Here is a the filter:
filter[or-group][group][conjunction]=OR&filter[games][condition][path]=field_game.id&filter[games][condition][operator]=IN&filter[games][condition][value][]=978ea07c-6bff-46e0-81a3-ee7eba8b5357&filter[games][condition][value][]=f1f6aea5-e291-4d8f-aa00-46948554aa5e&filter[games][condition][memberOf]=or-group&filter[teams][condition][path]=field_team.id&filter[teams][condition][operator]=IN&filter[teams][condition][value][]=172e5680-d8dc-4dbc-b277-f7004b531005&filter[teams][condition][memberOf]=or-group
| Comment | File | Size | Author |
|---|---|---|---|
| #16 | interdiff-3072384-14-16.txt | 1.31 KB | bbrala |
| #16 | when_filtering_by_en-3072384-16.patch | 4.29 KB | bbrala |
| #14 | failing-test-3072384-14.patch | 4.3 KB | bbrala |
Issue fork drupal-3072384
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 #1
Anonymous (not verified) commenteddrewbolles created an issue. See original summary.
Comment #2
Anonymous (not verified) commentedComment #3
Anonymous (not verified) commentedComment #4
ikphilipI don't have an answer but I've spit out the resulting queries that are close to the reporter's setup. Maybe this illuminates what might be happening. Clearly the query that doesn't work has some extra stuff going on.
Unauthenticated (doesn't return results)
Bypass content control (returns data)
Comment #5
wim leersComment #6
kenianbei commentedI'm also seeing this, my use case is I have a node (lesson) with two user entity reference fields: viewers (field_view) and editors (field_edit). In hook_entity_access I allow view access to the node if they current user is referenced in either field.
When I filter by only one field, I get the correct results. When I filter by both fields, using an OR group, I get no results. Here's my filters:
Query by both fields (doesn't work)
Resulting mysql query:
Query by one field (works)
Above resulting mysql query:
I've tried directly executing different versions of the first query and haven't had any success in getting it to work. It's difficult to understand why all the different JOINS are used.
Also, perhaps because I'm specifying access in hook_entity_access, setting bypass content access doesn't fix this for me.
However, If I add the same user reference to both fields, then that specific node entity will show up in the results correctly when filtered by both fields.
If I can get some direction on where to tinker in the jsonapi module I'm willing to try to get a patch written with my setup.
Comment #7
naveko commentedI see the same behaviour. In my case I want to filter by address in either the `address_line1` or the `address_line2` field provided by the Address module. These are the parameters:
For testing purposes I created one node having the value 'Street 1' in the `address_line1` field and another having the value 'Street 1' in the `address_line2` field. So logically, I should get two results, but none are found.
Comment #10
ocastle commentedI'm also having this same issue. It occurs when filtering against two user entity reference fields for me. If one of those fields are empty they will be omitted from the results.
I think i've found the issue resides within TemporaryQueryGuard::getAccessCondition called from TemporaryQueryGuard::secureQuery.
Comment #11
ocastle commentedCurrently the EntityCondition added from within Drupal\jsonapi\Access\TemporaryQueryGuard::secureQuery is simply appended onto the query without any context/care of the original filters conjunction.
Where i believe should be:
Comment #13
bbralaOk, i've put in some work to find out if i can proove this bug through a test. And it seems i can. Next is to work on a possible solution.
Comment #14
bbralaOops, kept a var_export in there.
Comment #15
bbrala@ocastle you are right, the problem is the fact that in the whole QueryGuard it doesn't really consider the grouping of the filters. It should make sure the extra conditions are applied together then.
Comment #16
bbralaUpdated patch to fix style issues.
Comment #17
wim leersWow, epic work here, @bbrala!
Comment #18
bbralaComment #21
gauravvvv commentedComment #22
bbralaYeah, sorry appearantly commited my shortcut to run a specfic test :) Doesn't need review though, this is a test only commit.
Comment #23
bbralaI'm exploring how to fix this. My current thinking is this;
The problem is in (NotSo)TemporaryQueryGuard.
Currently the
applyAccessControlsmethod flattens the fields and remove any reference to any existing conditions. This seem counterproductive. Instead of collecting all filtered fields and just blindly add conditions it should probably do the following:1. Collect the fields that are used.
2. Check for hardening (
applyAccesConditions) in the context of the specifc conditions.3. Apply the hardening explicitly on the condition in that nested context.
This would probably mean restructuring this code to walk through the conditions recursively and apply adustments to the conditions. This will be hard though. The question becomes, should this issue wait for the other issues that would make this class unneeded. At least #2809177: Introduce entity permission providers and maybe #777578: Add an entity query access API and deprecate hook_query_ENTITY_TYPE_access_alter().
Fixing this is hard and needs to be done carefully not to introduce security issues.
Comment #25
leon kessler commentedJust been battling with this one, and in my situation is was further complicated by the entity module, which would return
$result[JSONAPI_FILTER_AMONG_ALL] = $allowed; if no query access conditions were returned. This would make jsonapi avoid adding any additional filters to the query. Which actually is a fix for this issue, i.e. you get the correct results back. This means if you have the entity module enabled, you may not see this issue!
However in my case, as I am applying my own entity query access conditions, so I wasn't getting
JSONAPI_FILTER_AMONG_ALL. Instead I got the same empty results as others have reported here (although this confused the hell out of me, as I thought the issue was something to do with my custom query access filter because it would work when disabling this part of my code).Anyway, the workaround I am using for now is to implement my own
hook_jsonapi_entity_filter_access()and return[JSONAPI_FILTER_AMONG_ALL => AccessResult::allowed()];for situations where my query access subscriber is being applied. I just need to ensure that I apply the standardstatus = 1filters to the query.Sidenote: it seems as though these additional access filters only get added if there is a JSON:API filter in the url. See EntityResource.php#L893-898 . Again this initially confused me, I'm sure there's a reason why things are setup this way, but I would have thought we'd want to apply the same access filters to the query regardles of whether there was a JSON:API filter.
Comment #26
anas_maw commentedI'm having the same issue
Comment #27
leon kessler commentedJust to summarise my previous semi-rant, a workaround for this issue is to implement something like this:
The caveat of this is that it will avoid applying entity access filters to the entity query. This won't mean that you'll get back results the user shouldn't have access to, but it will mean that you'll get results in the
omittedpart of the JSON:API response. I.e. if you request 40 items you may only get back 35 due to restricted content (whereas previously you would get back the full 40).I believe this is correct, but anyone feel free to correct me.
Comment #29
freelockThis issue also affects other scenarios -- for me it was trying to get the top-level terms in a hierarchical vocabulary.
With filters defined as:
... the parent taxonomy term is pulled into the query with a LEFT JOIN, and checked for both "IS NULL" and status = 1. Which makes the query return no rows.
The fix is the same as @Leon Kessler identified -- implement the hook_jsonapi_entity_filter_access to set JSONAPI_FILTER_AMONG_ALL to AccessResult::allowed(), or enable the Entity API module which does this for you.
I've also confirmed that this loads unpublished terms in the underlying query, but these get stripped out of the response.