-
Notifications
You must be signed in to change notification settings - Fork 19
IBX-6773: Fixed loading Bookmarks for non-accessible content items #476
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 4.6
Are you sure you want to change the base?
Changes from all commits
54a8758
5324ef2
e8062af
070e342
245cba0
9635474
6cc6903
0d293e5
8e63f7e
310d457
3594b4f
5fb1a53
6c862de
ca42c8d
2e5d7c7
c700f40
7368c0d
abf0fff
fb61a41
690322f
4d3f4b7
80cb93e
89d995e
6a32843
2f69957
83deac2
ba5cf53
4d5dc1e
0c025cd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| <?php | ||
|
|
||
| /** | ||
| * @copyright Copyright (C) Ibexa AS. All rights reserved. | ||
| * @license For full copyright and license information view LICENSE file distributed with this source code. | ||
| */ | ||
| declare(strict_types=1); | ||
|
|
||
| namespace Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; | ||
|
|
||
| use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; | ||
| use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\Operator\Specifications; | ||
| use Ibexa\Contracts\Core\Repository\Values\Filter\FilteringCriterion; | ||
|
|
||
| /** | ||
| * A criterion that matches locations of bookmarks for a given user id. | ||
| * | ||
| * Supported operators: | ||
| * - EQ: matches against a unique user id | ||
| */ | ||
| final class IsBookmarked extends Criterion implements FilteringCriterion | ||
| { | ||
| public ?int $userId = null; | ||
|
|
||
| public function __construct( | ||
| bool $isBookmarked = true, | ||
| ?int $userId = null | ||
| ) { | ||
| $this->userId = $userId; | ||
| parent::__construct(null, null, $isBookmarked); | ||
| } | ||
|
|
||
| public function getSpecifications(): array | ||
| { | ||
| return [ | ||
| new Specifications(Operator::EQ, Specifications::FORMAT_SINGLE, Specifications::TYPE_BOOLEAN), | ||
| ]; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| <?php | ||
|
|
||
| /** | ||
| * @copyright Copyright (C) Ibexa AS. All rights reserved. | ||
| * @license For full copyright and license information view LICENSE file distributed with this source code. | ||
| */ | ||
| declare(strict_types=1); | ||
|
|
||
| namespace Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause; | ||
|
|
||
| use Ibexa\Contracts\Core\Repository\Values\Content\Query; | ||
| use Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause; | ||
| use Ibexa\Contracts\Core\Repository\Values\Filter\FilteringSortClause; | ||
|
|
||
| /** | ||
| * Sets sort direction on the bookmark id for a location query containing IsBookmarked criterion. | ||
| */ | ||
| final class BookmarkId extends SortClause implements FilteringSortClause | ||
| { | ||
| public function __construct(string $sortDirection = Query::SORT_ASC) | ||
| { | ||
| parent::__construct('id', $sortDirection); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,76 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| <?php | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * @copyright Copyright (C) Ibexa AS. All rights reserved. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * @license For full copyright and license information view LICENSE file distributed with this source code. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| declare(strict_types=1); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| namespace Ibexa\Core\Persistence\Legacy\Filter\CriterionQueryBuilder\Location; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| use Doctrine\DBAL\ParameterType; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| use Ibexa\Contracts\Core\Persistence\Filter\Doctrine\FilteringQueryBuilder; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\IsBookmarked; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| use Ibexa\Contracts\Core\Repository\Values\Filter\FilteringCriterion; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| use Ibexa\Core\Persistence\Legacy\Bookmark\Gateway\DoctrineDatabase; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| use Ibexa\Core\Repository\Permission\PermissionResolver; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * @internal for internal use by Repository Filtering | ||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| final class BookmarkQueryBuilder extends BaseLocationCriterionQueryBuilder | ||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| private PermissionResolver $permissionResolver; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| public function __construct( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| PermissionResolver $permissionResolver | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| $this->permissionResolver = $permissionResolver; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| public function accepts(FilteringCriterion $criterion): bool | ||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return $criterion instanceof IsBookmarked; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| public function buildQueryConstraint( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| FilteringQueryBuilder $queryBuilder, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| FilteringCriterion $criterion | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ): string { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /** @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.'); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| $userId = $criterion->userId ?? $this->permissionResolver->getCurrentUserReference()->getUserId(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @alongosz I don't see a safe way to detect in the queryBuilder if we are either in Content or Location context.. The other option is somehow to state that this filter can only use with Location ?
Suggested change
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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 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. |
||||||||||||||||||||||||||||||||||||||||||||||||||
| if ($isBookmarked) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| $queryBuilder | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ->joinOnce( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'location', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| DoctrineDatabase::TABLE_BOOKMARKS, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'bookmark', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'location.node_id = bookmark.node_id' | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| return $queryBuilder->expr()->eq( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'bookmark.user_id', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| $queryBuilder->createNamedParameter( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| $userId, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ParameterType::INTEGER | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| $queryBuilder | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ->leftJoinOnce( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'location', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| DoctrineDatabase::TABLE_BOOKMARKS, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'bookmark', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'location.node_id = bookmark.node_id AND bookmark.user_id = :userId' | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ->setParameter('userId', $userId); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| return $queryBuilder->expr()->isNull('bookmark.id'); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| <?php | ||
|
|
||
| /** | ||
| * @copyright Copyright (C) Ibexa AS. All rights reserved. | ||
| * @license For full copyright and license information view LICENSE file distributed with this source code. | ||
| */ | ||
| declare(strict_types=1); | ||
|
|
||
| namespace Ibexa\Core\Persistence\Legacy\Filter\SortClauseQueryBuilder\Bookmark; | ||
|
|
||
| use Ibexa\Contracts\Core\Persistence\Filter\Doctrine\FilteringQueryBuilder; | ||
| use Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause\BookmarkId; | ||
| use Ibexa\Contracts\Core\Repository\Values\Filter\FilteringSortClause; | ||
| use Ibexa\Contracts\Core\Repository\Values\Filter\SortClauseQueryBuilder; | ||
|
|
||
| final class IdSortClauseQueryBuilder implements SortClauseQueryBuilder | ||
| { | ||
| public function accepts(FilteringSortClause $sortClause): bool | ||
| { | ||
| return $sortClause instanceof BookmarkId; | ||
| } | ||
|
|
||
| public function buildQuery( | ||
| FilteringQueryBuilder $queryBuilder, | ||
| FilteringSortClause $sortClause | ||
| ): void { | ||
| if (!$sortClause instanceof BookmarkId) { | ||
| throw new \InvalidArgumentException(sprintf( | ||
| 'Expected %s, got %s', | ||
| BookmarkId::class, | ||
| get_class($sortClause), | ||
| )); | ||
| } | ||
| /** @var \Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause\BookmarkId $sortClause */ | ||
| $queryBuilder->addSelect('bookmark.id'); | ||
| $queryBuilder->addOrderBy('bookmark.id', $sortClause->direction); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should throw
\Ibexa\Core\Base\Exceptions\InvalidArgumentExceptioninstead and reporton the method