<?php
declare(strict_types=1);
namespace MetalementsTheme\Subscriber;
use Shopware\Core\Framework\Struct\ArrayStruct;
use Shopware\Core\Framework\Struct\ArrayEntity;
use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Content\Media\DataAbstractionLayer\MediaRepositoryDecorator;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
class ProductVariantenMedia implements EventSubscriberInterface
{
private $productRepository;
private MediaRepositoryDecorator $mediaRepository;
private $allOptionsIds = [];
//this variable woll contain ,at the end, the options to be disabled
private $optionsToBeDisabled = [];
public function __construct(EntityRepositoryInterface $productRepository, MediaRepositoryDecorator $mediaRepository)
{
$this->productRepository = $productRepository;
$this->mediaRepository = $mediaRepository;
}
public static function getSubscribedEvents(): array
{
return [
ProductPageLoadedEvent::class => 'onProductPageLoaded'
];
}
public function onProductPageLoaded(ProductPageLoadedEvent $event): void
{
$productColor = null;
$options_value = null;
$allOptions = [];
$filteredVariants = [];
$product = $event->getPage()->getProduct();
$parentProduct = $product->getParent();
if ($parentProduct !== null) {
$product = $parentProduct;
}
$optionSorted = $event->getPage()->getConfiguratorSettings(); // This gets the list of configuration, and how they are displayed in frontend, see file: configurator.html.twig
// if u want to change the priority of an option, for example u want to change the main option, u can change the order of the options in this variable: optionSortedIds.
//Just bring the option to the [0] key.
//OR change the order of options in frontend, you can do this on : Product > Varianten > Storefront-Darstellung > Anzege Reinfolge
foreach ($optionSorted as $propertyGroup) {
$optionSortedIds[] = $propertyGroup->getId();
}
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter(
'parentId',
$product->getParentId()
));
$criteria->addAssociation('cover.media');
$criteria->addAssociation('options.group');
// retrieve all product variants
$products = $this->productRepository->search($criteria, $event->getContext());
$matchingVariants = $products->getEntities()->getElements();
// find which options are selected, i.e. which 'Eigenschaften' does the current product have.
$NummberOfOptions = 0;
foreach ($product->getOptions() as $option) {
if (strpos($option->getGroup()->name, 'Design') === false) {
$options_value[] = $option->name;
$NummberOfOptions = $NummberOfOptions + 1;
}
$currentProductOptionIds[$option->groupId] = $option->id;
}
// then filter variants based on the selected 'Eigenschaften'
$NummberOfOptionsThatMatch = 0;
foreach ($matchingVariants as $variantProduct) {
$NummberOfOptionsThatMatch = 0;
$allOptions[] = 'Product:';
foreach ($variantProduct->getOptions() as $option) {
if (in_array($option->name, $options_value)) {
$NummberOfOptionsThatMatch = $NummberOfOptionsThatMatch + 1;
}
$allOptions[] = $option->name;
// these two if statements will save all options of the all available variants, in each separate group array
// allOptionsIds is used for a better structure of the options
if (!isset($this->allOptionsIds[$option->groupId])) {
$this->allOptionsIds[$option->groupId] = [];
}
if (!in_array($option->id, $this->allOptionsIds[$option->groupId])) {
$this->allOptionsIds[$option->groupId][] = $option->id;
}
}
if ($NummberOfOptionsThatMatch == $NummberOfOptions) {
$filteredVariants[] = $variantProduct;
}
}
// compine all options in one array,
foreach ($this->allOptionsIds as $groupId => $optionIds) {
if ($groupId !== $optionSortedIds[0])
$this->optionsToBeDisabled = array_merge($this->optionsToBeDisabled, $optionIds);
}
// Determine the options to be disabled
foreach ($matchingVariants as $variantProduct) {
$variantProductOptionIds = [];
foreach ($variantProduct->getOptions() as $option) {
$variantProductOptionIds[$option->groupId] = $option->id;
}
if ($variantProduct->getId() != $product->getId()) // dont check the currently displayed product
$this->checkOptions(
$variantProductOptionIds,
$optionSortedIds,
$currentProductOptionIds,
$this->allOptionsIds,
$this->optionsToBeDisabled,
0,
1
);
}
$this->optionsToBeDisabled = array_values($this->optionsToBeDisabled); // numerizes/cleans the array
foreach ($filteredVariants as $variant) {
$coverId = $variant->getCover()->getMediaId();
if ($coverId) {
$mediaCriteria = new Criteria();
$mediaCriteria->addFilter(new EqualsFilter('id', $coverId));
$mediaEntity = $this->mediaRepository->search($mediaCriteria, $event->getContext())->first();
if ($mediaEntity) {
$mediaEntity->addExtension('debugVariant', $variant);
$variant->addExtension('variantMedia', $mediaEntity);
}
}
}
$array = ['wct_product_varianten' => $filteredVariants];
$event->getPage()->assign($array);
$event->getPage()->assign(['all_options' => $allOptions]);
$event->getPage()->assign(['all_variants' => $matchingVariants]);
$event->getPage()->assign(['optionsToBeDisabled' => $this->optionsToBeDisabled]);
// die('<pre>'.print_r( $currentProductOptionIds , true).'</pre>');
}
function checkOptions($variantProductOptionIds, $optionSortedIds, $currentProductOptionIds, $allOptionsIds, &$optionsToBeDisabled, $n, $m)
{
for ($i = 0; $i < count($variantProductOptionIds); $i++) {
if (
isset($optionSortedIds[$m]) &&
isset($allOptionsIds[$optionSortedIds[$n]]) &&
isset($allOptionsIds[$optionSortedIds[$m]]) &&
$variantProductOptionIds[$optionSortedIds[$n]] === $currentProductOptionIds[$optionSortedIds[$n]] &&
in_array($variantProductOptionIds[$optionSortedIds[$m]], $allOptionsIds[$optionSortedIds[$m]])
) {
$keyToRemove = array_search($variantProductOptionIds[$optionSortedIds[$m]], $optionsToBeDisabled);
if ($keyToRemove !== false) {
unset($optionsToBeDisabled[$keyToRemove]);
}
$this->checkOptions(
$variantProductOptionIds,
$optionSortedIds,
$currentProductOptionIds,
$allOptionsIds,
$optionsToBeDisabled,
1 + $n,
1 + $m
);
}
}
}
}