Skip to content

Commit

Permalink
feat: add client
Browse files Browse the repository at this point in the history
  • Loading branch information
brokeyourbike committed Oct 21, 2021
1 parent 721aa9e commit 9984110
Show file tree
Hide file tree
Showing 28 changed files with 1,203 additions and 0 deletions.
15 changes: 15 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false

[*.{yml,yaml}]
indent_size = 2
11 changes: 11 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Auto detect text files and perform LF normalization
* text=auto

.gitattributes export-ignore
.github export-ignore
.gitignore export-ignore
.github/ export-ignore
tests/ export-ignore
phpunit.xml export-ignore
phpstan.neon export-ignore
psalm.xml export-ignore
43 changes: 43 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: ci

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
laravel-tests:
runs-on: ubuntu-latest
timeout-minutes: 5
strategy:
matrix:
php-version: [7.4,8.0]

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Install PHP
uses: shivammathur/setup-php@v2
with:
php-version: "${{ matrix.php-version }}"
coverage: "pcov"

- name: Install PHP dependencies
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist

- name: Run PHPUnit
run: vendor/bin/phpunit --coverage-clover=coverage.xml

- name: Upload coverage to codecov
uses: codecov/codecov-action@v2
with:
files: ./coverage.xml

- name: Upload coverage to codeclimate
uses: paambaati/codeclimate-action@v3.0.0
env:
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
with:
coverageLocations: ./coverage.xml
18 changes: 18 additions & 0 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: release-please

on:
push:
branches:
- main

jobs:
update_release_draft:
runs-on: ubuntu-latest
timeout-minutes: 5

steps:
- uses: google-github-actions/release-please-action@v2
with:
release-type: php
- uses: actions/checkout@v2
if: ${{ steps.release.outputs.release_created }}
37 changes: 37 additions & 0 deletions .github/workflows/static.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: static analysis

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
phpstan:
name: PHPStan
runs-on: ubuntu-latest
timeout-minutes: 5
strategy:
matrix:
php-version: [7.4,8.0]

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: "${{ matrix.php-version }}"
coverage: none
extensions: mbstring
tools: composer

- name: Download dependencies
run: composer update --no-interaction --no-progress

- name: Download PHPStan
run: composer bin phpstan require phpstan/phpstan

- name: Execute PHPStan
run: vendor/bin/phpstan analyze --no-progress
25 changes: 25 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/vendor/
/vendor-bin/
node_modules/
npm-debug.log
yarn-error.log

# Laravel 4 specific
bootstrap/compiled.php
app/storage/

# Laravel 5 & Lumen specific
public/storage
public/hot

# Laravel 5 & Lumen specific with changed public path
public_html/storage
public_html/hot

storage/*.key
.env
Homestead.yaml
Homestead.json
/.vagrant
.phpunit.result.cache
composer.lock
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,29 @@
# termii-api-client-php

[![Latest Stable Version](https://img.shields.io/github/v/release/brokeyourbike/termii-api-client-php)](https://github.com/brokeyourbike/termii-api-client-php/releases)
[![Total Downloads](https://poser.pugx.org/brokeyourbike/termii-api-client/downloads)](https://packagist.org/packages/brokeyourbike/termii-api-client)
[![License: MPL-2.0](https://img.shields.io/badge/license-MPL--2.0-purple.svg)](https://github.com/brokeyourbike/termii-api-client-php/blob/main/LICENSE)

[![ci](https://github.com/brokeyourbike/termii-api-client-php/actions/workflows/ci.yml/badge.svg)](https://github.com/brokeyourbike/termii-api-client-php/actions/workflows/ci.yml)
[![Maintainability](https://api.codeclimate.com/v1/badges/1cd42fecafb04e6ed6ff/maintainability)](https://codeclimate.com/github/brokeyourbike/termii-api-client-php/maintainability)
[![codecov](https://codecov.io/gh/brokeyourbike/termii-api-client-php/branch/main/graph/badge.svg?token=ImcgnxzGfc)](https://codecov.io/gh/brokeyourbike/termii-api-client-php)

Termii API Client for PHP

## Installation

```bash
composer require brokeyourbike/termii-api-client
```

## Usage

```php
use BrokeYourBike\Termii\Client;

$apiClient = new Client($config, $httpClient);
$apiClient->fetchBalanceRaw();
```

## License
[Mozilla Public License v2.0](https://github.com/brokeyourbike/termii-api-client-php/blob/main/LICENSE)
37 changes: 37 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "brokeyourbike/termii-api-client",
"description": "Termii API Client for PHP",
"type": "library",
"license": "MPL-2.0",
"autoload": {
"psr-4": {
"BrokeYourBike\\Termii\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"BrokeYourBike\\Termii\\Tests\\": "tests/"
}
},
"authors": [
{
"name": "Ivan Stasiuk",
"email": "brokeyourbike@gmail.com",
"homepage": "https://github.com/brokeyourbike"
}
],
"minimum-stability": "stable",
"require": {
"php": "^7.4 || ^8.0",
"brokeyourbike/http-client": "^1.0",
"brokeyourbike/resolve-uri": "^1.0",
"myclabs/php-enum": "^1.8",
"brokeyourbike/http-enums": "^1.0",
"brokeyourbike/has-source-model": "^2.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.4",
"phpunit/phpunit": "^9.5",
"mockery/mockery": "^1.4"
}
}
5 changes: 5 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
parameters:
checkMissingIterableValueType: false
level: max
paths:
- src
19 changes: 19 additions & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<phpunit
colors="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTestsThatDoNotTestAnything="true"
bootstrap="vendor/autoload.php"
>
<testsuites>
<testsuite name="HTTP Client Test Suite">
<directory suffix=".php">./tests</directory>
</testsuite>
</testsuites>

<coverage>
<include>
<directory suffix=".php">src</directory>
</include>
</coverage>
</phpunit>
20 changes: 20 additions & 0 deletions src/ApiConfigInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

// Copyright (C) 2021 Ivan Stasiuk <brokeyourbike@gmail.com>.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

namespace BrokeYourBike\Termii;

/**
* @author Ivan Stasiuk <brokeyourbike@gmail.com>
*/
interface ApiConfigInterface
{
public function getUrl(): string;
public function getPublicKey(): string;
public function getSecretKey(): string;
public function getWebhookSecret(): string;
}
124 changes: 124 additions & 0 deletions src/Client.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<?php

// Copyright (C) 2021 Ivan Stasiuk <brokeyourbike@gmail.com>.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

namespace BrokeYourBike\Termii;

use Psr\Http\Message\ResponseInterface;
use BrokeYourBike\Termii\OtpRequestInterface;
use BrokeYourBike\Termii\MessageInterface;
use BrokeYourBike\Termii\ApiConfigInterface;
use BrokeYourBike\ResolveUri\ResolveUriTrait;
use BrokeYourBike\HttpEnums\HttpMethodEnum;
use BrokeYourBike\HttpClient\HttpClientTrait;
use BrokeYourBike\HttpClient\HttpClientInterface;
use BrokeYourBike\HasSourceModel\SourceModelInterface;
use BrokeYourBike\HasSourceModel\HasSourceModelTrait;
use BrokeYourBike\HasSourceModel\Enums\RequestOptions;

/**
* @author Ivan Stasiuk <brokeyourbike@gmail.com>
*/
class Client implements HttpClientInterface
{
use HttpClientTrait;
use ResolveUriTrait;
use HasSourceModelTrait;

private ApiConfigInterface $config;

public function __construct(ApiConfigInterface $config, \GuzzleHttp\ClientInterface $httpClient)
{
$this->config = $config;
$this->httpClient = $httpClient;
}

public function fetchBalanceRaw(): ResponseInterface
{
return $this->performRequest(HttpMethodEnum::GET(), 'get-balance', []);
}

public function sendMessage(MessageInterface $message): ResponseInterface
{
if ($message instanceof SourceModelInterface) {
$this->setSourceModel($message);
}

return $this->performRequest(HttpMethodEnum::POST(), 'sms/send', [
'from' => $message->getFrom(),
'to' => $message->getTo(),
'sms' => $message->getMessageText(),
'type' => $message->getMessageType(),
'channel' => $message->getChannelType(),
]);
}

public function sendOneTimePassword(OtpRequestInterface $otpRequest): ResponseInterface
{
if ($otpRequest instanceof SourceModelInterface) {
$this->setSourceModel($otpRequest);
}

return $this->performRequest(HttpMethodEnum::POST(), 'sms/otp/send', [
'from' => $otpRequest->getFrom(),
'to' => $otpRequest->getTo(),
'channel' => $otpRequest->getChannelType(),
'message_type' => $otpRequest->getMessageType(),
'message_text' => $otpRequest->getMessageText(),
'pin_type' => $otpRequest->getPinType(),
'pin_attempts' => $otpRequest->getPinAttempts(),
'pin_time_to_live' => $otpRequest->getPinTtlMinutes(),
'pin_length' => $otpRequest->getPinLength(),
'pin_placeholder' => $otpRequest->getPinPlaceholder(),
]);
}

public function verifyOneTimePassword(OtpRequestInterface $otpRequest, string $pin): ResponseInterface
{
if ($otpRequest instanceof SourceModelInterface) {
$this->setSourceModel($otpRequest);
}

return $this->performRequest(HttpMethodEnum::POST(), 'sms/otp/verify', [
'pin_id' => $otpRequest->getPinId(),
'pin' => $pin,
]);
}

/**
* @param HttpMethodEnum $method
* @param string $uri
* @param array<mixed> $data
* @return ResponseInterface
*
* @throws \Exception
*/
private function performRequest(HttpMethodEnum $method, string $uri, array $data): ResponseInterface
{
$options = [
\GuzzleHttp\RequestOptions::HTTP_ERRORS => false,
\GuzzleHttp\RequestOptions::HEADERS => [
'Accept' => 'application/json',
],
];

$data['api_key'] = $this->config->getPublicKey();

if (HttpMethodEnum::GET()->equals($method)) {
$options[\GuzzleHttp\RequestOptions::QUERY] = $data;
} elseif (HttpMethodEnum::POST()->equals($method)) {
$options[\GuzzleHttp\RequestOptions::JSON] = $data;
}

if ($this->getSourceModel()) {
$options[RequestOptions::SOURCE_MODEL] = $this->getSourceModel();
}

$uri = (string) $this->resolveUriFor($this->config->getUrl(), $uri);
return $this->httpClient->request((string) $method, $uri, $options);
}
}
Loading

0 comments on commit 9984110

Please sign in to comment.