diff --git a/Model/Indexer/Product.php b/Model/Indexer/Product.php new file mode 100644 index 0000000..940ea75 --- /dev/null +++ b/Model/Indexer/Product.php @@ -0,0 +1,69 @@ +productIndexerRows = $productIndexerRows; + } + + /** + * Execute materialization on ids entities + * + * @param int[] $ids + * @throws \Magento\Framework\Exception\LocalizedException + * + * @return void + */ + public function execute($ids) + { + $this->productIndexerRows->execute($ids); + } + + /** + * Execute full indexation + * + * @return void + */ + public function executeFull() + { + // not implemented + } + + /** + * Execute partial indexation by ID list + * + * @param int[] $ids + * @throws \Magento\Framework\Exception\LocalizedException + * + * @return void + */ + public function executeList(array $ids) + { + $this->productIndexerRows->execute($ids); + } + + /** + * Execute partial indexation by ID + * + * @param int $id + * @throws \Magento\Framework\Exception\LocalizedException + * + * @return void + */ + public function executeRow($id) + { + $this->productIndexerRows->execute([$id]); + } +} diff --git a/Model/Indexer/Product/Action/Rows.php b/Model/Indexer/Product/Action/Rows.php new file mode 100644 index 0000000..28428a1 --- /dev/null +++ b/Model/Indexer/Product/Action/Rows.php @@ -0,0 +1,206 @@ +objectManager = $objectManager; + $this->scopeConfig = $scopeConfig; + $this->eventManager = $eventManager; + $this->productRepository = $productRepository; + $this->productType = $productType; + $this->api = $api; + } + + /** + * Execute action for given ids + * + * @param array|int $ids + * @throws \Magento\Framework\Exception\LocalizedException + * @return void + */ + public function execute($ids = null) + { + if (!$this->scopeConfig->getValue(Config::XML_PATH_PRODUCT_SYNCHRONIZATION_REAL_TIME_ENABLED)) { + return; + } + + if (!isset($ids) || empty($ids)) { + throw new \Magento\Framework\Exception\LocalizedException( + __('We can\'t rebuild the index for an undefined product.') + ); + } + + if (!is_array($ids)) { + $ids = [$ids]; + } + + foreach ($ids as $id) { + $this->reindexRow($id); + $this->updateParentProducts($id); + } + } + + /** + * Refresh entity index + * + * @param int $productId + * @return void + */ + protected function reindexRow($productId) + { + try { + $product = $this->productRepository->getById($productId); + } catch (NoSuchEntityException $e) { + $this->api->removeProduct($productId); + return; + } + + //Cancel if product visibility is not as defined + if ($product->getVisibility() != $this->scopeConfig->getValue(Config::XML_PATH_PRODUCT_SYNCHRONIZATION_VISIBILITY)) { + return; + } + + //Cancel if product is not saleable + if ($this->scopeConfig->getValue(Config::XML_PATH_PRODUCT_SYNCHRONIZATION_SALABLE_ONLY)) { + if (!$product->isSalable()) { + return; + } + } + + $store = $this->objectManager->get('Magento\Store\Model\StoreManagerInterface')->getStore(); + $imageUrl = $store->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA) . 'catalog/product' . $product->getImage(); + + $productItem = [ + 'id' => $product->getId(), + 'name' => $product->getName(), + 'description' => $product->getDescription(), + 'price' => $product->getFinalPrice(), + 'list_price' => $product->getPrice(), + 'image' => $imageUrl, + 'url' => $product->getUrlModel()->getUrl($product), + 'categories' => $product->getCategoryIds(), + 'sku' => $product->getSku(), + 'on_sale' => ($product->getFinalPrice() < $product->getPrice()), + ]; + + /** + * @todo Refactor to use fieldhandlers or similar + */ + $configFields = $this->scopeConfig->getValue( + Config::XML_PATH_PRODUCT_SYNCHRONIZATION_ADDITIONAL_FIELDS + ); + + $fields = explode(',', $configFields); + + foreach ($fields as $field) { + if (! isset($productItem[$field])) { + $productItem[$field] = $product->getData($field); + } + } + + $productObject = new \Magento\Framework\DataObject(); + $productObject->setData($productItem); + + $this->eventManager->dispatch('clerk_product_sync_before', ['product' => $productObject]); + + $this->api->addProduct($productObject->toArray()); + } + + /** + * Reindex parent configurable/bundle/grouped products + * + * @param int $productId + * @return void + * @see \Magento\Catalog\Model\Indexer\Product\Flat\AbstractAction::_getProductTypeInstances + */ + public function updateParentProducts($productId) + { + $parentIds = []; + + foreach ($this->getCompositeTypes() as $typeInstance) { + $parentIds = array_merge($parentIds, $typeInstance->getParentIdsByChild($productId)); + } + + foreach ($parentIds as $parentId) { + $this->reindexRow($parentId); + } + } + + /** + * @return AbstractType[] + * @throws \Magento\Framework\Exception\LocalizedException + */ + protected function getCompositeTypes() + { + if (null === $this->compositeTypes) { + $productEmulator = new \Magento\Framework\DataObject(); + foreach ($this->productType->getCompositeTypes() as $typeId) { + $productEmulator->setTypeId($typeId); + $this->compositeTypes[$typeId] = $this->productType->factory($productEmulator); + } + } + + return $this->compositeTypes; + } +} diff --git a/Observer/ProductDeleteAfterDoneObserver.php b/Observer/ProductDeleteAfterDoneObserver.php deleted file mode 100644 index c6be70f..0000000 --- a/Observer/ProductDeleteAfterDoneObserver.php +++ /dev/null @@ -1,45 +0,0 @@ -scopeConfig = $scopeConfig; - $this->api = $api; - } - - /** - * Remove product from Clerk - * - * @param Observer $observer - * @return void - */ - public function execute(\Magento\Framework\Event\Observer $observer) - { - if ($this->scopeConfig->getValue(Config::XML_PATH_PRODUCT_SYNCHRONIZATION_REAL_TIME_ENABLED)) { - $product = $observer->getProduct(); - - if ($product && $product->getId()) { - $this->api->removeProduct($product->getId()); - } - } - } -} \ No newline at end of file diff --git a/Observer/ProductSaveEntityAfterObserver.php b/Observer/ProductSaveEntityAfterObserver.php deleted file mode 100644 index 377c2e5..0000000 --- a/Observer/ProductSaveEntityAfterObserver.php +++ /dev/null @@ -1,115 +0,0 @@ -objectManager = $objectManager; - $this->scopeConfig = $scopeConfig; - $this->eventManager = $eventManager; - $this->api = $api; - } - - /** - * Add product to Clerk - * - * @param Observer $observer - * @return void - */ - public function execute(\Magento\Framework\Event\Observer $observer) - { - if ($this->scopeConfig->getValue(Config::XML_PATH_PRODUCT_SYNCHRONIZATION_REAL_TIME_ENABLED)) { - /** @var Product $product */ - $product = $observer->getProduct(); - - if ($product && $product->getId()) { - - //Cancel if product visibility is not as defined - if ($product->getVisibility() != $this->scopeConfig->getValue(Config::XML_PATH_PRODUCT_SYNCHRONIZATION_VISIBILITY)) { - return; - } - - //Cancel if product is not saleable - if ($this->scopeConfig->getValue(Config::XML_PATH_PRODUCT_SYNCHRONIZATION_SALABLE_ONLY)) { - if (!$product->isSalable()) { - return; - } - } - - $store = $this->objectManager->get('Magento\Store\Model\StoreManagerInterface')->getStore(); - $imageUrl = $store->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA) . 'catalog/product' . $product->getImage(); - - $productItem = [ - 'id' => $product->getId(), - 'name' => $product->getName(), - 'description' => $product->getDescription(), - 'price' => $product->getFinalPrice(), - 'list_price' => $product->getPrice(), - 'image' => $imageUrl, - 'url' => $product->getUrlModel()->getUrl($product), - 'categories' => $product->getCategoryIds(), - 'sku' => $product->getSku(), - 'on_sale' => ($product->getFinalPrice() < $product->getPrice()), - ]; - - /** - * @todo Refactor to use fieldhandlers or similar - */ - $configFields = $this->scopeConfig->getValue( - Config::XML_PATH_PRODUCT_SYNCHRONIZATION_ADDITIONAL_FIELDS - ); - - $fields = explode(',', $configFields); - - foreach ($fields as $field) { - if (! isset($productItem[$field])) { - $productItem[$field] = $product->getData($field); - } - } - - $productObject = new \Magento\Framework\DataObject(); - $productObject->setData($productItem); - - $this->eventManager->dispatch('clerk_product_sync_before', ['product' => $productObject]); - - $this->api->addProduct($productObject->toArray()); - } - } - } -} \ No newline at end of file diff --git a/Plugin/Catalog/Product.php b/Plugin/Catalog/Product.php new file mode 100644 index 0000000..5c83029 --- /dev/null +++ b/Plugin/Catalog/Product.php @@ -0,0 +1,61 @@ +indexer = $indexerRegistry->get('clerk_products'); + } + + /** + * @param \Magento\Catalog\Model\ResourceModel\Product $productResource + * @param \Closure $proceed + * @param \Magento\Framework\Model\AbstractModel $product + * @return mixed + */ + public function aroundSave( + \Magento\Catalog\Model\ResourceModel\Product $productResource, + \Closure $proceed, + \Magento\Framework\Model\AbstractModel $product + ) { + $productResource->addCommitCallback(function () use ($product) { + if (!$this->indexer->isScheduled()) { + $this->indexer->reindexRow($product->getId()); + } + }); + + return $proceed($product); + } + + /** + * @param \Magento\Catalog\Model\ResourceModel\Product $productResource + * @param \Closure $proceed + * @param \Magento\Framework\Model\AbstractModel $product + * @return mixed + */ + public function aroundDelete( + \Magento\Catalog\Model\ResourceModel\Product $productResource, + \Closure $proceed, + \Magento\Framework\Model\AbstractModel $product + ) { + $productResource->addCommitCallback(function () use ($product) { + if (!$this->indexer->isScheduled()) { + $this->indexer->reindexRow($product->getId()); + } + }); + + return $proceed($product); + } +} diff --git a/Plugin/Catalog/Product/Action.php b/Plugin/Catalog/Product/Action.php new file mode 100644 index 0000000..1b1118e --- /dev/null +++ b/Plugin/Catalog/Product/Action.php @@ -0,0 +1,67 @@ +indexer = $indexerRegistry->get('clerk_products'); + } + + /** + * @param \Magento\Catalog\Model\Product\Action $subject + * @param \Closure $closure + * @param array $productIds + * @param array $attrData + * @param $storeId + * @return mixed + */ + public function aroundUpdateAttributes( + \Magento\Catalog\Model\Product\Action $subject, + \Closure $closure, + array $productIds, + array $attrData, + $storeId + ) { + $result = $closure($productIds, $attrData, $storeId); + if (!$this->indexer->isScheduled()) { + $this->indexer->reindexList(array_unique($productIds)); + } + + return $result; + } + + /** + * @param \Magento\Catalog\Model\Product\Action $subject + * @param \Closure $closure + * @param array $productIds + * @param array $websiteIds + * @param $type + * @return mixed + */ + public function aroundUpdateWebsites( + \Magento\Catalog\Model\Product\Action $subject, + \Closure $closure, + array $productIds, + array $websiteIds, + $type + ) { + $result = $closure($productIds, $websiteIds, $type); + if (!$this->indexer->isScheduled()) { + $this->indexer->reindexList(array_unique($productIds)); + } + + return $result; + } +} diff --git a/Plugin/CatalogInventory/Stock/Item.php b/Plugin/CatalogInventory/Stock/Item.php new file mode 100644 index 0000000..9ec6467 --- /dev/null +++ b/Plugin/CatalogInventory/Stock/Item.php @@ -0,0 +1,49 @@ +indexer = $indexerRegistry->get('clerk_products'); + } + + public function aroundSave( + \Magento\CatalogInventory\Model\ResourceModel\Stock\Item $stockItemModel, + \Closure $proceed, + \Magento\CatalogInventory\Api\Data\StockItemInterface $stockItem + ) { + $stockItemModel->addCommitCallback(function () use ($stockItem) { + if (!$this->indexer->isScheduled()) { + $this->indexer->reindexRow($stockItem->getProductId()); + } + }); + + return $proceed($stockItem); + } + + public function aroundDelete( + \Magento\CatalogInventory\Model\ResourceModel\Stock\Item $stockItemResource, + \Closure $proceed, + \Magento\CatalogInventory\Api\Data\StockItemInterface $stockItem + ) { + $stockItemResource->addCommitCallback(function () use ($stockItem) { + if (!$this->indexer->isScheduled()) { + $this->indexer->reindexRow($stockItem->getProductId()); + } + }); + + return $proceed($stockItem); + } +} diff --git a/etc/adminhtml/events.xml b/etc/adminhtml/events.xml deleted file mode 100644 index 12f70ef..0000000 --- a/etc/adminhtml/events.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/etc/di.xml b/etc/di.xml index 86588cb..9ae4063 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -1,4 +1,13 @@ - \ No newline at end of file + + + + + + + + + + diff --git a/etc/indexer.xml b/etc/indexer.xml new file mode 100644 index 0000000..952b6c8 --- /dev/null +++ b/etc/indexer.xml @@ -0,0 +1,7 @@ + + + + Clerk Products + Clerk Products reindex when real time synchronization is enabled + + diff --git a/etc/mview.xml b/etc/mview.xml new file mode 100644 index 0000000..883dc77 --- /dev/null +++ b/etc/mview.xml @@ -0,0 +1,26 @@ + + + + + + +
+
+
+
+
+
+
+
+
+
+
+
+ + +