Skip to content

Commit 027a340

Browse files
authored
Merge pull request #16 from SynergiTech/v2
V2
2 parents 7656516 + 2feabd0 commit 027a340

28 files changed

Lines changed: 1193 additions & 232 deletions

.github/workflows/tests.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: Tests
2+
3+
on: [push]
4+
5+
jobs:
6+
build:
7+
runs-on: ubuntu-latest
8+
strategy:
9+
fail-fast: false
10+
matrix:
11+
php: [7.4, "8.0", 8.1, 8.2]
12+
13+
steps:
14+
- uses: actions/checkout@v3
15+
16+
- name: test on PHP ${{ matrix.php }}
17+
run: docker build . --build-arg PHP_VERSION=${{ matrix.php }}

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@ vendor/
22
.DS_Store
33
test.php
44
composer.lock
5+
*.cache
6+
coverage

Dockerfile

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
ARG PHP_VERSION=7.4
2+
FROM php:$PHP_VERSION-cli-alpine
3+
4+
RUN apk add git zip unzip autoconf make g++ icu-dev
5+
6+
RUN docker-php-ext-configure intl \
7+
&& docker-php-ext-install -j $(nproc) intl
8+
9+
RUN curl -sS https://getcomposer.org/installer | php \
10+
&& mv composer.phar /usr/local/bin/composer
11+
12+
RUN adduser -S php
13+
14+
WORKDIR /package
15+
16+
RUN chown php /package
17+
18+
USER php
19+
20+
COPY composer.json ./
21+
22+
RUN composer install
23+
24+
COPY src src
25+
COPY tests tests
26+
COPY ecs.php phpunit.xml phpstan.neon ./
27+
28+
RUN composer test

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Postal for PHP
22

3-
This library helps you send e-mails through [Postal](https://github.com/atech/postal) in PHP 5.4 and above.
3+
This library helps you send e-mails through [Postal](https://github.com/postalserver/postal) in PHP 7.4 and above.
44

55
## Installation
66

@@ -20,7 +20,7 @@ need to login to our web interface and generate a new API credential.
2020
$client = new Postal\Client('https://postal.yourdomain.com', 'your-api-key');
2121

2222
// Create a new message
23-
$message = new Postal\SendMessage($client);
23+
$message = new Postal\Send\Message();
2424

2525
// Add some recipients
2626
$message->to('john@example.com');
@@ -46,12 +46,12 @@ $message->header('X-PHP-Test', 'value');
4646
$message->attach('textmessage.txt', 'text/plain', 'Hello world!');
4747

4848
// Send the message and get the result
49-
$result = $message->send();
49+
$result = $client->send->message($message);
5050

5151
// Loop through each of the recipients to get the message ID
5252
foreach ($result->recipients() as $email => $message) {
53-
$email; // The e-mail address of the recipient
54-
$message->id(); // Returns the message ID
55-
$message->token(); // Returns the message's token
53+
$email; // The e-mail address of the recipient
54+
$message->id; // The message ID
55+
$message->token; // The message's token
5656
}
5757
```

composer.json

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,41 @@
88
{
99
"name": "Adam Cooke",
1010
"email": "me@adamcooke.io"
11+
},
12+
{
13+
"name": "Josh Grant",
14+
"email": "josh@grantj.io"
15+
},
16+
{
17+
"name": "William Hall",
18+
"email": "william.hall@synergitech.co.uk"
1119
}
1220
],
1321
"type": "library",
1422
"require": {
15-
"php": ">=5.4",
16-
"rmccue/requests": "^1.0"
23+
"php": "^7.4 || ^8.0",
24+
"guzzlehttp/guzzle": "^6 || ^7"
1725
},
1826
"autoload": {
1927
"psr-4": {
2028
"Postal\\": "src/"
2129
}
30+
},
31+
"require-dev": {
32+
"phpstan/phpstan": "^1.10",
33+
"phpunit/phpunit": "^9.6",
34+
"symplify/easy-coding-standard": "^11.3"
35+
},
36+
"scripts": {
37+
"test": [
38+
"ecs",
39+
"phpunit",
40+
"phpstan"
41+
]
42+
},
43+
"config": {
44+
"platform": {
45+
"php": "7.4"
46+
}
2247
}
2348
}

ecs.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
use Symplify\EasyCodingStandard\Config\ECSConfig;
4+
use Symplify\EasyCodingStandard\ValueObject\Set\SetList;
5+
6+
return static function (ECSConfig $ecsConfig): void {
7+
$ecsConfig->paths([__DIR__ . '/src', __DIR__ . '/tests']);
8+
9+
$ecsConfig->sets([
10+
SetList::ARRAY,
11+
SetList::CLEAN_CODE,
12+
SetList::CONTROL_STRUCTURES,
13+
SetList::DOCBLOCK,
14+
SetList::NAMESPACES,
15+
SetList::PSR_12,
16+
SetList::SPACES,
17+
]);
18+
};

phpstan.neon

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
parameters:
2+
level: 9
3+
paths:
4+
- src

phpunit.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
4+
bootstrap="vendor/autoload.php"
5+
colors="true"
6+
>
7+
<testsuites>
8+
<testsuite name="Unit">
9+
<directory suffix="Test.php">./tests</directory>
10+
</testsuite>
11+
</testsuites>
12+
<coverage processUncoveredFiles="true">
13+
<include>
14+
<directory suffix=".php">./src</directory>
15+
</include>
16+
</coverage>
17+
</phpunit>

src/ApiException.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Postal;
6+
7+
class ApiException extends \Exception
8+
{
9+
}

src/Client.php

Lines changed: 88 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,103 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
namespace Postal;
46

7+
use GuzzleHttp\Client as HttpClient;
8+
use Psr\Http\Message\ResponseInterface;
9+
510
class Client
611
{
7-
public function __construct($host, $serverKey)
12+
public MessagesService $messages;
13+
14+
public SendService $send;
15+
16+
protected HttpClient $httpClient;
17+
18+
public function __construct(
19+
string $host,
20+
string $apiKey,
21+
HttpClient $httpClient = null
22+
) {
23+
$this->httpClient = $httpClient ?: HttpClientFactory::create($host, $apiKey);
24+
$this->messages = new MessagesService($this);
25+
$this->send = new SendService($this);
26+
}
27+
28+
public function getHttpClient(): HttpClient
29+
{
30+
return $this->httpClient;
31+
}
32+
33+
/**
34+
* @template T
35+
* @param class-string<T> $class
36+
* @return T
37+
*/
38+
public function prepareResponse(ResponseInterface $response, $class)
39+
{
40+
return new $class($this->validateResponse($response));
41+
}
42+
43+
/**
44+
* @template T
45+
* @param class-string<T> $class
46+
* @return array<T>
47+
*/
48+
public function prepareListResponse(ResponseInterface $response, $class)
49+
{
50+
$list = $this->validateResponse($response);
51+
52+
// if (! array_is_list($list)) {
53+
if (! $this->arrayIsList($list)) {
54+
throw new ApiException('Unexpected response received, expected a list');
55+
}
56+
57+
return array_map(fn ($item) => new $class($item), $list);
58+
}
59+
60+
/**
61+
* @return array<string|int, mixed>
62+
*/
63+
protected function validateResponse(ResponseInterface $response): array
864
{
9-
$this->host = $host;
10-
$this->serverKey = $serverKey;
65+
$json = json_decode((string) $response->getBody(), true);
66+
67+
if (json_last_error() !== JSON_ERROR_NONE || ! is_array($json)) {
68+
throw new ApiException('Malformed response body received');
69+
}
70+
71+
if (! isset($json['status']) || $json['status'] !== 'success') {
72+
$message = $json['data']['message'] ?? 'An unexpected error was received';
73+
$code = 0;
74+
if (isset($json['data']['code'])) {
75+
$message = $json['data']['code'] . ': ' . $message;
76+
$code = $json['data']['code'];
77+
}
78+
79+
throw new ApiException($message, $code);
80+
}
81+
82+
if (! isset($json['data'])) {
83+
throw new ApiException('Unexpected response received');
84+
}
85+
86+
return $json['data'];
1187
}
1288

13-
public function makeRequest($controller, $action, $parameters)
89+
/**
90+
* @param array<mixed> $array
91+
*/
92+
private function arrayIsList(array $array): bool
1493
{
15-
$url = sprintf('%s/api/v1/%s/%s', $this->host, $controller, $action);
16-
17-
// Headers
18-
$headers = [
19-
'x-server-api-key' => $this->serverKey,
20-
'content-type' => 'application/json',
21-
];
22-
23-
// Make the body
24-
$json = json_encode($parameters);
25-
26-
// Make the request
27-
$response = \Requests::post($url, $headers, $json);
28-
29-
if ($response->status_code === 200) {
30-
$json = json_decode($response->body);
31-
32-
if ($json->status == 'success') {
33-
return $json->data;
34-
} else {
35-
if (isset($json->data->code)) {
36-
throw new Error(sprintf('[%s] %s', $json->data->code, $json->data->message));
37-
} else {
38-
throw new Error($json->data->message);
39-
}
94+
$i = 0;
95+
foreach ($array as $k => $v) {
96+
if ($k !== $i++) {
97+
return false;
4098
}
4199
}
42100

43-
throw new Error('Couldn’t send message to API');
101+
return true;
44102
}
45103
}

0 commit comments

Comments
 (0)