Completed
Push — master ( 4486c5...372f96 )
by Raza
01:29
created

DropboxClient   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 509
Duplicated Lines 8.84 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 91.37%

Importance

Changes 0
Metric Value
wmc 32
lcom 1
cbo 7
dl 45
loc 509
ccs 127
cts 139
cp 0.9137
rs 9.6
c 0
b 0
f 0

22 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A setClient() 0 12 2
A setAccessToken() 0 4 1
A copy() 11 11 1
A createFolder() 0 13 1
A delete() 0 10 1
A download() 0 12 1
A getMetaData() 0 10 1
A getTemporaryLink() 12 12 1
A getThumbnail() 0 14 1
A listFolder() 11 11 1
A listFolderContinue() 0 10 1
A move() 11 11 1
A upload() 0 22 2
A getAccountInfo() 0 6 1
A revokeToken() 0 6 1
A setupRequest() 0 4 1
A doDropboxApiRequest() 0 12 3
A setupDropboxHeaders() 0 14 2
A doDropboxApiContentRequest() 0 13 3
A normalizePath() 0 6 2
A determineException() 0 8 3

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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 Illuminate\Support\Collection;
9
use Srmklive\Dropbox\Exceptions\BadRequest;
10
use Srmklive\Dropbox\UploadContent;
11
12
class DropboxClient
13
{
14
    use UploadContent;
15
16
    const THUMBNAIL_FORMAT_JPEG = 'jpeg';
17
    const THUMBNAIL_FORMAT_PNG = 'png';
18
19
    const THUMBNAIL_SIZE_XS = 'w32h32';
20
    const THUMBNAIL_SIZE_S = 'w64h64';
21
    const THUMBNAIL_SIZE_M = 'w128h128';
22
    const THUMBNAIL_SIZE_L = 'w640h480';
23
    const THUMBNAIL_SIZE_XL = 'w1024h768';
24
25
    const MAX_CHUNK_SIZE = 150 * 1024 * 1024;
26
27
    /** @var \GuzzleHttp\Client */
28
    protected $client;
29
30
    /**
31
     * Dropbox OAuth access token.
32
     *
33
     * @var string
34
     */
35
    protected $accessToken;
36
37
    /**
38
     * Dropbox API v2 Url.
39
     *
40
     * @var string
41
     */
42
    protected $apiUrl;
43
44
    /**
45
     * Dropbox content API v2 url for uploading content.
46
     *
47
     * @var string
48
     */
49
    protected $apiContentUrl;
50
51
    /**
52
     * Dropbox API v2 endpoint.
53
     *
54
     * @var string
55
     */
56
    protected $apiEndpoint;
57
58
    /**
59
     * @var mixed
60
     */
61
    protected $content;
62
63
    /**
64
     * Collection containing Dropbox API request data.
65
     *
66
     * @var \Illuminate\Support\Collection
67
     */
68
    protected $request;
69
70
    /**
71 12
     * DropboxClient constructor.
72
     *
73 12
     * @param string             $token
74
     * @param \GuzzleHttp\Client $client
75 12
     */
76
    public function __construct($token, HttpClient $client = null)
77 12
    {
78 12
        $this->setAccessToken($token);
79 12
80
        $this->setClient($client);
81
82
        $this->apiUrl = 'https://api.dropboxapi.com/2/';
83
        $this->apiContentUrl = 'https://content.dropboxapi.com/2/';
84
    }
85
86 12
    /**
87
     * Set Http Client.
88 12
     *
89 11
     * @param \GuzzleHttp\Client $client
90 11
     */
91 1
    protected function setClient(HttpClient $client = null)
92
    {
93 1
        if ($client instanceof HttpClient) {
94 1
            $this->client = $client;
95 1
        } else {
96
            $this->client = new HttpClient([
97 12
                'headers' => [
98
                    'Authorization' => "Bearer {$this->accessToken}",
99
                ],
100
            ]);
101
        }
102
    }
103
104 12
    /**
105
     * Set Dropbox OAuth access token.
106 12
     *
107 12
     * @param string $token
108
     */
109
    protected function setAccessToken($token)
110
    {
111
        $this->accessToken = $token;
112
    }
113
114
    /**
115
     * Copy a file or folder to a different location in the user's Dropbox.
116
     *
117
     * If the source path is a folder all its contents will be copied.
118
     *
119
     * @param string $fromPath
120
     * @param string $toPath
121 1
     *
122
     * @return \Psr\Http\Message\ResponseInterface
123 1
     *
124 1
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-copy
125 1
     */
126 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...
127
    {
128 1
        $this->setupRequest([
129
            'from_path' => $this->normalizePath($fromPath),
130 1
            'to_path'   => $this->normalizePath($toPath),
131
        ]);
132
133
        $this->apiEndpoint = 'files/copy';
134
135
        return $this->doDropboxApiRequest();
136
    }
137
138
    /**
139
     * Create a folder at a given path.
140
     *
141
     * @param string $path
142 1
     *
143
     * @return \Psr\Http\Message\ResponseInterface
144 1
     *
145 1
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-create_folder
146 1
     */
147
    public function createFolder($path)
148 1
    {
149
        $this->setupRequest([
150 1
            'path' => $this->normalizePath($path),
151 1
        ]);
152
153 1
        $this->apiEndpoint = 'files/create_folder';
154
155
        $response = $this->doDropboxApiRequest();
156
        $response['.tag'] = 'folder';
157
158
        return $response;
159
    }
160
161
    /**
162
     * Delete the file or folder at a given path.
163
     *
164
     * If the path is a folder, all its contents will be deleted too.
165
     * A successful response indicates that the file or folder was deleted.
166
     *
167
     * @param string $path
168 1
     *
169
     * @return \Psr\Http\Message\ResponseInterface
170 1
     *
171 1
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-delete
172 1
     */
173
    public function delete($path)
174 1
    {
175
        $this->setupRequest([
176 1
            'path' => $this->normalizePath($path),
177
        ]);
178
179
        $this->apiEndpoint = 'files/delete';
180
181
        return $this->doDropboxApiRequest();
182
    }
183
184
    /**
185
     * Download a file from a user's Dropbox.
186
     *
187
     * @param string $path
188 1
     *
189
     * @return resource
190 1
     *
191 1
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-download
192 1
     */
193
    public function download($path)
194 1
    {
195
        $this->setupRequest([
196 1
            'path' => $this->normalizePath($path),
197
        ]);
198 1
199
        $this->apiEndpoint = 'files/download';
200
201
        $response = $this->doDropboxApiContentRequest();
202
203
        return StreamWrapper::getResource($response->getBody());
204
    }
205
206
    /**
207
     * Returns the metadata for a file or folder.
208
     *
209
     * Note: Metadata for the root folder is unsupported.
210
     *
211
     * @param string $path
212 1
     *
213
     * @return \Psr\Http\Message\ResponseInterface
214 1
     *
215 1
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-get_metadata
216 1
     */
217
    public function getMetaData($path)
218 1
    {
219
        $this->setupRequest([
220 1
            'path' => $this->normalizePath($path),
221
        ]);
222
223
        $this->apiEndpoint = 'files/get_metadata';
224
225
        return $this->doDropboxApiRequest();
226
    }
227
228
    /**
229
     * Get a temporary link to stream content of a file.
230
     *
231
     * This link will expire in four hours and afterwards you will get 410 Gone.
232
     * Content-Type of the link is determined automatically by the file's mime type.
233
     *
234
     * @param string $path
235 1
     *
236
     * @return string
237 1
     *
238 1
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-get_temporary_link
239 1
     */
240 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...
241 1
    {
242
        $this->setupRequest([
243 1
            'path' => $this->normalizePath($path),
244
        ]);
245 1
246
        $this->apiEndpoint = 'files/get_temporary_link';
247
248
        $response = $this->doDropboxApiRequest();
249
250
        return $response['link'];
251
    }
252
253
    /**
254
     * Get a thumbnail for an image.
255
     *
256
     * This method currently supports files with the following file extensions:
257
     * jpg, jpeg, png, tiff, tif, gif and bmp.
258
     *
259
     * Photos that are larger than 20MB in size won't be converted to a thumbnail.
260
     *
261
     * @param string $path
262 1
     * @param string $format
263
     * @param string $size
264 1
     *
265 1
     * @return string
266 1
     */
267 1
    public function getThumbnail($path, $format = 'jpeg', $size = 'w64h64')
268 1
    {
269
        $this->setupRequest([
270 1
            'path'   => $this->normalizePath($path),
271
            'format' => $format,
272 1
            'size'   => $size,
273
        ]);
274 1
275
        $this->apiEndpoint = 'files/get_thumbnail';
276
277
        $response = $this->doDropboxApiContentRequest();
278
279
        return (string) $response->getBody();
280
    }
281
282
    /**
283
     * Starts returning the contents of a folder.
284
     *
285
     * If the result's ListFolderResult.has_more field is true, call
286
     * list_folder/continue with the returned ListFolderResult.cursor to retrieve more entries.
287
     *
288
     * Note: auth.RateLimitError may be returned if multiple list_folder or list_folder/continue calls
289
     * with same parameters are made simultaneously by same API app for same user. If your app implements
290
     * retry logic, please hold off the retry until the previous request finishes.
291
     *
292
     * @param string $path
293
     * @param bool   $recursive
294 1
     *
295
     * @return \Psr\Http\Message\ResponseInterface
296 1
     *
297 1
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-list_folder
298 1
     */
299 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...
300
    {
301 1
        $this->setupRequest([
302
            'path'      => $this->normalizePath($path),
303 1
            'recursive' => $recursive,
304
        ]);
305
306
        $this->apiEndpoint = 'files/list_folder';
307
308
        return $this->doDropboxApiRequest();
309
    }
310
311
    /**
312
     * Once a cursor has been retrieved from list_folder, use this to paginate through all files and
313
     * retrieve updates to the folder, following the same rules as documented for list_folder.
314
     *
315
     * @param string $cursor
316 1
     *
317
     * @return \Psr\Http\Message\ResponseInterface
318 1
     *
319 1
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-list_folder-continue
320 1
     */
321
    public function listFolderContinue($cursor = '')
322 1
    {
323
        $this->setupRequest([
324 1
            'cursor' => $cursor,
325
        ]);
326
327
        $this->apiEndpoint = 'files/list_folder/continue';
328
329
        return $this->doDropboxApiRequest();
330
    }
331
332
    /**
333
     * Move a file or folder to a different location in the user's Dropbox.
334
     *
335
     * If the source path is a folder all its contents will be moved.
336
     *
337
     * @param string $fromPath
338
     * @param string $toPath
339 1
     *
340
     * @return \Psr\Http\Message\ResponseInterface
341 1
     *
342 1
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-move
343 1
     */
344 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...
345
    {
346 1
        $this->setupRequest([
347
            'from_path' => $this->normalizePath($fromPath),
348 1
            'to_path'   => $this->normalizePath($toPath),
349
        ]);
350
351
        $this->apiEndpoint = 'files/move_v2';
352
353
        return $this->doDropboxApiRequest();
354
    }
355
356
    /**
357
     * Create a new file with the contents provided in the request.
358
     *
359
     * Do not use this to upload a file larger than 150 MB. Instead, create an upload session with upload_session/start.
360
     *
361
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-upload
362
     *
363
     * @param string          $path
364 1
     * @param string|resource $contents
365
     * @param string|array    $mode
366 1
     *
367 1
     * @return array
368 1
     */
369 1
    public function upload($path, $contents, $mode = 'add')
370
    {
371 1
        if ($this->shouldUploadChunk($contents)) {
372
            return $this->uploadChunk($path, $contents, $mode);
0 ignored issues
show
Bug introduced by
It seems like $mode defined by parameter $mode on line 369 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...
373 1
        }
374
375 1
        $this->setupRequest([
376
            'path' => $this->normalizePath($path),
377 1
            'mode' => $mode,
378 1
        ]);
379
380 1
        $this->content = $contents;
381
382
        $this->apiEndpoint = 'files/upload';
383
384
        $response = $this->doDropboxApiContentRequest();
385
386
        $metadata = json_decode($response->getBody(), true);
387
        $metadata['.tag'] = 'file';
388
389
        return $metadata;
390
    }
391
392
    /**
393
     * Get Account Info for current authenticated user.
394
     *
395
     * @link https://www.dropbox.com/developers/documentation/http/documentation#users-get_current_account
396
     *
397
     * @return \Psr\Http\Message\ResponseInterface
398
     */
399
    public function getAccountInfo()
400
    {
401
        $this->apiEndpoint = 'users/get_current_account';
402
403
        return $this->doDropboxApiRequest();
404
    }
405
406
    /**
407
     * Revoke current access token.
408
     *
409
     * @link https://www.dropbox.com/developers/documentation/http/documentation#auth-token-revoke
410
     *
411
     * @return \Psr\Http\Message\ResponseInterface
412
     */
413
    public function revokeToken()
414
    {
415
        $this->apiEndpoint = 'auth/token/revoke';
416 11
417
        return $this->doDropboxApiRequest();
418 11
    }
419 11
420
    /**
421
     * Set Dropbox API request data.
422
     *
423
     * @param array $request
424
     */
425
    protected function setupRequest($request)
426
    {
427
        $this->request = new Collection($request);
428 8
    }
429
430
    /**
431 8
     * Perform Dropbox API request.
432 8
     *
433 8
     * @throws \Exception
434 8
     *
435
     * @return \Psr\Http\Message\ResponseInterface
436
     */
437
    protected function doDropboxApiRequest()
438 7
    {
439
        $request = empty($this->request) ? [] : ['json' => $this->request->toArray()];
440
441
        try {
442
            $response = $this->client->post("{$this->apiUrl}{$this->apiEndpoint}", $request);
443
        } catch (HttpClientException $exception) {
444
            throw $this->determineException($exception);
445
        }
446 3
447
        return json_decode($response->getBody(), true);
448
    }
449 3
450 3
    /**
451 3
     * Setup headers for Dropbox API request.
452 3
     *
453
     * @return array
454 3
     */
455 1
    protected function setupDropboxHeaders()
456 1
    {
457
        $headers = [
458 3
            'Dropbox-API-Arg' => json_encode(
459
                $this->request->toArray()
460
            ),
461
        ];
462
463
        if (!empty($this->content)) {
464
            $headers['Content-Type'] = 'application/octet-stream';
465
        }
466
467
        return $headers;
468 3
    }
469
470
    /**
471 3
     * Perform Dropbox API request.
472 3
     *
473 3
     * @throws \Exception
474 3
     *
475 3
     * @return \Psr\Http\Message\ResponseInterface
476
     */
477
    protected function doDropboxApiContentRequest()
478
    {
479 3
        try {
480
            $response = $this->client->post("{$this->apiContentUrl}{$this->apiEndpoint}", [
481
                'headers' => $this->setupDropboxHeaders(),
482
                'body'    => !empty($this->content) ? $this->content : '',
483
            ]);
484
        } catch (HttpClientException $exception) {
485
            throw $this->determineException($exception);
486
        }
487
488
        return $response;
489 10
    }
490
491 10
    /**
492
     * Normalize path.
493 10
     *
494
     * @param string $path
495
     *
496
     * @return string
497
     */
498
    protected function normalizePath($path)
499
    {
500
        $path = (trim($path, '/') === '') ? '' : '/'.$path;
501
502
        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