Files
2026-09-15 10:26:34 +08:00

194 lines
5.3 KiB
PHP

<?php
namespace Stemcell\Sms\Model;
use Stemcell\Sms\Api\Data\GatewayResponseInterface;
use Magento\Backend\App\ConfigInterface;
use Magento\Framework\Exception\InvalidArgumentException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Math\Random;
use Magento\Framework\Stdlib\DateTime\DateTimeFactory;
use \Magento\Framework\Api\DataObjectHelper;
/**
* property type should equal to captcha formId
* @package Stemcell\Sms\Model
*/
abstract class SmsSender implements SmsSendInterface
{
protected String $type;
protected String $mobile;
protected String $code;
protected bool $success;
protected String $message;
protected int $smsInterval = 0;
protected ConfigInterface $config;
protected Redis $redis;
protected DateTimeFactory $dateTimeFactory;
protected Random $random;
protected GatewayResponseInterface $gatewayResponse;
protected DataObjectHelper $dataObjectHelper;
public function __construct(
ConfigInterface $config,
Redis $redis,
DateTimeFactory $dateTimeFactory,
Random $random,
GatewayResponseInterface $gatewayResponse,
DataObjectHelper $dataObjectHelper,
array $data = []
) {
if (!isset($data['mobile']) || !isset($data['type'])) {
throw new LocalizedException(__('Mobile and Form Type is required'));
}
$this->mobile = $data['mobile'];
$this->random = $random;
$this->type = $data['type'];
$this->config = $config;
$this->redis = $redis;
$this->gatewayResponse = $gatewayResponse;
$this->dataObjectHelper = $dataObjectHelper;
$this->dateTimeFactory = $dateTimeFactory;
}
/**
* @return String
*/
public function getCode() {
return $this->code;
}
/**
* @return ConfigInterface
*/
public function getAppConfig() {
return $this->config;
}
public function getSmsConfig(String $field) {
$path = 'sms/'.$this->type.'/'.$field;
$value = $this->config->getValue($path);
if (!$value) {
throw new LocalizedException(__('please config %path', ['path'=>$path]));
}
return $value;
}
/**
* @param $path
* @return mixed
*/
protected function getGlobalConfig($path) {
$value = $this->config->getValue($path);
return $value;
}
public function getSuccess() {
return $this->success;
}
public function getMessage() {
return $this->message;
}
/**
* @return int
* @throws InvalidArgumentException
*/
public function getSmsInterval() {
if (!$this->type || !$this->mobile) {
throw new InvalidArgumentException(_('Please call setMobile,setType first'));
}
$sentAt = $this->smsInterval = (int)$this->redis->getRedis()
->hGet($this->type.'-'.$this->mobile, 'sent_at');
$now = $this->dateTimeFactory->create()->gmtTimestamp();
return $now-$sentAt;
}
/**
* @throws InvalidArgumentException
* @throws LocalizedException
*/
protected function beforeSend() {
if (!$this->type || !$this->mobile) {
throw new LocalizedException(__('Please call setMobile,setType first'));
}
$configInterval = $this->getGlobalConfig('sms/sms/time_interval');
if ($this->getSmsInterval() && $this->getSmsInterval() < $configInterval) {
throw new LocalizedException(__('SMS is sent too frequently, hold on please'));
}
}
/**
* @return GatewayResponseInterface
* @throws InvalidArgumentException
* @throws LocalizedException
*/
public function send(): GatewayResponseInterface
{
$this->beforeSend();
$this->code = Random::getRandomNumber(99999, 999999);
$response = $this->smsSend();
if ($response->getIsSuccess() || (int)$this->getGlobalConfig('sms/sms/debug')) {
$this->redis->getRedis()->hMSet(
$this->getSmsHashKey(),
[
'code' => $this->code,
'sent_at' => $this->dateTimeFactory->create()->gmtTimestamp()
]
);
$lifetime = (int)$this->getGlobalConfig('sms/sms/lifetime');
if ($lifetime){
$this->redis->getRedis()->expire($this->getSmsHashKey(), $lifetime);
}
}
return $response;
}
/**
* redis hash key
* @return string
*/
protected function getSmsHashKey() {
return $this->type.'-'.$this->mobile;
}
/**
* sms code validate
* @param string $code
* @return bool
*/
public function validate(string $code): bool
{
$storedCode = (int)$this->redis->getRedis()->hGet($this->getSmsHashKey(),'code');
if (!$storedCode) {
return false;
}
return $storedCode === (int)$code;
}
/**
* @param array $data
* @return GatewayResponseInterface
*/
protected function convertArrayToGatewayResponse(array $data) {
$this->dataObjectHelper->populateWithArray($this->gatewayResponse, $data, GatewayResponseInterface::class);
return $this->gatewayResponse;
}
protected abstract function smsSend(): GatewayResponseInterface;
protected abstract function getSenderType(): string;
}