From 28fd67f0a9a6a0ad427b2802c0ce5c78ef6745c6 Mon Sep 17 00:00:00 2001 From: Tomasz Kryszan Date: Fri, 16 Aug 2024 12:27:31 +0200 Subject: [PATCH] Reworked IsBookmarked criterion --- .../Query/Criterion/Location/IsBookmarked.php | 14 ++++-- .../legacy/criterion_handlers_location.yml | 3 ++ .../Location/IsBookmarked.php | 50 +++++++++++++++++-- .../Repository/SearchServiceBookmarkTest.php | 24 +++++++-- 4 files changed, 79 insertions(+), 12 deletions(-) diff --git a/src/contracts/Repository/Values/Content/Query/Criterion/Location/IsBookmarked.php b/src/contracts/Repository/Values/Content/Query/Criterion/Location/IsBookmarked.php index 08a9730ff0..0e42accd74 100644 --- a/src/contracts/Repository/Values/Content/Query/Criterion/Location/IsBookmarked.php +++ b/src/contracts/Repository/Values/Content/Query/Criterion/Location/IsBookmarked.php @@ -9,13 +9,21 @@ use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\Location; use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\Operator; use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\Operator\Specifications; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\Value\IsBookmarkedValue; use Ibexa\Contracts\Core\Repository\Values\Filter\FilteringCriterion; final class IsBookmarked extends Location implements FilteringCriterion { - public function __construct(int $userId) + public function __construct(bool $value, ?int $userId = null) { - parent::__construct(null, Operator::EQ, $userId); + $valueData = new IsBookmarkedValue($userId); + + parent::__construct( + null, + Operator::EQ, + $value, + $valueData + ); } public function getSpecifications(): array @@ -24,7 +32,7 @@ public function getSpecifications(): array new Specifications( Operator::EQ, Specifications::FORMAT_SINGLE, - Specifications::TYPE_INTEGER + Specifications::TYPE_BOOLEAN ), ]; } diff --git a/src/lib/Resources/settings/search_engines/legacy/criterion_handlers_location.yml b/src/lib/Resources/settings/search_engines/legacy/criterion_handlers_location.yml index 80bfda40ea..22443d221c 100644 --- a/src/lib/Resources/settings/search_engines/legacy/criterion_handlers_location.yml +++ b/src/lib/Resources/settings/search_engines/legacy/criterion_handlers_location.yml @@ -61,5 +61,8 @@ services: Ibexa\Core\Search\Legacy\Content\Location\Gateway\CriterionHandler\Location\IsBookmarked: parent: Ibexa\Core\Search\Legacy\Content\Common\Gateway\CriterionHandler + arguments: + $connection: '@ibexa.persistence.connection' + $permissionResolver: '@Ibexa\Contracts\Core\Repository\PermissionResolver' tags: - { name: ibexa.search.legacy.gateway.criterion_handler.location } diff --git a/src/lib/Search/Legacy/Content/Location/Gateway/CriterionHandler/Location/IsBookmarked.php b/src/lib/Search/Legacy/Content/Location/Gateway/CriterionHandler/Location/IsBookmarked.php index cf449835fd..fbfef9b84e 100644 --- a/src/lib/Search/Legacy/Content/Location/Gateway/CriterionHandler/Location/IsBookmarked.php +++ b/src/lib/Search/Legacy/Content/Location/Gateway/CriterionHandler/Location/IsBookmarked.php @@ -6,8 +6,11 @@ */ namespace Ibexa\Core\Search\Legacy\Content\Location\Gateway\CriterionHandler\Location; +use Doctrine\DBAL\Connection; use Doctrine\DBAL\Query\QueryBuilder; use Doctrine\DBAL\Types\Types; +use Ibexa\Contracts\Core\Exception\InvalidArgumentException; +use Ibexa\Contracts\Core\Repository\PermissionResolver; use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; use Ibexa\Core\Persistence\Legacy\Bookmark\Gateway\DoctrineDatabase; use Ibexa\Core\Search\Legacy\Content\Common\Gateway\CriteriaConverter; @@ -15,6 +18,17 @@ final class IsBookmarked extends CriterionHandler { + private PermissionResolver $permissionResolver; + + public function __construct( + Connection $connection, + PermissionResolver $permissionResolver + ) { + parent::__construct($connection); + + $this->permissionResolver = $permissionResolver; + } + public function accept(Criterion $criterion): bool { return $criterion instanceof Criterion\Location\IsBookmarked @@ -23,6 +37,8 @@ public function accept(Criterion $criterion): bool /** * @param array{languages: string[]} $languageSettings + * + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException */ public function handle( CriteriaConverter $converter, @@ -30,6 +46,8 @@ public function handle( Criterion $criterion, array $languageSettings ) { + $userId = $this->getUserId($criterion); + $subQueryBuilder = $this->connection->createQueryBuilder(); $subQueryBuilder ->select(DoctrineDatabase::COLUMN_LOCATION_ID) @@ -40,15 +58,37 @@ public function handle( ->eq( DoctrineDatabase::COLUMN_USER_ID, $queryBuilder->createNamedParameter( - $criterion->value[0], + $userId, Types::INTEGER ) ) ); - return $queryBuilder->expr()->in( - 't.node_id', - $subQueryBuilder->getSQL() - ); + $expressionBuilder = $queryBuilder->expr(); + if ($criterion->value[0]) { + return $expressionBuilder->in('t.node_id', $subQueryBuilder->getSQL()); + } + + return $expressionBuilder->notIn('t.node_id', $subQueryBuilder->getSQL()); + } + + /** + * @throws \Ibexa\Contracts\Core\Exception\InvalidArgumentException + */ + private function getUserId(Criterion $criterion): int + { + $valueData = $criterion->valueData; + if (!$valueData instanceof Criterion\Value\IsBookmarkedValue) { + throw new InvalidArgumentException( + '$criterion->valueData', + sprintf( + 'Is expected to be of type: "%s", got "%s"', + Criterion\Value\IsBookmarkedValue::class, + get_debug_type($valueData) + ) + ); + } + + return $valueData->getUserId() ?? $this->permissionResolver->getCurrentUserReference()->getUserId(); } } diff --git a/tests/integration/Core/Repository/SearchServiceBookmarkTest.php b/tests/integration/Core/Repository/SearchServiceBookmarkTest.php index 87bcefaeed..c19b05f2fb 100644 --- a/tests/integration/Core/Repository/SearchServiceBookmarkTest.php +++ b/tests/integration/Core/Repository/SearchServiceBookmarkTest.php @@ -56,7 +56,7 @@ public function provideDataForTestCriterion(): iterable yield 'All bookmarked locations' => [ 6, [ - new Query\Criterion\Location\IsBookmarked(self::ADMIN_USER_ID), + new Query\Criterion\Location\IsBookmarked(true, self::ADMIN_USER_ID), ], ]; @@ -64,7 +64,7 @@ public function provideDataForTestCriterion(): iterable 1, [ new Query\Criterion\ContentTypeIdentifier(self::FOLDER_CONTENT_TYPE_IDENTIFIER), - new Query\Criterion\Location\IsBookmarked(self::ADMIN_USER_ID), + new Query\Criterion\Location\IsBookmarked(true, self::ADMIN_USER_ID), ], ]; @@ -72,7 +72,7 @@ public function provideDataForTestCriterion(): iterable 4, [ new Query\Criterion\ContentTypeIdentifier('user_group'), - new Query\Criterion\Location\IsBookmarked(self::ADMIN_USER_ID), + new Query\Criterion\Location\IsBookmarked(true, self::ADMIN_USER_ID), ], ]; @@ -80,7 +80,23 @@ public function provideDataForTestCriterion(): iterable 1, [ new Query\Criterion\ContentTypeIdentifier('user'), - new Query\Criterion\Location\IsBookmarked(self::ADMIN_USER_ID), + new Query\Criterion\Location\IsBookmarked(true), + ], + ]; + + yield 'No bookmarked locations for user with id 10' => [ + 0, + [ + new Query\Criterion\ContentTypeIdentifier('user'), + new Query\Criterion\Location\IsBookmarked(true, 10), + ], + ]; + + yield 'All no bookmarked locations for content type user_group' => [ + 2, + [ + new Query\Criterion\ContentTypeIdentifier('user_group'), + new Query\Criterion\Location\IsBookmarked(false), ], ]; }