Completed
Pull Request — master (#7)
by
unknown
01:38
created

DropboxClient::doDropboxApiContentRequest()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3.072

Importance

Changes 0
Metric Value
dl 0
loc 14
ccs 8
cts 10
cp 0.8
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 10
nc 2
nop 0
crap 3.072
1
<?php
2
3
namespace Srmklive\Dropbox\Client;
4
5
use GuzzleHttp\Client as HttpClient;
6
use GuzzleHttp\Exception\ClientException as HttpClientException;
7
use GuzzleHttp\Psr7\StreamWrapper;
8
use Srmklive\Dropbox\Exceptions\BadRequest;
9
use Srmklive\Dropbox\UploadContent;
10
11
class DropboxClient
12
{
13
    use UploadContent;
14
15
    const THUMBNAIL_FORMAT_JPEG = 'jpeg';
16
    const THUMBNAIL_FORMAT_PNG = 'png';
17
18
    const THUMBNAIL_SIZE_XS = 'w32h32';
19
    const THUMBNAIL_SIZE_S = 'w64h64';
20
    const THUMBNAIL_SIZE_M = 'w128h128';
21
    const THUMBNAIL_SIZE_L = 'w640h480';
22
    const THUMBNAIL_SIZE_XL = 'w1024h768';
23
24
    const MAX_CHUNK_SIZE = 157286400;
25
26
    /** @var \GuzzleHttp\Client */
27
    protected $client;
28
29
    /**
30
     * Dropbox OAuth access token.
31
     *
32
     * @var string
33
     */
34
    protected $accessToken;
35
36
    /**
37
     * Dropbox API v2 Url.
38
     *
39
     * @var string
40
     */
41
    protected $apiUrl;
42
43
    /**
44
     * Dropbox content API v2 url for uploading content.
45
     *
46
     * @var string
47
     */
48
    protected $apiContentUrl;
49
50
    /**
51
     * Dropbox API v2 endpoint.
52
     *
53
     * @var string
54
     */
55
    protected $apiEndpoint;
56
57
    /**
58
     * @var mixed
59
     */
60
    protected $content;
61
62
    /**
63
     * Dropbox API request data.
64
     *
65
     * @var array
66
     */
67
    protected $request;
68
69
    /**
70
     * DropboxClient constructor.
71
     *
72
     * @param string             $token
73
     * @param \GuzzleHttp\Client $client
74
     */
75 20
    public function __construct($token, HttpClient $client = null)
76
    {
77 20
        $this->setAccessToken($token);
78
79 20
        $this->setClient($client);
80
81 20
        $this->apiUrl = 'https://api.dropboxapi.com/2/';
82 20
        $this->apiContentUrl = 'https://content.dropboxapi.com/2/';
83 20
    }
84
85
    /**
86
     * Set Http Client.
87
     *
88
     * @param \GuzzleHttp\Client $client
89
     */
90 20
    protected function setClient(HttpClient $client = null)
91
    {
92 20
        if ($client instanceof HttpClient) {
93 16
            $this->client = $client;
94 16
        } else {
95 4
            $this->client = new HttpClient([
96
                'headers' => [
97 4
                    'Authorization' => "Bearer {$this->accessToken}",
98 4
                ],
99 4
            ]);
100
        }
101 20
    }
102
103
    /**
104
     * Set Dropbox OAuth access token.
105
     *
106
     * @param string $token
107
     */
108 20
    protected function setAccessToken($token)
109
    {
110 20
        $this->accessToken = $token;
111 20
    }
112
113
    /**
114
     * Copy a file or folder to a different location in the user's Dropbox.
115
     *
116
     * If the source path is a folder all its contents will be copied.
117
     *
118
     * @param string $fromPath
119
     * @param string $toPath
120
     *
121
     * @return \Psr\Http\Message\ResponseInterface
122
     *
123
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-copy
124
     */
125 1 View Code Duplication
    public function copy($fromPath, $toPath)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
126
    {
127 1
        $this->setupRequest([
128 1
            'from_path' => $this->normalizePath($fromPath),
129 1
            'to_path'   => $this->normalizePath($toPath),
130 1
        ]);
131
132 1
        $this->apiEndpoint = 'files/copy';
133
134 1
        return $this->doDropboxApiRequest();
135
    }
136
137
    /**
138
     * Create a folder at a given path.
139
     *
140
     * @param string $path
141
     *
142
     * @return \Psr\Http\Message\ResponseInterface
143
     *
144
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-create_folder
145
     */
146 1
    public function createFolder($path)
147
    {
148 1
        $this->setupRequest([
149 1
            'path' => $this->normalizePath($path),
150 1
        ]);
151
152 1
        $this->apiEndpoint = 'files/create_folder';
153
154 1
        $response = $this->doDropboxApiRequest();
155 1
        $response['.tag'] = 'folder';
156
157 1
        return $response;
158
    }
159
160
    /**
161
     * Delete the file or folder at a given path.
162
     *
163
     * If the path is a folder, all its contents will be deleted too.
164
     * A successful response indicates that the file or folder was deleted.
165
     *
166
     * @param string $path
167
     *
168
     * @return \Psr\Http\Message\ResponseInterface
169
     *
170
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-delete
171
     */
172 1
    public function delete($path)
173
    {
174 1
        $this->setupRequest([
175 1
            'path' => $this->normalizePath($path),
176 1
        ]);
177
178 1
        $this->apiEndpoint = 'files/delete';
179
180 1
        return $this->doDropboxApiRequest();
181
    }
182
183
    /**
184
     * Download a file from a user's Dropbox.
185
     *
186
     * @param string $path
187
     *
188
     * @return resource
189
     *
190
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-download
191
     */
192 1
    public function download($path)
193
    {
194 1
        $this->setupRequest([
195 1
            'path' => $this->normalizePath($path),
196 1
        ]);
197
198 1
        $this->apiEndpoint = 'files/download';
199
200 1
        $response = $this->doDropboxApiContentRequest();
201
202 1
        return StreamWrapper::getResource($response->getBody());
203
    }
204
205
    /**
206
     * Returns the metadata for a file or folder.
207
     *
208
     * Note: Metadata for the root folder is unsupported.
209
     *
210
     * @param string $path
211
     *
212
     * @return \Psr\Http\Message\ResponseInterface
213
     *
214
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-get_metadata
215
     */
216 1
    public function getMetaData($path)
217
    {
218 1
        $this->setupRequest([
219 1
            'path' => $this->normalizePath($path),
220 1
        ]);
221
222 1
        $this->apiEndpoint = 'files/get_metadata';
223
224 1
        return $this->doDropboxApiRequest();
225
    }
226
227
    /**
228
     * Get a temporary link to stream content of a file.
229
     *
230
     * This link will expire in four hours and afterwards you will get 410 Gone.
231
     * Content-Type of the link is determined automatically by the file's mime type.
232
     *
233
     * @param string $path
234
     *
235
     * @return string
236
     *
237
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-get_temporary_link
238
     */
239 1 View Code Duplication
    public function getTemporaryLink($path)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
240
    {
241 1
        $this->setupRequest([
242 1
            'path' => $this->normalizePath($path),
243 1
        ]);
244
245 1
        $this->apiEndpoint = 'files/get_temporary_link';
246
247 1
        $response = $this->doDropboxApiRequest();
248
249 1
        return $response['link'];
250
    }
251
252
    /**
253
     * Get a thumbnail for an image.
254
     *
255
     * This method currently supports files with the following file extensions:
256
     * jpg, jpeg, png, tiff, tif, gif and bmp.
257
     *
258
     * Photos that are larger than 20MB in size won't be converted to a thumbnail.
259
     *
260
     * @param string $path
261
     * @param string $format
262
     * @param string $size
263
     *
264
     * @return string
265
     */
266 1
    public function getThumbnail($path, $format = 'jpeg', $size = 'w64h64')
267
    {
268 1
        $this->setupRequest([
269 1
            'path'   => $this->normalizePath($path),
270 1
            'format' => $format,
271 1
            'size'   => $size,
272 1
        ]);
273
274 1
        $this->apiEndpoint = 'files/get_thumbnail';
275
276 1
        $response = $this->doDropboxApiContentRequest();
277
278 1
        return (string) $response->getBody();
279
    }
280
281
    /**
282
     * Starts returning the contents of a folder.
283
     *
284
     * If the result's ListFolderResult.has_more field is true, call
285
     * list_folder/continue with the returned ListFolderResult.cursor to retrieve more entries.
286
     *
287
     * Note: auth.RateLimitError may be returned if multiple list_folder or list_folder/continue calls
288
     * with same parameters are made simultaneously by same API app for same user. If your app implements
289
     * retry logic, please hold off the retry until the previous request finishes.
290
     *
291
     * @param string $path
292
     * @param bool   $recursive
293
     *
294
     * @return \Psr\Http\Message\ResponseInterface
295
     *
296
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-list_folder
297
     */
298 1 View Code Duplication
    public function listFolder($path = '', $recursive = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
299
    {
300 1
        $this->setupRequest([
301 1
            'path'      => $this->normalizePath($path),
302 1
            'recursive' => $recursive,
303 1
        ]);
304
305 1
        $this->apiEndpoint = 'files/list_folder';
306
307 1
        return $this->doDropboxApiRequest();
308
    }
309
310
    /**
311
     * Once a cursor has been retrieved from list_folder, use this to paginate through all files and
312
     * retrieve updates to the folder, following the same rules as documented for list_folder.
313
     *
314
     * @param string $cursor
315
     *
316
     * @return \Psr\Http\Message\ResponseInterface
317
     *
318
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-list_folder-continue
319
     */
320 1
    public function listFolderContinue($cursor = '')
321
    {
322 1
        $this->setupRequest([
323 1
            'cursor' => $cursor,
324 1
        ]);
325
326 1
        $this->apiEndpoint = 'files/list_folder/continue';
327
328 1
        return $this->doDropboxApiRequest();
329
    }
330
331
    /**
332
     * Move a file or folder to a different location in the user's Dropbox.
333
     *
334
     * If the source path is a folder all its contents will be moved.
335
     *
336
     * @param string $fromPath
337
     * @param string $toPath
338
     *
339
     * @return \Psr\Http\Message\ResponseInterface
340
     *
341
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-move
342
     */
343 1 View Code Duplication
    public function move($fromPath, $toPath)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
344
    {
345 1
        $this->setupRequest([
346 1
            'from_path' => $this->normalizePath($fromPath),
347 1
            'to_path'   => $this->normalizePath($toPath),
348 1
        ]);
349
350 1
        $this->apiEndpoint = 'files/move_v2';
351
352 1
        return $this->doDropboxApiRequest();
353
    }
354
355
    /**
356
     * Create a new file with the contents provided in the request.
357
     *
358
     * Do not use this to upload a file larger than 150 MB. Instead, create an upload session with upload_session/start.
359
     *
360
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-upload
361
     *
362
     * @param string          $path
363
     * @param string|resource $contents
364
     * @param string|array    $mode
365
     *
366
     * @return array
367
     */
368 1
    public function upload($path, $contents, $mode = 'add')
369
    {
370 1
        if ($this->shouldUploadChunk($contents)) {
371
            return $this->uploadChunk($path, $contents, $mode);
0 ignored issues
show
Bug introduced by
It seems like $mode defined by parameter $mode on line 368 can also be of type array; however, Srmklive\Dropbox\UploadContent::uploadChunk() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
372
        }
373
374 1
        $this->setupRequest([
375 1
            'path' => $this->normalizePath($path),
376 1
            'mode' => $mode,
377 1
        ]);
378
379 1
        $this->content = $contents;
380
381 1
        $this->apiEndpoint = 'files/upload';
382
383 1
        $response = $this->doDropboxApiContentRequest();
384
385 1
        $metadata = json_decode($response->getBody(), true);
386 1
        $metadata['.tag'] = 'file';
387
388 1
        return $metadata;
389
    }
390
391
    /**
392
     * Get Account Info for current authenticated user.
393
     *
394
     * @link https://www.dropbox.com/developers/documentation/http/documentation#users-get_current_account
395
     *
396
     * @return \Psr\Http\Message\ResponseInterface
397
     */
398 1
    public function getAccountInfo()
399
    {
400 1
        $this->apiEndpoint = 'users/get_current_account';
401
402 1
        return $this->doDropboxApiRequest();
403
    }
404
405
    /**
406
     * Revoke current access token.
407
     *
408
     * @link https://www.dropbox.com/developers/documentation/http/documentation#auth-token-revoke
409
     *
410
     * @return \Psr\Http\Message\ResponseInterface
411
     */
412 1
    public function revokeToken()
413
    {
414 1
        $this->apiEndpoint = 'auth/token/revoke';
415
416 1
        return $this->doDropboxApiRequest();
417
    }
418
419
    /**
420
     * Set Dropbox API request data.
421
     *
422
     * @param array $request
423
     */
424 14
    protected function setupRequest($request)
425
    {
426 14
        $this->request = $request;
427 14
    }
428
429
    /**
430
     * Perform Dropbox API request.
431
     *
432
     * @throws \Exception
433
     *
434
     * @return \Psr\Http\Message\ResponseInterface
435
     */
436 10
    protected function doDropboxApiRequest()
437
    {
438 10
        $request = empty($this->request) ? [] : ['json' => $this->request];
439
440
        try {
441 10
            $response = $this->client->post("{$this->apiUrl}{$this->apiEndpoint}", $request);
442 10
        } catch (HttpClientException $exception) {
443
            throw $this->determineException($exception);
444
        }
445
446 10
        return json_decode($response->getBody(), true);
447
    }
448
449
    /**
450
     * Setup headers for Dropbox API request.
451
     *
452
     * @return array
453
     */
454 6
    protected function setupDropboxHeaders()
455
    {
456
        $headers = [
457 6
            'Dropbox-API-Arg' => json_encode(
458 6
                $this->request
459 6
            ),
460 6
        ];
461
462 6
        if (!empty($this->content)) {
463 4
            $headers['Content-Type'] = 'application/octet-stream';
464 4
        }
465
466 6
        return $headers;
467
    }
468
469
    /**
470
     * Perform Dropbox API request.
471
     *
472
     * @throws \Exception
473
     *
474
     * @return \Psr\Http\Message\ResponseInterface
475
     */
476 6
    protected function doDropboxApiContentRequest()
477
    {
478
        try {
479 6
            $response = $this->client->post("{$this->apiContentUrl}{$this->apiEndpoint}", [
480 6
                'headers' => $this->setupDropboxHeaders(),
481 6
                'body'    => !empty($this->content) ? $this->content : '',
482 6
            ]);
483 6
        } catch (HttpClientException $exception) {
484
            $this->content = null;
485
            throw $this->determineException($exception);
486
        }
487 6
        $this->content = null;
488 6
        return $response;
489
    }
490
491
    /**
492
     * Normalize path.
493
     *
494
     * @param string $path
495
     *
496
     * @return string
497
     */
498 10
    protected function normalizePath($path)
499
    {
500 10
        $path = (trim($path, '/') === '') ? '' : '/'.$path;
501
502 10
        return str_replace('//', '/', $path);
503
    }
504
505
    /**
506
     * Catch Dropbox API request exception.
507
     *
508
     * @param HttpClientException $exception
509
     *
510
     * @return \Exception
511
     */
512
    protected function determineException(HttpClientException $exception)
513
    {
514
        if (!empty($exception->getResponse()) && in_array($exception->getResponse()->getStatusCode(), [400, 409])) {
515
            return new BadRequest($exception->getResponse());
516
        }
517
518
        return $exception;
519
    }
520
}
521