Issues (12)

Client.php (1 issue)

1
<?php
2
3
/*
4
 * This file is part of datamolino client.
5
 *
6
 * (c) 2018 cwd.at GmbH <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Cwd\Datamolino;
15
16
use Cwd\Datamolino\Model\Token;
17
use GuzzleHttp\Psr7\Request;
18
use Http\Client\HttpClient;
19
use Http\Discovery\HttpClientDiscovery;
20
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
21
use Symfony\Component\Serializer\Encoder\JsonEncoder;
22
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
23
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
24
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
25
use Symfony\Component\Serializer\Serializer;
26
use GuzzleHttp\Client as GuzzleClient;
27
28
class Client
29
{
30
    private $apiUrl = 'https://beta.datamolino.com';
31
    private $apiVersion = 'v1_2';
32
    private $apiUri;
33
    private $tokenUrl;
34
    /** @var Token */
35
    private $token;
36
37
    /** @var HttpClient */
38
    private $client;
39
40
    /** @var Serializer */
41
    private $serializer;
42
43
    public function __construct(?GuzzleClient $client = null)
44
    {
45
        if (null === $client) {
46
            $this->client = HttpClientDiscovery::find();
47
        }
48
49
        $this->setUris();
50
51
        $normalizer = new ObjectNormalizer(null, new CamelCaseToSnakeCaseNameConverter(), null, new ReflectionExtractor());
52
        $this->serializer = new Serializer([new DateTimeNormalizer(), $normalizer], ['json' => new JsonEncoder()]);
53
    }
54
55
    /**
56
     * @param string|null     $payload
57
     * @param int|string|null $id
58
     * @param string          $endpoint
59
     * @param string|null     $hydrationClass
60
     * @param bool            $isList
61
     * @param string          $method
62
     * @param string|null     $urlExtension   - Special case only needed when retrieving original file!
63
     *
64
     * @throws \Http\Client\Exception
65
     * @throws \LogicException
66
     *
67
     * @return mixed
68
     */
69
    public function call($payload = null, $id = null, $endpoint = '', $hydrationClass = null, $isList = false, $method = 'POST', $urlExtension = null)
70
    {
71
        if (!$this->token instanceof Token) {
0 ignored issues
show
$this->token is always a sub-type of Cwd\Datamolino\Model\Token.
Loading history...
72
            throw new \LogicException('Token not set - Authenticate first - or store refresh token for later use');
73
        }
74
75
        if (in_array($method, ['GET', 'PUT', 'DELETE'])) {
76
            $format = (is_int($id)) ? '%s%s/%s' : '%s%s%s';
77
            $uri = sprintf($format, $this->apiUri, $endpoint, $id);
78
        } else {
79
            $uri = (null !== $id) ? sprintf('%s%s/%s', $this->apiUri, $endpoint, $id) : $this->apiUri.$endpoint;
80
        }
81
82
        /* Special case only needed for retrieve original file */
83
        if (null !== $urlExtension) {
84
            $uri .= $urlExtension;
85
        }
86
87
        $request = new Request($method, $uri, [
88
            'Authorization' => sprintf('Bearer %s', $this->token->getAccessToken()),
89
            'Content-Type' => 'application/json',
90
        ], $payload);
91
92
        $response = $this->client->sendRequest($request);
93
        $responseBody = $response->getBody()->getContents();
94
        $responseData = json_decode($responseBody);
95
96
        if ($response->getStatusCode() >= 300) {
97
            $message = isset($responseData->message) ?? 'Unknown';
98
            throw new \Exception(sprintf('Error on request %s: %s', $response->getStatusCode(), $message));
99
        }
100
101
        if (null !== $hydrationClass && class_exists($hydrationClass) && isset($responseData->$endpoint)) {
102
            return $this->denormalizeObject($hydrationClass, $responseData->$endpoint, $isList);
103
        } elseif (null !== $hydrationClass && !class_exists($hydrationClass)) {
104
            throw new \Exception(sprintf('HydrationClass (%s) does not exist', $hydrationClass));
105
        } elseif (null !== $hydrationClass && !isset($responseData->$endpoint)) {
106
            throw new \Exception(sprintf('Datapoint (%s) does not exist', $endpoint));
107
        }
108
109
        return $responseData;
110
    }
111
112
    /**
113
     * @param string $clientId
114
     * @param string $clientSecret
115
     * @param string $username
116
     * @param string $password
117
     *
118
     * @throws \Http\Client\Exception
119
     *
120
     * @return Token
121
     */
122
    public function authenticatePassword($clientId, string $clientSecret, string $username, string $password): Token
123
    {
124
        $request = new Request('POST', $this->tokenUrl, [
125
            'Content-Type' => 'application/json',
126
        ], json_encode([
127
            'client_id' => $clientId,
128
            'client_secret' => $clientSecret,
129
            'username' => $username,
130
            'password' => $password,
131
            'grant_type' => 'password',
132
        ]));
133
134
        $response = $this->getClient()->sendRequest($request);
135
        $responseBody = $response->getBody()->getContents();
136
        $this->token = $this->denormalizeObject(Token::class, [json_decode($responseBody)], false);
137
138
        return $this->token;
139
    }
140
141
    /**
142
     * @param string $clientId
143
     * @param string $clientSecret
144
     * @param string $refreshToken
145
     *
146
     * @throws \Http\Client\Exception
147
     *
148
     * @return Token
149
     */
150
    public function refreshToken($clientId, $clientSecret, $refreshToken): Token
151
    {
152
        $request = new Request('POST', $this->tokenUrl, [
153
            'Content-Type' => 'application/json',
154
        ], json_encode([
155
            'client_id' => $clientId,
156
            'client_secret' => $clientSecret,
157
            'refresh_token' => $refreshToken,
158
            'grant_type' => 'refresh_token',
159
        ]));
160
161
        $response = $this->getClient()->sendRequest($request);
162
        $responseBody = $response->getBody()->getContents();
163
164
        $this->token = $this->denormalizeObject(Token::class, [json_decode($responseBody)], false);
165
166
        return $this->token;
167
    }
168
169
    public function setToken(Token $token): Client
170
    {
171
        $this->token = $token;
172
173
        return $this;
174
    }
175
176
    /**
177
     * @return string
178
     */
179
    public function getApiUrl(): string
180
    {
181
        return $this->apiUrl;
182
    }
183
184
    /**
185
     * @param string $apiUrl
186
     *
187
     * @return Client
188
     */
189
    public function setApiUrl(string $apiUrl): Client
190
    {
191
        $this->apiUrl = $apiUrl;
192
        $this->setUris();
193
194
        return $this;
195
    }
196
197
    /**
198
     * @return string
199
     */
200
    public function getApiVersion(): string
201
    {
202
        return $this->apiVersion;
203
    }
204
205
    /**
206
     * @param string $apiVersion
207
     *
208
     * @return Client
209
     */
210
    public function setApiVersion(string $apiVersion): Client
211
    {
212
        $this->apiVersion = $apiVersion;
213
214
        return $this;
215
    }
216
217
    /**
218
     * @return string
219
     */
220
    public function getApiUri(): string
221
    {
222
        return $this->apiUri;
223
    }
224
225
    /**
226
     * @param string $apiUri
227
     *
228
     * @return Client
229
     */
230
    public function setApiUri(string $apiUri): Client
231
    {
232
        $this->apiUri = $apiUri;
233
        $this->setUris();
234
235
        return $this;
236
    }
237
238
    /**
239
     * @return string
240
     */
241
    public function getTokenUrl(): string
242
    {
243
        return $this->tokenUrl;
244
    }
245
246
    /**
247
     * @param string $tokenUrl
248
     *
249
     * @return Client
250
     */
251
    public function setTokenUrl(string $tokenUrl): Client
252
    {
253
        $this->tokenUrl = $tokenUrl;
254
255
        return $this;
256
    }
257
258
    public function denormalizeObject($hydrationClass, $dataObject, $isList = false)
259
    {
260
        $result = [];
261
262
        foreach ($dataObject as $data) {
263
            $result[] = $this->serializer->denormalize($data, $hydrationClass, null, [
264
                ObjectNormalizer::DISABLE_TYPE_ENFORCEMENT => true,
265
            ]);
266
        }
267
268
        if ($isList) {
269
            return $result;
270
        }
271
272
        return current($result);
273
    }
274
275
    protected function getClient(): HttpClient
276
    {
277
        return $this->client;
278
    }
279
280
    /**
281
     * @return Serializer
282
     */
283
    public function getSerializer(): Serializer
284
    {
285
        return $this->serializer;
286
    }
287
288
    private function setUris(): void
289
    {
290
        $this->apiUri = sprintf('%s/api/%s/', $this->apiUrl, $this->apiVersion);
291
        $this->tokenUrl = $this->apiUrl.'/oauth/token';
292
    }
293
}
294