diff --git a/.idea/php-client.iml b/.idea/php-client.iml index c30c550..b70dcac 100644 --- a/.idea/php-client.iml +++ b/.idea/php-client.iml @@ -3,7 +3,6 @@ - diff --git a/.idea/php-test-framework.xml b/.idea/php-test-framework.xml index 7ac299e..6ebdd70 100644 --- a/.idea/php-test-framework.xml +++ b/.idea/php-test-framework.xml @@ -5,6 +5,7 @@ + diff --git a/.idea/php.xml b/.idea/php.xml index 5a2a8f8..0bb2182 100644 --- a/.idea/php.xml +++ b/.idea/php.xml @@ -45,39 +45,34 @@ - - + + - - - /etc/php/7.4/cli/conf.d/10-mysqlnd.ini, /etc/php/7.4/cli/conf.d/10-opcache.ini, /etc/php/7.4/cli/conf.d/10-pdo.ini, /etc/php/7.4/cli/conf.d/15-xml.ini, /etc/php/7.4/cli/conf.d/20-bcmath.ini, /etc/php/7.4/cli/conf.d/20-calendar.ini, /etc/php/7.4/cli/conf.d/20-ctype.ini, /etc/php/7.4/cli/conf.d/20-curl.ini, /etc/php/7.4/cli/conf.d/20-dom.ini, /etc/php/7.4/cli/conf.d/20-exif.ini, /etc/php/7.4/cli/conf.d/20-ffi.ini, /etc/php/7.4/cli/conf.d/20-fileinfo.ini, /etc/php/7.4/cli/conf.d/20-ftp.ini, /etc/php/7.4/cli/conf.d/20-gd.ini, /etc/php/7.4/cli/conf.d/20-gettext.ini, /etc/php/7.4/cli/conf.d/20-gmp.ini, /etc/php/7.4/cli/conf.d/20-iconv.ini, /etc/php/7.4/cli/conf.d/20-imap.ini, /etc/php/7.4/cli/conf.d/20-json.ini, /etc/php/7.4/cli/conf.d/20-ldap.ini, /etc/php/7.4/cli/conf.d/20-mbstring.ini, /etc/php/7.4/cli/conf.d/20-mysqli.ini, /etc/php/7.4/cli/conf.d/20-pdo_mysql.ini, /etc/php/7.4/cli/conf.d/20-pdo_sqlite.ini, /etc/php/7.4/cli/conf.d/20-phar.ini, /etc/php/7.4/cli/conf.d/20-posix.ini, /etc/php/7.4/cli/conf.d/20-readline.ini, /etc/php/7.4/cli/conf.d/20-shmop.ini, /etc/php/7.4/cli/conf.d/20-simplexml.ini, /etc/php/7.4/cli/conf.d/20-soap.ini, /etc/php/7.4/cli/conf.d/20-sockets.ini, /etc/php/7.4/cli/conf.d/20-sqlite3.ini, /etc/php/7.4/cli/conf.d/20-sysvmsg.ini, /etc/php/7.4/cli/conf.d/20-sysvsem.ini, /etc/php/7.4/cli/conf.d/20-sysvshm.ini, /etc/php/7.4/cli/conf.d/20-tokenizer.ini, /etc/php/7.4/cli/conf.d/20-xdebug.ini, /etc/php/7.4/cli/conf.d/20-xmlreader.ini, /etc/php/7.4/cli/conf.d/20-xmlrpc.ini, /etc/php/7.4/cli/conf.d/20-xmlwriter.ini, /etc/php/7.4/cli/conf.d/20-xsl.ini, /etc/php/7.4/cli/conf.d/20-zip.ini - /etc/php/7.4/cli/php.ini + + + /home/aim/.asdf/installs/php/8.2.17RC2/conf.d/php.ini + - + - - - - - + - - + @@ -85,12 +80,10 @@ - - + - @@ -99,26 +92,24 @@ + + - - - - @@ -126,7 +117,7 @@ - + diff --git a/composer.json b/composer.json index 5fb2b74..a1a06fa 100755 --- a/composer.json +++ b/composer.json @@ -1,59 +1,60 @@ { - "authors": [ - { - "email": "support@seven.io", - "homepage": "https://www.seven.io", - "name": "seven communications GmbH & Co. KG", - "role": "Developer" - } - ], - "autoload": { - "psr-4": { - "Seven\\Api\\": "src/" - } - }, - "autoload-dev": { - "psr-4": { - "Seven\\Tests\\": "tests/" - } - }, - "config": { - "platform": { - "php": "7.4" - } - }, - "description": "Official API Client for requesting the seven.io SMS Gateway.", - "homepage": "https://github.com/seven-io/php-client", - "keywords": [ - "2fa", - "cnam", - "gateway", - "hlr", - "mnp", - "sms", - "text2speech", - "tts" - ], - "license": "MIT", - "name": "seven.io/api", - "require": { - "php": ">=7.4", - "ext-ctype": "*", - "ext-curl": "*", - "ext-mbstring": "*", - "ext-json": "*" - }, - "require-dev": { - "phpunit/phpunit": "^9", - "ext-xdebug": "*", - "ext-soap": "*", - "ext-simplexml": "*" - }, - "support": { - "docs": "https://github.com/seven-io/php-client", - "email": "support@seven.io", - "rss": "https://www.seven.io/en/feed/", - "source": "https://github.com/seven-io/php-client" - }, - "type": "library" + "authors": [ + { + "email": "support@seven.io", + "homepage": "https://www.seven.io", + "name": "seven communications GmbH & Co. KG", + "role": "Developer" + } + ], + "autoload": { + "psr-4": { + "Seven\\Api\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Seven\\Tests\\": "tests/" + } + }, + "config": { + "platform": { + "php": "8.2" + } + }, + "description": "Official API Client for requesting the seven.io messaging Gateway.", + "homepage": "https://github.com/seven-io/php-client", + "keywords": [ + "2fa", + "cnam", + "gateway", + "hlr", + "mnp", + "rcs", + "sms", + "text2speech", + "tts" + ], + "license": "MIT", + "name": "seven.io/api", + "require": { + "php": ">=8.2", + "ext-ctype": "*", + "ext-curl": "*", + "ext-mbstring": "*", + "ext-json": "*" + }, + "require-dev": { + "phpunit/phpunit": "^11", + "ext-xdebug": "*", + "ext-soap": "*", + "ext-simplexml": "*" + }, + "support": { + "docs": "https://github.com/seven-io/php-client", + "email": "support@seven.io", + "rss": "https://www.seven.io/en/feed/", + "source": "https://github.com/seven-io/php-client" + }, + "type": "library" } diff --git a/src/BaseClient.php b/src/BaseClient.php index 9f30181..0f75166 100644 --- a/src/BaseClient.php +++ b/src/BaseClient.php @@ -7,18 +7,18 @@ use Seven\Api\Constant\HttpMethod; use UnexpectedValueException; -abstract class BaseClient { +abstract class BaseClient +{ public const BASE_URI = 'https://gateway.seven.io/api'; - protected string $apiKey; - protected string $sentWith; - /** * @throws Exception */ - public function __construct(string $apiKey, string $sentWith = 'php-api') { - $this->apiKey = $apiKey; - $this->sentWith = $sentWith; + public function __construct( + protected string $apiKey, + protected string $sentWith = 'php-api' + ) + { if ('' === $apiKey) throw new InvalidArgumentException( "Invalid required constructor argument apiKey: $apiKey"); @@ -27,25 +27,23 @@ public function __construct(string $apiKey, string $sentWith = 'php-api') { "Invalid required constructor argument sentWith: $sentWith"); } - public function getApiKey(): string { + public function getApiKey(): string + { return $this->apiKey; } - public function getSentWith(): string { + public function getSentWith(): string + { return $this->sentWith; } - /** - * @return mixed - */ - public function delete(string $path, array $options = []) { + public function delete(string $path, array $options = []): mixed + { return $this->request($path, HttpMethod::DELETE, $options); } - /** - * @return mixed - */ - protected function request(string $path, string $method, array $options = []) { + protected function request(string $path, string $method, array $options = []): mixed + { $method = strtoupper($method); $methods = HttpMethod::values(); if (!in_array($method, $methods)) { @@ -58,16 +56,17 @@ protected function request(string $path, string $method, array $options = []) { $headers = [ 'Accept: application/json', 'Content-Type: application/json', - "SentWith: $this->sentWith", - "X-Api-Key: $this->apiKey", + 'SentWith: ' . $this->sentWith, + 'X-Api-Key:' . $this->apiKey, ]; - $url = self::BASE_URI . "/$path"; + $url = self::BASE_URI . '/' . $path; $params = http_build_query($options); - if (HttpMethod::GET === $method) $url .= "?$params"; + if (HttpMethod::GET === $method) $url .= '?' . $params; $ch = curl_init($url); if (HttpMethod::POST === $method) { + var_dump($options); $params = stripslashes(json_encode($options, JSON_UNESCAPED_UNICODE)); curl_setopt($ch, CURLOPT_POSTFIELDS, $params); @@ -88,23 +87,19 @@ protected function request(string $path, string $method, array $options = []) { try { $res = json_decode($res, false, 512, JSON_THROW_ON_ERROR); - } catch (Exception $e) { + } catch (Exception) { } return $res; } - /** - * @return mixed - */ - public function post(string $path, array $options = []) { + public function post(string $path, array $options = []): mixed + { return $this->request($path, HttpMethod::POST, $options); } - /** - * @return mixed - */ - public function get(string $path, array $options = []) { + public function get(string $path, array $options = []): mixed + { return $this->request($path, HttpMethod::GET, $options); } } diff --git a/src/Client.php b/src/Client.php index a85f956..513ab22 100755 --- a/src/Client.php +++ b/src/Client.php @@ -9,13 +9,15 @@ use Seven\Api\Resource\JournalResource; use Seven\Api\Resource\LookupResource; use Seven\Api\Resource\PricingResource; +use Seven\Api\Resource\RcsResource; use Seven\Api\Resource\SmsResource; use Seven\Api\Resource\StatusResource; use Seven\Api\Resource\SubaccountsResource; use Seven\Api\Resource\ValidateForVoiceResource; use Seven\Api\Resource\VoiceResource; -class Client extends BaseClient { +class Client extends BaseClient +{ public AnalyticsResource $analytics; public BalanceResource $balance; public ContactsResource $contacts; @@ -23,13 +25,15 @@ class Client extends BaseClient { public JournalResource $journal; public LookupResource $lookup; public PricingResource $pricing; + public RcsResource $rcs; public SmsResource $sms; public StatusResource $status; public SubaccountsResource $subaccounts; public ValidateForVoiceResource $validateForVoice; public VoiceResource $voice; - public function __construct(string $apiKey, string $sentWith = 'php-api') { + public function __construct(string $apiKey, string $sentWith = 'php-api') + { parent::__construct($apiKey, $sentWith); $this->analytics = new AnalyticsResource($this); @@ -39,6 +43,7 @@ public function __construct(string $apiKey, string $sentWith = 'php-api') { $this->journal = new JournalResource($this); $this->lookup = new LookupResource($this); $this->pricing = new PricingResource($this); + $this->rcs = new RcsResource($this); $this->sms = new SmsResource($this); $this->status = new StatusResource($this); $this->subaccounts = new SubaccountsResource($this); diff --git a/src/Params/Rcs/RcsEvent.php b/src/Params/Rcs/RcsEvent.php new file mode 100644 index 0000000..faf4e3b --- /dev/null +++ b/src/Params/Rcs/RcsEvent.php @@ -0,0 +1,9 @@ +msgId; + unset($arr['msgId']); + + $arr['event'] = $this->event->name; + + return $arr; + } +} diff --git a/src/Params/Rcs/RcsParams.php b/src/Params/Rcs/RcsParams.php new file mode 100644 index 0000000..890a4bc --- /dev/null +++ b/src/Params/Rcs/RcsParams.php @@ -0,0 +1,113 @@ +text = $text; + $this->to = $to; + } + + public function getTo(): string + { + return $this->to; + } + + public function getDelay(): ?DateTime + { + return $this->delay; + } + + public function setDelay(?DateTime $delay): self + { + $this->delay = $delay; + return $this; + } + + public function getForeignId(): ?string + { + return $this->foreign_id; + } + + public function setForeignId(?string $foreignId): self + { + $this->foreign_id = $foreignId; + return $this; + } + + public function getFrom(): ?string + { + return $this->from; + } + + public function setFrom(?string $from): self + { + $this->from = $from; + return $this; + } + + public function getLabel(): ?string + { + return $this->label; + } + + public function setLabel(?string $label): self + { + $this->label = $label; + return $this; + } + + public function getPerformanceTracking(): ?bool + { + return $this->performance_tracking; + } + + public function setPerformanceTracking(?bool $performanceTracking): self + { + $this->performance_tracking = $performanceTracking; + return $this; + } + + public function getText(): string + { + return $this->text; + } + + public function setText(string $text): self + { + $this->text = $text; + return $this; + } + + public function getTTL(): ?int + { + return $this->ttl; + } + + public function setTTL(?int $ttl): self + { + $this->ttl = $ttl; + return $this; + } + + public function toArray(): array + { + $arr = get_object_vars($this); + if ($this->delay) $arr['delay'] = $this->delay->format('Y-m-d h:i'); + return $arr; + } +} diff --git a/src/Params/SmsParams.php b/src/Params/SmsParams.php index d4213ca..7dfa5cc 100644 --- a/src/Params/SmsParams.php +++ b/src/Params/SmsParams.php @@ -4,7 +4,8 @@ use DateTime; -class SmsParams implements ParamsInterface { +class SmsParams implements ParamsInterface +{ protected ?DateTime $delay = null; protected array $files = []; protected ?bool $flash = null; @@ -20,161 +21,197 @@ class SmsParams implements ParamsInterface { protected ?bool $unicode = null; protected ?bool $utf8 = null; - public function __construct(string $text, string ...$to) { + public function __construct(string $text, string ...$to) + { $this->text = $text; $this->to = $to; } - public function getDelay(): ?DateTime { + public function getDelay(): ?DateTime + { return $this->delay; } - public function setDelay(?DateTime $delay): self { + public function setDelay(?DateTime $delay): self + { $this->delay = $delay; return $this; } - public function addFile(array $file): self { + public function addFile(array $file): self + { $this->files[] = $file; return $this; } - public function getFiles(): array { + public function getFiles(): array + { return $this->files; } - public function setFiles(array $files): self { + public function setFiles(array $files): self + { $this->files = $files; return $this; } - public function removeFile(int $index): self { + public function removeFile(int $index): self + { unset($this->files[$index]); return $this; } - public function removeFiles(): self { + public function removeFiles(): self + { $this->files = []; return $this; } - public function getFlash(): ?bool { + public function getFlash(): ?bool + { return $this->flash; } - public function setFlash(?bool $flash): self { + public function setFlash(?bool $flash): self + { $this->flash = $flash; return $this; } - public function getForeignId(): ?string { + public function getForeignId(): ?string + { return $this->foreign_id; } - public function setForeignId(?string $foreignId): self { + public function setForeignId(?string $foreignId): self + { $this->foreign_id = $foreignId; return $this; } - public function getFrom(): ?string { + public function getFrom(): ?string + { return $this->from; } - public function setFrom(?string $from): self { + public function setFrom(?string $from): self + { $this->from = $from; return $this; } - public function getLabel(): ?string { + public function getLabel(): ?string + { return $this->label; } - public function setLabel(?string $label): self { + public function setLabel(?string $label): self + { $this->label = $label; return $this; } - public function getNoReload(): ?bool { + public function getNoReload(): ?bool + { return $this->no_reload; } - public function setNoReload(?bool $noReload): self { + public function setNoReload(?bool $noReload): self + { $this->no_reload = $noReload; return $this; } - public function getPerformanceTracking(): ?bool { + public function getPerformanceTracking(): ?bool + { return $this->performance_tracking; } - public function setPerformanceTracking(?bool $performanceTracking): self { + public function setPerformanceTracking(?bool $performanceTracking): self + { $this->performance_tracking = $performanceTracking; return $this; } - public function getText(): string { + public function getText(): string + { return $this->text; } - public function setText(string $text): self { + public function setText(string $text): self + { $this->text = $text; return $this; } - public function addTo(string ...$to): self { + public function addTo(string ...$to): self + { $this->to = [...$this->to, ...$to]; return $this; } - public function getTo(): array { + public function getTo(): array + { return $this->to; } - public function setTo(array $to): self { + public function setTo(array $to): self + { $this->to = $to; return $this; } - public function getTtl(): ?int { + public function getTtl(): ?int + { return $this->ttl; } - public function setTtl(?int $ttl): self { + public function setTtl(?int $ttl): self + { $this->ttl = $ttl; return $this; } - public function getUdh(): ?string { + public function getUdh(): ?string + { return $this->udh; } - public function setUdh(?string $udh): self { + public function setUdh(?string $udh): self + { $this->udh = $udh; return $this; } - public function getUnicode(): ?bool { + public function getUnicode(): ?bool + { return $this->unicode; } - public function setUnicode(?bool $unicode): self { + public function setUnicode(?bool $unicode): self + { $this->unicode = $unicode; return $this; } - public function getUtf8(): ?bool { + public function getUtf8(): ?bool + { return $this->utf8; } - public function setUtf8(?bool $utf8): self { + public function setUtf8(?bool $utf8): self + { $this->utf8 = $utf8; return $this; } - public function toArray(): array { + public function toArray(): array + { $arr = get_object_vars($this); $arr['to'] = implode(',', $this->to); + if ($this->delay) $arr['delay'] = $this->delay->format('Y-m-d h:i'); + return $arr; } } diff --git a/src/Resource/RcsResource.php b/src/Resource/RcsResource.php new file mode 100644 index 0000000..834249d --- /dev/null +++ b/src/Resource/RcsResource.php @@ -0,0 +1,52 @@ +client->delete('rcs/messages/' . $id); + + return new RcsDeleted($res); + } + + /** + * @throws InvalidRequiredArgumentException + * @throws InvalidOptionalArgumentException + */ + public function dispatch(RcsParams $params): Rcs + { + $this->validate($params); + + $res = $this->client->post('rcs/messages', $params->toArray()); + var_dump($res); + + return new Rcs($res); + } + + /** + * @throws InvalidOptionalArgumentException + * @throws InvalidRequiredArgumentException + */ + public function validate($params): void + { + (new RcsValidator($params))->validate(); + } + + public function event(RcsEventParams $params): RcsEventDispatched + { + $res = $this->client->post('rcs/events', $params->toArray()); + + return new RcsEventDispatched($res); + } +} diff --git a/src/Response/Rcs/Rcs.php b/src/Response/Rcs/Rcs.php new file mode 100644 index 0000000..d50cf8c --- /dev/null +++ b/src/Response/Rcs/Rcs.php @@ -0,0 +1,58 @@ +balance = $data->balance; + $this->debug = $data->debug === 'true'; + $this->messages = array_map(fn($v) => new SmsMessage($v), $data->messages); + $this->smsType = $data->sms_type; + $this->success = (int)$data->success; + $this->totalPrice = $data->total_price; + } + + public function getBalance(): float + { + return $this->balance; + } + + public function isDebug(): bool + { + return $this->debug; + } + + public function getMessages(): array + { + return $this->messages; + } + + public function getSmsType(): string + { + return $this->smsType; + } + + public function getSuccess(): int + { + return $this->success; + } + + public function getTotalPrice(): float + { + return $this->totalPrice; + } +} diff --git a/src/Response/Rcs/RcsDeleted.php b/src/Response/Rcs/RcsDeleted.php new file mode 100644 index 0000000..5fa6b04 --- /dev/null +++ b/src/Response/Rcs/RcsDeleted.php @@ -0,0 +1,18 @@ +success = $data->success; + } + + public function isSuccess(): bool + { + return $this->success; + } +} diff --git a/src/Response/Rcs/RcsEventDispatched.php b/src/Response/Rcs/RcsEventDispatched.php new file mode 100644 index 0000000..78197b9 --- /dev/null +++ b/src/Response/Rcs/RcsEventDispatched.php @@ -0,0 +1,18 @@ +success = $data->success; + } + + public function isSuccess(): bool + { + return $this->success; + } +} diff --git a/src/Response/Rcs/RcsMessage.php b/src/Response/Rcs/RcsMessage.php new file mode 100644 index 0000000..90aa016 --- /dev/null +++ b/src/Response/Rcs/RcsMessage.php @@ -0,0 +1,103 @@ +channel = $data->channel; + $this->encoding = $data->encoding; + $this->error = $data->error; + $this->errorText = $data->error_text; + $this->id = $data->id ? (int)$data->id : null; + $this->isBinary = $data->is_binary; + $this->parts = $data->parts; + $this->price = $data->price; + $this->recipient = $data->recipient; + $this->sender = $data->sender; + $this->success = $data->success; + $this->text = $data->text; + $this->udh = $data->udh; + } + + public function getChannel(): string + { + return $this->channel; + } + + public function getEncoding(): string + { + return $this->encoding; + } + + public function getError(): ?string + { + return $this->error; + } + + public function getErrorText(): ?string + { + return $this->errorText; + } + + public function getId(): ?int + { + return $this->id; + } + + public function getParts(): int + { + return $this->parts; + } + + public function getPrice(): float + { + return $this->price; + } + + public function getRecipient(): string + { + return $this->recipient; + } + + public function getSender(): string + { + return $this->sender; + } + + public function isSuccess(): bool + { + return $this->success; + } + + public function getText(): string + { + return $this->text; + } + + public function getUdh(): ?string + { + return $this->udh; + } + + public function getIsBinary(): bool + { + return $this->isBinary; + } +} diff --git a/src/Validator/RcsValidator.php b/src/Validator/RcsValidator.php new file mode 100644 index 0000000..3830fb2 --- /dev/null +++ b/src/Validator/RcsValidator.php @@ -0,0 +1,178 @@ +delay(); + $this->foreign_id(); + $this->from(); + $this->label(); + $this->text(); + $this->to(); + $this->ttl(); + } + + /** @throws InvalidOptionalArgumentException */ + public function delay(): void + { + $delay = $this->params->getDelay(); + + if (!$delay) return; + + if ($delay < new DateTime) + throw new InvalidOptionalArgumentException('Delay must be a value from the future'); + } + + /** @throws InvalidOptionalArgumentException */ + public function foreign_id(): void + { + $foreignId = $this->params->getForeignId(); + + if (null === $foreignId || '' === $foreignId) { + return; + } + + $maxLength = SmsConstants::FOREIGN_ID_MAX_LENGTH; + if (mb_strlen($foreignId) > $maxLength) { + throw new InvalidOptionalArgumentException( + "foreign_id must not exceed '$maxLength' characters in length."); + } + + $pattern = SmsConstants::FOREIGN_ID_PATTERN; + if (strlen($foreignId) !== preg_match_all($pattern, $foreignId)) { + throw new InvalidOptionalArgumentException( + "foreign_id must match the regex pattern $pattern"); + } + } + + /** @throws InvalidOptionalArgumentException */ + public function from(): void + { + $from = $this->params->getFrom(); + + if (null === $from || '' === $from) { + return; + } + + $length = strlen($from); + + $alphaNumericMax = SmsConstants::FROM_ALPHANUMERIC_MAX; + $numericMax = SmsConstants::FROM_NUMERIC_MAX; + + $isNumeric = is_numeric($from); + + if ($length > $numericMax) { + throw new InvalidOptionalArgumentException( + "Argument 'from' may not exceed $numericMax chars."); + } + + if ($length > $alphaNumericMax && !$isNumeric) { + throw new InvalidOptionalArgumentException( + "Argument 'from' must be numeric. if > $alphaNumericMax chars."); + } + + if (!ctype_alnum( + str_ireplace(SmsConstants::FROM_ALLOWED_CHARS, '', $from))) { + throw new InvalidOptionalArgumentException( + "Argument 'from' must be alphanumeric."); + } + } + + /** @throws InvalidOptionalArgumentException */ + public function label(): void + { + $label = $this->params->getLabel(); + + if (null === $label || '' === $label) { + return; + } + + $max = SmsConstants::LABEL_MAX_LENGTH; + if (mb_strlen($label) > $max) { + throw new InvalidOptionalArgumentException( + "label must not exceed '$max' characters in length."); + } + + $pattern = SmsConstants::LABEL_PATTERN; + if (strlen($label) !== preg_match_all($pattern, $label)) { + throw new InvalidOptionalArgumentException( + "label must match the regex pattern $pattern"); + } + } + + /** @throws InvalidRequiredArgumentException */ + public function text(): void + { + $text = $this->params->getText() ?? ''; + + $length = strlen($text); + + if (null === $text || !$length) { + throw new InvalidRequiredArgumentException( + 'You cannot send an empty message.'); + } + + $maxTextLength = SmsConstants::TEXT_MAX_LENGTH; + + if ($maxTextLength < $length) { + throw new InvalidRequiredArgumentException( + "The text can not be longer than $maxTextLength characters."); + } + } + + /** @throws InvalidRequiredArgumentException */ + public function to(): void + { + $to = $this->params->getTo(); + + if (null === $to || '' === $to) { + throw new InvalidRequiredArgumentException( + 'You cannot send a message without specifying a recipient.'); + } + } + + /** @throws InvalidOptionalArgumentException */ + public function ttl(): void + { + $ttl = $this->params->getTtl(); + + if (null === $ttl) { + return; + } + + if (0 === $ttl) { + $this->params->setTtl(null); + return; + } + + $min = SmsConstants::TTL_MIN; + $max = SmsConstants::TTL_MAX; + + if ($ttl < $min) { + throw new InvalidOptionalArgumentException( + "ttl must be at least $min."); + } + + if ($ttl > $max) { + throw new InvalidOptionalArgumentException( + "ttl may not exceed $max."); + } + } +} diff --git a/src/Validator/SmsRules.php b/src/Validator/SmsRules.php new file mode 100644 index 0000000..707d17a --- /dev/null +++ b/src/Validator/SmsRules.php @@ -0,0 +1,161 @@ +params->getDelay(); + + if (!$delay) return; + + if ($delay < new DateTime) + throw new InvalidOptionalArgumentException('Delay must be a value from the future'); + } + + /** @throws InvalidOptionalArgumentException */ + public function foreign_id(): void + { + $foreignId = $this->params->getForeignId(); + + if (null === $foreignId || '' === $foreignId) { + return; + } + + $maxLength = SmsConstants::FOREIGN_ID_MAX_LENGTH; + if (mb_strlen($foreignId) > $maxLength) { + throw new InvalidOptionalArgumentException( + "foreign_id must not exceed '$maxLength' characters in length."); + } + + $pattern = SmsConstants::FOREIGN_ID_PATTERN; + if (strlen($foreignId) !== preg_match_all($pattern, $foreignId)) { + throw new InvalidOptionalArgumentException( + "foreign_id must match the regex pattern $pattern"); + } + } + + /** @throws InvalidOptionalArgumentException */ + public function from(): void + { + $from = $this->params->getFrom(); + + if (null === $from || '' === $from) { + return; + } + + $length = strlen($from); + + $alphaNumericMax = SmsConstants::FROM_ALPHANUMERIC_MAX; + $numericMax = SmsConstants::FROM_NUMERIC_MAX; + + $isNumeric = is_numeric($from); + + if ($length > $numericMax) { + throw new InvalidOptionalArgumentException( + "Argument 'from' may not exceed $numericMax chars."); + } + + if ($length > $alphaNumericMax && !$isNumeric) { + throw new InvalidOptionalArgumentException( + "Argument 'from' must be numeric. if > $alphaNumericMax chars."); + } + + if (!ctype_alnum( + str_ireplace(SmsConstants::FROM_ALLOWED_CHARS, '', $from))) { + throw new InvalidOptionalArgumentException( + "Argument 'from' must be alphanumeric."); + } + } + + /** @throws InvalidOptionalArgumentException */ + public function label(): void + { + $label = $this->params->getLabel(); + + if (null === $label || '' === $label) { + return; + } + + $max = SmsConstants::LABEL_MAX_LENGTH; + if (mb_strlen($label) > $max) { + throw new InvalidOptionalArgumentException( + "label must not exceed '$max' characters in length."); + } + + $pattern = SmsConstants::LABEL_PATTERN; + if (strlen($label) !== preg_match_all($pattern, $label)) { + throw new InvalidOptionalArgumentException( + "label must match the regex pattern $pattern"); + } + } + + /** @throws InvalidRequiredArgumentException */ + public function text(): void + { + $text = $this->params->getText() ?? ''; + + $length = strlen($text); + + if (null === $text || !$length) { + throw new InvalidRequiredArgumentException( + 'You cannot send an empty message.'); + } + + $maxTextLength = SmsConstants::TEXT_MAX_LENGTH; + + if ($maxTextLength < $length) { + throw new InvalidRequiredArgumentException( + "The text can not be longer than $maxTextLength characters."); + } + } + + /** @throws InvalidRequiredArgumentException */ + public function to(): void + { + $to = $this->params->getTo(); + + if (null === $to || '' === $to) { + throw new InvalidRequiredArgumentException( + 'You cannot send a message without specifying a recipient.'); + } + } + + /** @throws InvalidOptionalArgumentException */ + public function ttl(): void + { + $ttl = $this->params->getTtl(); + + if (null === $ttl) { + return; + } + + if (0 === $ttl) { + $this->params->setTtl(null); + return; + } + + $min = SmsConstants::TTL_MIN; + $max = SmsConstants::TTL_MAX; + + if ($ttl < $min) { + throw new InvalidOptionalArgumentException( + "ttl must be at least $min."); + } + + if ($ttl > $max) { + throw new InvalidOptionalArgumentException( + "ttl may not exceed $max."); + } + } +} diff --git a/src/Validator/SmsValidator.php b/src/Validator/SmsValidator.php index 743819f..150badf 100755 --- a/src/Validator/SmsValidator.php +++ b/src/Validator/SmsValidator.php @@ -2,24 +2,24 @@ namespace Seven\Api\Validator; -use Datetime; -use Seven\Api\Constant\SmsConstants; use Seven\Api\Exception\InvalidOptionalArgumentException; use Seven\Api\Exception\InvalidRequiredArgumentException; use Seven\Api\Params\SmsParams; -class SmsValidator { - protected SmsParams $params; +class SmsValidator +{ + use SmsRules; - public function __construct(SmsParams $params) { - $this->params = $params; + public function __construct(protected SmsParams $params) + { } /** * @throws InvalidOptionalArgumentException * @throws InvalidRequiredArgumentException */ - public function validate(): void { + public function validate(): void + { $this->delay(); $this->foreign_id(); $this->from(); @@ -28,144 +28,4 @@ public function validate(): void { $this->to(); $this->ttl(); } - - /** @throws InvalidOptionalArgumentException */ - public function delay(): void { - $delay = $this->params->getDelay(); - - if (!$delay) return; - - if ($delay < new DateTime) - throw new InvalidOptionalArgumentException('Delay must be a value from the future'); - } - - /** @throws InvalidOptionalArgumentException */ - public function foreign_id(): void { - $foreignId = $this->params->getForeignId(); - - if (null === $foreignId || '' === $foreignId) { - return; - } - - $maxLength = SmsConstants::FOREIGN_ID_MAX_LENGTH; - if (mb_strlen($foreignId) > $maxLength) { - throw new InvalidOptionalArgumentException( - "foreign_id must not exceed '$maxLength' characters in length."); - } - - $pattern = SmsConstants::FOREIGN_ID_PATTERN; - if (strlen($foreignId) !== preg_match_all($pattern, $foreignId)) { - throw new InvalidOptionalArgumentException( - "foreign_id must match the regex pattern $pattern"); - } - } - - /** @throws InvalidOptionalArgumentException */ - public function from(): void { - $from = $this->params->getFrom(); - - if (null === $from || '' === $from) { - return; - } - - $length = strlen($from); - - $alphaNumericMax = SmsConstants::FROM_ALPHANUMERIC_MAX; - $numericMax = SmsConstants::FROM_NUMERIC_MAX; - - $isNumeric = is_numeric($from); - - if ($length > $numericMax) { - throw new InvalidOptionalArgumentException( - "Argument 'from' may not exceed $numericMax chars."); - } - - if ($length > $alphaNumericMax && !$isNumeric) { - throw new InvalidOptionalArgumentException( - "Argument 'from' must be numeric. if > $alphaNumericMax chars."); - } - - if (!ctype_alnum( - str_ireplace(SmsConstants::FROM_ALLOWED_CHARS, '', $from))) { - throw new InvalidOptionalArgumentException( - "Argument 'from' must be alphanumeric."); - } - } - - /** @throws InvalidOptionalArgumentException */ - public function label(): void { - $label = $this->params->getLabel(); - - if (null === $label || '' === $label) { - return; - } - - $max = SmsConstants::LABEL_MAX_LENGTH; - if (mb_strlen($label) > $max) { - throw new InvalidOptionalArgumentException( - "label must not exceed '$max' characters in length."); - } - - $pattern = SmsConstants::LABEL_PATTERN; - if (strlen($label) !== preg_match_all($pattern, $label)) { - throw new InvalidOptionalArgumentException( - "label must match the regex pattern $pattern"); - } - } - - /** @throws InvalidRequiredArgumentException */ - public function text(): void { - $text = $this->params->getText() ?? ''; - - $length = strlen($text); - - if (null === $text || !$length) { - throw new InvalidRequiredArgumentException( - 'You cannot send an empty message.'); - } - - $maxTextLength = SmsConstants::TEXT_MAX_LENGTH; - - if ($maxTextLength < $length) { - throw new InvalidRequiredArgumentException( - "The text can not be longer than $maxTextLength characters."); - } - } - - /** @throws InvalidRequiredArgumentException */ - public function to(): void { - $to = $this->params->getTo(); - - if (null === $to || '' === $to) { - throw new InvalidRequiredArgumentException( - 'You cannot send a message without specifying a recipient.'); - } - } - - /** @throws InvalidOptionalArgumentException */ - public function ttl(): void { - $ttl = $this->params->getTtl(); - - if (null === $ttl) { - return; - } - - if (0 === $ttl) { - $this->params->setTtl(null); - return; - } - - $min = SmsConstants::TTL_MIN; - $max = SmsConstants::TTL_MAX; - - if ($ttl < $min) { - throw new InvalidOptionalArgumentException( - "ttl must be at least $min."); - } - - if ($ttl > $max) { - throw new InvalidOptionalArgumentException( - "ttl may not exceed $max."); - } - } } diff --git a/tests/Client/RcsTest.php b/tests/Client/RcsTest.php new file mode 100644 index 0000000..4a5b453 --- /dev/null +++ b/tests/Client/RcsTest.php @@ -0,0 +1,43 @@ +client->rcs->dispatch($params); + + $this->assertCount(1, $res->getMessages()); + $msg = $res->getMessages()[0]; + $this->assertEquals($params->getText(), $msg->getText()); + $this->assertEquals(str_replace('+', '', $params->getTo()), $msg->getRecipient()); + } + + public function testDelete(): void + { + $params = (new RcsParams('HI', '491716992343')) + ->setDelay((new DateTime)->add(DateInterval::createFromDateString('1 day'))); + $rcs = $this->client->rcs->dispatch($params); + $this->assertNotEmpty($rcs->getMessages()); + $msg = $rcs->getMessages()[0]; + + $res = $this->client->rcs->delete($msg->getId()); + $this->assertTrue($res->isSuccess()); + } + + public function testEvent(): void + { + $params = new RcsEventParams('4915237035388', RcsEvent::IS_TYPING); + $res = $this->client->rcs->event($params); + + $this->assertTrue($res->isSuccess()); + } +}