-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from techdivision/PAC-894
PAC-894 Add clean-up for grouped products
- Loading branch information
Showing
9 changed files
with
439 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
<?php | ||
/** | ||
* Copyright (c) 2024 TechDivision GmbH <info@techdivision.com> - 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\Grouped\Actions\Processors; | ||
|
||
use TechDivision\Import\Dbal\Collection\Actions\Processors\AbstractBaseProcessor; | ||
use TechDivision\Import\Product\Grouped\Utils\SqlStatementKeys; | ||
use TechDivision\Import\Product\Utils\MemberNames; | ||
|
||
/** | ||
* @copyright Copyright (c) 2024 TechDivision GmbH <info@techdivision.com> - TechDivision GmbH | ||
* @link http://www.techdivision.com | ||
* @author MET <met@techdivision.com> | ||
*/ | ||
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); | ||
} | ||
} |
196 changes: 196 additions & 0 deletions
196
src/Observers/CleanUpGroupedProductRelationObserver.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
<?php | ||
/** | ||
* Copyright (c) 2024 TechDivision GmbH <info@techdivision.com> - 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\Grouped\Observers; | ||
|
||
use Exception; | ||
use TechDivision\Import\Observers\StateDetectorInterface; | ||
use TechDivision\Import\Product\Grouped\Services\ProductGroupedProcessorInterface; | ||
use TechDivision\Import\Product\Grouped\Utils\ColumnKeys; | ||
use TechDivision\Import\Product\Grouped\Utils\ProductTypes; | ||
use TechDivision\Import\Product\Observers\AbstractProductImportObserver; | ||
use TechDivision\Import\Product\Utils\ConfigurationKeys; | ||
use TechDivision\Import\Product\Utils\MemberNames; | ||
|
||
/** | ||
* @copyright Copyright (c) 2024 TechDivision GmbH <info@techdivision.com> - TechDivision GmbH | ||
* @link http://www.techdivision.com | ||
* @author MET <met@techdivision.com> | ||
*/ | ||
class CleanUpGroupedProductRelationObserver extends AbstractProductImportObserver | ||
{ | ||
/** | ||
* @var ProductGroupedProcessorInterface | ||
*/ | ||
protected ProductGroupedProcessorInterface $productGroupedProcessor; | ||
|
||
/** | ||
* Initialize the observer with the passed grouped product data processor instance. | ||
* | ||
* @param ProductGroupedProcessorInterface $productGroupedProcessor The grouped product processor instance | ||
* @param StateDetectorInterface|null $stateDetector The state detector instance to use | ||
*/ | ||
public function __construct( | ||
ProductGroupedProcessorInterface $productGroupedProcessor, | ||
StateDetectorInterface $stateDetector = null | ||
) { | ||
// pass the state detector to the parent constructor | ||
parent::__construct($stateDetector); | ||
|
||
// initialize the grouped product processor instance | ||
$this->productGroupedProcessor = $productGroupedProcessor; | ||
} | ||
|
||
/** | ||
* Return's the grouped product processor instance. | ||
* | ||
* @return ProductGroupedProcessorInterface The grouped product processor instance | ||
*/ | ||
protected function getProductGroupedProcessor(): ProductGroupedProcessorInterface | ||
{ | ||
return $this->productGroupedProcessor; | ||
} | ||
|
||
/** | ||
* Process the observer's business logic. | ||
* | ||
* @return void | ||
* @throws Exception | ||
*/ | ||
protected function process() | ||
{ | ||
// query whether or not we've found a grouped product | ||
if ($this->getValue(ColumnKeys::PRODUCT_TYPE) !== ProductTypes::GROUPED) { | ||
return; | ||
} | ||
|
||
$subject = $this->getSubject(); | ||
$subjectConfiguration = $subject->getConfiguration(); | ||
|
||
if ($subjectConfiguration->hasParam(ConfigurationKeys::CLEAN_UP_LINKS) | ||
&& $subjectConfiguration->getParam(ConfigurationKeys::CLEAN_UP_LINKS)) { | ||
$this->cleanUpGrouped(); | ||
|
||
$subject->getSystemLogger()->info( | ||
$subject->appendExceptionSuffix( | ||
sprintf( | ||
'Successfully clean up grouped product with SKU "%s"', | ||
$this->getValue(ColumnKeys::SKU) | ||
) | ||
) | ||
); | ||
} | ||
} | ||
|
||
/** | ||
* Search for child products in the artefacts and check for differences in the database. | ||
* Remove entries in DB that do not exist in artefact. | ||
* | ||
* @return void | ||
* @throws Exception Is thrown if all the child products cannot be deleted | ||
*/ | ||
protected function cleanUpGrouped() | ||
{ | ||
// load the available artefacts from the subject | ||
$subject = $this->getSubject(); | ||
$artefacts = $subject->getArtefacts(); | ||
|
||
// return, if we do NOT have any grouped product artefacts | ||
if (!isset($artefacts[ProductGroupedObserver::ARTEFACT_TYPE])) { | ||
return; | ||
} | ||
|
||
// load the entity ID of the parent product | ||
$parentIdForArtefacts = $this->getLastEntityId(); | ||
|
||
// return, if we do NOT have any artefacts for the actual entity ID | ||
if (!isset($artefacts[ProductGroupedObserver::ARTEFACT_TYPE][$parentIdForArtefacts])) { | ||
return; | ||
} | ||
|
||
// initialize the array with the SKUs of the child IDs and the attribute codes | ||
$actualGrouped = []; | ||
|
||
// load the grouped product artefacts for the actual entity ID | ||
$allGrouped = $artefacts[ProductGroupedObserver::ARTEFACT_TYPE][$parentIdForArtefacts]; | ||
|
||
// iterate over the artefacts with the grouped product data | ||
foreach ($allGrouped as $groupedData) { | ||
// add the child SKU to the array | ||
$actualGrouped[] = $groupedData[ColumnKeys::GROUPED_CHILD_SKU]; | ||
} | ||
|
||
// load the row/entity ID of the parent product | ||
$parentId = $this->getLastPrimaryKey(); | ||
|
||
try { | ||
$this->cleanUpGroupedRelation($parentId, $actualGrouped); | ||
} catch (Exception $e) { | ||
// log a warning if debug mode has been enabled | ||
if ($subject->isDebugMode()) { | ||
$subject->getSystemLogger()->critical($subject->appendExceptionSuffix($e->getMessage())); | ||
} else { | ||
throw $e; | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Delete not exists import relations from database. | ||
* | ||
* @param int $parentProductId The ID of the parent product | ||
* @param array $childData The array of child products | ||
* | ||
* @return void | ||
* @throws Exception | ||
*/ | ||
protected function cleanUpGroupedRelation(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 child products from the database | ||
$this->getProductGroupedProcessor()->deleteProductRelation( | ||
[ | ||
MemberNames::PARENT_ID => $parentProductId, | ||
MemberNames::SKU => $childData, | ||
] | ||
); | ||
|
||
// log a debug message that the image has been removed | ||
$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 => child relation. | ||
* | ||
* @return int The PK to create the relation with | ||
*/ | ||
protected function getLastPrimaryKey(): int | ||
{ | ||
return (int)$this->getLastEntityId(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
<?php | ||
/** | ||
* Copyright (c) 2024 TechDivision GmbH <info@techdivision.com> - 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\Grouped\Repositories; | ||
|
||
use IteratorAggregate; | ||
use TechDivision\Import\Dbal\Utils\SqlCompilerInterface; | ||
use TechDivision\Import\Product\Grouped\Utils\SqlStatementKeys; | ||
|
||
/** | ||
* @copyright Copyright (c) 2024 TechDivision GmbH <info@techdivision.com> - TechDivision GmbH | ||
* @link http://www.techdivision.com | ||
* @author MET <met@techdivision.com> | ||
*/ | ||
class SqlStatementRepository extends \TechDivision\Import\Product\Repositories\SqlStatementRepository | ||
{ | ||
/** | ||
* The SQL statements. | ||
* | ||
* @var array | ||
*/ | ||
private array $statements = [ | ||
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))', | ||
]; | ||
|
||
/** | ||
* Initializes the SQL statement repository with the primary key and table prefix utility. | ||
* | ||
* @param IteratorAggregate<SqlCompilerInterface> $compilers The array with the compiler instances | ||
*/ | ||
public function __construct(IteratorAggregate $compilers) | ||
{ | ||
// pass primary key + table prefix utility to parent instance | ||
parent::__construct($compilers); | ||
|
||
// compile the SQL statements | ||
$this->compile($this->statements); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.