IBX-6773: Fixed loading Bookmarks for non-accessible content items#476
IBX-6773: Fixed loading Bookmarks for non-accessible content items#476vidarl wants to merge 29 commits into
Conversation
bdac332 to
9164daa
Compare
|
9164daa to
ec96060
Compare
konradoboza
left a comment
There was a problem hiding this comment.
Did you make sure none of the deprecated classes are still in use?
|
@konradoboza : FYI : Had to add related PR : ibexa/admin-ui#1835 |
| $this->assertEquals($contactUsLocationId, $afterSwap->items[0]->id); | ||
| $this->assertEquals($beforeSwap->items[1]->id, $afterSwap->items[1]->id); |
There was a problem hiding this comment.
Why this change? It's not clear at first glance.
There was a problem hiding this comment.
@konradoboza
The testcase initially tests swapping two locations that are both bookmarked.
I modified the test to check behavior when 1 location is bookmarked and the other is not
…tion/BookmarkQueryBuilderTest.php Co-authored-by: Konrad Oboza <konrad.oboza@ibexa.co>
Co-authored-by: Konrad Oboza <konrad.oboza@ibexa.co>
…cationService::count()
…cationService::count()
… and LocationService::count()
Co-authored-by: Konrad Oboza <konrad.oboza@ibexa.co>
5343730 to
6c862de
Compare
Adjusted tests accoringly to latest commits
This reverts commit 2e5d7c7.
| /** @var \Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\IsBookmarked $criterion */ | ||
| $isBookmarked = $criterion->value; | ||
| $userId = $criterion->userId ?? $this->permissionResolver->getCurrentUserReference()->getUserId(); | ||
|
|
There was a problem hiding this comment.
@alongosz
There is one problem with this queryBuilder.. In Bookmark table, we store node_id, so we need to join with ezcontentobject_tree. That is no problem if LocationService::find() is used.
However, ATM it won't work with Content filtering (ContentService::find() as that table is already join in that case
I don't see a safe way to detect in the queryBuilder if we are either in Content or Location context..
I have a proposal below using $queryBuilder->getExistingTableAliasJoinCondition but not sure if it is really safe. It checks if alias "location" is joined at that time or not. But not sure if order is deterministic and if this good enough, but not sure if there is any other alternative ?
The other option is somehow to state that this filter can only use with Location ?
| $isContentQuery = $queryBuilder->getExistingTableAliasJoinCondition('location') === null; | |
| if ($isContentQuery) { | |
| $connection = $queryBuilder->getConnection(); | |
| $subQb = $connection->createQueryBuilder(); | |
| $paramName = $queryBuilder->createNamedParameter( | |
| $userId, | |
| ParameterType::INTEGER | |
| ); | |
| $subQuerySql = $subQb | |
| ->select('1') | |
| ->from(Gateway::CONTENT_TREE_TABLE, 'l') | |
| ->innerJoin('l', DoctrineDatabase::TABLE_BOOKMARKS, 'b', 'l.node_id = b.node_id') | |
| ->where('l.contentobject_id = content.id') | |
| ->andWhere("b.user_id = $paramName") | |
| ->getSQL(); | |
| return $isBookmarked | |
| ? "EXISTS ($subQuerySql)" | |
| : "NOT EXISTS ($subQuerySql)"; | |
| } |
There was a problem hiding this comment.
Well... You could join main location for content filtering, but there's a group of filtering criteria that was not meant for content search. AFAICS you don't need it for your use case, so you should just move it to Criterion\Location\IsBookmarked and change extends to \Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\Location. This - maybe not in a straightforward way - designates a criterion to work with Location filtering only.
Warning
Which brings me back to my main question from this current review...
BTW.
EXISTS (...)
NOT EXISTS (...)was exactly what I'd expect in such query builder anyway - it's way faster than joining.
| * @copyright Copyright (C) Ibexa AS. All rights reserved. | ||
| * @license For full copyright and license information view LICENSE file distributed with this source code. | ||
| */ | ||
| namespace Ibexa\Tests\Integration\Core\Repository\Filtering; |
There was a problem hiding this comment.
@alongosz : I created a integration test for IsBookmarked. Didn't actually find any other similar integration tests for other criterieons, so added it here. Not sure if there is a better place to put it ?
There was a problem hiding this comment.
I created a integration test for IsBookmarked. Didn't actually find any other similar integration tests for other criterieons, so added it here. Not sure if there is a better place to put it ?
There's \Ibexa\Tests\Integration\Core\Repository\Filtering\LocationFilteringTest. It rather should be added there through data providers.
|
alongosz
left a comment
There was a problem hiding this comment.
Hey @vidarl. Again apologies for another long wait...
I've now allocated more time to look into this carefully. One question that I have when looking at the whole codebase is - have you tried to use existing \Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\Location\IsBookmarked introduced via #417?
Honestly, this is where I'd move that criterion, given it's for Locations only, but... it already exists.
The issue that needs to be fixed is that it was declared as a filtering criterion, it's documented as a filtering criterion, but it doesn't have the query building logic for filtering, only for search. I think I've missed this when reviewing #417... The good news is that your PR already provides that.
I should've given this feedback back in February, I just completely forgot that we've been there before, I'm sorry :(
The query builder and integration tests remarks:
| /** @var \Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\IsBookmarked $criterion */ | ||
| $isBookmarked = $criterion->value[0] ?? null; | ||
| if (!is_bool($isBookmarked)) { | ||
| throw new \InvalidArgumentException('IsBookmarked criterion value must be boolean at index 0.'); |
There was a problem hiding this comment.
You should throw \Ibexa\Core\Base\Exceptions\InvalidArgumentException instead and report
/**
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
*/on the method
| * @copyright Copyright (C) Ibexa AS. All rights reserved. | ||
| * @license For full copyright and license information view LICENSE file distributed with this source code. | ||
| */ | ||
| namespace Ibexa\Tests\Integration\Core\Repository\Filtering; |
There was a problem hiding this comment.
I created a integration test for IsBookmarked. Didn't actually find any other similar integration tests for other criterieons, so added it here. Not sure if there is a better place to put it ?
There's \Ibexa\Tests\Integration\Core\Repository\Filtering\LocationFilteringTest. It rather should be added there through data providers.
| /** @var \Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\IsBookmarked $criterion */ | ||
| $isBookmarked = $criterion->value; | ||
| $userId = $criterion->userId ?? $this->permissionResolver->getCurrentUserReference()->getUserId(); | ||
|
|
There was a problem hiding this comment.
Well... You could join main location for content filtering, but there's a group of filtering criteria that was not meant for content search. AFAICS you don't need it for your use case, so you should just move it to Criterion\Location\IsBookmarked and change extends to \Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\Location. This - maybe not in a straightforward way - designates a criterion to work with Location filtering only.
Warning
Which brings me back to my main question from this current review...
BTW.
EXISTS (...)
NOT EXISTS (...)was exactly what I'd expect in such query builder anyway - it's way faster than joining.



v4.6Related PRs:
loadBookmarkscall with Repository filtering requirements admin-ui#1835Description:
If user bookmark some location which he later looses access too, then the bookmark list in admin-ui fails with an exception.
Simply fixing
BookmarkService::loadBookmarks()would be easy. The problem is to implementcountUserBookmarks()in persistence layer and having it taking into account user permissions so that BC would be kept.Talked with Adam on how to solve this without breaking BC and he suggested implementing it using filtering
The Bookmark filter will only work with location filtering (
LocationService::find()), not with content (ContentService::find())This is a port of ezsystems/ezplatform-kernel#408 which was not approved and merge in time before 3.3 went EOL.
For QA:
Read ticket for info on how to reproduce
Documentation:
Documentation for the new filter needs to be made, indeed