diff --git a/src/Actions/Processors/ProductRelationDeleteProcessor.php b/src/Actions/Processors/ProductRelationDeleteProcessor.php new file mode 100644 index 0000000..3264a8e --- /dev/null +++ b/src/Actions/Processors/ProductRelationDeleteProcessor.php @@ -0,0 +1,61 @@ + - TechDivision GmbH + * All rights reserved + * + * This product includes proprietary software developed at TechDivision GmbH, Germany + * For more information see https://www.techdivision.com + * + * To obtain a valid license for using this software, please contact us at + * license@techdivision.com + */ +declare(strict_types=1); + +namespace TechDivision\Import\Product\Variant\Actions\Processors; + +use TechDivision\Import\Dbal\Collection\Actions\Processors\AbstractBaseProcessor; +use TechDivision\Import\Product\Variant\Utils\MemberNames; +use TechDivision\Import\Product\Variant\Utils\SqlStatementKeys; + +/** + * @copyright Copyright (c) 2024 TechDivision GmbH - TechDivision GmbH + * @link http://www.techdivision.com + * @author MET + */ +class ProductRelationDeleteProcessor extends AbstractBaseProcessor +{ + /** + * Delete all relations that are not imported. + * + * @param array $row The row to persist + * @param string|null $name The name of the prepared statement that has to be executed + * @param string|null $primaryKeyMemberName The primary key member name of the entity to use + * + * @return void + */ + public function execute($row, $name = null, $primaryKeyMemberName = null): void + { + // load the SKUs from the row + $skus = $row[MemberNames::SKU]; + + // make sure we've an array + if (!is_array($skus)) { + $skus = [$skus]; + } + + // all SKUs that should NOT be deleted + $vals = implode(',', $skus); + + // concatenate the SKUs as comma separated SQL string + $vals = str_replace(',', "','", sprintf("'%s'", $vals)); + + // replace the placeholders + $sql = str_replace( + [':parent_id', ':skus'], + [$row[MemberNames::PARENT_ID], $vals], + $this->loadStatement(SqlStatementKeys::DELETE_PRODUCT_RELATION) + ); + + $this->getConnection()->query($sql); + } +} diff --git a/src/Observers/CleanUpVariantProductRelationObserver.php b/src/Observers/CleanUpVariantProductRelationObserver.php index ae065aa..70f80d5 100644 --- a/src/Observers/CleanUpVariantProductRelationObserver.php +++ b/src/Observers/CleanUpVariantProductRelationObserver.php @@ -14,6 +14,7 @@ namespace TechDivision\Import\Product\Variant\Observers; +use Exception; use TechDivision\Import\Utils\ProductTypes; use TechDivision\Import\Observers\StateDetectorInterface; use TechDivision\Import\Product\Observers\AbstractProductImportObserver; @@ -154,6 +155,7 @@ protected function cleanUpVariants() // delete not exists import variants from database $this->cleanUpVariantChildren($parentId, $actualVariants); $this->cleanUpVariantAttributes($parentId, $actualAttributes); + $this->cleanUpVariantRelation($parentId, $actualVariants); } catch (\Exception $e) { // log a warning if debug mode has been enabled if ($this->getSubject()->isDebugMode()) { @@ -197,7 +199,7 @@ protected function cleanUpVariantChildren($parentProductId, array $childData) // log a debug message that the image has been removed $this->getSubject() ->getSystemLogger() - ->debug( + ->info( $this->getSubject()->appendExceptionSuffix( sprintf( 'Successfully clean up variants for product with SKU "%s" except "%s"', @@ -261,6 +263,44 @@ protected function cleanUpVariantAttributes($parentProductId, array $actualAttri ); } + /** + * Delete not exists import relations from database. + * + * @param int $parentProductId The ID of the parent product + * @param array $childData The array of variants + * + * @return void + * @throws Exception + */ + protected function cleanUpVariantRelation(int $parentProductId, array $childData) + { + // we don't want to delete everything + if (empty($childData)) { + return; + } + + // load the SKU of the parent product + $parentSku = $this->getValue(ColumnKeys::SKU); + + // remove the old variants from the database + $this->getProductVariantProcessor()->deleteProductRelation( + [ + MemberNames::PARENT_ID => $parentProductId, + MemberNames::SKU => $childData, + ] + ); + + $subject = $this->getSubject(); + $subject->getSystemLogger()->info( + $subject->appendExceptionSuffix( + sprintf( + 'Successfully clean up relations for product with SKU "%s"', + $parentSku + ) + ) + ); + } + /** * Return's the PK to create the product => variant relation. * diff --git a/src/Repositories/SqlStatementRepository.php b/src/Repositories/SqlStatementRepository.php index 12f5d74..4ebbf63 100644 --- a/src/Repositories/SqlStatementRepository.php +++ b/src/Repositories/SqlStatementRepository.php @@ -89,6 +89,12 @@ class SqlStatementRepository extends \TechDivision\Import\Product\Repositories\S WHERE product_id = :product_id AND attribute_id NOT IN (:attribute_ids)', + SqlStatementKeys::DELETE_PRODUCT_RELATION => + 'DELETE + FROM ${table:catalog_product_relation} + WHERE parent_id = :parent_id + AND child_id + NOT IN (SELECT `entity_id` FROM ${table:catalog_product_entity} WHERE `sku` IN (:skus))', ); /** diff --git a/src/Services/ProductVariantProcessor.php b/src/Services/ProductVariantProcessor.php index 35e36a2..96a7919 100755 --- a/src/Services/ProductVariantProcessor.php +++ b/src/Services/ProductVariantProcessor.php @@ -651,4 +651,17 @@ public function deleteProductSuperAttribute(array $row, $name = null) { return $this->getProductSuperAttributeAction()->delete($row, $name); } + + /** + * Deletes the passed product relation data. + * + * @param array $row The product relation to be deleted + * @param string|null $name The name of the prepared statement that has to be executed + * + * @return void + */ + public function deleteProductRelation(array $row, string $name = null): void + { + $this->getProductRelationAction()->delete($row, $name); + } } diff --git a/src/Services/ProductVariantProcessorInterface.php b/src/Services/ProductVariantProcessorInterface.php index bbb43c4..b8806fb 100644 --- a/src/Services/ProductVariantProcessorInterface.php +++ b/src/Services/ProductVariantProcessorInterface.php @@ -209,4 +209,14 @@ public function deleteProductSuperLink(array $row, $name = null); * @return string The ID of the persisted product super attribute entity */ public function deleteProductSuperAttribute(array $row, $name = null); + + /** + * Deletes the passed product relation data. + * + * @param array $row The product relation to be deleted + * @param null|string $name The name of the prepared statement that has to be executed + * + * @return void + */ + public function deleteProductRelation(array $row, string $name = null): void; } diff --git a/src/Utils/SqlStatementKeys.php b/src/Utils/SqlStatementKeys.php index 61a0396..3a9ab86 100644 --- a/src/Utils/SqlStatementKeys.php +++ b/src/Utils/SqlStatementKeys.php @@ -89,6 +89,13 @@ class SqlStatementKeys extends \TechDivision\Import\Product\Utils\SqlStatementKe */ const DELETE_PRODUCT_SUPER_ATTRIBUTE = 'delete.product_super_attribute'; + /** + * The SQL statement to delete a product relation. + * + * @var string + */ + public const DELETE_PRODUCT_RELATION = 'delete.product_relation'; + /** * The SQL statement to create a new product super attribute label. * diff --git a/symfony/Resources/config/services.xml b/symfony/Resources/config/services.xml index 3a81ffb..2f2d6e8 100644 --- a/symfony/Resources/config/services.xml +++ b/symfony/Resources/config/services.xml @@ -116,6 +116,11 @@ + + + + + @@ -132,6 +137,11 @@ + + + + + @@ -147,7 +157,7 @@ - + @@ -234,4 +244,4 @@ - \ No newline at end of file +