summaryrefslogtreecommitdiffstats
path: root/src/Core/Communicator.php
blob: 68f43ed72b89d1ffcf5297df7854037cde54daa5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
<?php
/**
* PHP version 7.1.1
* @author Hannes Kindströmmer <hannes@kindstrommer.se>
* @copyright 2017 iP.1 Networks AB
* @license https://www.gnu.org/licenses/lgpl-3.0.txt LGPL-3.0
* @version 0.3.1-beta
* @since File available since Release 0.1.0-beta
* @link http://api.ip1sms.com/Help
* @link https://github.com/iP1SMS/ip1-php-sdk
*/
namespace IP1\RESTClient\Core;

use IP1\RESTClient\Recipient\RecipientFactory;
use IP1\RESTClient\Recipient\ProcessedBlacklistEntry;
use IP1\RESTClient\Core\ProcessedComponentInterface;
use IP1\RESTClient\Core\UpdatableComponentInterface;
use IP1\RESTClient\Core\ProcessableComponentInterface;
use \Httpful\Response;

/**
* Handles request to the API and converts the responses into the data classes.
* For the available endpoints check out link.
*/
class Communicator
{
    /**
    * The accountToken used for the first argument in HTTP Basic Auth.
    * @var string $accountToken
    */
    private $accountToken;
    /**
    * The apiToken used for the second argument in HTTP Basic Auth.
    * @var string $apiToken
    */
    private $apiToken;
    /**
    * An array of \Httpful\Response that returned HTTP code above or equal to 400.
    * @var array \Httpful\Response
    */
    public $errorResponses = [];
    const DOMAIN = "api.ip1sms.com";
    /**
    * Communicator constructor
    * @param string $accountToken Account ID. Provided by IP1.
    * @param string $apiToken     API Key.
    */
    public function __construct(string $accountToken, string $apiToken)
    {
        $this->accountToken = $accountToken;
        $this->apiToken = $apiToken;
    }
    /**
    * Adds the param to the API and returns the response as the corresponding object.
    * @param ProcessableComponentInterface $component A Contact, Group, Membership or OutGoingSMS.
    * @return ProcessedComponentInterface ProcessedContact, ProcessedGroup, PrcessedMembership or a ClassValidatinArray
    *           filled with ProcessedOutGoingSMS.
    * @throws \InvalidArgumentException When param isn't any of the classes listed in param args.
    */
    public function add(ProcessableComponentInterface $component)
    {
        switch (get_class($component)) {
            case "IP1\RESTClient\Recipient\Contact":
                $response = $this->sendRequest("api/contacts", "POST", json_encode($component));
                return RecipientFactory::createProcessedContactFromJSON($response);

            case "IP1\RESTClient\Recipient\Group":
                $response = $this->sendRequest("api/groups", "POST", json_encode($component));
                return RecipientFactory::createProcessedGroupFromJSON($response);

            case "IP1\RESTClient\Recipient\Membership":
                $response = $this->sendRequest("api/memberships", "POST", json_encode($component));
                return RecipientFactory::createProcessedMembershipFromJSON($response);

            case "IP1\RESTClient\SMS\OutGoingSMS":
                $response = $this->sendRequest("api/sms/send", "POST", json_encode($component));
                return RecipientFactory::createProcessedOutGoingSMSFromJSONArray($response);
            case "IP1\RESTClient\Recipient\BlacklistEntry":
                $response = $this->sendRequest("api/blacklist", "POST", json_encode($component));
                $stdResponse = json_decode($response);
                $created = new \DateTime($stdResponse->Created);
                return new ProcessedBlacklistEntry($stdResponse->Phone, $stdResponse->ID, $created);
            default:
                throw new \InvalidArgumentException("Given JsonSerializable not supported.");
        }
    }
    /**
    * Removes the param to the API and returns the response as the corresponding object.
    * @param ProcessedComponentInterface $component A Contact, Group, Membership.
    * @return ProcessedComponentInterface ProcessedContact, ProcessedGroup, PrcessedMembership or a ClassValidatinArray
    *           filled with ProcessedOutGoingSMS.
    * @throws \InvalidArgumentException When param isn't any of the classes listed in param args.
    */
    public function remove(ProcessedComponentInterface $component): ProcessedComponentInterface
    {
        switch (get_class($component)) {
            case "IP1\RESTClient\Recipient\ProcessedContact":
                $response = $this->sendRequest("api/contacts/".$component->getID(), "DELETE");
                return RecipientFactory::createProcessedContactFromJSON($response);

            case "IP1\RESTClient\Recipient\ProcessedGroup":
                $response = $this->sendRequest("api/groups/".$component->getID(), "DELETE");
                return RecipientFactory::createProcessedGroupFromJSON($response);

            case "IP1\RESTClient\Recipient\ProcessedMembership":
                $response = $this->sendRequest("api/memberships/".$component->getID(), "DELETE");
                return RecipientFactory::createProcessedMembershipFromJSON($response);

            case "IP1\RESTClient\Recipient\ProcessedBlacklistEntry":
                $response = $this->sendRequest("api/blacklist/".$component->getID(), "DELETE");
                $stdResponse = json_decode($response);
                $created = new \DateTime($stdResponse->Created);
                return new ProcessedBlacklistEntry($stdResponse->Phone, $stdResponse->ID, $created);

            default:
                throw new \InvalidArgumentException("Given JsonSerializable not supported.");
        }
    }
    /**
    * Edits the param to the API and returns the response as the corresponding object.
    * @param UpdatableComponentInterface $component A Contact, Group, Membership.
    * @return UpdatableComponentInterface ProcessedContact, ProcessedGroup or PrcessedMembership.
    * @throws \InvalidArgumentException When param isn't any of the classes listed in param args.
    */
    public function edit(UpdatableComponentInterface $component): UpdatableComponentInterface
    {
        switch (get_class($component)) {
            case "IP1\RESTClient\Recipient\ProcessedContact":
                $response = $this->sendRequest(
                    "api/contacts/".$component->getID(),
                    "PUT",
                    json_encode($component)
                );
                return RecipientFactory::createProcessedContactFromJSON($response);

            case "IP1\RESTClient\Recipient\ProcessedGroup":
                $response = $this->sendRequest(
                    "api/groups/".$component->getID(),
                    "PUT",
                    json_encode($component)
                );
                return RecipientFactory::createProcessedGroupFromJSON($response);
            default:
                throw new \InvalidArgumentException("Given JsonSerializable not supported.");
        }
    }

    /**
    * Fetches a ProcessedComponentInterface(s) from the given URI.
    * @param string $endPoint API URI.
    * @return string JSON API Response.
    */
    public function get(string $endPoint)
    {
        $parsedEndPoint = self::parseEndPoint($endPoint);
        return $this->sendRequest($parsedEndPoint, "GET");
    }
    /**
    * Adds the content object to the endpoint and returns a processed version of given object.
    * @param string            $endPoint API URI.
    * @param \JsonSerializable $content  The ProcessableComponentInterface that is to be posted to the API.
    * @return string JSON API Response.
    */
    public function post(string $endPoint, \JsonSerializable $content): string
    {
        $parsedEndPoint = self::parseEndPoint($endPoint);
        return $this->sendRequest($parsedEndPoint, "POST", json_encode($content));
    }
    /**
    * Deletes the object at the given endpoint
    * @param string $endPoint API URI.
    * @return string JSON string of what got deleted.
    */
    public function delete(string $endPoint): string
    {
        $parsedEndPoint = self::parseEndPoint($endPoint);
        return $this->sendRequest($parsedEndPoint, "DELETE");
    }
    /**
    * Replaces a ProcessedComponentInterface with the arguments given.
    * @param string            $endPoint API URI.
    * @param \JsonSerializable $content  The JsonSerializable that is to be PUT to the API.
    * @return string JSON API Response.
    */
    public function put(string $endPoint, \JsonSerializable $content): string
    {
        $parsedEndPoint = self::parseEndPoint($endPoint);
        return $this->sendRequest($parsedEndPoint, "PUT", json_encode($content));
    }
    /**
    * Turns the given endPoint string into a usable.
    * @param string $endPoint API URI.
    * @return string Fixed endpoint string.
    */
    private static function parseEndPoint(string $endPoint)
    {
        $endPoint = trim($endPoint, '/');
        $endPointArray = explode('/', $endPoint);
        if ($endPointArray[0] == "api") {
            return $endPoint;
        }
        array_unshift($endPointArray, "api");

        return implode('/', array_filter($endPointArray));
    }
    /**
    * Sends a HTTP request to the RESTful API and returns the result as a JSON string.
    *
    *   @param string  $endPoint The URI that the function should use.
    *   @param string  $method   The HTTP method that should be used, valid ones are:
    *                                   METH_POST, METH_GET, METH_DELETE and METH_PUT.
    *   @param string  $content  A JSON string containing all additional data that can not be provided by $endPoint.
    *   @param boolean $https    Whether the the API call should use HTTPS or not(HTTP).
    *   @return string             The response from the API.
    */
    private function sendRequest(string $endPoint, string $method, string $content = "", bool $https = true): Response
    {
        $url = ($https ? "https://" : "http://") . self::DOMAIN . "/" .$endPoint;
        $request = \Httpful\Request::init($method, 'application/json');
        $request->basicAuth($this->accountToken, $this->apiToken)
                ->addHeader('User-Agent', 'iP1sms/indev')
                ->expectsJson()
                ->Uri($url)
                ->body($content, 'application/json')
                ->neverSerialize();

        $response = $request->send();

        if ($response->hasErrors()) {
            $this->errorResponses[] = $response;
        }
        return $response;
    }
}