Skip to content
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

IBX-8726: Added support for IsBookmarked criterion #75

Merged
merged 12 commits into from
Sep 4, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
namespace Ibexa\Solr\FieldMapper\ContentFieldMapper;

use Ibexa\Contracts\Core\Persistence\Bookmark\Handler as BookmarkHandler;
use Ibexa\Contracts\Core\Persistence\Content;
use Ibexa\Contracts\Core\Persistence\Content\Location;
use Ibexa\Contracts\Core\Persistence\Content\Location\Handler as LocationHandler;
Expand All @@ -23,8 +24,13 @@ class ContentDocumentLocationFields extends ContentFieldMapper
*/
protected $locationHandler;

public function __construct(LocationHandler $locationHandler)
{
private BookmarkHandler $bookmarkHandler;

public function __construct(
BookmarkHandler $bookmarkHandler,
LocationHandler $locationHandler
) {
$this->bookmarkHandler = $bookmarkHandler;
$this->locationHandler = $locationHandler;
}

Expand Down Expand Up @@ -89,6 +95,12 @@ public function mapFields(Content $content)
$locationData['ancestors'],
new FieldType\MultipleIdentifierField()
);

$fields[] = new Field(
'location_bookmarked_user_ids',
$this->bookmarkHandler->loadUserIdsByLocation($location),
new FieldType\MultipleIdentifierField()
);
}

if ($mainLocation !== null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
namespace Ibexa\Solr\FieldMapper\LocationFieldMapper;

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

protected ContentTypeHandler $contentTypeHandler;

private BookmarkHandler $bookmarkHandler;

public function __construct(
BookmarkHandler $bookmarkHandler,
ContentHandler $contentHandler,
ContentTypeHandler $contentTypeHandler
) {
$this->bookmarkHandler = $bookmarkHandler;
$this->contentHandler = $contentHandler;
$this->contentTypeHandler = $contentTypeHandler;
}
Expand Down Expand Up @@ -121,6 +126,11 @@ public function mapFields(Location $location)
$contentType->isContainer,
new FieldType\BooleanField()
),
new Field(
'location_bookmarked_user_ids',
$this->bookmarkHandler->loadUserIdsByLocation($location),
new FieldType\MultipleIdentifierField()
),
];
}

Expand Down
57 changes: 57 additions & 0 deletions src/lib/Query/Location/CriterionVisitor/Location/IsBookmarked.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?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\Solr\Query\Location\CriterionVisitor\Location;
ciastektk marked this conversation as resolved.
Show resolved Hide resolved

use Ibexa\Contracts\Core\Repository\PermissionResolver;
use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion;
use Ibexa\Contracts\Solr\Query\CriterionVisitor;
use LogicException;

final class IsBookmarked extends CriterionVisitor
{
private const SEARCH_FIELD = 'location_bookmarked_user_ids_mid';

private PermissionResolver $permissionResolver;

public function __construct(PermissionResolver $permissionResolver)
{
$this->permissionResolver = $permissionResolver;
}

public function canVisit(Criterion $criterion): bool
{
return $criterion instanceof Criterion\Location\IsBookmarked
&& $criterion->operator === Criterion\Operator::EQ;
}

public function visit(
Criterion $criterion,
CriterionVisitor $subVisitor = null
): string {
if (!is_array($criterion->value)) {
throw new LogicException(sprintf(
'Expected %s Criterion value to be an array, received %s',
Criterion\Location\IsBookmarked::class,
get_debug_type($criterion->value),
));
}

$userId = $this->permissionResolver
->getCurrentUserReference()
->getUserId();

$query = self::SEARCH_FIELD . ':"' . $userId . '"';

if (!$criterion->value[0]) {
$query = 'NOT ' . $query;
}

return $query;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,12 @@ services:
tags:
- { name: ibexa.search.solr.query.location.criterion.visitor }

Ibexa\Solr\Query\Location\CriterionVisitor\Location\IsBookmarked:
arguments:
$permissionResolver: '@Ibexa\Contracts\Core\Repository\PermissionResolver'
tags:
- { name: ibexa.search.solr.query.location.criterion.visitor }

Ibexa\Solr\Query\Location\CriterionVisitor\Factory\LocationFullTextFactory:
parent: Ibexa\Solr\Query\Common\CriterionVisitor\Factory\FullTextFactoryAbstract

Expand Down
8 changes: 5 additions & 3 deletions src/lib/Resources/config/container/solr/field_mappers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ services:

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

Expand All @@ -57,8 +58,9 @@ services:

Ibexa\Solr\FieldMapper\LocationFieldMapper\LocationDocumentBaseFields:
arguments:
- '@Ibexa\Contracts\Core\Persistence\Content\Handler'
- '@Ibexa\Contracts\Core\Persistence\Content\Type\Handler'
$bookmarkHandler: '@Ibexa\Contracts\Core\Persistence\Bookmark\Handler'
$contentHandler: '@Ibexa\Contracts\Core\Persistence\Content\Handler'
$contentTypeHandler: '@Ibexa\Contracts\Core\Persistence\Content\Type\Handler'
tags:
- {name: ibexa.search.solr.field.mapper.location}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<?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\Tests\Solr\Search\Query\Location\CriterionVisitor\Location;

use Ibexa\Contracts\Core\Repository\PermissionResolver;
use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion;
use Ibexa\Contracts\Solr\Query\CriterionVisitor;
use Ibexa\Core\Repository\Values\User\UserReference;
use Ibexa\Solr\Query\Location\CriterionVisitor\Location\IsBookmarked;
use PHPUnit\Framework\TestCase;

/**
* @covers \Ibexa\Solr\Query\Location\CriterionVisitor\Location\IsBookmarked
*/
final class IsBookmarkedTest extends TestCase
{
private const USER_ID = 123;

private CriterionVisitor $visitor;

/** @var \Ibexa\Contracts\Core\Repository\PermissionResolver&\PHPUnit\Framework\MockObject\MockObject */
private PermissionResolver $permissionResolver;

protected function setUp(): void
{
$this->permissionResolver = $this->createMock(PermissionResolver::class);
$this->visitor = new IsBookmarked($this->permissionResolver);
}

/**
* @dataProvider provideDataForTestCanVisit
*/
public function testCanVisit(
bool $expected,
Criterion $criterion
): void {
self::assertSame(
$expected,
$this->visitor->canVisit($criterion)
);
}

/**
* @return iterable<array{
* bool,
* \Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion
* }>
*/
public function provideDataForTestCanVisit(): iterable
{
yield 'Not supported criterion' => [
false,
new Criterion\ContentId(123),
];

yield 'Supported criterion' => [
true,
new Criterion\Location\IsBookmarked(),
];
}

/**
* @dataProvider provideDataForTestVisit
*/
public function testVisit(
string $expected,
Criterion $criterion
): void {
$this->mockPermissionResolverGetCurrentUserReference();

self::assertSame(
$expected,
$this->visitor->visit($criterion)
);
}

/**
* @return iterable<array{
* string,
* \Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion
* }>
*/
public function provideDataForTestVisit(): iterable
{
yield 'Query for bookmarked locations' => [
'location_bookmarked_user_ids_mid:"123"',
new Criterion\Location\IsBookmarked(),
];

yield 'Query for not bookmarked locations' => [
'NOT location_bookmarked_user_ids_mid:"123"',
new Criterion\Location\IsBookmarked(false),
];
}

private function mockPermissionResolverGetCurrentUserReference(): void
{
$this->permissionResolver
->method('getCurrentUserReference')
->willReturn(new UserReference(self::USER_ID));
}
}
Loading