Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PAC-903: Add new validator for store_view_code #189

Merged
merged 7 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 <met@techdivision.com>
* @copyright 2024 TechDivision GmbH <info@techdivision.com>
* @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 <met@techdivision.com>
* @copyright 2024 TechDivision GmbH <info@techdivision.com>
* @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>
Loading