<?php
declare(strict_types=1);
namespace Bodymed\Webshop\Core\Subscriber;
use Bodymed\Interop\Enum\Noms\Sequence\SequenceType;
use Bodymed\Interop\Struct\Noms\Customer\CustomerAddress;
use Bodymed\Interop\Util\Address\StreetHouseNumberTool;
use Bodymed\Webshop\Constants;
use Bodymed\Webshop\Core\Checkout\Customer\NomsCustomerAddressExtension\NomsCustomerAddressExtensionEntity;
use Bodymed\Webshop\Core\Checkout\Customer\NomsSequence\NomsSequenceService;
use Shopware\Core\Checkout\Customer\Aggregate\CustomerAddress\CustomerAddressEntity;
use Shopware\Core\Checkout\Customer\CustomerEvents;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityLoadedEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\Event\DataMappingEvent;
use Shopware\Core\Framework\Uuid\Uuid;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class CustomerAddressExtensionSubscriber implements EventSubscriberInterface
{
public function __construct(
private EntityRepository $nomsCustomerAddressExtensionRepository,
private EntityRepository $customerAddressRepository,
private NomsSequenceService $nomsSequenceService
) {
}
public static function getSubscribedEvents(): array
{
return [
//CustomerRegisterEvent::class => 'onCreateCustomer',
#AddressController::class => 'onSaveAddress',
CustomerEvents::MAPPING_ADDRESS_CREATE => 'onMappingAddress',
CustomerEvents::MAPPING_REGISTER_ADDRESS_SHIPPING => 'onMappingAddress',
CustomerEvents::MAPPING_REGISTER_ADDRESS_BILLING => 'onMappingAddress',
CustomerEvents::CUSTOMER_ADDRESS_LOADED_EVENT => 'onCustomerAddressLoaded',
'customer_address.written' => 'onCustomerAddressWritten',
];
}
public function onCustomerAddressWritten(EntityWrittenEvent $event)
{
$context = $event->getContext();
$customerAddressIds = $event->getIds();
$criteria = (new Criteria($customerAddressIds));
$customerAddresses = $this->customerAddressRepository->search($criteria, $context);
$upsertData = [];
/* @var $customerAddress CustomerAddressEntity */
foreach ($customerAddresses as $customerAddress) {
$customerAddressExtension = $customerAddress->getExtension(Constants::ADDRESS_EXTENSION_NOMS_EXTENSION_KEY);
$customerId = $customerAddress->getCustomerId();
$customerAddressId = $customerAddress->getId();
if (!$customerAddressExtension instanceof NomsCustomerAddressExtensionEntity) {
$customerAddressExtensionId = Uuid::randomHex();
$nomsStreetAddress = StreetHouseNumberTool::buildNomsHouseNumberFromStreetAndNumber($customerAddress->getStreet());
$plainStreet = $nomsStreetAddress->street;
$houseNumber = $nomsStreetAddress->houseNumber;
$nomsPhoneId = null;
if (empty($plainStreet)) {
continue;
}
if ($this->isAcceptablePhoneNumber($customerAddress->getPhoneNumber())) {
$nomsPhoneId = $this->generateNomsPhoneId($context);
}
$nomsAddressId = $this->generateNomsAddressId($context);
$nomsContactId = $this->generateNomsContactId($context);
} else {
$customerAddressExtensionId = $customerAddressExtension->getId();
$plainStreet = $customerAddressExtension->getStreet();
$houseNumber = $customerAddressExtension->getStreetnumber();
$nomsPhoneId = $customerAddressExtension->getNomsPhoneId();
$nomsAddressId = $customerAddressExtension->getNomsAddressId();
$nomsContactId = $customerAddressExtension->getNomsContactId();
$mergedStreetAndNumber = StreetHouseNumberTool::mergeStreetAndNumber($plainStreet, $houseNumber);
/* Wenn die Straße geändert wurde und die Änderungen nicht mehr zum gesplitteten Wert passen, müssen diese auch geändert werden */
if ($mergedStreetAndNumber !== $customerAddress->getStreet()) {
$nomsStreetAddress = StreetHouseNumberTool::buildNomsHouseNumberFromStreetAndNumber($customerAddress->getStreet());
$plainStreet = $nomsStreetAddress->street;
$houseNumber = $nomsStreetAddress->houseNumber;
}
if (null === $nomsPhoneId) {
$nomsPhoneId = $this->generateNomsPhoneId($context);
}
if (null === $nomsAddressId) {
$nomsAddressId = $this->generateNomsAddressId($context);
}
if (null === $nomsContactId) {
$nomsContactId = $this->generateNomsContactId($context);
}
}
$upsertData[] = [
'id' => $customerAddressExtensionId,
'customerId' => $customerId,
'customerAddressId' => $customerAddressId,
'street' => $plainStreet,
'streetnumber' => empty($houseNumber) ? ' ' : $houseNumber,
'nomsAddressId' => $nomsAddressId,
'nomsContactId' => $nomsContactId,
'nomsPhoneId' => $nomsPhoneId,
];
}
$this->nomsCustomerAddressExtensionRepository->upsert($upsertData, $context);
}
public function onCustomerAddressLoaded(EntityLoadedEvent $event): void
{
$context = $event->getContext();
$addresses = $event->getEntities();
/* @var $address CustomerAddressEntity */
foreach ($addresses as $address) {
$id = $address->getId();
/* @todo Wird nicht mehr benötigt */
/*$criteria = (new Criteria())->addFilter(
new EqualsFilter('customerAddressId', $id),
);
$result = $this->nomsCustomerAddressExtensionRepository->search($criteria, $context);
$nomsCustomerAddressExtension = $result->first();
if ($nomsCustomerAddressExtension instanceof NomsCustomerAddressExtensionEntity) {
$address->addExtension(
Constants::ADDRESS_EXTENSION_NOMS_EXTENSION_KEY,
$nomsCustomerAddressExtension
);
}*/
/*
if($address->getCustomFields()){
if(isset($address->getCustomFields()['nomsStreet']) and $address->getExtensions()['nomsCustomerAddress'] == null){
$this->nomsCustomerAddressRepository->create([
[
'customerAddressId' => $address->getId(),
'customerId' => $address->getCustomerId(),
'street' => $address->getCustomFields()['nomsStreet'],
'streetnumber' => $address->getCustomFields()['nomsStreetnumber']
]
], $context);
$criteria = (new Criteria())->addFilter(
new EqualsFilter('customerAddressId', $id),
);
$result = $this->nomsCustomerAddressRepository->search($criteria, $context);
$nomsCustomerAddress = $result->first();
$address->addExtension(
'nomsCustomerAddress',
$nomsCustomerAddress
);
}
}*/
}
}
/*public function onCreateCustomer(CustomerRegisterEvent $event): void
{
$context = $event->getSalesChannelContext()->getContext();
$street = $event->getCustomer()->getDefaultBillingAddress()->getCustomFields()['nomsStreet'];
$streetnumber = $event->getCustomer()->getDefaultBillingAddress()->getCustomFields()['nomsStreetnumber'];
$customerId = $event->getCustomer()->getId();
$customerBillingAddressId = $event->getCustomer()->getDefaultBillingAddress()->getId();
$customerShippingAddressId = $event->getCustomer()->getDefaultShippingAddress()->getId();
$this->nomsCustomerAddressRepository->create([
[
'customerAddressId' => $customerBillingAddressId,
'customerId' => $customerId,
'street' => $street,
'streetnumber' => $streetnumber
]
], $context);
if ($customerBillingAddressId != $customerShippingAddressId) {
$street = $event->getCustomer()->getDefaultShippingAddress()->getCustomFields()['nomsStreet'];
$streetnumber = $event->getCustomer()->getDefaultShippingAddress()->getCustomFields()['nomsStreetnumber'];
$this->nomsCustomerAddressRepository->create([
[
'customerAddressId' => $customerShippingAddressId,
'customerId' => $customerId,
'street' => $street,
'streetnumber' => $streetnumber
]
], $context);
}
}*/
public function onMappingAddress(DataMappingEvent $event): void
{
$data = $event->getInput();
$address = $event->getOutput();
$context = $event->getContext();
$plainStreet = $address['street'];
$houseNumber = $data->get('streetnumber');
if (null === $houseNumber) {
$streetNumberArray = StreetHouseNumberTool::splitStreetToStreetAndNumber($plainStreet);
$plainStreet = $streetNumberArray['street'];
$houseNumber = $streetNumberArray['houseNumber'];
}
//Set Street and Streetnumber in shopware orginal field
$address['customFields']['nomsStreet'] = $plainStreet;
$address['customFields']['nomsStreetnumber'] = $houseNumber;
$address['street'] = StreetHouseNumberTool::mergeStreetAndNumber($plainStreet, $houseNumber);
$shouldCreatePhoneId = false;
/* PhoneNumberId muss nur erzeugt werden, wenn eine Telefonnummer angegbeen wurde */
if (\strlen((string) $address['phoneNumber']) > 1) {
$shouldCreatePhoneId = true;
}
$addressId = $data->get('id');
if (null !== $addressId) {
$criteria = (new Criteria())->addFilter(
new EqualsFilter('customerAddressId', $addressId),
);
$nomsCustomerAddressExtension = $this->nomsCustomerAddressExtensionRepository->search(
$criteria,
$context
)->first();
if ($nomsCustomerAddressExtension instanceof NomsCustomerAddressExtensionEntity) {
$nomsAddressId = $nomsCustomerAddressExtension->getNomsAddressId();
$nomsPhoneId = $nomsCustomerAddressExtension->getNomsPhoneId();
$nomsContactId = $nomsCustomerAddressExtension->getNomsContactId();
if (null === $nomsAddressId) {
$nomsAddressId = $this->generateNomsAddressId($context);
}
if (null === $nomsContactId) {
$nomsContactId = $this->generateNomsContactId($context);
}
if (null === $nomsPhoneId && true === $shouldCreatePhoneId) {
$nomsPhoneId = $this->generateNomsPhoneId($context);
}
$this->nomsCustomerAddressExtensionRepository->update([
[
'id' => $nomsCustomerAddressExtension->getId(),
'street' => $address['customFields']['nomsStreet'],
'streetnumber' => $address['customFields']['nomsStreetnumber'],
'nomsAddressId' => $nomsAddressId,
'nomsContactId' => $nomsContactId,
'nomsPhoneId' => $nomsPhoneId,
],
], $context);
} else {
$nomsAddressId = $this->generateNomsAddressId($context);
$nomsContactId = $this->generateNomsContactId($context);
$nomsPhoneId = null;
if ($shouldCreatePhoneId) {
$nomsPhoneId = $this->generateNomsPhoneId($context);
}
$customerId = $data->get('customerId');
if (null !== $customerId) {
$this->nomsCustomerAddressExtensionRepository->create([
[
'customerAddressId' => $addressId,
'customerId' => $data->get('customerId'),
'street' => $address['customFields']['nomsStreet'],
'streetnumber' => $address['customFields']['nomsStreetnumber'],
'nomsAddressId' => $nomsAddressId,
'nomsContactId' => $nomsContactId,
'nomsPhoneId' => $nomsPhoneId,
],
], $context);
}
}
}
$event->setOutput($address);
}
private function generateNomsPhoneId(Context $context): ?int
{
return $this->nomsSequenceService->pop(SequenceType::PHONE_ID, $context);
}
private function generateNomsAddressId(Context $context): ?int
{
return $this->nomsSequenceService->pop(SequenceType::ADDRESS_ID, $context);
}
public function generateNomsContactId(Context $context): ?int
{
return $this->nomsSequenceService->pop(SequenceType::CONTACT_ID, $context);
}
private function isAcceptablePhoneNumber(?string $phoneNumber): bool
{
return \mb_strlen((string) $phoneNumber) > 3;
}
}