Skip to content

Commit

Permalink
Merge pull request #189 from techdivision/pac-903
Browse files Browse the repository at this point in the history
PAC-903: Add new validator for store_view_code
  • Loading branch information
kenza-ya authored Oct 11, 2024
2 parents 119135c + 774ec3b commit 36cac69
Show file tree
Hide file tree
Showing 3 changed files with 328 additions and 0 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
# Version 26.1.0

## Bugfixes

* None

## Features

* New validation added, whether the product of the website is assigned to the current shop view line
* `"import.callback.store.in.website.validator"`

# Version 26.0.2

## Bugfixes
Expand Down
312 changes: 312 additions & 0 deletions src/Observers/StoreWebsiteValidatorObserver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,312 @@
<?php

/**
* TechDivision\Import\Product\Observers\StoreWebsiteValidatorObserver
*
* PHP version 7
*
* @author MET <[email protected]>
* @copyright 2024 TechDivision GmbH <[email protected]>
* @license https://opensource.org/licenses/MIT
* @link https://github.com/techdivision/import
* @link http://www.techdivision.com
*/

namespace TechDivision\Import\Product\Observers;

use Exception;
use TechDivision\Import\Observers\StateDetectorInterface;
use TechDivision\Import\Product\Msi\Utils\ColumnKeys;
use TechDivision\Import\Product\Services\ProductBunchProcessorInterface;
use TechDivision\Import\Services\ImportProcessorInterface;
use TechDivision\Import\Product\Utils\MemberNames;
use TechDivision\Import\Utils\RegistryKeys;
use TechDivision\Import\Utils\StoreViewCodes;

/**
* Store view validator implementation.
*
* @author MET <[email protected]>
* @copyright 2024 TechDivision GmbH <[email protected]>
* @license https://opensource.org/licenses/MIT
* @link https://github.com/techdivision/import
* @link http://www.techdivision.com
*/
class StoreWebsiteValidatorObserver extends AbstractProductImportObserver
{
/**
* The store websites.
*
* @var array
*/
protected $storeWebsites = array();

/**
* The admin row
*
* @var array
*/
protected $adminRow = array();

/**
* The product bunch processor instance.
*
* @var ProductBunchProcessorInterface
*/
protected $productBunchProcessor;

/** @var array */
protected array $entity;

/** @var string */
protected string $lastEntityId;

/** @var ImportProcessorInterface */
protected $importProcessor;

/**
* @param ProductBunchProcessorInterface $productBunchProcessor
* @param ImportProcessorInterface $importProcessor
* @param StateDetectorInterface|null $stateDetector
*/
public function __construct(
ProductBunchProcessorInterface $productBunchProcessor,
ImportProcessorInterface $importProcessor,
StateDetectorInterface $stateDetector = null
) {
// initialize the bunch processor instance
$this->productBunchProcessor = $productBunchProcessor;
$this->importProcessor = $importProcessor;
// pass the processor and the state detector to the parent constructor
parent::__construct($stateDetector);
}

/**
* @return void
* @throws \Exception
*/
public function process()
{
$sku = $this->getValue(ColumnKeys::SKU);
$storeViewCode = $this->getValue(ColumnKeys::STORE_VIEW_CODE);
$productWebsites = $this->getValue(ColumnKeys::PRODUCT_WEBSITES, [], [$this, 'explode']);

// Initialize the store view code
$this->getSubject()->prepareStoreViewCode();

// Handle product websites for admin store view
if ($this->isAdminStoreView()) {
$this->setAdminProductWebsites($sku, $productWebsites);
}
// Init data
$this->setLastEntityRowId($sku);
$this->setStoreWebsites();

// if the value is null or empty, it is not processed
if ($this->isNullable($storeViewCode)) {
return;
}

// Get or resolve product websites
$productWebsites = $this->resolveProductWebsites($productWebsites, $sku);

// Validate store view codes by website code
$storeViewCodesByWebsiteCode = $this->getStoreViewCodesForWebsites($productWebsites);
foreach ($productWebsites as $productWebsite) {
$this->validateStoreViewCode($storeViewCode, $storeViewCodesByWebsiteCode, $productWebsite, $sku);
}
}

/**
* @return array|mixed|null
*/
private function resolveStoreViewCode()
{
$storeViewCode = $this->getValue(ColumnKeys::STORE_VIEW_CODE);
if ($this->isNullable($storeViewCode)) {
$storeViewCode = $this->getSubject()->getDefaultStoreViewCode();
}
return $storeViewCode;
}

/**
* @return bool
*/
private function isAdminStoreView()
{
return $this->getStoreViewCode(StoreViewCodes::ADMIN) === StoreViewCodes::ADMIN;
}

/**
* @param $sku
* @param $productWebsites
* @return void
*/
private function setAdminProductWebsites($sku, $productWebsites)
{
$this->adminRow[$sku][ColumnKeys::PRODUCT_WEBSITES] = $productWebsites;
}

/**
* @param $productWebsites
* @param $sku
* @return mixed
*/
private function resolveProductWebsites($productWebsites, $sku)
{
if ($this->isNullable($productWebsites) && $this->entity[MemberNames::ENTITY_ID] === (int)$this->lastEntityId) {
return $this->adminRow[$sku][ColumnKeys::PRODUCT_WEBSITES];
}
return $productWebsites;
}

/**
* @param $productWebsites
* @return array
*/
private function getStoreViewCodesForWebsites($productWebsites)
{
$storeViewCodesByWebsiteCode = [];
foreach ($productWebsites as $productWebsite) {
if (isset($this->storeWebsites[$productWebsite])) {
$websiteCode = $this->storeWebsites[$productWebsite]['code'];

if (!isset($storeViewCodesByWebsiteCode[$productWebsite])) {
$storeViewCodesByWebsiteCode[$productWebsite] = [];
}

// Merge the store view codes
$storeViewCodesByWebsiteCode[$productWebsite] = array_merge(
$storeViewCodesByWebsiteCode[$productWebsite],
$this->getStoreViewCodesByWebsiteCode($websiteCode)
);
}
}
return $storeViewCodesByWebsiteCode;
}

/**
* @param $storeViewCode
* @param $storeViewCodesByWebsiteCode
* @param $productWebsite
* @param $sku
* @return void
* @throws Exception
*/
private function validateStoreViewCode($storeViewCode, $storeViewCodesByWebsiteCode, $productWebsite, $sku)
{
if (!in_array($storeViewCode, $storeViewCodesByWebsiteCode[$productWebsite])) {
$message = sprintf(
'The store "%s" for SKU "%s" does not belong to the website "%s". Please check your data.',
$storeViewCode,
$sku,
$productWebsite
);

$this->getSubject()
->getSystemLogger()
->warning($this->getSubject()->appendExceptionSuffix($message));

$this->getSubject()->mergeStatus([
RegistryKeys::NO_STRICT_VALIDATIONS => [
basename($this->getSubject()->getFilename()) => [
$this->getSubject()->getLineNumber() => [
ColumnKeys::STORE_VIEW_CODE => $message
]
]
]
]);
}
}

/**
* Query whether or not the passed value IS empty and empty values are allowed.
*
* @param string $attributeValue The attribute value to query for
*
* @return boolean TRUE if empty values are allowed and the passed value IS empty
*/
protected function isNullable($attributeValue)
{
return $attributeValue === '' || $attributeValue === null || empty($attributeValue);
}

/**
* Returns an array with the codes of the store views related with the passed website code.
*
* @param string $websiteCode The code of the website to return the store view codes for
*
* @return array The array with the matching store view codes
*/
protected function getStoreViewCodesByWebsiteCode($websiteCode)
{
return $this->getSubject()->getStoreViewCodesByWebsiteCode($websiteCode);
}

/**
* Set's the ID of the product that has been created recently.
*
* @param string $lastEntityId The entity ID
*
* @return void
*/
protected function setLastEntityId($lastEntityId)
{
$this->getSubject()->setLastEntityId($lastEntityId);
}

/**
* Return's the ID of the product that has been created recently.
*
* @return string The entity Id
*/
protected function getLastEntityId()
{
return $this->getSubject()->getLastEntityId();
}

/**
* Return's the product bunch processor instance.
*
* @return ProductBunchProcessorInterface The product bunch processor instance
*/
protected function getProductBunchProcessor()
{
return $this->productBunchProcessor;
}

/**
* Load's and return's the product with the passed SKU.
*
* @param string $sku The SKU of the product to load
*
* @return array The product
*/
protected function loadProduct($sku)
{
return $this->getProductBunchProcessor()->loadProduct($sku);
}

/**
* @return void
*/
public function setLastEntityRowId($sku): void
{
if (!$this->hasBeenProcessed($sku)) {
$this->entity = $this->loadProduct($sku);
$this->setLastEntityId($this->entity[MemberNames::ENTITY_ID]);
$this->lastEntityId = $this->getLastEntityId();
}
}

/**
* @return void
*/
protected function setStoreWebsites()
{
// initialize the array with the store websites
foreach ($this->importProcessor->getStoreWebsites() as $storeWebsite) {
$this->storeWebsites[$storeWebsite[MemberNames::CODE]] = $storeWebsite;
}
}
}
5 changes: 5 additions & 0 deletions symfony/Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -858,6 +858,11 @@
<argument type="service" id="import_product.utils.entity.type.code.mapping"/>
</service>

<service id="import_product.store.in.website.validator.observer" class="TechDivision\Import\Product\Observers\StoreWebsiteValidatorObserver">
<argument type="service" id="import_product.processor.product.bunch"/>
<argument type="service" id="import.processor.import"/>
</service>

</services>

</container>

0 comments on commit 36cac69

Please sign in to comment.