diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category.php b/app/code/Magento/Catalog/Model/ResourceModel/Category.php
index 6c9867359d40..fa68ae3f865e 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Category.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Category.php
@@ -11,6 +11,8 @@
*/
namespace Magento\Catalog\Model\ResourceModel;
+use Magento\Catalog\Model\Indexer\Category\Product\Processor;
+use Magento\Framework\DataObject;
use Magento\Framework\EntityManager\EntityManager;
/**
@@ -82,6 +84,11 @@ class Category extends AbstractResource
*/
protected $aggregateCount;
+ /**
+ * @var Processor
+ */
+ private $indexerProcessor;
+
/**
* Category constructor.
* @param \Magento\Eav\Model\Entity\Context $context
@@ -90,6 +97,7 @@ class Category extends AbstractResource
* @param \Magento\Framework\Event\ManagerInterface $eventManager
* @param Category\TreeFactory $categoryTreeFactory
* @param Category\CollectionFactory $categoryCollectionFactory
+ * @param Processor $indexerProcessor
* @param array $data
* @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
*/
@@ -100,6 +108,7 @@ public function __construct(
\Magento\Framework\Event\ManagerInterface $eventManager,
\Magento\Catalog\Model\ResourceModel\Category\TreeFactory $categoryTreeFactory,
\Magento\Catalog\Model\ResourceModel\Category\CollectionFactory $categoryCollectionFactory,
+ Processor $indexerProcessor,
$data = [],
\Magento\Framework\Serialize\Serializer\Json $serializer = null
) {
@@ -113,6 +122,7 @@ public function __construct(
$this->_categoryCollectionFactory = $categoryCollectionFactory;
$this->_eventManager = $eventManager;
$this->connectionName = 'catalog';
+ $this->indexerProcessor = $indexerProcessor;
$this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
->get(\Magento\Framework\Serialize\Serializer\Json::class);
}
@@ -197,6 +207,18 @@ protected function _beforeDelete(\Magento\Framework\DataObject $object)
$this->deleteChildren($object);
}
+ /**
+ * Mark Category indexer as invalid to be picked up by cron.
+ *
+ * @param DataObject $object
+ * @return $this
+ */
+ protected function _afterDelete(DataObject $object)
+ {
+ $this->indexerProcessor->markIndexerAsInvalid();
+ return parent::_afterDelete($object);
+ }
+
/**
* Delete children categories of specific category
*
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/CategoryTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/CategoryTest.php
index 4812751792f1..b7d05fd2b70e 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/CategoryTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/CategoryTest.php
@@ -7,6 +7,7 @@
namespace Magento\Catalog\Test\Unit\Model\ResourceModel;
use Magento\Catalog\Model\Factory;
+use Magento\Catalog\Model\Indexer\Category\Product\Processor;
use Magento\Catalog\Model\ResourceModel\Category;
use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory;
use Magento\Eav\Model\Config;
@@ -91,6 +92,11 @@ class CategoryTest extends \PHPUnit\Framework\TestCase
*/
private $serializerMock;
+ /**
+ * @var Processor|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $indexerProcessorMock;
+
/**
* {@inheritDoc}
*/
@@ -121,6 +127,9 @@ protected function setUp()
$this->collectionFactoryMock = $this->getMockBuilder(CollectionFactory::class)
->disableOriginalConstructor()
->getMock();
+ $this->indexerProcessorMock = $this->getMockBuilder(Processor::class)
+ ->disableOriginalConstructor()
+ ->getMock();
$this->serializerMock = $this->getMockBuilder(Json::class)->getMock();
@@ -131,6 +140,7 @@ protected function setUp()
$this->managerMock,
$this->treeFactoryMock,
$this->collectionFactoryMock,
+ $this->indexerProcessorMock,
[],
$this->serializerMock
);
diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Model/Plugin/Category.php b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Model/Plugin/Category.php
new file mode 100644
index 000000000000..ed841996ea07
--- /dev/null
+++ b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Model/Plugin/Category.php
@@ -0,0 +1,45 @@
+fulltextIndexerProcessor = $fulltextIndexerProcessor;
+ }
+
+ /**
+ * Mark fulltext indexer as invalid post-deletion of category.
+ *
+ * @param Resource $subjectCategory
+ * @param Resource $resultCategory
+ * @return Resource
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function afterDelete(Resource $subjectCategory, Resource $resultCategory) : Resource
+ {
+ $this->fulltextIndexerProcessor->markIndexerAsInvalid();
+
+ return $resultCategory;
+ }
+}
diff --git a/app/code/Magento/CatalogSearch/etc/adminhtml/di.xml b/app/code/Magento/CatalogSearch/etc/adminhtml/di.xml
index d6c72d883fed..2d41d17889e4 100644
--- a/app/code/Magento/CatalogSearch/etc/adminhtml/di.xml
+++ b/app/code/Magento/CatalogSearch/etc/adminhtml/di.xml
@@ -31,4 +31,7 @@
Magento\CatalogSearch\Ui\DataProvider\Product\AddFulltextFilterToCollection
+
+
+
diff --git a/app/code/Magento/CatalogSearch/etc/webapi_rest/di.xml b/app/code/Magento/CatalogSearch/etc/webapi_rest/di.xml
new file mode 100644
index 000000000000..c7293783dc60
--- /dev/null
+++ b/app/code/Magento/CatalogSearch/etc/webapi_rest/di.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
diff --git a/app/code/Magento/CatalogSearch/etc/webapi_soap/di.xml b/app/code/Magento/CatalogSearch/etc/webapi_soap/di.xml
new file mode 100644
index 000000000000..c7293783dc60
--- /dev/null
+++ b/app/code/Magento/CatalogSearch/etc/webapi_soap/di.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Category/ProductTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Category/ProductTest.php
index 6efd2638c0d5..dab47c818ece 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Category/ProductTest.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Category/ProductTest.php
@@ -27,6 +27,11 @@ class ProductTest extends \PHPUnit\Framework\TestCase
*/
protected $productResource;
+ /**
+ * @var \Magento\Catalog\Api\CategoryRepositoryInterface
+ */
+ private $categoryRepository;
+
protected function setUp()
{
/** @var \Magento\Framework\Indexer\IndexerInterface indexer */
@@ -39,6 +44,10 @@ protected function setUp()
$this->productResource = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
\Magento\Catalog\Model\ResourceModel\Product::class
);
+
+ $this->categoryRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+ \Magento\Catalog\Api\CategoryRepositoryInterface::class
+ );
}
/**
@@ -200,6 +209,25 @@ public function testCategoryCreate()
}
}
+ /**
+ * @magentoAppArea adminhtml
+ * @depends testReindexAll
+ */
+ public function testCatalogCategoryProductIndexInvalidateAfterDelete()
+ {
+ $indexerShouldBeValid = (bool)$this->indexer->isInvalid();
+
+ $categories = $this->getCategories(1);
+ $this->categoryRepository->delete(array_pop($categories));
+
+ $state = $this->indexer->getState();
+ $state->loadByIndexer($this->indexer->getId());
+ $status = $state->getStatus();
+
+ $this->assertFalse($indexerShouldBeValid);
+ $this->assertEquals(\Magento\Framework\Indexer\StateInterface::STATUS_INVALID, $status);
+ }
+
/**
* @param int $count
* @return Category[]
diff --git a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Indexer/Fulltext/Model/Plugin/CategoryTest.php b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Indexer/Fulltext/Model/Plugin/CategoryTest.php
new file mode 100644
index 000000000000..ec2a14abafc1
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Indexer/Fulltext/Model/Plugin/CategoryTest.php
@@ -0,0 +1,69 @@
+indexerProcessor = Bootstrap::getObjectManager()->create(Processor::class);
+ $this->categoryRepository = Bootstrap::getObjectManager()->create(CategoryRepositoryInterface::class);
+ }
+
+ /**
+ * @magentoDataFixture Magento/Catalog/_files/indexer_catalog_category.php
+ * @magentoAppArea adminhtml
+ */
+ public function testIndexerInvalidatedAfterCategoryDelete()
+ {
+ $this->indexerProcessor->reindexAll();
+ $isIndexerValid = (bool)$this->indexerProcessor->getIndexer()->isValid();
+
+ $category = $this->getCategories(1);
+ $this->categoryRepository->delete(array_pop($category));
+
+ $state = $this->indexerProcessor->getIndexer()->getState();
+ $state->loadByIndexer($this->indexerProcessor->getIndexerId());
+ $status = $state->getStatus();
+
+ $this->assertTrue($isIndexerValid);
+ $this->assertEquals(\Magento\Framework\Indexer\StateInterface::STATUS_INVALID, $status);
+ }
+
+ /**
+ * @param int $count
+ * @return Category[]
+ */
+ private function getCategories($count)
+ {
+ /** @var Category $category */
+ $category = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+ \Magento\Catalog\Model\Category::class
+ );
+
+ $result = $category->getCollection()->addAttributeToSelect('name')->getItems();
+ $result = array_slice($result, 2);
+
+ return array_slice($result, 0, $count);
+ }
+}