Skip to content

Commit 6dbe045

Browse files
ciastektkkonradobozaSteveb-p
authored
IBX-8726: Added support for IsBookmarked criterion (#75)
For more details see https://issues.ibexa.co/browse/IBX-8726 and #75 Key changes: * Added IsBookmarked criterion visitor * Added location_bookmarked_user_ids search field * [Tests] Added IsBookmarkedTest --------- Co-Authored-By: Konrad Oboza <[email protected]> Co-Authored-By: Paweł Niedzielski <[email protected]>
1 parent c2333a0 commit 6dbe045

File tree

6 files changed

+200
-5
lines changed

6 files changed

+200
-5
lines changed

src/lib/FieldMapper/ContentFieldMapper/ContentDocumentLocationFields.php

+14-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77
namespace Ibexa\Solr\FieldMapper\ContentFieldMapper;
88

9+
use Ibexa\Contracts\Core\Persistence\Bookmark\Handler as BookmarkHandler;
910
use Ibexa\Contracts\Core\Persistence\Content;
1011
use Ibexa\Contracts\Core\Persistence\Content\Location;
1112
use Ibexa\Contracts\Core\Persistence\Content\Location\Handler as LocationHandler;
@@ -23,8 +24,13 @@ class ContentDocumentLocationFields extends ContentFieldMapper
2324
*/
2425
protected $locationHandler;
2526

26-
public function __construct(LocationHandler $locationHandler)
27-
{
27+
private BookmarkHandler $bookmarkHandler;
28+
29+
public function __construct(
30+
BookmarkHandler $bookmarkHandler,
31+
LocationHandler $locationHandler
32+
) {
33+
$this->bookmarkHandler = $bookmarkHandler;
2834
$this->locationHandler = $locationHandler;
2935
}
3036

@@ -89,6 +95,12 @@ public function mapFields(Content $content)
8995
$locationData['ancestors'],
9096
new FieldType\MultipleIdentifierField()
9197
);
98+
99+
$fields[] = new Field(
100+
'location_bookmarked_user_ids',
101+
$this->bookmarkHandler->loadUserIdsByLocation($location),
102+
new FieldType\MultipleIdentifierField()
103+
);
92104
}
93105

94106
if ($mainLocation !== null) {

src/lib/FieldMapper/LocationFieldMapper/LocationDocumentBaseFields.php

+10
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77
namespace Ibexa\Solr\FieldMapper\LocationFieldMapper;
88

9+
use Ibexa\Contracts\Core\Persistence\Bookmark\Handler as BookmarkHandler;
910
use Ibexa\Contracts\Core\Persistence\Content\Handler as ContentHandler;
1011
use Ibexa\Contracts\Core\Persistence\Content\Location;
1112
use Ibexa\Contracts\Core\Persistence\Content\Type\Handler as ContentTypeHandler;
@@ -26,10 +27,14 @@ class LocationDocumentBaseFields extends LocationFieldMapper
2627

2728
protected ContentTypeHandler $contentTypeHandler;
2829

30+
private BookmarkHandler $bookmarkHandler;
31+
2932
public function __construct(
33+
BookmarkHandler $bookmarkHandler,
3034
ContentHandler $contentHandler,
3135
ContentTypeHandler $contentTypeHandler
3236
) {
37+
$this->bookmarkHandler = $bookmarkHandler;
3338
$this->contentHandler = $contentHandler;
3439
$this->contentTypeHandler = $contentTypeHandler;
3540
}
@@ -121,6 +126,11 @@ public function mapFields(Location $location)
121126
$contentType->isContainer,
122127
new FieldType\BooleanField()
123128
),
129+
new Field(
130+
'location_bookmarked_user_ids',
131+
$this->bookmarkHandler->loadUserIdsByLocation($location),
132+
new FieldType\MultipleIdentifierField()
133+
),
124134
];
125135
}
126136

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) Ibexa AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace Ibexa\Solr\Query\Location\CriterionVisitor\Location;
10+
11+
use Ibexa\Contracts\Core\Repository\PermissionResolver;
12+
use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion;
13+
use Ibexa\Contracts\Solr\Query\CriterionVisitor;
14+
use LogicException;
15+
16+
final class IsBookmarked extends CriterionVisitor
17+
{
18+
private const SEARCH_FIELD = 'location_bookmarked_user_ids_mid';
19+
20+
private PermissionResolver $permissionResolver;
21+
22+
public function __construct(PermissionResolver $permissionResolver)
23+
{
24+
$this->permissionResolver = $permissionResolver;
25+
}
26+
27+
public function canVisit(Criterion $criterion): bool
28+
{
29+
return $criterion instanceof Criterion\Location\IsBookmarked
30+
&& $criterion->operator === Criterion\Operator::EQ;
31+
}
32+
33+
public function visit(
34+
Criterion $criterion,
35+
CriterionVisitor $subVisitor = null
36+
): string {
37+
if (!is_array($criterion->value)) {
38+
throw new LogicException(sprintf(
39+
'Expected %s Criterion value to be an array, received %s',
40+
Criterion\Location\IsBookmarked::class,
41+
get_debug_type($criterion->value),
42+
));
43+
}
44+
45+
$userId = $this->permissionResolver
46+
->getCurrentUserReference()
47+
->getUserId();
48+
49+
$query = self::SEARCH_FIELD . ':"' . $userId . '"';
50+
51+
if (!$criterion->value[0]) {
52+
$query = 'NOT ' . $query;
53+
}
54+
55+
return $query;
56+
}
57+
}

src/lib/Resources/config/container/solr/criterion_visitors.yml

+6
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,12 @@ services:
299299
tags:
300300
- { name: ibexa.search.solr.query.location.criterion.visitor }
301301

302+
Ibexa\Solr\Query\Location\CriterionVisitor\Location\IsBookmarked:
303+
arguments:
304+
$permissionResolver: '@Ibexa\Contracts\Core\Repository\PermissionResolver'
305+
tags:
306+
- { name: ibexa.search.solr.query.location.criterion.visitor }
307+
302308
Ibexa\Solr\Query\Location\CriterionVisitor\Factory\LocationFullTextFactory:
303309
parent: Ibexa\Solr\Query\Common\CriterionVisitor\Factory\FullTextFactoryAbstract
304310

src/lib/Resources/config/container/solr/field_mappers.yml

+5-3
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ services:
4040

4141
Ibexa\Solr\FieldMapper\ContentFieldMapper\ContentDocumentLocationFields:
4242
arguments:
43-
- '@Ibexa\Contracts\Core\Persistence\Content\Location\Handler'
43+
$bookmarkHandler: '@Ibexa\Contracts\Core\Persistence\Bookmark\Handler'
44+
$locationHandler: '@Ibexa\Contracts\Core\Persistence\Content\Location\Handler'
4445
tags:
4546
- {name: ibexa.search.solr.field.mapper.content}
4647

@@ -57,8 +58,9 @@ services:
5758

5859
Ibexa\Solr\FieldMapper\LocationFieldMapper\LocationDocumentBaseFields:
5960
arguments:
60-
- '@Ibexa\Contracts\Core\Persistence\Content\Handler'
61-
- '@Ibexa\Contracts\Core\Persistence\Content\Type\Handler'
61+
$bookmarkHandler: '@Ibexa\Contracts\Core\Persistence\Bookmark\Handler'
62+
$contentHandler: '@Ibexa\Contracts\Core\Persistence\Content\Handler'
63+
$contentTypeHandler: '@Ibexa\Contracts\Core\Persistence\Content\Type\Handler'
6264
tags:
6365
- {name: ibexa.search.solr.field.mapper.location}
6466

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) Ibexa AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace Ibexa\Tests\Solr\Search\Query\Location\CriterionVisitor\Location;
10+
11+
use Ibexa\Contracts\Core\Repository\PermissionResolver;
12+
use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion;
13+
use Ibexa\Contracts\Solr\Query\CriterionVisitor;
14+
use Ibexa\Core\Repository\Values\User\UserReference;
15+
use Ibexa\Solr\Query\Location\CriterionVisitor\Location\IsBookmarked;
16+
use PHPUnit\Framework\TestCase;
17+
18+
/**
19+
* @covers \Ibexa\Solr\Query\Location\CriterionVisitor\Location\IsBookmarked
20+
*/
21+
final class IsBookmarkedTest extends TestCase
22+
{
23+
private const USER_ID = 123;
24+
25+
private CriterionVisitor $visitor;
26+
27+
/** @var \Ibexa\Contracts\Core\Repository\PermissionResolver&\PHPUnit\Framework\MockObject\MockObject */
28+
private PermissionResolver $permissionResolver;
29+
30+
protected function setUp(): void
31+
{
32+
$this->permissionResolver = $this->createMock(PermissionResolver::class);
33+
$this->visitor = new IsBookmarked($this->permissionResolver);
34+
}
35+
36+
/**
37+
* @dataProvider provideDataForTestCanVisit
38+
*/
39+
public function testCanVisit(
40+
bool $expected,
41+
Criterion $criterion
42+
): void {
43+
self::assertSame(
44+
$expected,
45+
$this->visitor->canVisit($criterion)
46+
);
47+
}
48+
49+
/**
50+
* @return iterable<array{
51+
* bool,
52+
* \Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion
53+
* }>
54+
*/
55+
public function provideDataForTestCanVisit(): iterable
56+
{
57+
yield 'Not supported criterion' => [
58+
false,
59+
new Criterion\ContentId(123),
60+
];
61+
62+
yield 'Supported criterion' => [
63+
true,
64+
new Criterion\Location\IsBookmarked(),
65+
];
66+
}
67+
68+
/**
69+
* @dataProvider provideDataForTestVisit
70+
*/
71+
public function testVisit(
72+
string $expected,
73+
Criterion $criterion
74+
): void {
75+
$this->mockPermissionResolverGetCurrentUserReference();
76+
77+
self::assertSame(
78+
$expected,
79+
$this->visitor->visit($criterion)
80+
);
81+
}
82+
83+
/**
84+
* @return iterable<array{
85+
* string,
86+
* \Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion
87+
* }>
88+
*/
89+
public function provideDataForTestVisit(): iterable
90+
{
91+
yield 'Query for bookmarked locations' => [
92+
'location_bookmarked_user_ids_mid:"123"',
93+
new Criterion\Location\IsBookmarked(),
94+
];
95+
96+
yield 'Query for not bookmarked locations' => [
97+
'NOT location_bookmarked_user_ids_mid:"123"',
98+
new Criterion\Location\IsBookmarked(false),
99+
];
100+
}
101+
102+
private function mockPermissionResolverGetCurrentUserReference(): void
103+
{
104+
$this->permissionResolver
105+
->method('getCurrentUserReference')
106+
->willReturn(new UserReference(self::USER_ID));
107+
}
108+
}

0 commit comments

Comments
 (0)