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-6413: Search Suggestion (Autocomplete for search) #33

Merged
merged 66 commits into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
fb6b642
Added autocomplete configuration
kisztof Sep 18, 2023
4e67ad5
Added tests
kisztof Sep 19, 2023
2c7a5e3
Search Autocomplete Endpoint
kisztof Oct 9, 2023
885f626
Breadcrumps subscriber
kisztof Oct 11, 2023
7966db2
Removed root location
kisztof Oct 11, 2023
527468d
Proper Json Response
kisztof Oct 11, 2023
e8a862d
Code style fixes, PHPStan fixed
kisztof Oct 11, 2023
d1e4c95
Fixed response return type
kisztof Oct 12, 2023
64b2ec2
Refactored extension point
kisztof Oct 17, 2023
94cf57b
Added improvements
kisztof Oct 18, 2023
a5b5db3
Fixed suggestion configuration
kisztof Oct 19, 2023
d8fb688
Added tests
kisztof Oct 19, 2023
bb0781c
Added Truncate functionality
kisztof Oct 23, 2023
bfa1021
Fixed tests and models
kisztof Oct 23, 2023
3d8fe63
Generated baseline
kisztof Oct 23, 2023
12d9547
Fixed code suggestions
kisztof Oct 24, 2023
b1689ab
Added ParamConverter test
kisztof Oct 24, 2023
6efdc5b
Cleanup
kisztof Oct 24, 2023
c61c781
More improvements
kisztof Oct 24, 2023
fe7f398
Code review fixes
kisztof Oct 25, 2023
9685877
Added Custom Suggestion Normalizers
kisztof Oct 26, 2023
89a9a39
Fixed code smells
kisztof Oct 26, 2023
429ce34
Fixed yaml
kisztof Oct 26, 2023
aac1b4f
Expose route to JS
kisztof Oct 26, 2023
ff1728d
Fixed sonar cloud allert
kisztof Oct 26, 2023
c604cdb
Fixes
kisztof Oct 26, 2023
609a2c3
Fixed CS
kisztof Oct 26, 2023
3fc20a1
Code review suggestions applied
kisztof Oct 27, 2023
d086898
Argument Resolver added
kisztof Oct 27, 2023
ecd2748
Updated PHPUnit to v9
kisztof Oct 27, 2023
23d42e4
Removed deprecated "withConsecutive" method
kisztof Oct 27, 2023
da8c648
Update src/bundle/Resources/config/services/normalizers.yaml
kisztof Oct 27, 2023
fa58cef
Changed serializer
kisztof Oct 27, 2023
debf12e
Update tests/contracts/EventDispatcher/Event/SuggestionEventTest.php
kisztof Oct 27, 2023
58857dd
Additional fixes
kisztof Oct 27, 2023
258575c
Fixed removing root location
kisztof Oct 27, 2023
03288c1
Update composer.json
kisztof Oct 31, 2023
89b782d
Applied CR suggestions
kisztof Oct 31, 2023
fca194d
Code review suggestions applied
kisztof Oct 31, 2023
21aa941
Code review suggestions applied
kisztof Oct 31, 2023
5d130e6
Code review suggestions applied
kisztof Nov 2, 2023
4970986
Code review suggestions applied
kisztof Nov 2, 2023
df7e476
Code review suggestions applied
kisztof Nov 3, 2023
ac106c0
Code review suggestions applied
kisztof Nov 3, 2023
68a5e84
Code review suggestions applied
kisztof Nov 3, 2023
a5f395c
Added container.service_subscriber for serializer
kisztof Nov 7, 2023
c360c2a
Fixed phpstan.neon
kisztof Nov 7, 2023
739ff56
Fixed ContentType serialization
kisztof Nov 7, 2023
319359f
Update src/contracts/Model/Suggestion/SuggestionCollection.php
kisztof Nov 7, 2023
248cede
Update src/contracts/Model/Suggestion/ParentLocationCollection.php
kisztof Nov 7, 2023
746eeaa
Update src/contracts/Model/Suggestion/SuggestionCollection.php
kisztof Nov 7, 2023
308cc46
Update src/contracts/Model/Suggestion/SuggestionCollection.php
kisztof Nov 7, 2023
1cb0968
Update src/contracts/Model/Suggestion/ParentLocationCollection.php
kisztof Nov 7, 2023
28d94e7
Made changes in ContentSuggestion - Complete object provided
kisztof Nov 7, 2023
2336f02
BeforeSuggestioEvent and SuggestionEvent moved to Service namespace
kisztof Nov 7, 2023
280f8ce
Tests improvements
kisztof Nov 8, 2023
05513c9
Moved config resolving
kisztof Nov 8, 2023
132f0d9
Fixed sonar cloud
kisztof Nov 8, 2023
aa28f89
Fixed tests
kisztof Nov 8, 2023
db57d92
Fixed indent
kisztof Nov 8, 2023
9d9d9c5
Fixed test
kisztof Nov 8, 2023
9f110c9
Fixed issue with normalizer
kisztof Nov 14, 2023
40f2473
Fixed issue with normalizer
kisztof Nov 15, 2023
0ecc817
Fixed issue with normalizer
kisztof Nov 16, 2023
61bd3ce
Code review improvements
kisztof Nov 16, 2023
bd48916
Fixed default values
kisztof Nov 17, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
"symfony/config": "^5.0",
"symfony/form": "^5.0",
"symfony/event-dispatcher": "^5.0",
"pagerfanta/pagerfanta": "^2.1"
"pagerfanta/pagerfanta": "^2.1",
"symfony/serializer": "^5.4"
},
"require-dev": {
"phpunit/phpunit": "^8.5",
Expand All @@ -41,7 +42,8 @@
"ibexa/doctrine-schema": "~4.6.x-dev",
"phpstan/phpstan": "^1.10",
"phpstan/phpstan-phpunit": "^1.3",
"phpstan/phpstan-symfony": "^1.3"
"phpstan/phpstan-symfony": "^1.3",
"matthiasnoback/symfony-dependency-injection-test": "^4.3"
},
"scripts": {
"fix-cs": "php-cs-fixer fix --config=.php-cs-fixer.php --show-progress=dots",
Expand Down
5 changes: 5 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,11 @@ parameters:
count: 1
path: src/lib/Mapper/PagerSearchContentToDataMapper.php

-
message: "#^Property Ibexa\\\\Contracts\\\\Core\\\\Repository\\\\Values\\\\Content\\\\Search\\\\SearchHit\\:\\:\\$score \\(float\\) on left side of \\?\\? is not nullable\\.$#"
count: 1
path: src/lib/Mapper/SearchHitToContentSuggestionMapper.php

-
message: "#^Method Ibexa\\\\Search\\\\QueryType\\\\SearchQueryType\\:\\:doGetQuery\\(\\) has parameter \\$parameters with no value type specified in iterable type array\\.$#"
count: 1
Expand Down
45 changes: 45 additions & 0 deletions src/bundle/Controller/SuggestionController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?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\Bundle\Search\Controller;

use Ibexa\Search\Model\SuggestionQuery;
use Ibexa\Search\Service\SuggestionService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Serializer\SerializerInterface;

final class SuggestionController extends AbstractController
{
private SuggestionService $suggestionService;

private SerializerInterface $serializer;

public function __construct(
SerializerInterface $serializer,
SuggestionService $suggestionService
) {
$this->suggestionService = $suggestionService;
$this->serializer = $serializer;
}

public function suggestAction(Request $request): JsonResponse
{
$query = $request->get('query');
$limit = (int) $request->get('limit');
kisztof marked this conversation as resolved.
Show resolved Hide resolved
$language = $request->get('language');

$suggestionQuery = new SuggestionQuery($query, $limit, $language);
$result = $this->suggestionService->suggest($suggestionQuery);

$serializedResults = $this->serializer->serialize($result, 'json');
kisztof marked this conversation as resolved.
Show resolved Hide resolved

return (new JsonResponse(null, 200))->setJson($serializedResults);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?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\Bundle\Search\DependencyInjection\Configuration\Parser\SiteAccessAware;

use Ibexa\Bundle\Core\DependencyInjection\Configuration\AbstractParser;
use Ibexa\Bundle\Core\DependencyInjection\Configuration\SiteAccessAware\ContextualizerInterface;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\NodeBuilder;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;

/**
* Configuration parser for search.
*
* @Example configuration:
*
* ```yaml
* ibexa:
* system:
* default: # configuration per siteaccess or siteaccess group
* search:
* suggestion:
* min_query_length: 3
* result_limit: 5
* ```
*/
final class SuggestionParser extends AbstractParser
{
/**
* @param array<string, mixed> $scopeSettings
*/
public function mapConfig(
array &$scopeSettings,
$currentScope,
ContextualizerInterface $contextualizer
): void {
if (empty($scopeSettings['search'])) {
return;
}

$settings = $scopeSettings['search'];

$this->addSuggestionParameters($settings, $currentScope, $contextualizer);
}

public function addSemanticConfig(NodeBuilder $nodeBuilder): void
{
$rootProductCatalogNode = $nodeBuilder->arrayNode('search');
$rootProductCatalogNode->append($this->addSuggestionConfiguration());
}

/**
* @param array<string, mixed> $settings
*/
private function addSuggestionParameters(
$settings,
kisztof marked this conversation as resolved.
Show resolved Hide resolved
string $currentScope,
ContextualizerInterface $contextualizer
): void {
$names = [
'min_query_length',
'result_limit',
];
foreach ($names as $name) {
if (isset($settings['suggestion'][$name])) {
$contextualizer->setContextualParameter(
'search.suggestion.' . $name,
$currentScope,
$settings['suggestion'][$name]
);
}
}
}

private function addSuggestionConfiguration(): ArrayNodeDefinition
{
$treeBuilder = new TreeBuilder('suggestion');
$node = $treeBuilder->getRootNode();

$node
->addDefaultsIfNotSet()
->children()
->integerNode('min_query_length')
->isRequired()
->defaultValue(3)
kisztof marked this conversation as resolved.
Show resolved Hide resolved
->min(3)
->end()
->integerNode('result_limit')
->isRequired()
->defaultValue(5)
->min(5)
->end()
->end();

return $node;
}
}
2 changes: 2 additions & 0 deletions src/bundle/IbexaSearchBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

use Ibexa\Bundle\Search\DependencyInjection\Configuration\Parser\Search;
use Ibexa\Bundle\Search\DependencyInjection\Configuration\Parser\SearchView;
use Ibexa\Bundle\Search\DependencyInjection\Configuration\Parser\SiteAccessAware\SuggestionParser;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

Expand All @@ -21,6 +22,7 @@ public function build(ContainerBuilder $container)
$core->addDefaultSettings(__DIR__ . '/Resources/config', ['default_settings.yaml']);
$core->addConfigParser(new Search());
$core->addConfigParser(new SearchView());
$core->addConfigParser(new SuggestionParser());
}
}

Expand Down
6 changes: 6 additions & 0 deletions src/bundle/Resources/config/routing.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,9 @@ ibexa.search:
methods: ['GET']
defaults:
_controller: 'Ibexa\Bundle\Search\Controller\SearchController::searchAction'

ibexa.search.suggestion:
path: /suggestion
methods: ['GET']
kisztof marked this conversation as resolved.
Show resolved Hide resolved
defaults:
_controller: 'Ibexa\Bundle\Search\Controller\SuggestionController::suggestAction'
kisztof marked this conversation as resolved.
Show resolved Hide resolved
56 changes: 34 additions & 22 deletions src/bundle/Resources/config/services.yaml
Original file line number Diff line number Diff line change
@@ -1,25 +1,37 @@
imports:
- { resource: forms.yaml }
- { resource: twig.yaml }
- { resource: sorting_definitions.yaml }
- { resource: views.yaml }
- { resource: forms.yaml }
- { resource: twig.yaml }
- { resource: sorting_definitions.yaml }
- { resource: views.yaml }

services:
_defaults:
autoconfigure: true
autowire: true
public: false

Ibexa\Bundle\Search\Controller\SearchController:
tags:
- controller.service_arguments

Ibexa\Search\Mapper\PagerSearchContentToDataMapper:
arguments:
$contentTypeService: '@ibexa.api.service.content_type'
$userService: '@ibexa.api.service.user'
$userLanguagePreferenceProvider: '@Ibexa\Core\MVC\Symfony\Locale\UserLanguagePreferenceProvider'
$translationHelper: '@Ibexa\Core\Helper\TranslationHelper'
$languageService: '@ibexa.api.service.language'

Ibexa\Search\QueryType\SearchQueryType: ~
_defaults:
autoconfigure: true
autowire: true
public: false

Ibexa\Bundle\Search\Controller\SearchController:
tags:
- controller.service_arguments

Ibexa\Bundle\Search\Controller\SuggestionController:
tags:
- controller.service_arguments

Ibexa\Search\Mapper\PagerSearchContentToDataMapper:
arguments:
$contentTypeService: '@ibexa.api.service.content_type'
$userService: '@ibexa.api.service.user'
$userLanguagePreferenceProvider: '@Ibexa\Core\MVC\Symfony\Locale\UserLanguagePreferenceProvider'
$translationHelper: '@Ibexa\Core\Helper\TranslationHelper'
$languageService: '@ibexa.api.service.language'

Ibexa\Search\QueryType\SearchQueryType: ~
Steveb-p marked this conversation as resolved.
Show resolved Hide resolved

Ibexa\Search\EventDispatcher\EventListener\ContentSuggestionSubscriber: ~

Ibexa\Search\Mapper\SearchHitToContentSuggestionMapper: ~

Ibexa\Contracts\Search\Mapper\SearchHitToContentSuggestionMapper: '@Ibexa\Search\Mapper\SearchHitToContentSuggestionMapper'

Ibexa\Search\Service\SuggestionService: ~
46 changes: 46 additions & 0 deletions src/contracts/Event/AfterSuggestionEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?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\Search\Event;

use Ibexa\Contracts\Core\Repository\Event\AfterEvent;
use Ibexa\Search\Model\Suggestion\SuggestionCollection;
use Ibexa\Search\Model\SuggestionQuery;

final class AfterSuggestionEvent extends AfterEvent
kisztof marked this conversation as resolved.
Show resolved Hide resolved
{
private SuggestionQuery $query;

private SuggestionCollection $suggestionCollection;

public function __construct(SuggestionQuery $query, SuggestionCollection $suggestionCollection)
{
$this->query = $query;
$this->suggestionCollection = $suggestionCollection;
}

public function setQuery(SuggestionQuery $query): void
{
$this->query = $query;
kisztof marked this conversation as resolved.
Show resolved Hide resolved
}

public function getQuery(): SuggestionQuery
{
return $this->query;
}

public function setSuggestionCollection(SuggestionCollection $suggestionCollection): void
{
$this->suggestionCollection = $suggestionCollection;
}

public function getSuggestionCollection(): SuggestionCollection
{
return $this->suggestionCollection;
}
}
46 changes: 46 additions & 0 deletions src/contracts/Event/BeforeSuggestionEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?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\Search\Event;

use Ibexa\Contracts\Core\Repository\Event\BeforeEvent;
use Ibexa\Search\Model\Suggestion\SuggestionCollection;
use Ibexa\Search\Model\SuggestionQuery;

final class BeforeSuggestionEvent extends BeforeEvent
{
private SuggestionQuery $query;

private SuggestionCollection $suggestionCollection;

public function __construct(SuggestionQuery $query, SuggestionCollection $suggestionCollection)
{
$this->query = $query;
$this->suggestionCollection = $suggestionCollection;
}

public function setQuery(SuggestionQuery $query): void
{
$this->query = $query;
}

public function getQuery(): SuggestionQuery
{
return $this->query;
}

public function getSuggestionCollection(): SuggestionCollection
{
return $this->suggestionCollection;
}

public function setSuggestionCollection(SuggestionCollection $suggestionCollection): void
{
$this->suggestionCollection = $suggestionCollection;
}
}
17 changes: 17 additions & 0 deletions src/contracts/Mapper/SearchHitToContentSuggestionMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?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\Search\Mapper;

use Ibexa\Contracts\Core\Repository\Values\Content\Search\SearchHit;
use Ibexa\Search\Model\Suggestion\ContentSuggestion;
kisztof marked this conversation as resolved.
Show resolved Hide resolved

interface SearchHitToContentSuggestionMapper
kisztof marked this conversation as resolved.
Show resolved Hide resolved
{
public function map(SearchHit $searchHit): ?ContentSuggestion;
}
Loading
Loading