diff --git a/Classes/AssetExtraction/NullAssetExtractor.php b/Classes/AssetExtraction/NullAssetExtractor.php new file mode 100644 index 0000000..7a7741a --- /dev/null +++ b/Classes/AssetExtraction/NullAssetExtractor.php @@ -0,0 +1,17 @@ +nodeIndexer->indexNode($currentNode, null, false); } catch (NodeException|IndexingException|EelException $exception) { - throw new Exception(sprintf('Error during indexing of node %s (%s)', $currentNode->getPath(), $currentNode->getIdentifier()), 1579170291, $exception); + throw new Exception(sprintf('Error during indexing of node %s (%s)', $currentNode->findNodePath(), (string) $currentNode->getNodeAggregateIdentifier()), 1579170291, $exception); } $this->indexedNodes++; foreach ($currentNode->findChildNodes() as $childNode) { diff --git a/Classes/Indexer/NodeIndexer.php b/Classes/Indexer/NodeIndexer.php index ad0efd5..1b8a0e6 100644 --- a/Classes/Indexer/NodeIndexer.php +++ b/Classes/Indexer/NodeIndexer.php @@ -1,8 +1,8 @@ indexAllNodeVariants($node); @@ -161,7 +161,7 @@ public function indexNode(NodeInterface $node, $targetWorkspaceName = null, $ind * @param NodeInterface $node * @return void */ - public function removeNode(NodeInterface $node) + public function removeNode(NodeInterface $node): void { $identifier = $this->generateUniqueNodeIdentifier($node); $this->indexClient->removeData($identifier); @@ -170,7 +170,7 @@ public function removeNode(NodeInterface $node) /** * @return void */ - public function flush() + public function flush(): void { $this->indexedNodeData = []; } @@ -182,7 +182,7 @@ public function flush() */ protected function indexAllNodeVariants(NodeInterface $node): void { - $nodeIdentifier = $node->getIdentifier(); + $nodeIdentifier = (string) $node->getNodeAggregateIdentifier(); $allIndexedVariants = $this->indexClient->executeStatement( $this->queryBuilder->getFindIdentifiersByNodeIdentifierQuery('identifier'), @@ -248,13 +248,13 @@ protected function findFulltextRoot(NodeInterface $node): ?NodeInterface return null; } - $currentNode = $node->getParent(); + $currentNode = $node->findParentNode(); while ($currentNode !== null) { if (in_array($currentNode->getNodeType()->getName(), $this->fulltextRootNodeTypes, true)) { return $currentNode; } - $currentNode = $currentNode->getParent(); + $currentNode = $currentNode->findParentNode(); } return null; diff --git a/Classes/NotImplementedException.php b/Classes/NotImplementedException.php new file mode 100644 index 0000000..953162c --- /dev/null +++ b/Classes/NotImplementedException.php @@ -0,0 +1,8 @@ +getSimpleSearchQueryBuilder()->sortDesc($propertyName); + return $this; + } + + public function sortAsc(string $propertyName): QueryBuilderInterface + { + $this->getSimpleSearchQueryBuilder()->sortAsc($propertyName); + return $this; + } + + public function limit($limit): QueryBuilderInterface + { + $this->getSimpleSearchQueryBuilder()->limit($limit); + return $this; + } + + public function from($from): QueryBuilderInterface + { + $this->getSimpleSearchQueryBuilder()->from($from); + return $this; + } + + public function fulltext(string $searchWord, array $options = []): QueryBuilderInterface + { + $this->getSimpleSearchQueryBuilder()->fulltext($searchWord); + return $this; + } + + /** + * @param NodeInterface $contextNode + * @return MysqlQueryBuilder + * @throws IllegalObjectTypeException + */ + public function query(NodeInterface $contextNode): QueryBuilderInterface + { + $this->getSimpleSearchQueryBuilder()->customCondition("(__parentPath LIKE '%#" . $contextNode->findNodePath() . "#%' OR __path LIKE '" . $contextNode->findNodePath() . "')"); + $this->getSimpleSearchQueryBuilder()->like('__path', (string) $contextNode->findNodePath()); + $this->getSimpleSearchQueryBuilder()->like('__workspace', "#" . $contextNode->getContext()->getWorkspace()->getName() . "#"); + $this->getSimpleSearchQueryBuilder()->like('__dimensionshash', "#" . md5(json_encode($contextNode->getContext()->getDimensions())) . "#"); + $this->contextNode = $contextNode; + + return $this; + } + + /** + * @param string $nodeIdentifierPlaceholder + * @return string + */ + abstract public function getFindIdentifiersByNodeIdentifierQuery(string $nodeIdentifierPlaceholder); + + /** + * HIGH-LEVEL API + */ + + /** + * Filter by node type, taking inheritance into account. + * + * @param string $nodeType the node type to filter for + * @return QueryBuilderInterface + */ + public function nodeType($nodeType): QueryBuilderInterface + { + $this->getSimpleSearchQueryBuilder()->like('__typeAndSuperTypes', "#" . $nodeType . "#"); + + return $this; + } + + /** + * add an exact-match query for a given property + * + * @param string $propertyName + * @param mixed $propertyValue + * @return QueryBuilderInterface + */ + public function exactMatch($propertyName, $propertyValue): QueryBuilderInterface + { + if ($propertyValue instanceof NodeInterface) { + $propertyValue = (string) $propertyValue->getNodeAggregateIdentifier(); + } + + $this->getSimpleSearchQueryBuilder()->exactMatch($propertyName, $propertyValue); + return $this; + } + + /** + * add an like query for a given property + * + * @param string $propertyName + * @param mixed $propertyValue + * @return QueryBuilderInterface + */ + public function like(string $propertyName, $propertyValue): QueryBuilderInterface + { + if ($propertyValue instanceof NodeInterface) { + $propertyValue = (string) $propertyValue->getNodeAggregateIdentifier(); + } + + $this->getSimpleSearchQueryBuilder()->like($propertyName, $propertyValue); + return $this; + } + + /** + * add a greater than query for a given property + * + * @param string $propertyName + * @param mixed $propertyValue + * @return QueryBuilderInterface + */ + public function greaterThan($propertyName, $propertyValue) + { + if ($propertyValue instanceof NodeInterface) { + $propertyValue = (string) $propertyValue->getNodeAggregateIdentifier(); + } + + $this->getSimpleSearchQueryBuilder()->greaterThan($propertyName, $propertyValue); + return $this; + } + + /** + * add a greater than or equal query for a given property + * + * @param string $propertyName + * @param mixed $propertyValue + * @return QueryBuilderInterface + */ + public function greaterThanOrEqual($propertyName, $propertyValue) + { + if ($propertyValue instanceof NodeInterface) { + $propertyValue = (string) $propertyValue->getNodeAggregateIdentifier(); + } + + $this->getSimpleSearchQueryBuilder()->greaterThanOrEqual($propertyName, $propertyValue); + return $this; + } + + /** + * add a less than query for a given property + * + * @param string $propertyName + * @param mixed $propertyValue + * @return QueryBuilderInterface + */ + public function lessThan($propertyName, $propertyValue) + { + if ($propertyValue instanceof NodeInterface) { + $propertyValue = (string) $propertyValue->getNodeAggregateIdentifier(); + } + + $this->getSimpleSearchQueryBuilder()->lessThan($propertyName, $propertyValue); + return $this; + } + + /** + * add a less than query for a given property + * + * @param string $propertyName + * @param mixed $propertyValue + * @return QueryBuilderInterface + */ + public function lessThanOrEqual($propertyName, $propertyValue) + { + if ($propertyValue instanceof NodeInterface) { + $propertyValue = (string) $propertyValue->getNodeAggregateIdentifier(); + } + + $this->getSimpleSearchQueryBuilder()->lessThanOrEqual($propertyName, $propertyValue); + return $this; + } + + /** + * Execute the query and return the list of nodes as result + * + * @return array<\Neos\ContentRepository\Domain\Model\NodeInterface> + */ + public function execute(): \Traversable + { + // Adding implicit sorting by __sortIndex (as last fallback) as we can expect it to be there for nodes. + $this->getSimpleSearchQueryBuilder()->sortAsc("__sortIndex"); + + $timeBefore = microtime(true); + $result = $this->getSimpleSearchQueryBuilder()->execute(); + $timeAfterwards = microtime(true); + + if ($this->queryLogEnabled === true) { + $this->logger->debug('Query Log (' . $this->logMessage . '): -- execution time: ' . (($timeAfterwards - $timeBefore) * 1000) . ' ms -- Total Results: ' . count($result)); + } + + $nodes = []; + foreach ($result as $hit) { + $nodePath = $hit['__path']; + $node = $this->contextNode->getNode($nodePath); + if ($node instanceof NodeInterface) { + $nodes[(string) $node->getNodeAggregateIdentifier()] = $node; + } + } + + return (new \ArrayObject(array_values($nodes)))->getIterator(); + } + + /** + * Log the current request for debugging after it has been executed. + * + * @param string $message an optional message to identify the log entry + * @return AbstractQueryBuilder + */ + public function log($message = null) + { + $this->queryLogEnabled = true; + $this->logMessage = $message; + + return $this; + } + + /** + * Return the total number of hits for the query. + * + * @return integer + */ + public function count(): int + { + $timeBefore = microtime(true); + $count = $this->getSimpleSearchQueryBuilder()->count(); + $timeAfterwards = microtime(true); + + if ($this->queryLogEnabled === true) { + $this->logger->debug('Query Log (' . $this->logMessage . '): -- execution time: ' . (($timeAfterwards - $timeBefore) * 1000) . ' ms -- Total Results: ' . $count); + } + + return $count; + } + + /** + * @param string $methodName + * @return boolean + */ + public function allowsCallOfMethod($methodName) + { + if ($methodName !== 'getFindIdentifiersByNodeIdentifierQuery') { + // query must be called first to establish a context and starting point. + return !($this->contextNode === null && $methodName !== 'query'); + } + return false; + } +} diff --git a/Classes/Search/MysqlQueryBuilder.php b/Classes/Search/MysqlQueryBuilder.php index bc25c30..92880e0 100644 --- a/Classes/Search/MysqlQueryBuilder.php +++ b/Classes/Search/MysqlQueryBuilder.php @@ -3,61 +3,24 @@ namespace Flowpack\SimpleSearch\ContentRepositoryAdaptor\Search; -use Flowpack\SimpleSearch\Search\MysqlQueryBuilder as SimpleSearchMysqlQueryBuilder; -use Neos\ContentRepository\Domain\Model\NodeInterface; -use Neos\ContentRepository\Search\Search\QueryBuilderInterface; -use Neos\Eel\ProtectedContextAwareInterface; +use Flowpack\SimpleSearch\Search\QueryBuilderInterface; use Neos\Flow\Annotations as Flow; -use Neos\Flow\Persistence\Exception\IllegalObjectTypeException; -use Psr\Log\LoggerInterface; +use Flowpack\SimpleSearch\Search\MysqlQueryBuilder as SimpleSearchMysqlQueryBuilder; /** - * Query Builder for Content Repository searches - * - * Note: some signatures are not as strict as in the interfaces, because two query builder interfaces are "mixed" + * MySQL Query Builder for Content Repository searches */ -class MysqlQueryBuilder extends SimpleSearchMysqlQueryBuilder implements QueryBuilderInterface, ProtectedContextAwareInterface +class MysqlQueryBuilder extends AbstractQueryBuilder { /** * @Flow\Inject - * @var LoggerInterface - */ - protected $logger; - - /** - * The node inside which searching should happen - * - * @var NodeInterface - */ - protected $contextNode; - - /** - * Optional message for a log entry on execution of this Query. - * - * @var string - */ - protected $logMessage; - - /** - * Should this Query be logged? - * - * @var boolean + * @var SimpleSearchMysqlQueryBuilder */ - protected $queryLogEnabled = false; + protected $mysqlQueryBuilder; - /** - * @param NodeInterface $contextNode - * @return MysqlQueryBuilder - * @throws IllegalObjectTypeException - */ - public function query(NodeInterface $contextNode) + protected function getSimpleSearchQueryBuilder(): QueryBuilderInterface { - $this->where[] = "(__parentPath LIKE '%#" . $contextNode->getPath() . "#%' OR __path LIKE '" . $contextNode->getPath() . "')"; - $this->where[] = "(__workspace LIKE '%#" . $contextNode->getContext()->getWorkspace()->getName() . "#%')"; - $this->where[] = "(__dimensionshash LIKE '%#" . md5(json_encode($contextNode->getContext()->getDimensions())) . "#%')"; - $this->contextNode = $contextNode; - - return $this; + return $this->mysqlQueryBuilder; } /** @@ -69,195 +32,8 @@ public function getFindIdentifiersByNodeIdentifierQuery(string $nodeIdentifierPl return 'SELECT "__identifier__" FROM "fulltext_objects" WHERE "__identifier" = :' . $nodeIdentifierPlaceholder; } - /** - * HIGH-LEVEL API - */ - - /** - * Filter by node type, taking inheritance into account. - * - * @param string $nodeType the node type to filter for - * @return \Flowpack\SimpleSearch\Search\QueryBuilderInterface - */ - public function nodeType($nodeType) - { - $this->where[] = "(__typeAndSuperTypes LIKE '%#" . $nodeType . "#%')"; - - return $this; - } - - /** - * add an exact-match query for a given property - * - * @param string $propertyName - * @param mixed $propertyValue - * @return \Flowpack\SimpleSearch\Search\QueryBuilderInterface - */ - public function exactMatch($propertyName, $propertyValue): \Flowpack\SimpleSearch\Search\QueryBuilderInterface - { - if ($propertyValue instanceof NodeInterface) { - $propertyValue = $propertyValue->getIdentifier(); - } - - return parent::exactMatch($propertyName, $propertyValue); - } - - /** - * add an like query for a given property - * - * @param string $propertyName - * @param mixed $propertyValue - * @return \Flowpack\SimpleSearch\Search\QueryBuilderInterface - */ - public function like(string $propertyName, $propertyValue): \Flowpack\SimpleSearch\Search\QueryBuilderInterface - { - if ($propertyValue instanceof NodeInterface) { - $propertyValue = $propertyValue->getIdentifier(); - } - - return parent::like($propertyName, $propertyValue); - } - - /** - * add a greater than query for a given property - * - * @param string $propertyName - * @param mixed $propertyValue - * @return \Flowpack\SimpleSearch\Search\QueryBuilderInterface - */ - public function greaterThan($propertyName, $propertyValue) - { - if ($propertyValue instanceof NodeInterface) { - $propertyValue = $propertyValue->getIdentifier(); - } - - return parent::greaterThan($propertyName, $propertyValue); - } - - /** - * add a greater than or equal query for a given property - * - * @param string $propertyName - * @param mixed $propertyValue - * @return \Flowpack\SimpleSearch\Search\QueryBuilderInterface - */ - public function greaterThanOrEqual($propertyName, $propertyValue) - { - if ($propertyValue instanceof NodeInterface) { - $propertyValue = $propertyValue->getIdentifier(); - } - - return parent::greaterThanOrEqual($propertyName, $propertyValue); - } - - /** - * add a less than query for a given property - * - * @param string $propertyName - * @param mixed $propertyValue - * @return \Flowpack\SimpleSearch\Search\QueryBuilderInterface - */ - public function lessThan($propertyName, $propertyValue) - { - if ($propertyValue instanceof NodeInterface) { - $propertyValue = $propertyValue->getIdentifier(); - } - - return parent::lessThan($propertyName, $propertyValue); - } - - /** - * add a less than query for a given property - * - * @param string $propertyName - * @param mixed $propertyValue - * @return \Flowpack\SimpleSearch\Search\QueryBuilderInterface - */ - public function lessThanOrEqual($propertyName, $propertyValue) - { - if ($propertyValue instanceof NodeInterface) { - $propertyValue = $propertyValue->getIdentifier(); - } - - return parent::lessThanOrEqual($propertyName, $propertyValue); - } - - /** - * Execute the query and return the list of nodes as result - * - * @return array<\Neos\ContentRepository\Domain\Model\NodeInterface> - */ - public function execute(): array - { - // Adding implicit sorting by __sortIndex (as last fallback) as we can expect it to be there for nodes. - $this->sorting[] = '"fulltext_objects"."__sortIndex" ASC'; - - $timeBefore = microtime(true); - $result = parent::execute(); - $timeAfterwards = microtime(true); - - if ($this->queryLogEnabled === true) { - $this->logger->debug('Query Log (' . $this->logMessage . '): -- execution time: ' . (($timeAfterwards - $timeBefore) * 1000) . ' ms -- Total Results: ' . count($result)); - } - - if (empty($result)) { - return []; - } - - $nodes = []; - foreach ($result as $hit) { - $nodePath = $hit['__path']; - $node = $this->contextNode->getNode($nodePath); - if ($node instanceof NodeInterface) { - $nodes[$node->getIdentifier()] = $node; - } - } - - return array_values($nodes); - } - - /** - * Log the current request for debugging after it has been executed. - * - * @param string $message an optional message to identify the log entry - * @return MysqlQueryBuilder - */ - public function log($message = null) - { - $this->queryLogEnabled = true; - $this->logMessage = $message; - - return $this; - } - - /** - * Return the total number of hits for the query. - * - * @return integer - */ - public function count(): int - { - $timeBefore = microtime(true); - $count = parent::count(); - $timeAfterwards = microtime(true); - - if ($this->queryLogEnabled === true) { - $this->logger->debug('Query Log (' . $this->logMessage . '): -- execution time: ' . (($timeAfterwards - $timeBefore) * 1000) . ' ms -- Total Results: ' . $count); - } - - return $count; - } - - /** - * @param string $methodName - * @return boolean - */ - public function allowsCallOfMethod($methodName) + public function fulltextMatchResult($searchword, $resultTokens = 200, $ellipsis = '...', $beginModifier = '', $endModifier = ''): string { - if ($methodName !== 'getFindIdentifiersByNodeIdentifierQuery') { - // query must be called first to establish a context and starting point. - return !($this->contextNode === null && $methodName !== 'query'); - } - return false; + return $this->mysqlQueryBuilder->fulltextMatchResult($searchword, $resultTokens, $ellipsis, $beginModifier, $endModifier); } } diff --git a/Classes/Search/SqLiteQueryBuilder.php b/Classes/Search/SqLiteQueryBuilder.php index 3031527..108f512 100644 --- a/Classes/Search/SqLiteQueryBuilder.php +++ b/Classes/Search/SqLiteQueryBuilder.php @@ -3,61 +3,25 @@ namespace Flowpack\SimpleSearch\ContentRepositoryAdaptor\Search; +use Flowpack\SimpleSearch\Search\QueryBuilderInterface; use Flowpack\SimpleSearch\Search\SqLiteQueryBuilder as SimpleSearchSqLiteQueryBuilder; -use Neos\ContentRepository\Domain\Model\NodeInterface; -use Neos\ContentRepository\Search\Search\QueryBuilderInterface; -use Neos\Eel\ProtectedContextAwareInterface; use Neos\Flow\Annotations as Flow; -use Neos\Flow\Persistence\Exception\IllegalObjectTypeException; -use Psr\Log\LoggerInterface; /** - * Query Builder for Content Repository searches + * Sqlite Query Builder for Content Repository searches * - * Note: some signatures are not as strict as in the interfaces, because two query builder interfaces are "mixed" */ -class SqLiteQueryBuilder extends SimpleSearchSqLiteQueryBuilder implements QueryBuilderInterface, ProtectedContextAwareInterface +class SqLiteQueryBuilder extends AbstractQueryBuilder { /** * @Flow\Inject - * @var LoggerInterface + * @var SimpleSearchSqLiteQueryBuilder */ - protected $logger; + protected $sqLiteQueryBuilder; - /** - * The node inside which searching should happen - * - * @var NodeInterface - */ - protected $contextNode; - - /** - * Optional message for a log entry on execution of this Query. - * - * @var string - */ - protected $logMessage; - - /** - * Should this Query be logged? - * - * @var boolean - */ - protected $queryLogEnabled = false; - - /** - * @param NodeInterface $contextNode - * @return SqLiteQueryBuilder - * @throws IllegalObjectTypeException - */ - public function query(NodeInterface $contextNode) + protected function getSimpleSearchQueryBuilder(): QueryBuilderInterface { - $this->where[] = "(__parentPath LIKE '%#" . $contextNode->getPath() . "#%' OR __path LIKE '" . $contextNode->getPath() . "')"; - $this->where[] = "(__workspace LIKE '%#" . $contextNode->getContext()->getWorkspace()->getName() . "#%')"; - $this->where[] = "(__dimensionshash LIKE '%#" . md5(json_encode($contextNode->getContext()->getDimensions())) . "#%')"; - $this->contextNode = $contextNode; - - return $this; + return $this->sqLiteQueryBuilder; } /** @@ -69,195 +33,8 @@ public function getFindIdentifiersByNodeIdentifierQuery(string $nodeIdentifierPl return 'SELECT __identifier__ FROM objects WHERE __identifier = :' . $nodeIdentifierPlaceholder; } - /** - * HIGH-LEVEL API - */ - - /** - * Filter by node type, taking inheritance into account. - * - * @param string $nodeType the node type to filter for - * @return SqLiteQueryBuilder - */ - public function nodeType($nodeType) - { - $this->where[] = "(__typeAndSuperTypes LIKE '%#" . $nodeType . "#%')"; - - return $this; - } - - /** - * add an exact-match query for a given property - * - * @param string $propertyName - * @param mixed $propertyValue - * @return \Flowpack\SimpleSearch\Search\QueryBuilderInterface - */ - public function exactMatch($propertyName, $propertyValue): \Flowpack\SimpleSearch\Search\QueryBuilderInterface - { - if ($propertyValue instanceof NodeInterface) { - $propertyValue = $propertyValue->getIdentifier(); - } - - return parent::exactMatch($propertyName, $propertyValue); - } - - /** - * add an like query for a given property - * - * @param string $propertyName - * @param mixed $propertyValue - * @return \Flowpack\SimpleSearch\Search\QueryBuilderInterface - */ - public function like(string $propertyName, $propertyValue): \Flowpack\SimpleSearch\Search\QueryBuilderInterface - { - if ($propertyValue instanceof NodeInterface) { - $propertyValue = $propertyValue->getIdentifier(); - } - - return parent::like($propertyName, $propertyValue); - } - - /** - * add a greater than query for a given property - * - * @param string $propertyName - * @param mixed $propertyValue - * @return \Flowpack\SimpleSearch\Search\QueryBuilderInterface - */ - public function greaterThan(string $propertyName, $propertyValue): \Flowpack\SimpleSearch\Search\QueryBuilderInterface - { - if ($propertyValue instanceof NodeInterface) { - $propertyValue = $propertyValue->getIdentifier(); - } - - return parent::greaterThan($propertyName, $propertyValue); - } - - /** - * add a greater than or equal query for a given property - * - * @param string $propertyName - * @param mixed $propertyValue - * @return \Flowpack\SimpleSearch\Search\QueryBuilderInterface - */ - public function greaterThanOrEqual(string $propertyName, $propertyValue): \Flowpack\SimpleSearch\Search\QueryBuilderInterface - { - if ($propertyValue instanceof NodeInterface) { - $propertyValue = $propertyValue->getIdentifier(); - } - - return parent::greaterThanOrEqual($propertyName, $propertyValue); - } - - /** - * add a less than query for a given property - * - * @param string $propertyName - * @param mixed $propertyValue - * @return \Flowpack\SimpleSearch\Search\QueryBuilderInterface - */ - public function lessThan(string $propertyName, $propertyValue): \Flowpack\SimpleSearch\Search\QueryBuilderInterface - { - if ($propertyValue instanceof NodeInterface) { - $propertyValue = $propertyValue->getIdentifier(); - } - - return parent::lessThan($propertyName, $propertyValue); - } - - /** - * add a less than query for a given property - * - * @param string $propertyName - * @param mixed $propertyValue - * @return \Flowpack\SimpleSearch\Search\QueryBuilderInterface - */ - public function lessThanOrEqual(string $propertyName, $propertyValue): \Flowpack\SimpleSearch\Search\QueryBuilderInterface - { - if ($propertyValue instanceof NodeInterface) { - $propertyValue = $propertyValue->getIdentifier(); - } - - return parent::lessThanOrEqual($propertyName, $propertyValue); - } - - /** - * Execute the query and return the list of nodes as result - * - * @return array<\Neos\ContentRepository\Domain\Model\NodeInterface> - */ - public function execute(): array - { - // Adding implicit sorting by __sortIndex (as last fallback) as we can expect it to be there for nodes. - $this->sorting[] = 'objects.__sortIndex ASC'; - - $timeBefore = microtime(true); - $result = parent::execute(); - $timeAfterwards = microtime(true); - - if ($this->queryLogEnabled === true) { - $this->logger->debug('Query Log (' . $this->logMessage . '): -- execution time: ' . (($timeAfterwards - $timeBefore) * 1000) . ' ms -- Total Results: ' . count($result)); - } - - if (empty($result)) { - return []; - } - - $nodes = []; - foreach ($result as $hit) { - $nodePath = $hit['__path']; - $node = $this->contextNode->getNode($nodePath); - if ($node instanceof NodeInterface) { - $nodes[$node->getIdentifier()] = $node; - } - } - - return array_values($nodes); - } - - /** - * Log the current request for debugging after it has been executed. - * - * @param string $message an optional message to identify the log entry - * @return SqLiteQueryBuilder - */ - public function log($message = null) - { - $this->queryLogEnabled = true; - $this->logMessage = $message; - - return $this; - } - - /** - * Return the total number of hits for the query. - * - * @return integer - */ - public function count(): int - { - $timeBefore = microtime(true); - $count = parent::count(); - $timeAfterwards = microtime(true); - - if ($this->queryLogEnabled === true) { - $this->logger->debug('Query Log (' . $this->logMessage . '): -- execution time: ' . (($timeAfterwards - $timeBefore) * 1000) . ' ms -- Total Results: ' . $count); - } - - return $count; - } - - /** - * @param string $methodName - * @return boolean - */ - public function allowsCallOfMethod($methodName) + public function fulltextMatchResult(string $searchword, int $resultTokens = 60, string $ellipsis = '...', string $beginModifier = '', string $endModifier = ''): string { - if ($methodName !== 'getFindIdentifiersByNodeIdentifierQuery') { - // query must be called first to establish a context and starting point. - return !($this->contextNode === null && $methodName !== 'query'); - } - return false; + return $this->sqLiteQueryBuilder->fulltextMatchResult($searchword, $resultTokens, $ellipsis, $beginModifier, $endModifier); } } diff --git a/Configuration/Objects.yaml b/Configuration/Objects.yaml index e98bc98..d64e151 100644 --- a/Configuration/Objects.yaml +++ b/Configuration/Objects.yaml @@ -14,7 +14,7 @@ Neos\ContentRepository\Search\Search\QueryBuilderInterface: Neos\ContentRepository\Search\Indexer\NodeIndexerInterface: className: 'Flowpack\SimpleSearch\ContentRepositoryAdaptor\Indexer\NodeIndexer' -Flowpack\SimpleSearch\ContentRepositoryAdaptor\Search\SqLiteQueryBuilder: +Flowpack\SimpleSearch\Search\SqLiteQueryBuilder: properties: indexClient: object: @@ -24,7 +24,7 @@ Flowpack\SimpleSearch\ContentRepositoryAdaptor\Search\SqLiteQueryBuilder: 1: value: 'Neos_CR' -Flowpack\SimpleSearch\ContentRepositoryAdaptor\Search\MysqlQueryBuilder: +Flowpack\SimpleSearch\Search\MysqlQueryBuilder: properties: indexClient: object: diff --git a/Resources/Private/Fusion/Root.fusion b/Resources/Private/Fusion/Root.fusion index f783a51..529958d 100644 --- a/Resources/Private/Fusion/Root.fusion +++ b/Resources/Private/Fusion/Root.fusion @@ -3,9 +3,17 @@ prototype(Flowpack.SimpleSearch.ContentRepositoryAdaptor:Search) < prototype(Neo searchResults = ${Search.query(site).nodeType('Neos.Neos:Document').log().fulltext(request.arguments.search.word).execute()} searchWord = ${request.arguments.search.word} + searchQuery = ${this.searchWord ? Search.query(site).nodeType('Neos.Neos:Document').log().fulltext(request.arguments.search.word) : null} searchResultContent = ${Search.query(searchResult).nodeType('Neos.Neos:Content').fulltextMatchResult(request.arguments.search.word)} + configuration = Neos.Fusion:DataStructure { + itemsPerPage = 25 + insertAbove = false + insertBelow = true + maximumNumberOfLinks = 10 + } + @cache { mode = 'uncached' diff --git a/Resources/Private/Templates/NodeTypes/Search.html b/Resources/Private/Templates/NodeTypes/Search.html index 98a5847..4285037 100644 --- a/Resources/Private/Templates/NodeTypes/Search.html +++ b/Resources/Private/Templates/NodeTypes/Search.html @@ -1,6 +1,6 @@ {namespace neos=Neos\Neos\ViewHelpers} {namespace fusion=Neos\Fusion\ViewHelpers} -{namespace cr=Neos\ContentRepository\ViewHelpers} +{namespace search=Neos\ContentRepository\Search\ViewHelpers}