Skip to content

Commit

Permalink
FEATURE: Add basic code for Autocomplete and Suggestions
Browse files Browse the repository at this point in the history
  • Loading branch information
daniellienert committed Jul 24, 2024
1 parent ad1bcd8 commit d844cba
Show file tree
Hide file tree
Showing 10 changed files with 121 additions and 12 deletions.
61 changes: 58 additions & 3 deletions Classes/Eel/IndexingHelper.php
Original file line number Diff line number Diff line change
@@ -1,20 +1,75 @@
<?php
declare(strict_types=1);

namespace PunktDe\Search\AlternativeSearchWords\Eel;
namespace PunktDe\Neos\AdvancedSearch\Eel;

use Flowpack\SearchPlugin\EelHelper\SuggestionIndexHelper;
use Flowpack\SearchPlugin\Exception;
use Neos\ContentRepository\Domain\Model\NodeInterface;
use Neos\ContentRepository\Exception\NodeException;
use Neos\Eel\ProtectedContextAwareInterface;
use PunktDe\Search\AlternativeSearchWords\TextTokenizer;
use PunktDe\Neos\AdvancedSearch\NodeTypeDefinitionInterface;
use PunktDe\Neos\AdvancedSearch\TextTokenizer;


class IndexingHelper implements ProtectedContextAwareInterface
{

public function __construct(
private TextTokenizer $textTokenizer,
private readonly TextTokenizer $textTokenizer,
private readonly SuggestionIndexHelper $suggestionIndexHelper,
) {
}

/**
* @param NodeInterface $node
* @param string[] $properties
* @return string
* @throws NodeException
*/
public function indexCompletionIfSearchable(NodeInterface $node, array $properties): string
{
if ($node->getNodeType()->isOfType(NodeTypeDefinitionInterface::MIXIN_HIDDEN_FROM_INTERNAL_SEARCH)) {
return '';
}

return implode(' ', $this->extractNodeProperties($properties, $node));
}

/**
* @param NodeInterface $node
* @param string[] $properties
* @param int $weight
* @return string[]
* @throws NodeException
* @throws Exception
*/
public function indexSuggestionIfSearchable(NodeInterface $node, array $properties, int $weight = 1): array
{
if ($node->isHidden() || $node->getNodeType()->isOfType(NodeTypeDefinitionInterface::MIXIN_HIDDEN_FROM_INTERNAL_SEARCH)) {
return [];
}
return $this->suggestionIndexHelper->build($this->extractNodeProperties($properties, $node), $weight);
}

/**
* @param string[] $properties
* @param NodeInterface $node
* @return string[]
* @throws NodeException
*/
private function extractNodeProperties(array $properties, NodeInterface $node): array
{
$completionContent = [];

foreach ($properties as $propertyName) {
if (is_string($node->getProperty($propertyName))) {
$completionContent[] = strip_tags($node->getProperty($propertyName));
}
}
return $completionContent;
}

/**
* @param string $input
* @param NodeInterface $node
Expand Down
9 changes: 9 additions & 0 deletions Classes/NodeTypeDefinitionInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php
declare(strict_types=1);

namespace PunktDe\Neos\AdvancedSearch;

interface NodeTypeDefinitionInterface
{
public const MIXIN_HIDDEN_FROM_INTERNAL_SEARCH = 'PunktDe.Neos.AdvancedSearch:Mixin.HiddenFromInternalSearch';
}
4 changes: 2 additions & 2 deletions Classes/TextTokenizer.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php
declare(strict_types=1);

namespace PunktDe\Search\AlternativeSearchWords;
namespace PunktDe\Neos\AdvancedSearch;

use Neos\Utility\Files;
use Neos\Flow\Annotations as Flow;
Expand All @@ -15,7 +15,7 @@ class TextTokenizer
/**
* @var string[]
*/
#[Flow\InjectConfiguration(path: "stopWordFolders", package: "PunktDe.Search.AlternativeSearchWords")]
#[Flow\InjectConfiguration(path: "stopWordFolders", package: "PunktDe.Neos.AdvancedSearch")]
protected array $stopWordFolders = [];

private const REMOVE_CHARACTERS = ['', '', '«', '»', ')', '(', '!', '?', '&'];
Expand Down
2 changes: 1 addition & 1 deletion Configuration/Settings.Elasticsearch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ Neos:
ContentRepository:
Search:
defaultContext:
PunktDe.Search.AlternativeSearchWords: PunktDe\Search\AlternativeSearchWords\Eel\IndexingHelper
PunktDe.Neos.AdvancedSearch.Indexing: PunktDe\Neos\AdvancedSearch\Eel\IndexingHelper
6 changes: 3 additions & 3 deletions Configuration/Settings.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
PunktDe:
Search:
AlternativeSearchWords:
Neos:
AdvancedSearch:
stopWordFolders:
languageFolder: '%FLOW_PATH_PACKAGES%/Application/PunktDe.Search.AlternativeSearchWords/Resources/Private/StopWords'
languageFolder: '%FLOW_PATH_PACKAGES%/Application/PunktDe.Neos.AdvancedSearch/Resources/Private/StopWords'
# All files within this folder are loaded
customerSpecificFolder: ''

24 changes: 24 additions & 0 deletions NodeTypes/Override/NodeTypes.Override.Document.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'Neos.Neos:Document':
superTypes:
'Flowpack.SearchPlugin:AutocompletableMixin': true
'Flowpack.SearchPlugin:SuggestableMixin': true

properties:
neos_fulltext_parts:
search:
elasticSearchMapping:
type: flattened
ignore_above: 1000
enabled: ~

esDocumentFacet:
search:
elasticSearchMapping:
type: keyword
indexing: "${'page'}"

esAlternativeSearchword:
search:
elasticSearchMapping:
type: keyword
indexing: "${PunktDe.Neos.AdvancedSearch.stopWordFilteredTokenize(q(node).property('title') + ' ' + q(node).property('metaKeywords') + ' ' + q(node).property('metaDescription'), node)}"
10 changes: 10 additions & 0 deletions NodeTypes/Override/NodeTypes.Override.Mixin.Autocompletable.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'Flowpack.SearchPlugin:AutocompletableMixin':
abstract: true
properties:
'neos_completion':
search:
elasticSearchMapping:
type: text
analyzer: autocomplete
fielddata: true
indexing: "${PunktDe.Neos.AdvancedSearch.Indexing.indexCompletionIfSearchable(node, ['title', 'metaDescription'])}"
11 changes: 11 additions & 0 deletions NodeTypes/Override/NodeTypes.Override.Mixin.Suggestable.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
'Flowpack.SearchPlugin:SuggestableMixin':
abstract: true
properties:
'neos_suggestion':
search:
indexing: "${PunktDe.Neos.AdvancedSearch.Indexing.indexSuggestionIfSearchable(node, ['title','metaKeywords','metaDescription'], 20)}"

esSuggestionSnippet:
search:
type: text
indexing: "${Neos.Node.isOfType(node, 'PunktDe.Neos.AdvancedSearch:Mixin.HiddenFromInternalSearch') || node.hidden == true ? '' : FusionRendering.render(node, 'suggestion')}"
2 changes: 1 addition & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ Tokenize and ingest the alternatives within your document
search:
elasticSearchMapping:
type: keyword
indexing: "${PunktDe.Search.AlternativeSearchWords.stopWordFilteredTokenize(q(node).property('title') + ' ' + q(node).property('metaKeywords') + ' ' + q(node).property('metaDescription'), node)}"
indexing: "${PunktDe.Neos.AdvancedSearch.stopWordFilteredTokenize(q(node).property('title') + ' ' + q(node).property('metaKeywords') + ' ' + q(node).property('metaDescription'), node)}"
```
4 changes: 2 additions & 2 deletions Tests/Functional/TextTokenizerTestCase.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<?php
declare(strict_types=1);

namespace PunktDe\Search\AlternativeSearchWords\Tests\Functional;
namespace PunktDe\Neos\AdvancedSearch\Tests\Functional;

use Neos\Flow\Tests\FunctionalTestCase;
use PunktDe\Search\AlternativeSearchWords\TextTokenizer;
use PunktDe\Neos\AdvancedSearch\TextTokenizer;

class TextTokenizerTestCase extends FunctionalTestCase
{
Expand Down

0 comments on commit d844cba

Please sign in to comment.