Merge branch 'rel_1.x' into dev_1.x_tests

This commit is contained in:
Daniel Seifert 2022-12-25 13:00:44 +01:00
commit bf77b65ad5
Signed by: DanielS
GPG Key ID: 6A513E13AEE66170
24 changed files with 557 additions and 162 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.php_cs.cache

View File

@ -6,7 +6,7 @@ $finder = PhpCsFixer\Finder::create()
$config = new PhpCsFixer\Config();
return $config->setRules([
'@PHP70Migration' => true,
'@PHP71Migration' => true,
'@PSR12' => true
])
->setFinder($finder)

View File

@ -1,9 +1,30 @@
# Changelog
All notable changes to this project will be documented in this file.
---
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 1.0.0.0 (2022-07-13)
## [Unreleased](https://git.d3data.de/D3Private/linkmobility4oxid/compare/1.1.0.1...rel_1.x)
## [1.1.0.1](https://git.d3data.de/D3Private/linkmobility4oxid/compare/1.1.0.0...1.1.0.1) - 2022-09-29
### Changed
- adjust readme
## [1.1.0.0](https://git.d3data.de/D3Private/linkmobility4oxid/compare/1.0.0.0...1.1.0.0) - 2022-07-28
### Added
- phpstan code checks
### Changed
- improved changelog
### Fixed
- type in IntelliSenseHelper class name
### Removed
- PHP 7.0 support
## [1.0.0.0](https://git.d3data.de/D3Private/linkmobility4oxid/releases/tag/1.0.0.0) - 2022-07-13
### Added
- initial implementation
Send message on:
- Order completion, sending order confirmation message.

View File

@ -1,7 +1,7 @@
[![deutsche Version](https://logos.oxidmodule.com/de2_xs.svg)](README.md)
[![english version](https://logos.oxidmodule.com/en2_xs.svg)](README.en.md)
# Integration of the LINK Mobility Austria service into the OXID eShop
# Integration of the LINK Mobility service into the OXID eShop
[LINK Mobility](https://www.linkmobility.de/) provides a service for sending mobile messages (SMS, Whatsapp, RCS, Chatbot, ...).
@ -25,8 +25,9 @@ Message dispatch (currently SMS) can be activated individually for the following
This package requires an OXID eShop installed with Composer in one of the following versions:
- 6.2.4 or above
- 6.3.x
- 6.3.1 or above
- 6.4.x
- 6.5.x
and its requirements.
@ -54,6 +55,12 @@ If you have a suggestion that would make this better, please fork the repo and c
- Push to the Branch (git push origin feature/AmazingFeature)
- Open a Pull Request
## Support
If you have any questions about the *messaging service* and its *contracts*, please contact the [LINK Mobility Team](https://www.linkmobility.de/kontakt).
For *technical inquiries* you will find the contact options in the [composer.json](composer.json).
## License
(status: 2022-07-13)

View File

@ -1,7 +1,7 @@
[![deutsche Version](https://logos.oxidmodule.com/de2_xs.svg)](README.md)
[![english version](https://logos.oxidmodule.com/en2_xs.svg)](README.en.md)
# Integration des LINK Mobility Austria Dienstes in den OXID eShop
# Integration des LINK Mobility Dienstes in den OXID eShop
[LINK Mobility](https://www.linkmobility.de/) stellt einen Service zum Versenden von mobilen Nachrichten (SMS, Whatsapp, RCS, Chatbot, ...) zur Verfügung.
@ -25,8 +25,9 @@ Bei folgenden Aktionen kann der Nachrichtenversand (derzeit SMS) einzeln aktivie
Dieses Paket erfordert einen mit Composer installierten OXID eShop in einer der folgenden Versionen:
- 6.2.4 oder höher
- 6.3.x
- 6.3.1 oder höher
- 6.4.x
- 6.5.x
und dessen Anforderungen.
@ -54,6 +55,12 @@ Wenn Sie eine Verbesserungsvorschlag haben, legen Sie einen Fork des Repositorie
- Übertragen Sie den Branch (git push origin feature/AmazingFeature)
- Öffnen Sie einen Pull Request
## Support
Bei Fragen zum *Messaging Service* und dessen *Verträgen* kontaktieren Sie bitte das [LINK Mobility Team](https://www.linkmobility.de/kontakt).
Zu *technischen Anfragen* finden Sie die Kontaktmöglichkeiten in der [composer.json](composer.json).
## Lizenz
(Stand: 13.07.2022)

View File

@ -17,10 +17,18 @@
"role": "Owner"
}
],
"license": [
"GPL-3.0-or-later"
],
"require": {
"php": "^7.0 || ^8.0",
"oxid-esales/oxideshop-ce": "6.7 - 6.10",
"d3/linkmobility-php-client": "^1.2.0"
"php": "^7.1 || ^8.0",
"oxid-esales/oxideshop-ce": "6.7 - 6.13",
"d3/linkmobility-php-client": "^1.2.0 || ^2.0.0"
},
"require-dev": {
"oxid-esales/oxideshop-ce": "~6.10.0",
"friendsofphp/php-cs-fixer": "^2.19",
"phpstan/phpstan": "^1.8"
},
"require-dev": {
"d3/modcfg": "^5.3.7.0 || ^6.0"

10
phpstan.neon Normal file
View File

@ -0,0 +1,10 @@
parameters:
scanFiles:
- src/IntelliSenseHelper.php
- ../../oxid-esales/oxideshop-ce/source/oxfunctions.php
paths:
- src
level: 9
phpVersion: 70100
ignoreErrors:
- '#Psr\\Container\\ContainerExceptionInterface is not subtype of Throwable#'

View File

@ -58,24 +58,25 @@ class AdminOrder extends AdminController
try {
return oxNew(OrderRecipients::class, $this->order)->getSmsRecipient();
} catch (noRecipientFoundException $e) {
Registry::getUtilsView()->addErrorToDisplay(
Registry::getLang()->translateString($e->getMessage())
);
/** @var string $message */
$message = Registry::getLang()->translateString($e->getMessage());
Registry::getUtilsView()->addErrorToDisplay($message);
}
return false;
}
/**
* @return void
* @throws Exception
*/
public function send()
public function send(): void
{
$messageBody = Registry::getRequest()->getRequestEscapedParameter('messagebody');
if (false === is_string($messageBody) || strlen($messageBody) <= 1) {
Registry::getUtilsView()->addErrorToDisplay(
Registry::getLang()->translateString('D3LM_EXC_MESSAGE_NO_LENGTH')
);
/** @var string $message */
$message = Registry::getLang()->translateString('D3LM_EXC_MESSAGE_NO_LENGTH');
Registry::getUtilsView()->addErrorToDisplay($message);
return;
}
@ -85,17 +86,15 @@ class AdminOrder extends AdminController
try {
$sms = oxNew(Sms::class, $messageBody);
if ($sms->sendOrderMessage($order)) {
$smsCount = $sms->getResponse() ? $sms->getResponse()->getSmsCount() : 0;
Registry::getUtilsView()->addErrorToDisplay(
oxNew(successfullySentException::class, $sms->getResponse()->getSmsCount())
oxNew(successfullySentException::class, $smsCount)
);
} else {
$errorMsg = $sms->getResponse() instanceof ResponseInterface ? $sms->getResponse()->getErrorMessage() : 'no response';
Registry::getUtilsView()->addErrorToDisplay(
sprintf(
Registry::getLang()->translateString('D3LM_EXC_MESSAGE_UNEXPECTED_ERR_SEND'),
$errorMsg
)
);
/** @var string $format */
$format = Registry::getLang()->translateString('D3LM_EXC_MESSAGE_UNEXPECTED_ERR_SEND');
Registry::getUtilsView()->addErrorToDisplay(sprintf($format, $errorMsg));
}
} catch (noRecipientFoundException $e) {
Registry::getUtilsView()->addErrorToDisplay($e);

View File

@ -57,24 +57,26 @@ class AdminUser extends AdminController
try {
return oxNew(UserRecipients::class, $this->user)->getSmsRecipient();
} catch (noRecipientFoundException $e) {
Registry::getUtilsView()->addErrorToDisplay(
Registry::getLang()->translateString($e->getMessage())
);
/** @var string $message */
$message = Registry::getLang()->translateString($e->getMessage());
Registry::getUtilsView()->addErrorToDisplay($message);
}
return false;
}
/**
* @return void
* @throws Exception
*/
public function send()
public function send(): void
{
/** @var string $messageBody */
$messageBody = Registry::getRequest()->getRequestEscapedParameter('messagebody');
if (strlen($messageBody) <= 1) {
Registry::getUtilsView()->addErrorToDisplay(
Registry::getLang()->translateString('D3LM_EXC_MESSAGE_NO_LENGTH')
);
/** @var string $message */
$message = Registry::getLang()->translateString('D3LM_EXC_MESSAGE_NO_LENGTH');
Registry::getUtilsView()->addErrorToDisplay($message);
return;
}
@ -83,20 +85,15 @@ class AdminUser extends AdminController
$sms = oxNew(Sms::class, $messageBody);
if ($sms->sendUserAccountMessage($user)) {
Registry::getUtilsView()->addErrorToDisplay(
sprintf(
Registry::getLang()->translateString('D3LM_EXC_SMS_SUCC_SENT'),
$sms->getResponse()->getSmsCount()
)
);
/** @var string $format */
$format = Registry::getLang()->translateString('D3LM_EXC_SMS_SUCC_SENT');
$smsCount = $sms->getResponse() ? $sms->getResponse()->getSmsCount() : 0;
Registry::getUtilsView()->addErrorToDisplay(sprintf($format, $smsCount));
} else {
$errorMsg = $sms->getResponse() instanceof ResponseInterface ? $sms->getResponse()->getErrorMessage() : 'no response';
Registry::getUtilsView()->addErrorToDisplay(
sprintf(
Registry::getLang()->translateString('D3LM_EXC_MESSAGE_UNEXPECTED_ERR_SEND'),
$errorMsg
)
);
/** @var string $format */
$format = Registry::getLang()->translateString('D3LM_EXC_MESSAGE_UNEXPECTED_ERR_SEND');
Registry::getUtilsView()->addErrorToDisplay(sprintf($format, $errorMsg));
}
}
}

View File

@ -16,18 +16,36 @@ declare(strict_types=1);
namespace D3\Linkmobility4OXID\Application\Model;
use Assert\Assert;
use OxidEsales\Eshop\Application\Model\Order;
use OxidEsales\Eshop\Application\Model\User;
use OxidEsales\Eshop\Core\Registry;
class Configuration
{
public const DEBUG = "d3linkmobility_debug";
public const GENERAL_APITOKEN = "d3linkmobility_apitoken";
public const GENERAL_DEBUG = "d3linkmobility_debug";
public const ORDER_RECFIELDS = "d3linkmobility_smsOrderRecipientsFields";
public const USER_RECFIELDS = "d3linkmobility_smsUserRecipientsFields";
public const SMS_SENDERNR = "d3linkmobility_smsSenderNumber";
public const SMS_SENDERCOUNTRY = "d3linkmobility_smsSenderCountry";
public const SENDBY_ORDERED = "d3linkmobility_orderActive";
public const SENDBY_SENDEDNOW = "d3linkmobility_sendedNowActive";
public const SENDBY_CANCELED = "d3linkmobility_cancelOrderActive";
public const ARGS_CHECKKEYS = "checkKeys";
public const ARGS_CHECKCLASS = "checkClassName";
/**
* @return string
*/
public function getApiToken(): string
{
$token = trim((string) Registry::getConfig()->getConfigParam('d3linkmobility_apitoken'));
/** @var string $token */
$token = Registry::getConfig()->getConfigParam(self::GENERAL_APITOKEN);
$token = trim($token);
Assert::that($token)->string()->notEmpty();
@ -39,7 +57,7 @@ class Configuration
*/
public function getTestMode(): bool
{
return (bool) Registry::getConfig()->getConfigParam(self::DEBUG);
return (bool) Registry::getConfig()->getConfigParam(self::GENERAL_DEBUG);
}
/**
@ -47,7 +65,9 @@ class Configuration
*/
public function getSmsSenderNumber()
{
$number = trim(Registry::getConfig()->getConfigParam('d3linkmobility_smsSenderNumber'));
/** @var string $number */
$number = Registry::getConfig()->getConfigParam(self::SMS_SENDERNR);
$number = trim($number);
return strlen($number) ? $number : null;
}
@ -55,13 +75,102 @@ class Configuration
/**
* @return string|null
*/
public function getSmsSenderCountry(): string
public function getSmsSenderCountry(): ?string
{
$country = trim(Registry::getConfig()->getConfigParam('d3linkmobility_smsSenderCountry'));
/** @var string $country */
$country = Registry::getConfig()->getConfigParam(self::SMS_SENDERCOUNTRY);
$country = trim($country);
$country = strlen($country) ? strtoupper($country) : null;
Assert::that($country)->nullOr()->string()->length(2);
return $country;
}
/**
* @return string[]
*/
public function getOrderRecipientFields(): array
{
/** @var string[] $customFields */
$customFields = Registry::getConfig()->getConfigParam(self::ORDER_RECFIELDS) ?: [];
array_walk(
$customFields,
[$this, 'checkFieldExists'],
[self::ARGS_CHECKKEYS => true, self::ARGS_CHECKCLASS => Order::class]
);
$customFields = array_filter($customFields);
Assert::that($customFields)->isArray();
return $customFields;
}
/**
* @return string[]
*/
public function getUserRecipientFields(): array
{
/** @var string[] $customFields */
$customFields = Registry::getConfig()->getConfigParam(self::USER_RECFIELDS) ?: [];
array_walk(
$customFields,
[$this, 'checkFieldExists'],
[self::ARGS_CHECKKEYS => false, self::ARGS_CHECKCLASS => User::class]
);
$customFields = array_filter($customFields);
Assert::that($customFields)->isArray();
return $customFields;
}
/**
* @template T
* @param string $checkPhoneFieldName
* @param string $checkCountryFieldName
* @param array{checkKeys: bool, checkClassName: class-string<T>} $args
* @return void
*/
protected function checkFieldExists(string &$checkPhoneFieldName, string $checkCountryFieldName, array $args): void
{
$checkCountryFieldName = $args[self::ARGS_CHECKKEYS] ? trim($checkCountryFieldName) : $checkCountryFieldName;
$checkPhoneFieldName = trim($checkPhoneFieldName);
$allFieldNames = oxNew($args[self::ARGS_CHECKCLASS])->getFieldNames() ?: [];
array_walk($allFieldNames, function (&$value) {
$value = strtolower($value);
});
$checkPhoneFieldName = in_array(strtolower($checkPhoneFieldName), $allFieldNames) && (
false === $args[self::ARGS_CHECKKEYS] ||
in_array(strtolower($checkCountryFieldName), $allFieldNames)
) ? $checkPhoneFieldName : null;
}
/**
* @return bool
*/
public function sendOrderFinishedMessage(): bool
{
return (bool) Registry::getConfig()->getConfigParam(self::SENDBY_ORDERED);
}
/**
* @return bool
*/
public function sendOrderSendedNowMessage(): bool
{
return (bool) Registry::getConfig()->getConfigParam(self::SENDBY_SENDEDNOW);
}
/**
* @return bool
*/
public function sendOrderCanceledMessage(): bool
{
return (bool) Registry::getConfig()->getConfigParam(self::SENDBY_CANCELED);
}
}

View File

@ -15,6 +15,6 @@ declare(strict_types=1);
namespace D3\Linkmobility4OXID\Application\Model\Exceptions;
interface abortSendingExceptionInterface
interface abortSendingExceptionInterface extends \Throwable
{
}

View File

@ -16,19 +16,21 @@ declare(strict_types=1);
namespace D3\Linkmobility4OXID\Application\Model\Exceptions;
use Exception;
use OxidEsales\Eshop\Core\Exception\StandardException;
use OxidEsales\Eshop\Core\Registry;
use Throwable;
class successfullySentException extends Exception
class successfullySentException extends StandardException
{
/**
* @param int $messageCount
* @param int $code
* @param Throwable|null $previous
* @param Exception|null $previous
*/
public function __construct($messageCount = 1, $code = 0, Throwable $previous = null)
public function __construct($messageCount = 1, $code = 0, Exception $previous = null)
{
$message = sprintf(Registry::getLang()->translateString('D3LM_EXC_SMS_SUCC_SENT'), $messageCount);
/** @var string $format */
$format = Registry::getLang()->translateString('D3LM_EXC_SMS_SUCC_SENT');
$message = sprintf($format, $messageCount);
parent::__construct($message, $code, $previous);
}

View File

@ -19,51 +19,57 @@ use D3\Linkmobility4OXID\Application\Model\Exceptions\noRecipientFoundException;
use D3\Linkmobility4OXID\Application\Model\MessageTypes\Sms;
use Exception;
use OxidEsales\Eshop\Application\Model\Order;
use OxidEsales\Eshop\Core\Registry;
class MessageSender
{
/**
* @param Order $order
* @param $messageBody
* @param string $messageBody
* @return void
* @throws Exception
*/
public function sendOrderFinishedMessage(Order $order, $messageBody)
public function sendOrderFinishedMessage(Order $order, string $messageBody): void
{
$this->sendMessageByOrder('d3linkmobility_orderActive', $order, $messageBody);
if ((oxNew(Configuration::class))->sendOrderFinishedMessage()) {
$this->sendMessageByOrder($order, $messageBody);
}
}
/**
* @param Order $order
* @param $messageBody
* @param string $messageBody
* @return void
* @throws Exception
*/
public function sendSendedNowMessage(Order $order, $messageBody)
public function sendSendedNowMessage(Order $order, string $messageBody): void
{
$this->sendMessageByOrder('d3linkmobility_sendedNowActive', $order, $messageBody);
if ((oxNew(Configuration::class))->sendOrderSendedNowMessage()) {
$this->sendMessageByOrder($order, $messageBody);
}
}
/**
* @param Order $order
* @param $messageBody
* @param string $messageBody
* @return void
* @throws Exception
*/
public function sendCancelOrderMessage(Order $order, $messageBody)
public function sendCancelOrderMessage(Order $order, string $messageBody): void
{
$this->sendMessageByOrder('d3linkmobility_cancelOrderActive', $order, $messageBody);
if ((oxNew(Configuration::class))->sendOrderCanceledMessage()) {
$this->sendMessageByOrder($order, $messageBody);
}
}
/**
* @param $configParam
* @param Order $order
* @param $messageBody
* @param string $messageBody
* @return void
* @throws Exception
*/
public function sendMessageByOrder($configParam, Order $order, $messageBody)
public function sendMessageByOrder(Order $order, string $messageBody): void
{
if (false === (bool) Registry::getConfig()->getConfigParam($configParam)
|| (bool) strlen(trim($messageBody)) === false
) {
if ((bool) strlen(trim($messageBody)) === false) {
return;
}

View File

@ -22,13 +22,18 @@ use OxidEsales\Eshop\Application\Model\Remark;
abstract class AbstractMessage
{
const REMARK_IDENT = 'LINKMOB';
public const REMARK_IDENT = 'LINKMOB';
/** @var string */
protected $message;
/** @var bool */
protected $removeLineBreaks = true;
/** @var bool */
protected $removeMultipleSpaces = true;
/** @var ResponseInterface */
protected $response;
/** @var Recipient[] */
protected $recipients = [];
/**
@ -48,13 +53,14 @@ abstract class AbstractMessage
}
/**
* @param $userId
* @param $recipients
* @param $message
* @param string $userId
* @param string $recipients
* @param string $message
*
* @return void
* @throws Exception
*/
protected function setRemark($userId, $recipients, $message)
protected function setRemark(string $userId, string $recipients, string $message): void
{
$remark = oxNew(Remark::class);
$remark->assign([
@ -74,7 +80,7 @@ abstract class AbstractMessage
}
/**
* @param array $recipients
* @param array<Recipient> $recipients
* @return void
*/
protected function setRecipients(array $recipients)
@ -97,17 +103,17 @@ abstract class AbstractMessage
}
/**
* @param $message
* @param string $message
*
* @return string
*/
protected function sanitizeMessage($message): string
protected function sanitizeMessage(string $message): string
{
$message = trim(strip_tags($message));
$message = $this->removeLineBreaks ? str_replace(["\r", "\n"], ' ', $message) : $message;
$regexp = '/\s{2,}/m';
return $this->removeMultipleSpaces ? preg_replace($regexp, ' ', $message) : $message;
return $this->removeMultipleSpaces ? (string) preg_replace($regexp, ' ', $message) : $message;
}
abstract public function getTypeName() : string;
abstract public function getTypeName(): string;
}

View File

@ -98,7 +98,7 @@ class Sms extends AbstractMessage
}
/**
* @param array $recipientsArray
* @param array<Recipient> $recipientsArray
*
* @return bool
*/
@ -137,16 +137,17 @@ class Sms extends AbstractMessage
return $response->isSuccessful();
} catch (abortSendingExceptionInterface $e) {
Registry::getLogger()->warning($e->getMessage());
Registry::getUtilsView()->addErrorToDisplay($e);
// Oxid does not accept throwable interface only exceptions according by definition
Registry::getUtilsView()->addErrorToDisplay($e->getMessage());
} catch (GuzzleException $e) {
Registry::getLogger()->warning($e->getMessage());
Registry::getUtilsView()->addErrorToDisplay($e);
Registry::getUtilsView()->addErrorToDisplay($e->getMessage());
} catch (ApiException $e) {
Registry::getLogger()->warning($e->getMessage());
Registry::getUtilsView()->addErrorToDisplay($e);
Registry::getUtilsView()->addErrorToDisplay($e->getMessage());
} catch (InvalidArgumentException $e) {
Registry::getLogger()->warning($e->getMessage());
Registry::getUtilsView()->addErrorToDisplay($e);
Registry::getUtilsView()->addErrorToDisplay($e->getMessage());
}
return false;

View File

@ -16,10 +16,12 @@ declare(strict_types=1);
namespace D3\Linkmobility4OXID\Application\Model;
use D3\Linkmobility4OXID\Application\Model\Exceptions\noRecipientFoundException;
use D3\LinkmobilityClient\Exceptions\RecipientException;
use D3\LinkmobilityClient\LoggerHandler;
use D3\LinkmobilityClient\ValueObject\Recipient;
use libphonenumber\NumberParseException;
use OxidEsales\Eshop\Application\Model\Country;
use OxidEsales\Eshop\Application\Model\Order;
use OxidEsales\Eshop\Core\Registry;
class OrderRecipients
{
@ -40,17 +42,28 @@ class OrderRecipients
public function getSmsRecipient(): Recipient
{
foreach ($this->getSmsRecipientFields() as $phoneFieldName => $countryIdFieldName) {
$content = trim((string) $this->order->getFieldData($phoneFieldName));
/** @var string $content */
$content = $this->order->getFieldData($phoneFieldName) ?: '';
$content = trim($content);
$country = oxNew(Country::class);
if (strlen($content)) {
$country = oxNew(Country::class);
$country->load($this->order->getFieldData($countryIdFieldName));
return oxNew(Recipient::class, $content, $country->getFieldData('oxisoalpha2'));
try {
if (strlen($content)) {
/** @var string $countryId */
$countryId = $this->order->getFieldData(trim($countryIdFieldName));
$country->load($countryId);
return oxNew(Recipient::class, $content, $country->getFieldData('oxisoalpha2'));
}
} catch (NumberParseException $e) {
LoggerHandler::getInstance()->getLogger()->info($e->getMessage(), [$content, $country->getFieldData('oxisoalpha2')]);
} catch (RecipientException $e) {
LoggerHandler::getInstance()->getLogger()->info($e->getMessage(), [$content, $country->getFieldData('oxisoalpha2')]);
}
}
throw oxNew(noRecipientFoundException::class);
/** @var noRecipientFoundException $exc */
$exc = oxNew(noRecipientFoundException::class);
throw $exc;
}
/**
@ -58,7 +71,7 @@ class OrderRecipients
*/
public function getSmsRecipientFields(): array
{
$customFields = $this->getSanitizedCustomFields();
$customFields = (oxNew(Configuration::class))->getOrderRecipientFields();
return count($customFields) ?
$customFields :
@ -67,28 +80,4 @@ class OrderRecipients
'oxbillfon' => 'oxbillcountryid'
];
}
/**
* @return array
*/
public function getSanitizedCustomFields(): array
{
$customFields = (array) Registry::getConfig()->getConfigParam('d3linkmobility_smsOrderRecipientsFields');
array_walk($customFields, [$this, 'checkFieldExists']);
return array_filter($customFields);
}
public function checkFieldExists(&$checkPhoneFieldName, $checkCountryFieldName)
{
$checkCountryFieldName = trim($checkCountryFieldName);
$checkPhoneFieldName = trim($checkPhoneFieldName);
$allFieldNames = oxNew(Order::class)->getFieldNames();
array_walk($allFieldNames, function (&$value) {
$value = strtolower($value);
});
$checkPhoneFieldName = in_array(strtolower($checkPhoneFieldName), $allFieldNames) &&
in_array(strtolower($checkCountryFieldName), $allFieldNames) ? $checkPhoneFieldName : null;
}
}

View File

@ -25,6 +25,7 @@ class RequestFactory extends \D3\LinkmobilityClient\SMS\RequestFactory
{
$configuration = oxNew(Configuration::class);
/** @var SmsRequestInterface $request */
$request = parent::getSmsRequest();
$request->setTestMode($configuration->getTestMode())
->setSenderAddress(

View File

@ -16,10 +16,12 @@ declare(strict_types=1);
namespace D3\Linkmobility4OXID\Application\Model;
use D3\Linkmobility4OXID\Application\Model\Exceptions\noRecipientFoundException;
use D3\LinkmobilityClient\Exceptions\RecipientException;
use D3\LinkmobilityClient\LoggerHandler;
use D3\LinkmobilityClient\ValueObject\Recipient;
use libphonenumber\NumberParseException;
use OxidEsales\Eshop\Application\Model\Country;
use OxidEsales\Eshop\Application\Model\User;
use OxidEsales\Eshop\Core\Registry;
class UserRecipients
{
@ -40,16 +42,28 @@ class UserRecipients
public function getSmsRecipient(): Recipient
{
foreach ($this->getSmsRecipientFields() as $fieldName) {
$content = trim($this->user->getFieldData($fieldName));
if (strlen($content)) {
$country = oxNew(Country::class);
$country->load($this->user->getFieldData('oxcountryid'));
/** @var string $content */
$content = $this->user->getFieldData($fieldName) ?: '';
$content = trim($content);
$country = oxNew(Country::class);
return oxNew(Recipient::class, $content, $country->getFieldData('oxisoalpha2'));
try {
if (strlen($content)) {
/** @var string $countryId */
$countryId = $this->user->getFieldData('oxcountryid');
$country->load($countryId);
return oxNew(Recipient::class, $content, $country->getFieldData('oxisoalpha2'));
}
} catch (NumberParseException $e) {
LoggerHandler::getInstance()->getLogger()->info($e->getMessage(), [$content, $country->getFieldData('oxisoalpha2')]);
} catch (RecipientException $e) {
LoggerHandler::getInstance()->getLogger()->info($e->getMessage(), [$content, $country->getFieldData('oxisoalpha2')]);
}
}
throw oxNew(noRecipientFoundException::class);
/** @var noRecipientFoundException $exc */
$exc = oxNew(noRecipientFoundException::class);
throw $exc;
}
/**
@ -57,7 +71,7 @@ class UserRecipients
*/
public function getSmsRecipientFields(): array
{
$customFields = $this->getSanitizedCustomFields();
$customFields = (oxNew(Configuration::class))->getUserRecipientFields();
return count($customFields) ?
$customFields :
@ -67,29 +81,4 @@ class UserRecipients
'oxprivfon'
];
}
/**
* @return array
*/
public function getSanitizedCustomFields(): array
{
$customFields = (array) Registry::getConfig()->getConfigParam('d3linkmobility_smsUserRecipientsFields');
array_walk($customFields, [$this, 'checkFieldExists']);
return array_filter($customFields);
}
/**
* @param $checkFieldName
*/
public function checkFieldExists(&$checkFieldName)
{
$checkFieldName = trim($checkFieldName);
$allFieldNames = oxNew(User::class)->getFieldNames();
array_walk($allFieldNames, function (&$value) {
$value = strtolower($value);
});
$checkFieldName = in_array(strtolower($checkFieldName), $allFieldNames) ? $checkFieldName : null;
}
}

View File

@ -13,7 +13,7 @@
declare(strict_types=1);
namespace D3\Linkmobility4OXID\Modules\Aplication\Model {
namespace D3\Linkmobility4OXID\Modules\Application\Model {
use OxidEsales\Eshop\Application\Model\Order;

View File

@ -15,15 +15,24 @@ declare(strict_types=1);
namespace D3\Linkmobility4OXID\Modules\Application\Model;
use D3\Linkmobility4OXID\Modules\Core\EmailCore;
use OxidEsales\Eshop\Core\Email;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
class OrderModel extends OrderModel_parent
{
public function cancelOrder()
/**
* @return void
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function cancelOrder(): void
{
parent::cancelOrder();
if ($this->getFieldData('oxstorno') === 1) {
if ((bool) $this->getFieldData('oxstorno') === true) {
/** @var EmailCore $Email */
$Email = oxNew(Email::class);
$Email->d3SendCancelMessage($this);
}

View File

@ -21,18 +21,25 @@ use OxidEsales\Eshop\Application\Model\Order;
use OxidEsales\EshopCommunity\Internal\Container\ContainerFactory;
use OxidEsales\EshopCommunity\Internal\Framework\Templating\TemplateRendererBridgeInterface;
use OxidEsales\EshopCommunity\Internal\Framework\Templating\TemplateRendererInterface;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
class EmailCore extends EmailCore_parent
{
/** @var string */
protected $d3OrderCustSmsTemplate = 'd3sms_ordercust.tpl';
/** @var string */
protected $d3OrderSendedNowSmsTemplate = 'd3sms_sendednow.tpl';
/** @var string */
protected $d3OrderCanceledSmsTemplate = 'd3sms_ordercanceled.tpl';
/**
* @param Order $order
* @param null $subject
* @param string $subject
*
* @return bool
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function sendOrderEmailToUser($order, $subject = null)
{
@ -45,9 +52,11 @@ class EmailCore extends EmailCore_parent
/**
* @param Order $order
* @param null $subject
* @param string $subject
*
* @return bool
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function sendSendedNowMail($order, $subject = null)
{
@ -60,8 +69,13 @@ class EmailCore extends EmailCore_parent
/**
* @param Order $order
*
* @return void
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws Exception
*/
public function d3SendOrderFinishedMessageToUser(Order $order)
public function d3SendOrderFinishedMessageToUser(Order $order): void
{
$messageSender = oxNew(MessageSender::class);
$messageSender->sendOrderFinishedMessage($order, $this->d3GetOrderFinishedSmsMessageBody($order));
@ -71,6 +85,8 @@ class EmailCore extends EmailCore_parent
* @param Order $order
*
* @return string
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
protected function d3GetOrderFinishedSmsMessageBody(Order $order): string
{
@ -83,9 +99,12 @@ class EmailCore extends EmailCore_parent
/**
* @param Order $order
*
* @return void
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws Exception
*/
public function d3SendedNowMessage(Order $order)
public function d3SendedNowMessage(Order $order): void
{
$messageSender = oxNew(MessageSender::class);
$messageSender->sendSendedNowMessage($order, $this->d3GetSendedNowSmsMessageBody($order));
@ -95,6 +114,8 @@ class EmailCore extends EmailCore_parent
* @param Order $order
*
* @return string
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
protected function d3GetSendedNowSmsMessageBody(Order $order): string
{
@ -104,7 +125,15 @@ class EmailCore extends EmailCore_parent
return $renderer->renderTemplate($this->d3OrderSendedNowSmsTemplate, $this->getViewData());
}
public function d3SendCancelMessage($order)
/**
* @param Order $order
*
* @return void
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws Exception
*/
public function d3SendCancelMessage(Order $order): void
{
$messageSender = oxNew(MessageSender::class);
$messageSender->sendCancelOrderMessage($order, $this->d3GetCancelOrderSmsMessageBody($order));
@ -114,6 +143,8 @@ class EmailCore extends EmailCore_parent
* @param Order $order
*
* @return string
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
protected function d3GetCancelOrderSmsMessageBody(Order $order): string
{
@ -127,9 +158,12 @@ class EmailCore extends EmailCore_parent
* Templating instance getter
*
* @return TemplateRendererInterface
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
protected function d3GetTplRenderer(): TemplateRendererInterface
{
/** @var TemplateRendererBridgeInterface $bridge */
$bridge = ContainerFactory::getInstance()->getContainer()
->get(TemplateRendererBridgeInterface::class);
$bridge->setEngine($this->_getSmarty());

147
src/Setup/Actions.php Normal file
View File

@ -0,0 +1,147 @@
<?php
/**
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* https://www.d3data.de
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
* @link https://www.oxidmodule.com
*/
declare(strict_types=1);
namespace D3\Linkmobility4OXID\Setup;
use D3\Linkmobility4OXID\Application\Model\MessageTypes\AbstractMessage;
use Doctrine\DBAL\Driver\Exception as DoctrineDriverException;
use Doctrine\DBAL\Exception as DoctrineException;
use Doctrine\DBAL\Query\QueryBuilder;
use OxidEsales\Eshop\Core\DatabaseProvider;
use OxidEsales\Eshop\Core\DbMetaDataHandler;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
use OxidEsales\Eshop\Core\Exception\DatabaseException;
use OxidEsales\Eshop\Core\Registry;
use OxidEsales\EshopCommunity\Internal\Container\ContainerFactory;
use OxidEsales\EshopCommunity\Internal\Framework\Database\QueryBuilderFactoryInterface;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
class Actions
{
/**
* @return void
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function setupDatabase()
{
try {
if (!$this->hasRemarkTypeEnumValue()) {
$this->addRemarkTypeEnumValue();
}
} catch (DatabaseException|DoctrineDriverException|DoctrineException $e) {
Registry::getLogger()->error($e->getMessage());
Registry::getUtilsView()->addErrorToDisplay($e);
}
}
/**
* Regenerate views for changed tables
*/
public function regenerateViews()
{
$oDbMetaDataHandler = oxNew(DbMetaDataHandler::class);
$oDbMetaDataHandler->updateViews();
}
/**
* @return bool
* @throws ContainerExceptionInterface
* @throws DoctrineDriverException
* @throws DoctrineException
* @throws NotFoundExceptionInterface
*/
protected function hasRemarkTypeEnumValue(): bool
{
$fieldType = $this->getRemarkTypeFieldType();
$patternEnumCheck = '/^\b(enum)\b/mi';
if (!preg_match($patternEnumCheck, $fieldType)) {
throw oxNew(DatabaseException::class, 'remark type field has not the expected enum type');
}
$patternValueCheck = '/\b('.preg_quote(AbstractMessage::REMARK_IDENT).')\b/mi';
return (bool) preg_match($patternValueCheck, $fieldType);
}
/**
* @return string
* @throws DoctrineDriverException
* @throws DoctrineException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
protected function getRemarkTypeFieldType(): string
{
/** @var QueryBuilder $qb */
$qb = ContainerFactory::getInstance()->getContainer()->get(QueryBuilderFactoryInterface::class)->create();
$qb->select('column_type')
->from('INFORMATION_SCHEMA.COLUMNS')
->where(
$qb->expr()->and(
$qb->expr()->eq(
'table_schema',
$qb->createNamedParameter(Registry::getConfig()->getConfigParam('dbName'))
),
$qb->expr()->eq(
'table_name',
$qb->createNamedParameter('oxremark')
),
$qb->expr()->eq(
'COLUMN_NAME',
$qb->createNamedParameter('oxtype')
)
)
);
return (string) $qb->execute()->fetchOne();
}
/**
* @return void
* @throws DoctrineDriverException
* @throws DoctrineException
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
protected function addRemarkTypeEnumValue()
{
$valuePattern = '/(?<=enum\().*(?=\))/i';
preg_match($valuePattern, $this->getRemarkTypeFieldType(), $matches);
$items = array_unique(
array_merge(
str_getcsv($matches[0], ',', "'"),
[AbstractMessage::REMARK_IDENT]
)
);
$db = DatabaseProvider::getDb();
$query = 'ALTER TABLE '.$db->quoteIdentifier('oxremark').
' CHANGE '.$db->quoteIdentifier('OXTYPE'). ' '.$db->quoteIdentifier('OXTYPE') .
' enum('.implode(',', $db->quoteArray($items)).')'.
' COLLATE '.$db->quote('utf8_general_ci').' NOT NULL DEFAULT '.$db->quote('r');
$db->execute($query);
}
}

48
src/Setup/Events.php Normal file
View File

@ -0,0 +1,48 @@
<?php
/**
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* https://www.d3data.de
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
* @link https://www.oxidmodule.com
*/
declare(strict_types=1);
// @codeCoverageIgnoreStart
namespace D3\Linkmobility4OXID\Setup;
use D3\ModCfg\Application\Model\Exception\d3ShopCompatibilityAdapterException;
use D3\ModCfg\Application\Model\Install\d3install;
use Doctrine\DBAL\DBALException;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
use OxidEsales\Eshop\Core\Exception\StandardException;
use OxidEsales\Eshop\Core\Exception\SystemComponentException;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
class Events
{
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public static function onActivate()
{
/** @var Actions $actions */
$actions = oxNew(Actions::class);
$actions->setupDatabase();
$actions->regenerateViews();
}
public static function onDeactivate()
{
}
}
// @codeCoverageIgnoreEnd

View File

@ -17,6 +17,7 @@ use D3\Linkmobility4OXID\Application\Controller\Admin\AdminOrder;
use D3\Linkmobility4OXID\Application\Controller\Admin\AdminUser;
use D3\Linkmobility4OXID\Modules\Application\Model\OrderModel;
use D3\Linkmobility4OXID\Modules\Core\EmailCore;
use D3\Linkmobility4OXID\Setup\Events;
use OxidEsales\Eshop\Application\Model\Order;
use OxidEsales\Eshop\Core\Email;
@ -34,7 +35,7 @@ $aModule = [
'de' => 'Anbindung der LINK Mobility API (Nachrichtenversand per SMS) an den Shop',
'en' => 'Connection of the LINK Mobility API ( sending messages via SMS) to the shop',
],
'version' => '1.0.0.0',
'version' => '1.1.0.0',
'thumbnail' => 'picture.png',
'author' => 'D&sup3; Data Development (Inh.: Thomas Dartsch)',
'email' => 'support@shopmodule.com',
@ -54,7 +55,10 @@ $aModule = [
'd3sms_sendednow.tpl' => 'd3/linkmobility/Application/views/tpl/SMS/sendednow.tpl',
'd3sms_ordercanceled.tpl' => 'd3/linkmobility/Application/views/tpl/SMS/ordercanceled.tpl',
],
'events' => [],
'events' => [
'onActivate' => Events::class.'::onActivate',
'onDeactivate' => Events::class.'::onDeactivate',
],
'blocks' => [
[
'template' => 'order_remark.tpl',