diff --git a/Classes/Indexer/AbstractNodeIndexer.php b/Classes/Indexer/AbstractNodeIndexer.php index 827db0e..2fc5922 100644 --- a/Classes/Indexer/AbstractNodeIndexer.php +++ b/Classes/Indexer/AbstractNodeIndexer.php @@ -52,6 +52,7 @@ abstract class AbstractNodeIndexer implements NodeIndexerInterface * Called by the Flow object framework after creating the object and resolving all dependencies. * * @param integer $cause Creation cause + * @throws \Neos\Flow\Configuration\Exception\InvalidConfigurationTypeException */ public function initializeObject($cause) { @@ -91,6 +92,8 @@ protected function evaluateEelExpression($expression, NodeInterface $node, $prop * @param string $fulltextExtractionExpression * @param array $fulltextIndexOfNode * @throws IndexingException + * @throws \Neos\ContentRepository\Exception\NodeException + * @throws \Neos\Eel\Exception */ protected function extractFulltext(NodeInterface $node, $propertyName, $fulltextExtractionExpression, array &$fulltextIndexOfNode) { @@ -118,6 +121,9 @@ protected function extractFulltext(NodeInterface $node, $propertyName, $fulltext * @param array $fulltextData * @param \Closure $nonIndexedPropertyErrorHandler * @return array + * @throws IndexingException + * @throws \Neos\ContentRepository\Exception\NodeException + * @throws \Neos\Eel\Exception */ protected function extractPropertiesAndFulltext(NodeInterface $node, array &$fulltextData, \Closure $nonIndexedPropertyErrorHandler = null) { @@ -169,4 +175,4 @@ protected function isFulltextEnabled(NodeInterface $node) return false; } -} \ No newline at end of file +} diff --git a/Classes/Indexer/NodeIndexingManager.php b/Classes/Indexer/NodeIndexingManager.php index a8150c6..e3e9839 100644 --- a/Classes/Indexer/NodeIndexingManager.php +++ b/Classes/Indexer/NodeIndexingManager.php @@ -37,6 +37,11 @@ class NodeIndexingManager */ protected $targetWorkspaceNamesForNodesToBeIndexed = []; + /** + * @var array + */ + protected $targetWorkspaceNamesForNodesToBeRemoved = []; + /** * the indexing batch size (from the settings) * @@ -71,28 +76,35 @@ public function injectSettings(array $settings) * Schedule a node for indexing * * @param NodeInterface $node - * @param mixed $targetWorkspace In case this is triggered during publishing, a Workspace will be passed in + * @param Workspace $targetWorkspace In case this is triggered during publishing, a Workspace will be passed in * @return void */ - public function indexNode(NodeInterface $node, $targetWorkspace = null) + public function indexNode(NodeInterface $node, Workspace $targetWorkspace = null) { - $this->nodesToBeRemoved->detach($node); - $this->nodesToBeIndexed->attach($node); - $this->targetWorkspaceNamesForNodesToBeIndexed[$node->getContextPath()] = $targetWorkspace instanceof Workspace ? $targetWorkspace->getName() : null; + // if this is triggered via afterNodePublishing, it could be a deletion, check and handle + if ($node->isRemoved() && $targetWorkspace !== null && $targetWorkspace->getBaseWorkspace() === null) { + $this->removeNode($node, $targetWorkspace); + } else { + $this->nodesToBeRemoved->detach($node); + $this->nodesToBeIndexed->attach($node); + $this->targetWorkspaceNamesForNodesToBeIndexed[$node->getContextPath()] = $targetWorkspace instanceof Workspace ? $targetWorkspace->getName() : null; - $this->flushQueuesIfNeeded(); + $this->flushQueuesIfNeeded(); + } } /** * Schedule a node for removal of the index * * @param NodeInterface $node + * @param Workspace $targetWorkspace In case this is triggered during publishing, a Workspace will be passed in * @return void */ - public function removeNode(NodeInterface $node) + public function removeNode(NodeInterface $node, Workspace $targetWorkspace = null) { $this->nodesToBeIndexed->detach($node); $this->nodesToBeRemoved->attach($node); + $this->targetWorkspaceNamesForNodesToBeRemoved[$node->getContextPath()] = $targetWorkspace instanceof Workspace ? $targetWorkspace->getName() : null; $this->flushQueuesIfNeeded(); } @@ -129,13 +141,18 @@ public function flushQueues() /** @var NodeInterface $nodeToBeRemoved */ foreach ($this->nodesToBeRemoved as $nodeToBeRemoved) { - $this->nodeIndexer->removeNode($nodeToBeRemoved); + if (isset($this->targetWorkspaceNamesForNodesToBeRemoved[$nodeToBeRemoved->getContextPath()])) { + $this->nodeIndexer->removeNode($nodeToBeRemoved, $this->targetWorkspaceNamesForNodesToBeRemoved[$nodeToBeRemoved->getContextPath()]); + } else { + $this->nodeIndexer->removeNode($nodeToBeRemoved); + } } $this->nodeIndexer->flush(); $this->nodesToBeIndexed = new \SplObjectStorage(); $this->nodesToBeRemoved = new \SplObjectStorage(); $this->targetWorkspaceNamesForNodesToBeIndexed = []; + $this->targetWorkspaceNamesForNodesToBeRemoved = []; }; if ($this->nodeIndexer instanceof BulkNodeIndexerInterface) { diff --git a/Classes/Package.php b/Classes/Package.php index bff7cd6..33024ff 100644 --- a/Classes/Package.php +++ b/Classes/Package.php @@ -54,13 +54,13 @@ public function registerIndexingSlots(Bootstrap $bootstrap) $settings = $configurationManager->getConfiguration(ConfigurationManager::CONFIGURATION_TYPE_SETTINGS, $this->getPackageKey()); if (isset($settings['realtimeIndexing']['enabled']) && $settings['realtimeIndexing']['enabled'] === true) { // handle changes to nodes - $bootstrap->getSignalSlotDispatcher()->connect(Node::class, 'nodeAdded', Indexer\NodeIndexingManager::class, 'indexNode'); - $bootstrap->getSignalSlotDispatcher()->connect(Node::class, 'nodeUpdated', Indexer\NodeIndexingManager::class, 'indexNode'); - $bootstrap->getSignalSlotDispatcher()->connect(Node::class, 'nodeRemoved', Indexer\NodeIndexingManager::class, 'removeNode'); + $bootstrap->getSignalSlotDispatcher()->connect(Node::class, 'nodeAdded', Indexer\NodeIndexingManager::class, 'indexNode', false); + $bootstrap->getSignalSlotDispatcher()->connect(Node::class, 'nodeUpdated', Indexer\NodeIndexingManager::class, 'indexNode', false); + $bootstrap->getSignalSlotDispatcher()->connect(Node::class, 'nodeRemoved', Indexer\NodeIndexingManager::class, 'removeNode', false); // all publishing calls (Workspace, PublishingService) eventually trigger this - and publishing is triggered in various ways $bootstrap->getSignalSlotDispatcher()->connect(Workspace::class, 'afterNodePublishing', Indexer\NodeIndexingManager::class, 'indexNode', false); // make sure we always flush at the end, regardless of indexingBatchSize - $bootstrap->getSignalSlotDispatcher()->connect(PersistenceManager::class, 'allObjectsPersisted', Indexer\NodeIndexingManager::class, 'flushQueues'); + $bootstrap->getSignalSlotDispatcher()->connect(PersistenceManager::class, 'allObjectsPersisted', Indexer\NodeIndexingManager::class, 'flushQueues', false); } } }