diff --git a/Classes/Command/IndexCommandController.php b/Classes/Command/IndexCommandController.php index b14d4b3..70816ed 100644 --- a/Classes/Command/IndexCommandController.php +++ b/Classes/Command/IndexCommandController.php @@ -50,7 +50,6 @@ class IndexCommandController extends CommandController */ public function indexCommand($identifier) { - // TODO: Also allow to index everything? try { $this->indexerFactory->getIndexer($identifier)->indexAllDocuments(); $this->outputLine($identifier . ' was indexed.'); @@ -58,4 +57,19 @@ class IndexCommandController extends CommandController $this->outputLine('No indexer found for: ' . $identifier); } } + + /** + * Will delete the given identifier. + * + * @param string $identifier + */ + public function deleteCommand($identifier) + { + try { + $this->indexerFactory->getIndexer($identifier)->delete(); + $this->outputLine($identifier . ' was deleted.'); + } catch (NoMatchingIndexerException $e) { + $this->outputLine('No indexer found for: ' . $identifier); + } + } } diff --git a/Classes/Connection/ConnectionInterface.php b/Classes/Connection/ConnectionInterface.php index a130f9e..59cf9f8 100644 --- a/Classes/Connection/ConnectionInterface.php +++ b/Classes/Connection/ConnectionInterface.php @@ -77,4 +77,13 @@ interface ConnectionInterface * @return SearchResultInterface */ public function search(SearchRequestInterface $searchRequest); + + /** + * Will delete the whole index / db. + * + * @param string $documentType + * + * @return void + */ + public function deleteIndex($documentType); } diff --git a/Classes/Connection/Elasticsearch.php b/Classes/Connection/Elasticsearch.php index 4c66b6a..8a3cb2b 100644 --- a/Classes/Connection/Elasticsearch.php +++ b/Classes/Connection/Elasticsearch.php @@ -156,6 +156,18 @@ class Elasticsearch implements Singleton, ConnectionInterface ); } + public function deleteIndex($documentType) + { + $index = $this->connection->getClient()->getIndex('typo3content'); + + if (! $index->exists()) { + $this->logger->notice('Index did not exist, therefore was not deleted.', [$documentType, 'typo3content']); + return; + } + + $index->delete(); + } + /** * Execute given callback with Elastica Type based on provided documentType * diff --git a/Classes/Domain/Index/AbstractIndexer.php b/Classes/Domain/Index/AbstractIndexer.php index de8072d..0f986eb 100644 --- a/Classes/Domain/Index/AbstractIndexer.php +++ b/Classes/Domain/Index/AbstractIndexer.php @@ -105,6 +105,13 @@ abstract class AbstractIndexer implements IndexerInterface $this->logger->info('Finish indexing'); } + public function delete() + { + $this->logger->info('Start deletion of index.'); + $this->connection->deleteIndex($this->getDocumentName()); + $this->logger->info('Finish deletion.'); + } + /** * @return \Generator */ diff --git a/Classes/Domain/Index/IndexerInterface.php b/Classes/Domain/Index/IndexerInterface.php index 5a4ca6c..72ebb9d 100644 --- a/Classes/Domain/Index/IndexerInterface.php +++ b/Classes/Domain/Index/IndexerInterface.php @@ -33,9 +33,9 @@ interface IndexerInterface public function indexAllDocuments(); /** - * Fetches a single document from the indexerService and pushes it to the connection. + * Fetches a single document and pushes it to the connection. * - * @param string $identifier identifier, the indexer needs to identify a single document + * @param string $identifier * * @return void */ @@ -49,4 +49,11 @@ interface IndexerInterface * @return void */ public function setIdentifier($identifier); + + /** + * Delete the whole index. + * + * @return void + */ + public function delete(); } diff --git a/Documentation/source/usage.rst b/Documentation/source/usage.rst index 1ca50d2..fb98a99 100644 --- a/Documentation/source/usage.rst +++ b/Documentation/source/usage.rst @@ -18,6 +18,19 @@ This will index the table ``tt_content`` using the :ref:`TcaIndexer`. Only one index per call is available, to run multiple indexers, just make multiple calls. The indexers have to be defined in TypoScript via :ref:`configuration_options_index`. +.. _usage_manual_deletion: + +Manual deletion +--------------- + +You can trigger deletion for a single index from CLI:: + + ./typo3/cli_dispatch.phpsh extbase index:delete --identifier 'tt_content' + +This will delete the index for the table ``tt_content``. + +Only one delete per call is available, to run multiple deletions, just make multiple calls. + .. _usage_auto_indexing: Auto indexing diff --git a/Tests/Functional/Connection/Elasticsearch/IndexDeletionTest.php b/Tests/Functional/Connection/Elasticsearch/IndexDeletionTest.php new file mode 100644 index 0000000..8297a2a --- /dev/null +++ b/Tests/Functional/Connection/Elasticsearch/IndexDeletionTest.php @@ -0,0 +1,50 @@ + + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +use Codappix\SearchCore\Domain\Index\IndexerFactory; +use TYPO3\CMS\Extbase\Object\ObjectManager; + +class IndexDeletionTest extends AbstractFunctionalTestCase +{ + /** + * @test + */ + public function indexIsDeleted() + { + $this->client->getIndex('typo3content')->create(); + $this->assertTrue( + $this->client->getIndex('typo3content')->exists(), + 'Could not create index for test.' + ); + + \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class) + ->get(IndexerFactory::class) + ->getIndexer('tt_content') + ->delete() + ; + + $this->assertFalse( + $this->client->getIndex('typo3content')->exists(), + 'Index could not be deleted through command controller.' + ); + } +} diff --git a/Tests/Unit/Command/IndexCommandControllerTest.php b/Tests/Unit/Command/IndexCommandControllerTest.php index 4c81672..9dcc7f3 100644 --- a/Tests/Unit/Command/IndexCommandControllerTest.php +++ b/Tests/Unit/Command/IndexCommandControllerTest.php @@ -91,4 +91,41 @@ class IndexCommandControllerTest extends AbstractUnitTestCase $this->subject->indexCommand('allowedTable'); } + + /** + * @test + */ + public function deletionIsPossible() + { + $indexerMock = $this->getMockBuilder(TcaIndexer::class) + ->disableOriginalConstructor() + ->getMock(); + $this->subject->expects($this->once()) + ->method('outputLine') + ->with('allowedTable was deleted.'); + $this->indexerFactory->expects($this->once()) + ->method('getIndexer') + ->with('allowedTable') + ->will($this->returnValue($indexerMock)); + + $indexerMock->expects($this->once()) + ->method('delete'); + $this->subject->deleteCommand('allowedTable'); + } + + /** + * @test + */ + public function deletionForNonExistingIndexerDoesNotWork() + { + $this->subject->expects($this->once()) + ->method('outputLine') + ->with('No indexer found for: nonAllowedTable'); + $this->indexerFactory->expects($this->once()) + ->method('getIndexer') + ->with('nonAllowedTable') + ->will($this->throwException(new NoMatchingIndexerException)); + + $this->subject->deleteCommand('nonAllowedTable'); + } }