Passed
Push — master ( 36b0e9...650f65 )
by Ludwig
02:12
created

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 ($client === null) {
46
            $this->client = HttpClientDiscovery::find();
47
        }
48
        $this->apiUri = sprintf('%s/api/%s/', $this->apiUrl, $this->apiVersion);
49
        $this->tokenUrl = $this->apiUrl.'/oauth/token';
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
     * @return Token
120
     */
121
    public function authenticatePassword($clientId, string $clientSecret, string $username, string $password): Token
122
    {
123
        $request = new Request('POST', $this->tokenUrl, [
124
            'Content-Type' => 'application/json',
125
        ], json_encode([
126
            'client_id' => $clientId,
127
            'client_secret' => $clientSecret,
128
            'username' => $username,
129
            'password' => $password,
130
            'grant_type' => 'password',
131
        ]));
132
133
        $response = $this->getClient()->sendRequest($request);
134
        $responseBody = $response->getBody()->getContents();
135
        $this->token = $this->denormalizeObject(Token::class, [json_decode($responseBody)], false);
136
137
        return $this->token;
138
    }
139
140
    /**
141
     * @param string $clientId
142
     * @param string $clientSecret
143
     * @param string $refreshToken
144
     *
145
     * @throws \Http\Client\Exception
146
     *
147
     * @return Token
148
     */
149
    public function refreshToken($clientId, $clientSecret, $refreshToken): Token
150
    {
151
        $request = new Request('POST', $this->tokenUrl, [
152
            'Content-Type' => 'application/json',
153
        ], json_encode([
154
            'client_id' => $clientId,
155
            'client_secret' => $clientSecret,
156
            'refresh_token' => $refreshToken,
157
            'grant_type' => 'refresh_token',
158
        ]));
159
160
        $response = $this->getClient()->sendRequest($request);
161
        $responseBody = $response->getBody()->getContents();
162
163
        $this->token = $this->denormalizeObject(Token::class, [json_decode($responseBody)], false);
164
165
        return $this->token;
166
    }
167
168
    public function setToken(Token $token): Client
169
    {
170
        $this->token = $token;
171
172
        return $this;
173
    }
174
175
    /**
176
     * @return string
177
     */
178
    public function getApiUrl(): string
179
    {
180
        return $this->apiUrl;
181
    }
182
183
    /**
184
     * @param string $apiUrl
185
     *
186
     * @return Client
187
     */
188
    public function setApiUrl(string $apiUrl): Client
189
    {
190
        $this->apiUrl = $apiUrl;
191
192
        return $this;
193
    }
194
195
    /**
196
     * @return string
197
     */
198
    public function getApiVersion(): string
199
    {
200
        return $this->apiVersion;
201
    }
202
203
    /**
204
     * @param string $apiVersion
205
     *
206
     * @return Client
207
     */
208
    public function setApiVersion(string $apiVersion): Client
209
    {
210
        $this->apiVersion = $apiVersion;
211
212
        return $this;
213
    }
214
215
    /**
216
     * @return string
217
     */
218
    public function getApiUri(): string
219
    {
220
        return $this->apiUri;
221
    }
222
223
    /**
224
     * @param string $apiUri
225
     *
226
     * @return Client
227
     */
228
    public function setApiUri(string $apiUri): Client
229
    {
230
        $this->apiUri = $apiUri;
231
232
        return $this;
233
    }
234
235
    /**
236
     * @return string
237
     */
238
    public function getTokenUrl(): string
239
    {
240
        return $this->tokenUrl;
241
    }
242
243
    /**
244
     * @param string $tokenUrl
245
     *
246
     * @return Client
247
     */
248
    public function setTokenUrl(string $tokenUrl): Client
249
    {
250
        $this->tokenUrl = $tokenUrl;
251
252
        return $this;
253
    }
254
255
    public function denormalizeObject($hydrationClass, $dataObject, $isList = false)
256
    {
257
        $result = [];
258
259
        foreach ($dataObject as $data) {
260
            $result[] = $this->serializer->denormalize($data, $hydrationClass, null, [
261
                ObjectNormalizer::DISABLE_TYPE_ENFORCEMENT => true,
262
            ]);
263
        }
264
265
        if ($isList) {
266
            return $result;
267
        }
268
269
        return current($result);
270
    }
271
272
    protected function getClient(): HttpClient
273
    {
274
        return $this->client;
275
    }
276
277
    /**
278
     * @return Serializer
279
     */
280
    public function getSerializer(): Serializer
281
    {
282
        return $this->serializer;
283
    }
284
}
285