diff --git a/Classes/Indexer/NodeIndexer.php b/Classes/Indexer/NodeIndexer.php index 192e35a..5ed8f1c 100644 --- a/Classes/Indexer/NodeIndexer.php +++ b/Classes/Indexer/NodeIndexer.php @@ -3,6 +3,7 @@ namespace Flowpack\SimpleSearch\ContentRepositoryAdaptor\Indexer; +use Flowpack\SimpleSearch\ContentRepositoryAdaptor\Service\NodeTypeIndexingConfiguration; use Flowpack\SimpleSearch\Domain\Service\IndexInterface; use Neos\ContentRepository\Domain\Model\NodeInterface; use Neos\ContentRepository\Domain\Repository\WorkspaceRepository; @@ -14,8 +15,10 @@ use Neos\ContentRepository\Search\Indexer\AbstractNodeIndexer; use Neos\Eel\Exception; use Neos\Flow\Annotations as Flow; +use Neos\Flow\Log\Utility\LogEnvironment; use Neos\Flow\Persistence\PersistenceManagerInterface; use Neos\Flow\Security\Context; +use Psr\Log\LoggerInterface; use Symfony\Component\Yaml\Yaml; /** @@ -83,6 +86,18 @@ class NodeIndexer extends AbstractNodeIndexer */ protected $indexedNodeData = []; + /** + * @Flow\Inject + * @var NodeTypeIndexingConfiguration + */ + protected $nodeTypeIndexingConfiguration; + + /** + * @Flow\Inject + * @var LoggerInterface + */ + protected $logger; + /** * Called by the Flow object framework after creating the object and resolving all dependencies. * @@ -121,6 +136,11 @@ public function getIndexClient(): IndexInterface */ public function indexNode(NodeInterface $node, $targetWorkspaceName = null, $indexVariants = true): void { + if ($this->nodeTypeIndexingConfiguration->isIndexable($node->getNodeType()) === false) { + $this->logger->debug(sprintf('Node "%s" (%s) skipped, Node Type is not allowed in the index.', $node->getContextPath(), $node->getNodeType()), LogEnvironment::fromMethodName(__METHOD__)); + return; + } + if ($indexVariants === true) { $this->indexAllNodeVariants($node); return; diff --git a/Classes/Service/NodeTypeIndexingConfiguration.php b/Classes/Service/NodeTypeIndexingConfiguration.php new file mode 100644 index 0000000..e78157e --- /dev/null +++ b/Classes/Service/NodeTypeIndexingConfiguration.php @@ -0,0 +1,77 @@ +settings === null || !is_array($this->settings)) { + return true; + } + + if (isset($this->settings[$nodeType->getName()]['indexed'])) { + return (bool)$this->settings[$nodeType->getName()]['indexed']; + } + + $nodeTypeParts = explode(':', $nodeType->getName()); + $namespace = reset($nodeTypeParts) . ':*'; + if (isset($this->settings[$namespace]['indexed'])) { + return (bool)$this->settings[$namespace]['indexed']; + } + if (isset($this->settings['*']['indexed'])) { + return (bool)$this->settings['*']['indexed']; + } + + return false; + } + + /** + * @return array + * @throws Exception + */ + public function getIndexableConfiguration(): array + { + $nodeConfigurations = []; + /** @var NodeType $nodeType */ + foreach ($this->nodeTypeManager->getNodeTypes(false) as $nodeType) { + $nodeConfigurations[$nodeType->getName()] = $this->isIndexable($nodeType); + } + + return $nodeConfigurations; + } +} \ No newline at end of file diff --git a/Configuration/Testing/NodeTypes.yaml b/Configuration/Testing/NodeTypes.yaml new file mode 100644 index 0000000..ef882f5 --- /dev/null +++ b/Configuration/Testing/NodeTypes.yaml @@ -0,0 +1,7 @@ +'Flowpack.SimpleSearch.ContentRepositoryAdaptor:BaseType': + superTypes: { } +'Flowpack.SimpleSearch.ContentRepositoryAdaptor:Type1': + superTypes: + 'Flowpack.SimpleSearch.ContentRepositoryAdaptor:BaseType': true +'Flowpack.SimpleSearch.ContentRepositoryAdaptor:Type2': + superTypes: { } diff --git a/Configuration/Testing/Settings.yaml b/Configuration/Testing/Settings.yaml new file mode 100644 index 0000000..1486d17 --- /dev/null +++ b/Configuration/Testing/Settings.yaml @@ -0,0 +1,11 @@ +Neos: + ContentRepository: + Search: + realtimeIndexing: + enabled: false + defaultConfigurationPerNodeType: + '*': + indexed: true + 'Flowpack.SimpleSearch.ContentRepositoryAdaptor:Type1': + indexed: false + diff --git a/README.md b/README.md index 393e281..136bb61 100644 --- a/README.md +++ b/README.md @@ -48,3 +48,30 @@ and configure the DB connection as needed: value: '%env:DATABASE_PASSWORD%' The `arguments` are the index identifier (can be chosen freely) and the DSN. + +## Exclude NodeTypes from indexing + +By default the indexing processes all NodeTypes, but you can change this in your *Settings.yaml*: + +```yaml +Neos: + ContentRepository: + Search: + defaultConfigurationPerNodeType: + '*': + indexed: true + 'Neos.Neos:FallbackNode': + indexed: false + 'Neos.Neos:Shortcut': + indexed: false + 'Neos.Neos:ContentCollection': + indexed: false +``` + +You need to explicitly configure the individual NodeTypes (this feature does not check the Super Type configuration). +But you can use a special notation to configure a full namespace, `Acme.AcmeCom:*` will be applied for all node +types in the `Acme.AcmeCom` namespace. The most specific configuration is used in this order: + +- NodeType name (`Neos.Neos:Shortcut`) +- Full namespace notation (`Neos.Neos:*`) +- Catch all (`*`) diff --git a/Tests/Functional/Service/NodeTypeIndexingConfigurationTest.php b/Tests/Functional/Service/NodeTypeIndexingConfigurationTest.php new file mode 100644 index 0000000..1082bd5 --- /dev/null +++ b/Tests/Functional/Service/NodeTypeIndexingConfigurationTest.php @@ -0,0 +1,79 @@ +nodeTypeManager = $this->objectManager->get(NodeTypeManager::class); + $this->nodeTypeIndexingConfiguration = $this->objectManager->get(NodeTypeIndexingConfiguration::class); + } + + public function nodeTypeDataProvider(): array + { + return [ + 'notIndexable' => [ + 'nodeTypeName' => 'Flowpack.SimpleSearch.ContentRepositoryAdaptor:Type1', + 'expected' => false, + ], + 'indexable' => [ + 'nodeTypeName' => 'Flowpack.SimpleSearch.ContentRepositoryAdaptor:Type2', + 'expected' => true, + ], + ]; + } + + /** + * @test + * @dataProvider nodeTypeDataProvider + * + * @param string $nodeTypeName + * @param bool $expected + * @throws \Neos\ContentRepository\Exception\NodeTypeNotFoundException + */ + public function isIndexable(string $nodeTypeName, bool $expected): void + { + self::assertEquals($expected, $this->nodeTypeIndexingConfiguration->isIndexable($this->nodeTypeManager->getNodeType($nodeTypeName))); + } + + /** + * @test + * @dataProvider nodeTypeDataProvider + * + * @param string $nodeTypeName + * @param bool $expected + */ + public function getIndexableConfiguration(string $nodeTypeName, bool $expected): void + { + $indexableConfiguration = $this->nodeTypeIndexingConfiguration->getIndexableConfiguration(); + self::assertEquals($indexableConfiguration[$nodeTypeName], $expected); + } +}