<?php declare(strict_types=1);
namespace Schoettler\SteincoProducts\Subscriber;
use Schoettler\SteincoProducts\Constants;
use Schoettler\SteincoProducts\Struct\PropertiesStruct;
use Shopware\Core\Content\Product\ProductEntity;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Shopware\Core\Content\Product\ProductEvents;
use Shopware\Core\Checkout\Customer\Event\CustomerRegisterEvent;
use Shopware\Core\Checkout\Customer\CustomerEvents;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityDeletedEvent;
use Shopware\Core\System\User\UserEvents;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Content\Property\Aggregate\PropertyGroupOption\PropertyGroupOptionEntity;
use Shopware\Core\Framework\Context;
use Shopware\Core\Content\Product\Events\ProductListingCriteriaEvent;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
class ProductSubscriber implements EventSubscriberInterface
{
/**
* @var EntityRepositoryInterface
*/
private $propertyRepository;
private $propertyGroupTranslationsRepository;
private $productRepository;
private $product_propertyRepository;
private $propertyGroupRepository;
private $propertyGroupOptionRepository;
private $session;
public function __construct(EntityRepositoryInterface $propertyRepository,
EntityRepositoryInterface $propertyGroupTranslationsRepository,
EntityRepositoryInterface $productRepository,
EntityRepositoryInterface $product_propertyRepository,
EntityRepositoryInterface $propertyGroupRepository,
EntityRepositoryInterface $propertyGroupOptionRepository,
SessionInterface $session)
{
$this->propertyRepository = $propertyRepository;
$this->propertyGroupTranslationsRepository = $propertyGroupTranslationsRepository;
$this->productRepository = $productRepository;
$this->product_propertyRepository = $product_propertyRepository;
$this->propertyGroupRepository = $propertyGroupRepository;
$this->propertyGroupOptionRepository = $propertyGroupOptionRepository;
$this->session = $session;
}
public static function getSubscribedEvents(): array
{
// Return the events to listen to as array like this: <event to listen to> => <method to execute>
return [
ProductEvents::PRODUCT_LOADED_EVENT => 'onProductLoaded',
ProductEvents::PRODUCT_WRITTEN_EVENT => 'onProductWritten',
ProductEvents::PRODUCT_LISTING_CRITERIA => 'onProductListing'
];
}
public function onProductListing(ProductListingCriteriaEvent $event): void
{
// Aktuell gesetztes Tag ermitteln "Rolle", "Rad" oder "Zubehoer"
$productTag = $this->session->get(Constants::TAG_NAME, Constants::TAG_ROLLE);
// dump( $productTag);
$criteria = $event->getCriteria();
if ($criteria) {
$criteria->addFilter(
new EqualsFilter('product.tags.name', $productTag)
);
}
}
public function onProductLoaded(EntityLoadedEvent $event): void
{
/** @var ProductEntity $productEntity */
foreach ($event->getEntities() as $productEntity) {
//$properties = new PropertiesStruct();
//$properties->property_options = $this->get_product_properties($productEntity);
$properties = $this->get_propertystruct($productEntity, $event->getContext());
$productEntity->addExtension('properties', $properties);
}
}
public function get_propertystruct(ProductEntity $product, $context) : PropertiesStruct
{
$result = new PropertiesStruct();
$properties = $product->getProperties();
$propertyOptions = null; // array of propertyGroupOptionElements
if(!$context) {
$context = \Shopware\Core\Framework\Context::createDefaultContext();
}
if ($properties) {
$propertyOptions = $properties->getElements();
} else {
$propertyids = $product->getPropertyIds();
if($propertyids){
/** @var EntityCollection $propentitiesEntities */
$propentitiesEntities = $this->propertyRepository->search(
(new Criteria(array_keys(array_flip($propertyids))))->addAssociation('group'),
$context
);
$propertyOptions = $propentitiesEntities->getEntities()->getElements();
}
}
$counter = 0;
if(!empty($propertyOptions)){
foreach( $propertyOptions as $value) {
$name= $this->getNameWithDefault( $value, $context);
$description = null;
$groupName = "Unnamed_" .$counter;
if($value->getGroup()){
$description = $value->getGroup()->getDescription();
$groupName = $value->getGroup()->getName();
}
if(!$description){
// to prevent nullpointerexceptions
// following if-clause prevents a nullpointerexception in ajax-requests in backend.
// Not sure what causes this, as there were various calls on group in the code above.
if($value->getGroup()){
$description = $this->fetchDefaultValueForGroup( $value->getGroup(), "description", $context);
} else {
$description = 'No_Group_' .$counter++;
}
if(!$description) {
// to prevent nullpointerexceptions
$description = 'Unnamed_' . $counter++;
}
}
if(!$groupName){
// to prevent nullpointerexceptions
$groupName = $this->fetchDefaultValueForGroup( $value->getGroup(), "name", $context);
if(!$groupName) {
// to prevent nullpointerexceptions
$groupName = 'Unnamed_' . $counter++;
}
}
// TODO: Branche needs some special parameters
// for the future: we need to get the ids for the unlocalized property and compare to that
if($description === "Branche") {
$result->branchen[] = $name;
}
if($description === "Anwendungsbereiche"){
$result->anwendungen[] = $name;
}
if ($description === 'Rolle_Bauhoehe_mm')
{
$result->bauhoehe = $name;
}
if ($description === 'Rad_Durchmesser_mm')
{
$result->durchmesser = $name;
}
if ($description === 'Rolle_Tragkraft_kg')
{
$result->tragkraft = $name;
}
if(array_key_exists($description, $result->property_options)){
$result->property_options[$description]['name'] = $groupName;
$result->property_options[$description]['value'] =
$result->property_options[$description]['value'] . ", " . $name;
}
else {
$result->property_options[$description]['name'] = $groupName;
$result->property_options[$description]['value'] = $name;
}
}
}
return $result;
}
public function onProductWritten(EntityWrittenEvent $event)
{
//look at the written Product
$productID = null;
$writeResult = $event->getWriteResults()[0];
$payload = $event->getPayLoads()[0];
if($payload && array_key_exists('id', $payload)){
$productID = $event->getPayLoads()[0]['id'];
} else {
// we need to get the id from the writeResult
$writeResult = $event->getWriteResults()[0];
$productID = $writeResult->getPrimaryKey();
}
// look into the writeresult if stock has been changed
// if ( array_key_exists('stock', $payload))
{
// get the product
$productSearchCriteria = new Criteria();
$productSearchCriteria->addFilter(new EqualsFilter('id' , $productID));
$productSearchCriteria->addAssociation('properties');
$productSearchCriteria->addAssociation('properties.group');
$entity = $this->productRepository->search(
$productSearchCriteria,
\Shopware\Core\Framework\Context::createDefaultContext()
)->first();
$stock = $entity->getStock();
$available_stock = $entity->getAvailableStock();
$properties = $entity->getProperties()->getElements();
$current_availabiltyPropertyOption = null;
foreach ($properties as $propertyOption) {
$propertyGroup = $propertyOption->getGroup()->getDescription();
if($propertyGroup == 'Filter_Verfuegbarkeit')
{
$current_availabiltyPropertyOption = $propertyOption;
$this->availabilityFilterPropertyGroupId = $propertyOption->getGroup()->getId();
break;
}
}
if ($stock > 0)
{
// dump("Stock > 0");
if($available_stock > 0)
{
//check if "Auf Lager" is set. if not, set it ( and delete current setting).
if (!$current_availabiltyPropertyOption || $current_availabiltyPropertyOption->getPosition() != 1)
{
//search the correct Propertyoption
$this->changeAvailabilityPropertyOption($current_availabiltyPropertyOption, 1, $productID);
}
} else
{
//check if "aktuell nicht verfügbar" is set. if not, set it ( and delete current setting).(pos 2)
if (!$current_availabiltyPropertyOption ||$current_availabiltyPropertyOption->getPosition() != 2)
{
//search the correct Propertyoption
//delete wrong option
//set correct option
$this->changeAvailabilityPropertyOption($current_availabiltyPropertyOption, 2, $productID);
}
}
} else {
//check if "Auf Anfrage" is set. if not, set it ( and delete current setting). (pos 3)
if (!$current_availabiltyPropertyOption || $current_availabiltyPropertyOption->getPosition() != 3)
{
//search the correct Propertyoption
//delete wrong option
//set correct option
$this->changeAvailabilityPropertyOption($current_availabiltyPropertyOption, 3, $productID);
}
}
}
}
private function changeAvailabilityPropertyOption($currentPropertyOption,int $positionToSet, $productId){
// delete the current product_property entry
if ($currentPropertyOption) {
$currentPropertyId = $currentPropertyOption->getId();
$this->product_propertyRepository->delete([
[
'productId' => $productId,
'optionId' => $currentPropertyId
]
],
\Shopware\Core\Framework\Context::createDefaultContext()
);
} else {
$propertygroupFilter = new EqualsFilter('description', 'Filter_Verfuegbarkeit');
$propertyCriteria = new Criteria();
$propertyCriteria->addFilter($propertygroupFilter);
$propertySearchResult = $this->propertyGroupRepository->search($propertyCriteria,
\Shopware\Core\Framework\Context::createDefaultContext()
)->first();
$this->availabilityFilterPropertyGroupId = $propertySearchResult->getId();
}
// find correct option
$search_criteria = new Criteria();
$optiongroupFilter = new EqualsFilter('group.id', $this->availabilityFilterPropertyGroupId);
$positionfilter = new EqualsFilter('position', $positionToSet);
$search_criteria->addFilter($optiongroupFilter);
$search_criteria->addFilter($positionfilter);
$searchResult = $this->propertyRepository->search($search_criteria,
\Shopware\Core\Framework\Context::createDefaultContext())->first();
$updateJson = [['id'=>$productId, 'properties'=>[['id'=>$searchResult->getId()]]]];
//set the new association
$this->productRepository->update( $updateJson , \Shopware\Core\Framework\Context::createDefaultContext() );
}
private function getNameWithDefault( $property, $context): ?string {
$value = $property->getName();
if ( !$value) {
return $this->fetchDefaultValueForProperty($property, 'name', $context);
}
return $value;
}
private function fetchDefaultValueForProperty($property, string $field, $context): ?string {
$defaultContext = $this->getDefaultContext($context);
$criteria = new Criteria([$property->getId()]);
$criteria->addAssociation('translations');
// $criteria->addFilter(new EqualsFilter('language_id', '94F6E662FA184F45A31A047B538F249D'));
$defaultProperty = $this->propertyGroupOptionRepository->search($criteria, $defaultContext)->first();
if ($defaultProperty) {
$translations = $defaultProperty->getTranslations();
$englishTranslation = $translations->filterByLanguageId('94f6e662fa184f45a31a047b538f249d')->first();
if ($englishTranslation) {
return $englishTranslation->get($field);
}
}
return null;
}
private function fetchDefaultValueForGroup($group, string $field, $context): ?string {
$defaultContext = $this->getDefaultContext($context);
$criteria = new Criteria([$group->getId()]);
$criteria->addAssociation('translations');
$defaultGroup = $this->propertyGroupRepository->search($criteria, $defaultContext)->first();
if ($defaultGroup) {
$translations = $defaultGroup->getTranslations();
$englishTranslation = $translations->filterByLanguageId('94f6e662fa184f45a31a047b538f249d')->first();
if ($englishTranslation) {
return $englishTranslation->get($field);
}
}
return null;
}
private function getDefaultContext($context): Context
{
return Context::createDefaultContext();
}
}