custom/plugins/SteincoProducts/src/Subscriber/CustomerEventsSubscriber.php line 65

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Schoettler\SteincoProducts\Subscriber;
  3. use Schoettler\SteincoProducts\SharedFunctions;
  4. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  5. use Shopware\Core\Checkout\Customer\Event\CustomerRegisterEvent;
  6. use Shopware\Core\Checkout\Customer\CustomerEvents;
  7. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
  8. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityDeletedEvent;
  9. use Shopware\Core\System\SystemConfig\SystemConfigService;
  10. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  11. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  12. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  13. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityPreWriteEvent;
  14. class CustomerEventsSubscriber implements EventSubscriberInterface
  15. {
  16.     public static function getSubscribedEvents(): array
  17.     {
  18.         // Return the events to listen to as array like this:  <event to listen to> => <method to execute>
  19.         return [
  20.             CustomerEvents::CUSTOMER_REGISTER_EVENT => 'onCustomerRegistered',
  21.             CustomerEvents::CUSTOMER_WRITTEN_EVENT => 'onCustomerWritten',
  22.             CustomerEvents::CUSTOMER_DELETED_EVENT => 'onCustomerDeleted'
  23.             /* 
  24.             CustomerEvents::CUSTOMER_ADDRESS_WRITTEN_EVENT => 'onCustomerAddressWritten',
  25.             CustomerEvents::CUSTOMER_ADDRESS_DELETED_EVENT => 'onCustomerAddressDeleted',
  26.             */
  27.         ];
  28.     }
  29.     private $systemConfigService;
  30.     private $customerRepository;
  31.     private $addressRepository;
  32.     private $countryRepository;
  33.     private $stateRepository;
  34.     private $languageRepository;
  35.     public function __construct(
  36.         SystemConfigService $systemConfigService,
  37.         EntityRepository $customerRepository,
  38.         EntityRepository $addressRepository,
  39.         EntityRepository $countryRepository,
  40.         EntityRepository $stateRepository,
  41.         EntityRepository $languageRepository
  42.     )
  43.     {
  44.         $this->systemConfigService $systemConfigService;
  45.         $this->customerRepository $customerRepository;
  46.         $this->addressRepository $addressRepository;
  47.         $this->countryRepository $countryRepository;
  48.         $this->stateRepository $stateRepository;
  49.         $this->languageRepository $languageRepository;
  50.     }
  51.     public function onCustomerRegistered(CustomerRegisterEvent $event): void
  52.     {
  53.         $customerId $event->getPayLoads()[0]['id'];
  54.         $this->registerInExternalDatabase($customerId0);
  55.         $this->adjustSalesChannel($customerId);
  56.     }
  57.     public function onCustomerWritten(EntityWrittenEvent $event): void
  58.     {
  59.         SharedFunctions::dumpToLog("onCustomerWritten()");
  60.         $payload $event->getPayLoads()[0];
  61.         if ($payload && array_key_exists('id'$payload)) {
  62.             $customerId $event->getPayLoads()[0]['id'];
  63.         } else {
  64.             // we need to get the id from the writeResult
  65.             $writeResult $event->getWriteResults()[0];
  66.             $customerId $writeResult->getPrimaryKey();
  67.         }
  68.         if ($customerId) {
  69.             $this->registerInExternalDatabase($customerId1);
  70.             $this->adjustSalesChannel($customerId);
  71.         }
  72.     }
  73.     public function onCustomerDeleted(EntityDeletedEvent $event): void
  74.     {
  75.         $customerId $event->getPayLoads()[0]['id'];
  76.         $this->registerInExternalDatabase($customerId2);
  77.     }
  78.     public function onCustomerAddressWritten(EntityWrittenEvent $event): void
  79.     {
  80.         $writeResults $event->getWriteResults();
  81.         $writeResult reset($writeResults);
  82.         $customerId $writeResult->getPayload()['customerId'];
  83.         $this->registerInExternalDatabase($customerId1);
  84.     }
  85.     public function onCustomerAddressDeleted(EntityDeletedEvent $event): void
  86.     {
  87.         //dump($event); die();
  88.         $this->registerInExternalDatabase(1);
  89.     }
  90.     private function registerInExternalDatabase($customerId$created_or_changed_or_deleted)
  91.     {
  92.         // create a connection to the external database
  93.         SharedFunctions::dumpToLog("registerInExternalDatabase()");
  94.         $dbHost $this->systemConfigService->get('SteincoProductsController.config.externalDatabaseHost');
  95.         $dbUser $this->systemConfigService->get('SteincoProductsController.config.externalDatabaseUser');
  96.         $dbPass $this->systemConfigService->get('SteincoProductsController.config.externalDatabasePassword');
  97.         $dbName $this->systemConfigService->get('SteincoProductsController.config.externalDatabaseName');
  98.         $mySql = new \mysqli($dbHost$dbUser$dbPass$dbName);
  99.         if ($mySql->connect_errno) {
  100.             // Log the error somehow
  101.             //dump($mysqli->connect_errno);
  102.         }
  103.         // get the user or set dummy data
  104.         $customerSearchResult $this->customerRepository->search(
  105.             (new Criteria([]))->addAssociation('salutation')->addAssociation('title')->addFilter(new EqualsFilter('id'$customerId)),
  106.             \Shopware\Core\Framework\Context::createDefaultContext()
  107.         );
  108.         $elements $customerSearchResult->getEntities()->getElements();
  109.         $customer reset($elements);
  110.         // Sprache des Kunden mit Locale-Assoziation abrufen
  111.         $languageSearchResult $this->languageRepository->search(
  112.             (new Criteria([]))
  113.                 ->addFilter(new EqualsFilter('id'$customer->getLanguageId()))
  114.                 ->addAssociation('locale'),
  115.             \Shopware\Core\Framework\Context::createDefaultContext()
  116.         );
  117.         $language $languageSearchResult->first();
  118.         if ($language && $language->getLocale()) {
  119.             $language_name $language->getName();
  120.             // Extrahiere den Ländercode nach dem Bindestrich
  121.             $locale_parts explode('-'$language->getLocale()->getCode());
  122.             $language_locale end($locale_parts); // Nimmt den letzten Teil nach dem Bindestrich
  123.         } else {
  124.             // Fallback-Werte setzen
  125.             $language_name 'Deutsch';
  126.             $language_locale 'DE';
  127.         }
  128.         // we need to get some data from the db:
  129.         $customer_group null// no customergroups yet, will be from $customer->groupId
  130.         // Salutation
  131.         $salutation $customer->getSalutation();
  132.         // address-data from the billing address
  133.         $addressId $customer->getDefaultBillingAddressId();
  134.         $address_searchresult $this->addressRepository->search(
  135.             (new Criteria([]))->addAssociation('countryState')->addFilter(new EqualsFilter('id'$addressId)),
  136.             \Shopware\Core\Framework\Context::createDefaultContext());
  137.         $address_elements $address_searchresult->getEntities()->getElements();
  138.         $address reset($address_elements);
  139.         $department $address->getDepartment(); // part of address
  140.         $iso_3 null;
  141.         // search for countryId
  142.         $country_searchresult $this->countryRepository->search(
  143.             (new Criteria([]))->addFilter(new EqualsFilter('id'$address->getCountryId())),
  144.             \Shopware\Core\Framework\Context::createDefaultContext());
  145.         $country_elements $country_searchresult->getEntities()->getElements();
  146.         $country_element reset($country_elements);
  147.         if ($country_element) {
  148.             $country $country_element->getName(); //part of address
  149.             $iso_3 $country_element->getIso3();
  150.         } else {
  151.             $country "";
  152.         }
  153.         // search for countryStateId
  154.         if ($address->getCountryState()) {
  155.             $state $address->getCountryState()->getName(); // bundesland, part of address
  156.         } else {
  157.             $state "";
  158.         }
  159.         if ($address->getCountryStateId()) {
  160.             $state_searchresult $this->stateRepository->search(
  161.                 (new Criteria([]))->addFilter(new EqualsFilter('id'$address->getCountryStateId())),
  162.                 \Shopware\Core\Framework\Context::createDefaultContext());
  163.             $state_elements $state_searchresult->getEntities()->getElements();
  164.             $state_element reset($state_elements);
  165.             $state_element->getName();
  166.         }
  167.         $street $address->getStreet(); // part of address
  168.         $postal_code $address->getZipcode(); // part of address
  169.         $city $address->getCity(); // part of address
  170.         $address_addition_1 $address->getAdditionalAddressLine1(); // part of address
  171.         $address_addition_2 $address->getAdditionalAddressLine2();  // part of address
  172.         $phone_number $address->getPhoneNumber();  // part of address
  173.         $webpage null// ???
  174.         $id '0x0';
  175.         $transaktions_id null// auto-increment
  176.         $art $created_or_changed_or_deleted;
  177.         $kundengruppe $customer_group;
  178.         $sprache_name $language_name;
  179.         $sprache_gebietsschema $language_locale;
  180.         $kundennummer $customer->getCustomerNumber();
  181.         $titel $customer->getTitle();
  182.         $anrede $salutation->getDisplayName();
  183.         $vorname $customer->getFirstName();
  184.         $nachname $customer->getLastName();
  185.         $firma $customer->getCompany();
  186.         if (empty($firma))
  187.             $firma $address->getCompany();
  188.         $abteilung $address->getDepartment(); // part of address
  189.         $USt_id $customer->getVatIds()[0] ?? "";
  190.         $land $country;
  191.         $bundesland $state;
  192.         $strasse $street;
  193.         $postleitzahl $postal_code;
  194.         $ort $city;
  195.         $adresse_Zusatz_Zeile1 $address_addition_1;
  196.         $adresse_Zusatz_Zeile2 $address_addition_2;
  197.         $email $customer->getEmail();
  198.         $telefon $phone_number;
  199.         $geburtstag $customer->getBirthday();
  200.         $aktiv $customer->getActive();
  201.         $werbezusage $customer->getNewsletter() ? 0;
  202.         $IP_Adresse $customer->getRemoteAddress(); // $customer->getNewsletter() ? 'TODO' : null;//ip only if werbezusage
  203.         /* The function gets the remote IP which is stored by nginx in
  204.          * the headers send to Apache.
  205.          */
  206.         $IP_Adresse SharedFunctions::getRemoteIP();
  207.         $email_alt null;//should be done by a trigger in db
  208.         $webseite $webpage;
  209.         $zu_uebertragen 0//(always 0 for us)
  210.         $gast $customer->getGuest() ? 0;
  211.         $erste_Anmeldung $customer->getFirstLogin();
  212.         $letzte_Anmeldung $customer->getLastLogin();
  213.         $erstellt_am $customer->getCreatedAt();
  214.         $geaendert_am $customer->getUpdatedAt();
  215.         $gesperrt 0;
  216.         if (isset($customer->getCustomFields()['custom_customer_blocked'])) {
  217.             $gesperrt $customer->getCustomFields()['custom_customer_blocked'];
  218.         }
  219.         if ($firma) {
  220.             $firma substr($firma040); // Firma darf maximal 40 Zeichen lang sein
  221.             $firma str_replace('"'"'"$firma); // Damit die D.3 Schnittstelle funktioniert
  222.         }
  223.         // if geaendert_am is null this is the registration of the customer
  224.         if ($geaendert_am == null) {
  225.             $art 0;
  226.         }
  227.         // avoid double entries
  228.         $last_entry_sql 'SELECT NOT EXISTS( SELECT `geaendert_am` FROM `Kundendaten_Shop` WHERE `Email` = ' $this->valueString($email)
  229.             . ' AND `geaendert_am` BETWEEN '
  230.             $this->dateString($geaendert_am) . ' - INTERVAL 2 SECOND AND '
  231.             $this->dateString($geaendert_am) . ' ) AS `lastEntry`';
  232.         if ($result $mySql->query($last_entry_sql)) {
  233.             // $result indicates that no entry for the customer with that name exists which is less than 2 seconds old
  234.             // so we can insert the data
  235.             $row mysqli_fetch_array($result);
  236.             $no_entry_exists $row['lastEntry'];
  237.             $result->close();
  238.             // create the query and send it to the external database
  239.             // no need for a prepared statement
  240.             if ($no_entry_exists == "1") {
  241.                 $sql 'INSERT INTO `Kundendaten_Shop` (`id`, `Transaktions_Id`, `Art`, `Kundengruppe`,'
  242.                     ' `Sprache_Name`, `Sprache_Gebietsschema`, `Kundennummer`, `Titel`,'
  243.                     ' `Anrede`, `Vorname`, `Nachname`, `Firma`, `Abteilung`, `USt_id`,'
  244.                     ' `Land`, `Bundesland`, `Strasse`, `Postleitzahl`, `Ort`, `Adresse_Zusatz_Zeile1`,'
  245.                     ' `Adresse_Zusatz_Zeile2`, `Email`, `Telefon`, `Geburtstag`, `aktiv`, `gesperrt`,'
  246.                     ' `Werbezusage`, `IP_Adresse`, `Email_alt`, `Webseite`, `zu_uebertragen`,'
  247.                     ' `Gast`, `erste_Anmeldung`, `letzte_Anmeldung`, `erstellt_am`, `geaendert_am`, `Land_ISO_3`)'
  248.                     ' VALUES (' $id ', ' $this->valueString($transaktions_id) . ', ' $art ', ' $this->valueString($kundengruppe) . ', '
  249.                     $this->valueString($sprache_name) . ',' $this->valueString($sprache_gebietsschema) . ', '
  250.                     $this->valueString($kundennummer) . ', ' $this->valueString($titel) . ', ' $this->valueString($anrede)
  251.                     . ', ' $this->valueString($vorname) . ', ' $this->valueString($nachname) . ', '
  252.                     $this->valueString($firma40) . ', ' $this->valueString($abteilung35) . ', '
  253.                     $this->valueString($USt_id) . ' ,' $this->valueString($land) . ', '
  254.                     $this->valueString($bundesland) . ', ' $this->valueString($strasse) . ', '
  255.                     $this->valueString($postleitzahl) . ', ' $this->valueString($ort) . ', '
  256.                     $this->valueString($adresse_Zusatz_Zeile1) . ', ' $this->valueString($adresse_Zusatz_Zeile2) . ', '
  257.                     $this->valueString($email) . ', ' $this->valueString($telefon) . ', ' $this->dateString($geburtstag) . ', '
  258.                     $this->booleanString($aktiv) . ', ' $this->booleanString($gesperrt) . ', ' $werbezusage ', ' $this->valueString($IP_Adresse) . ', '
  259.                     $this->valueString($email_alt) . ', ' $this->valueString($webseite) . ', 0, '
  260.                     $gast ', ' $this->dateString($erste_Anmeldung) . ', '
  261.                     $this->dateString($letzte_Anmeldung) . ', ' $this->dateString($erstellt_am)
  262.                     . ', ' $this->dateString($geaendert_am)
  263.                     . ', ' $this->valueString($iso_3) . ')';
  264.                 if (!$mySql->query($sql)) {
  265.                     //query did not succeed, log this somehow
  266.                     //dump(mysqli_error($mysqli), $sql, $customer);
  267.                 }
  268.             }
  269.         } else {
  270.             // either there is an entry for the customer or there was an error
  271.             // dump(mysqli_error($mysqli));
  272.         }
  273.     }
  274.     private function adjustSalesChannel($customerId)
  275.     {
  276.         /* Hier wird der Standard-Saleschannel für den Kunden korrigiert.
  277.             Es muss sich immer um den Shop-channel handeln, da für den Kunden sonst
  278.             keine manuellen Bestellungen erzeugt werden können. Leider ist dieser
  279.             Eintrag im Backend nicht bearbeitbar und wird bei Anlage des Kunden auf
  280.             den in diesem Moment aktuellen Channel gesetzt.
  281.         */
  282.         SharedFunctions::dumpToLog("adjustSalesChannel()");
  283.         $dbHost $this->systemConfigService->get('SteincoProductsController.config.externalDatabaseHost');
  284.         $dbUser $this->systemConfigService->get('SteincoProductsController.config.externalDatabaseUser');
  285.         $dbPass $this->systemConfigService->get('SteincoProductsController.config.externalDatabasePassword');
  286.         $dbName $this->systemConfigService->get('SteincoProductsController.config.shopDatabaseName');
  287.         $mySql = new \mysqli($dbHost$dbUser$dbPass$dbName);
  288.         if ($mySql->connect_errno) {
  289.             SharedFunctions::dumpToLog('Could not connect to MySQL: ' $mySql->connect_error);
  290.             return;
  291.         }
  292.         $salesChannelId $this->systemConfigService->get('SteincoProductsController.config.scShopUUID');
  293.         SharedFunctions::dumpToLog($salesChannelId);
  294.         try {
  295.             // Vorher prüfen, ob ein Update notwendig ist
  296.             $checkSql "SELECT HEX(sales_channel_id) AS sales_channel_id FROM `customer` WHERE id = UNHEX('" $customerId "')";
  297.             $result $mySql->query($checkSql);
  298.             if ($result) {
  299.                 $row $result->fetch_assoc();
  300.                 if ($row && $row['sales_channel_id'] !== strtoupper($salesChannelId)) {
  301.                     // Update durchführen, wenn der neue Wert unterschiedlich ist
  302.                     $updateSql "UPDATE `customer` SET sales_channel_id = UNHEX('" $salesChannelId "') WHERE id = UNHEX('" $customerId "')";
  303.                     if (!$mySql->query($updateSql)) {
  304.                         // Query did not succeed, log this somehow
  305.                         SharedFunctions::dumpToLog('Error executing: ' $updateSql);
  306.                         SharedFunctions::dumpToLog('SQL-Error: ' $mySql->error);
  307.                     } else {
  308.                         SharedFunctions::dumpToLog('Aktualisierung des SalesChannels erfolgt. ' $mySql->affected_rows ' Zeile(n).');
  309.                     }
  310.                     SharedFunctions::dumpToLog($updateSql);
  311.                 } else {
  312.                     SharedFunctions::dumpToLog('Kein Update notwendig. SalesChannelId ist bereits gesetzt.');
  313.                 }
  314.             } else {
  315.                 SharedFunctions::dumpToLog('Error executing: ' $checkSql);
  316.                 SharedFunctions::dumpToLog('SQL-Error: ' $mySql->error);
  317.             }
  318.         } catch (\Exception $e) {
  319.             // Logge die Fehlermeldung in eine Datei oder verarbeite den Fehler entsprechend
  320.             SharedFunctions::dumpToLog('Aktualisierung des SalesChannels fehlgeschlagen.');
  321.             SharedFunctions::dumpToLog($e->getMessage());
  322.         }
  323.     }
  324.     private function valueString($value$maxLength null)
  325.     {
  326.         $result 'NULL';
  327.         if ($value) {
  328.             $valueString '"' $value '" ';
  329.             if (is_null($maxLength)) {
  330.                 $result $valueString;
  331.             } else {
  332.                 // Beschränke die Länge des Ergebnisses auf $maxLength Zeichen
  333.                 $result substr($valueString0$maxLength);
  334.             }
  335.         }
  336.         return $result;
  337.     }
  338.     private function dateString($date)
  339.     {
  340.         $result 'NULL';
  341.         if ($date) {
  342.             $result '"' $date->format('Y-m-d H:i:s') . '" ';
  343.         }
  344.         return $result;
  345.     }
  346.     private function booleanString($a_boolean)
  347.     {
  348.         if ($a_boolean) {
  349.             return '1';
  350.         }
  351.         return '0';
  352.     }
  353. }